This question already exists:
writing a Makefile that compiles an executable [closed]
Closed 9 years ago.
Apologize in advance, I asked a similar question earlier but I didn't get a clear answer and I'm desperate since I've been trying to figure it out for 6 hours without a teacher and since my assignments due tonight I just can't take it any more. I have directory with just one file in it: "proj1.cpp" with a lot of code on it. I need to use a file 'makefile' in the same directory (it's named makefile), in order to "compile an executable called: proj1.x". (I have to do this in Linux by the way, through an SSH shell).
I'd really appreciate if someone could sort of walk me through step my step instructions how / why to do this for my situation and not just redirect me to a different page? I only ask because I know the solution is easy to an experienced programmer.
You can do the job very simply:
proj1.x: proj1.cpp
${CXX} ${CXXFLAGS} -o $# proj1.cpp
That's two lines of makefile. There must be a Tab at the start of the second line. The first line says that proj1.x depends on proj1.cpp; if proj1.cpp is newer than proj1.x (or proj1.x does not exist), then do the actions on the second line. The second line runs the C++ compiler to produce proj1.x (that's the $#; you could write proj1.x there if you wanted to, though $# is better in the long run). I'm assuming your make uses ${CXX} for the C++ compiler, and ${CXXFLAGS} for the compiler options. If you need extra libraries, you can add those. Etc.
That's a completely bare-bones makefile. It will probably get you going. (Incidentally, 188 lines of code is not a lot.)
Adding libraries:
LDFLAGS = -L …
LDLIBS = -lxyz -lpqr
proj1.x: proj1.cpp
${CXX} ${CXXFLAGS} -o $# proj1.cpp ${LDFLAGS} ${LDLIBS}
Note that many (probably most) people use the alternative $(VAR) notation in preference to ${VAR}. I prefer the curly brace notation, so that's what I use unless there's a coding standard to the contrary — but you've been informed of the alternative.
Note that source files and object files are listed before libraries unless you've got a very good reason to do otherwise.
Related
I want to type the following:
make fileName.cpp
To compile, and then to execute:
./fileName
If I have a make file like this:
commandToCompileFileName:
g++ -o fileName fileName.cpp
Then I can do:
make commandToCompileFileName
And then:
./fileName
I want to be able to do this with different files, without having to write a different prompt for each of them in makefile. So something would be in place of
commandToCompileFileName
in the makefile that would just compile whatever I type in after make, and the executable would just be named the same minus the .cpp.
This page in the very first paragraph describes precisely what I want and probably answers my question, yet I couldn't figure it out after playing around with '$#' and '$<'.
You actually do not need a Makefile to do this: make ships with a whole bunch of default rules, one of which creates programs from .cpp files.
In other words, just type make fileName, and be happy :)
(if you want to custom compilation flags, see the CXXFLAGS and LDFLAGS variables)
I use the following:
run_% : %
#echo "---- running $< ----"
$<
.PHONY : run_%
So that when you do, for example, make run_test it builds test target and runs it.
How this simple make script knows that some of cpp files is changed? Does it means that for each .o file it will look for corresponding .cpp one? What if extension will be different - for example .c
hellomake: hellomake.o hellofunc.o
gcc -o hellomake hellomake.o hellofunc.o -I.
UPD:
According to my understanding scrip I provide should not look to c and cpp files. And when I asked to build project second time MAKE told me "make: 'hellomake' is up to date.
But I was surprised when I have changed hellomake.cpp MAKE has decided do rebuild project. Why?
GNU make has many builtin rules. Run make -p to find them. And use the existing rules in your Makefile, see this or that or this
Obvious documentation links were already provided. I just wanted to comment on your example. You told make the following:
The file hellomake relies on hellomake.o and hellofunc.o, ie. both are prerequisites of hellomake. If any prerequisite changes since the last build, hellomake will be rebuilt. How (re-) building is done is the second line, ie. the gcc invocation.
To answer your question: The snippet provided, will not look for any cpp files. You need different rules in addition for that, ie. something like
%.o: %.cpp
gcc -I. -c #< -o $#
In case you are searching for a rather generic Makefile to start with, I'd recommend this one. It has been the basis for many of my Makefiles in use.
I generated a makefile out of a codeblocks project (written in c++11), so I can use Atom as IDE. But it does not update the object files when I i.e. change the default constructors parameter in the header file, which is really annoying. It just links the existing object files again. But even if I make a little change to the .cpp file, it recompiles the object without recognizing the changes in the header file. The only quick fix I found is to delete the object file manually, so it really generates it completely new. The header part I currently often change looks like this:
VRParticles(): VRParticles(123){}
The whole makefile is available here (generated using cbp2make): https://github.com/Pfeil/polyvr/blob/master/Makefile
(Please note that I am just a fairly new contributor and not responsible for the way this is programmed ;) )
I use the makefile mostly with one of those two commands:
make -j 3 build_debug
make debug
Note that everything compiles fine when I delete VRParticles.o or do make clean and make debug.
Please note that my experience with makefiles is very low. The makefile basically works like this (remember the link to the full version above):
OBJ_DEBUG = # all object files
build_debug: before_debug out_debug after_debug
debug: before_build build_debug after_build
out_debug: before_debug $(OBJ_DEBUG) $(DEP_DEBUG)
$(LD) $(LIBDIR_DEBUG) -o $(OUT_DEBUG) $(OBJ_DEBUG) $(LDFLAGS_DEBUG) $(LIB_DEBUG)
$(OBJDIR_DEBUG)/src/addons/Bullet/Particles/VRParticles.o: src/addons/Bullet/Particles/VRParticles.cpp
$(CXX) $(CFLAGS_DEBUG) $(INC_DEBUG) -c src/addons/Bullet/Particles/VRParticles.cpp -o $(OBJDIR_DEBUG)/src/addons/Bullet/Particles/VRParticles.o
I'd really like give more information, but I have no idea what else could be important, so please ask if you need more. My question basically is how I need to modify the makefile (I guess this file contains the issue) so the object files get updated if needed. Without recompiling everything.
I'm on Linux (Ubuntu 14.04 LTS).
If we look at your dependencies for VRParticles.o:
VRParticles.o : src/addons/Bullet/Particles/VRParticles.cpp
You are telling make that the object file only depends on VRParticles.cpp. So when you update VRParticles.h, that doesn't matter - you never listed VRParticles.h as a dependency! Thankfully, gcc can generate those dependencies for you automatically:
$(CC) $(other flag stuff) -MP -MMD -MF $(#:.o=.d) -o $# -c $<
That will create a file VRParticles.d which will have make-style rules for dependencies, in this case something like:
VRParticles.o : VRParticles.d
So at that point, all we need is to include them:
DEPENDENCY_FILES = $(....)
-include $(DEPENDENCY_FILES)
I should preface this by saying I am very new to Makefiles.
I created the following Makefile:
all: tiling_graph.o
g++ -o tiling_graph tiling_graph.o -L/usr/local/lib -ligraph
I am trying to make sure that -ligraph is included. However, when I type "make", I get the following output: "c++ -c -o tiling_graph.o tiling_graph.cpp"
Why is it not using the Makefile that I created in the current directory? I have tried using "make -f Makefile" and "make --file=Makefile" but none of these are working.
Also, right after I first made the Makefile, it worked correctly. The output after typing make was
"g++ -o tiling_graph tiling_graph.o -L/usr/local/lib -ligraph"
I executed ./tiling_graph and it was successful.
Then I edited tiling_graph.cpp, ran make again, and the output was "c++ -c -o tiling_graph.o tiling_graph.cpp" and has been ever since.
I would really appreciate any help. Thanks!
A simple way to think about a make rule:
target: dependency list
commands to make the target
is that it is a recipe for making the file called target from the list of files in the dependency list. Since make can see the file system, it can tell whether any file in the dependency list is newer than the file named target, which is its signal for recreating target. After all, if none of the dependencies have changed, the target must be up-to-date.
Note that make knows quite a lot about how to build files. In particular, it has a lot of built-in "pattern" rules, so it knows, for example, how to make an object file (prog.o) from a C++ source file (prog.cpp) or from a C source file (prog.c) or many other things. So you only need to actually write a makefile when you have other requirements, like a library (and even then you could just add that to an environment variable, but the makefile is better).
Now, you don't actually want to build a file called all. You want to build a file called tiling_graph. So the correct make rule would be:
tiling_graph: tiling_graph.o
g++ -o tiling_graph tiling_graph.o -L/usr/local/lib -ligraph
Since make already knows how to create tiling_graph.o, it can actually figure out how to make tiling_graph from tiling_graph.cpp.
So where does this all come from? The usual way to use all is:
all: program1 program2 program3
which tells make that the all target requires program1, program2 and program3. So if you need to build all three of those programs, the all rule would let you just do one make command. Since there is no file named all, that's a "phony" target and (with gnu make, at least) it should be declared as a phony target:
all: tiling_graph
.PHONY: all
But you really don't need that if you just want to build one program.
When you just type make (as opposed to make target), make chooses the first target in the makefile. So if you put the thing you usually want to build first, you'll save some typing.
I'm setting up Autotools for a large scientific code written primarily in C++, but also some CUDA. I've found an example for compiling & linking CUDA code to C code within Autotools, but I cannot duplicate that success with C++ code. I've heard that this is much easier with CMake, but we're committed to Autotools, unfortunately.
In our old hand-written Makefile, we simply use a make rule to compile 'cuda_kernels.cu' into 'cuda_kernels.o' using nvcc, and add cuda_kernels.o to the list of objects to be compiled into the final binary. Nice, simple, and it works.
The basic strategy with Autotools, on the other hand, seems to be to use Libtool to compile the .cu files into a 'libcudafiles.la', and then link the rest of the code against that library. However, this fails upon linking, with a whole bunch of "undefined reference to ..." statements coming from the linker. This seems like it might be a name-mangling issue with g++ vs. the nvcc compiler (which would explain why it works with C code), but I'm not sure what to do at this point.
All .cpp and .cu files are in the top/src directory, and all the compilation is done in the top/obj directory. Here's the relevant details of obj/Makefile.am:
cuda_kernals.cu.o:
$(NVCC) -gencode=arch=compute_20,code=sm_20 -o $# -c $<
libcudafiles_la_LINK= $(LIBTOOL) --mode=link $(CXX) -o $# $(CUDA_LDFLAGS) $(CUDA_LIBS)
noinst_LTLIBRARIES = libcudafiles.la
libcudafiles_la_SOURCES = ../src/cuda_kernels.cu
___bin_main_LDADD += libcudafiles.la
___bin_main_LDFLAGS += -static
For reference, the example which I managed to get working on our GPU cluster is available at clusterchimps.org.
Any help is appreciated!
libtool in conjunction with automake currently generates foo.lo (libtool-object metadata) files, the non-PIC (static) object foo.o, and the PIC object .libs/foo.o.
For consistent .lo files, I'd use a rule like:
.cu.lo:
$(LIBTOOL) --tag=CC --mode=compile $(NVCC) [options...] -c $<
I have no idea if, or how, -PIC flags are handled by nvcc. More options here. I don't know what calls you are making from the program, but are you forward declaring CUDA code with C linkage? e.g.,
extern "C" void cudamain (....);
It seems others have run up against the libtool problem. At worst, you might need a 'script' solution that mimics the .lo syntax and file locations, as described on the clusterchimps site.