Since it is said that order of dependencies does matter in a makefile. I wish to understand how:
finalObjectFile: x.o main.o y.o
g++ x.o main.o y.o -o finalObjectFile
main.o: header/x.h source/main.cpp
g++ -c source/main.cpp
x.o: header/x.h source/x.cpp
g++ -c source/x.cpp
y.o: source/y.cpp header/x.h
g++ -c source/y.cpp
In the above code I have swapped the positions of the header file x.h:
x.o: header/x.h source/x.cpp
g++ -c source/x.cpp
y.o: source/y.cpp header/x.h
g++ -c source/y.cpp
but the output doesn't get effected!
Which kind of dependencies are ACTUALLY important to be in order?
In the context shown, there is no significant difference between header before source and source before header. The rules say (for example):
x.o must be more recent than header/x.h and source/x.cpp.
It doesn't matter which sequence those two dependencies appear in; if either dependency is newer than x.o, the command will be executed.
When does the order matter? That's a bit trickier to exemplify, but might be a factor if you have multiple intermediate files that get generated as you go. It might especially be a problem if some of the commands you execute affect multiple files but you don't properly tell make about all those interactions.
However, dependency order normally isn't a problem.
It matters in real make files, because you tend to use packaged rules.
In a rule, $< is replaced by the first prerequisite. Thus:
compile = g++ -c $< -o $#
x.o : source/x.cpp header/x.h
$(compile)
y.o : header/y.h source/y.cpp
$(compile)
The first rule will compile source/x.cpp, as desired. The second rule
will attempt to compile header/y.h, which is definitely not what is
wanted.
Since this is a far more typical (and rational) way of writing
makefiles, you do have to respect order, at least with regards to which
element comes first.
Another case it might matter (but which shouldn't be the case in a well
written makefile): in many cases, make will resolve the dependencies
in a left to right order; i.e. given:
x.o : source/x.cpp header/x1.h header/x2.h
...
make will first check that source/x.cpp is up to date, and build it
if necessary, and then do the same for header/x1.h and header/x2.h,
in that order. If you have any non-stated dependencies, which require
header/x1.h to be built before header/x2.h, then changing their
order will also cause problems. This is, however, an error in the
makefile; the dependency should be made explicit (e.g. a rule with
header/x1.h : header/x2.h). Because this order is not guaranteed
otherwise; in the case of GNU make, for example, it may be violated if
you use the -j option.
header/x.h, then swapping the order may cause problems.
Related
I am trying to compile a TBB and OpenMp comparison program that I made. It is compiling fine with the default visual studio compiler. So, I know that TBB is installed correctly. However, I would like to use g++ instead. I have created a Makefile, and from what I read the -ltbb flag is needed.
My error is, "c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: cannot find -ltbb".
I am not an expert when it comes to making sure I have everything linked correctly and am still trying to learn.
This is my current Makefile
CPLUSPLUS = g++
OPTFLAGS = -O3
TBB_INCLUDE_PATH = C:\tbb-2020.1-win\tbb\include
TBB_LIBRARY_PATH = C:\tbb\tbb\lib\intel64\vc14
all: pps
pps: avl.o main.o parPlaneSweep.o
$(CPLUSPLUS) -I$(TBB_INCLUDE_PATH) -L$(TBB_LIBRARY_PATH) $(OPTFLAGS) -o $# $^ -ltbb
avl.o: avl.h avl.c
$(CC) -c $(OPTFLAGS) -fPIC avl.c
main.o: main.cpp parPlaneSweep.h
$(CPLUSPLUS) -c $(OPTFLAGS) -fopenmp main.cpp
parPlaneSweep.o: parPlaneSweep.h parPlaneSweep.cpp
$(CPLUSPLUS) -c $(OPTFLAGS) -fPIC -fopenmp parPlaneSweep.cpp
clean:
rm *.o
rm pps
Please update your question rather than pointing people at other websites.
First, you should never use backslashes in makefiles, even on Windows (there are exceptions to this on Windows but they're very rare). Always use forward slashes as directory separators.
Second, you define the variables TBB_INCLUDE_PATH and TBB_LIBRARY_PATH but then you never use them. Just mentioning the name of the variable doesn't use the variable. You have to include it in $(...) to use it, like $(TBB_INCLUDE_PATH).
Finally, all common linkers are single-pass linkers, which means the order in which you put the libraries and object files on the link line is critically important. You should always put the object files first, and the libraries last. If you have multiple libraries the order in which they appear may be important as well. Your link line should be something like this:
pps: avl.o main.o parPlaneSweep.o
$(CPLUSPLUS) -I$(TBB_INCLUDE_PATH) -L$(TBB_LIBRARY_PATH) $(OPTFLAGS) -o $# $^ -ltbb
If you want to know what $# and $^ mean, you can read about automatic variables.
I have a binary which is linked using a large number of object files with many interdependencies. Whenever I recompile even one of these, I need to link the entire binary.
Do linkers (specifically, those of GCC or Clang) support some method of "differential linking", in which enough information is kept about the inter-relations between all the other linked parts, so that the only work that needs to be done when a single part is recompiled is its relations to the other parts + putting them together in the binary?
Note: I'm mostly interested in C++ but I guess this question generalizes at least to C and probably to other compiled languages.
In MSVC this is called "incremental linking". Interestingly, what I've found that GCC might support that to some extent, try using the "-Wl,-i" or "-Wl,-r" parameters to GCC (should be actually also supported by CLang, as these "-Wl" parameters are just passed to ld).
I never used it before, but I made this work with the following makefile:
OBJS := a.o b.o c.o main.o
all: test_app
test_app: test_app.reloc
g++ -o $# $^
# build a "relocatable" object for incremental linking (either -i or -r)
test_app.reloc: $(OBJS)
g++ -Wl,-i -nostdlib -nostartfiles -o $# $^
$(OBJS): makefile
%.o: %.cpp
g++ -c -o $# $<
This builds the app, but I'm not entirely sure what it does internally, if it really does something like "incremental linking" done in MSVC.
In particular, the parameter "-nostdlib" is necessary when using the "-Wl,-i" so that the default libs will not be passed to the ld (which then can't find them - without it I had the error "/usr/bin/ld: cannot find -lgcc_s").
Another version which might actually work better (not sure, this would need to be tested on a bigger application to see if there is some gain in the link time for single object updates):
OBJS := a.ro b.ro c.ro main.ro
all: test_app
test_app: $(OBJS)
g++ -o $# $^
%.o: %.cpp
g++ -c -o $# $<
%.ro: %.o
g++ -Wl,-i -nostdlib -nostartfiles -o $# $<
Basically creating relocatable file for each object (which might be perhaps a significant portion of the linkage of obj files into the executable) and then just updating the relocatables necessary. For the final link step using the relocatables to link everything together (but part of the linkage has been already done before).
It is also possible to create "groups" of object files to be grouped in a single relocatable, so that there will be less of them at the end (not sure if that would bring anything at the end though).
While working on a C++ project, I noticed that I was making changes to one of the header files linked in my main code, but the make utility was not registering it. I had to force it to compile differently given the changes using "make - B".
I want to know why this is the case; is it because of how my makefile is written, how my files depend on each other, both, or neither?
Here is my makefile:
CXXFLAGS = -Wall -Werror -std=c++11 -pedantic -Wvla -g
//CXXFLAGS = -std=c++11
all: main.o game.o zombie.o
g++ $(FLAGS) game.o main.o zombie.o -o main $(CXXFLAGS)
game: game.cpp
g++ $(FLAGS) -c game.cpp $(CXXFLAGS)
zombie: zombie.cpp
g++ $(FLAGS) -c zombie.cpp $(CXXFLAGS)
main: main.cpp
g++ $(FLAGS) -c main.cpp pairing_heap.h $(CXXFLAGS)
I made a change to pairing_heap.h which is #included in my main file.
Why did make not notice that it should compile again? Because I feel like this is a conceptual misunderstanding, I felt that it was not necessary to include the changes I made or the output difference when I did "make - B". They were simple things like cout's and cerr's included in the new pairing_heap.h that were not being picked up until forced.
Let me know if I need to provide any more information.
Thank you.
You are listing pairing_heap.h in the recipe for main, which does not make it a dependency of main (besides, you should never pass headers to the compiler like this), for that you need to write the rule as follows:
main: main.cpp pairing_heap.h
g++ $(FLAGS) -c main.cpp $(CXXFLAGS)
There are a number of other things that are incorrect in your file, such as the fact that your targets are not actual files (main: should be main.o: etc.), and you aren't making use of automatic variables or pattern rules, but it's probably easier to just replace everything with the following
CPPFLAGS := -MMD -MP
CXXFLAGS := -Wall -Werror -std=c++11 -pedantic -Wvla -g
SOURCES := $(wildcard *.cpp)
main: $(SOURCES:.cpp=.o)
-include $(SOURCES:.cpp=.d)
which leverages make's implicit rules and gcc's/clang's auto dependency generation to make an executable called main.
Make doesn't really know anything about any particular programming language or tool, so it doesn't understand that C/C++ files depend on headers as well as source files. It just has rules of the form
target: dependencies
actions
All it knows from this is that the file target depends on the files listed in dependencies, and if any of those files are newer, the commands in actions should be run to update target. That's really it -- everything that make does comes from this simple idea of target files, dependencies, and actions.
Now there is more to it -- make has a bunch of built-in rules for common things you often want to do, as well as ways to specify 'pattern' rules -- rules where the target contains a wildcard, so can be used for many different targets that depend on other files with related names.
Now in your case, you have the rule:
all: main.o game.o zombie.o
g++ $(FLAGS) game.o main.o zombie.o -o main $(CXXFLAGS)
which says to remake the file all, if its older than the files main.o, game.o or zombie.o it should run the command. That's the first rule in the file, so it is what gets built by default when you type make.
Now, you probably don't have a file called all (if you did make probably wouldn't do anything), but that's generally fine, as if it doesn't exist, its obviously not up to date, so the command needs to run.
When a command needs to run, it also checks any of the dependencies to see if they in turn have dependencies that are older (so need to be rebuilt). Since these files all end in .o, they match a built-in rule that knows how to build them from a file with the same name, except ending with .cpp, so its runs those actions if (and only if) the .cpp file is newer.
Now, you say, "what about my other rules -- what do they do?" Well it turns out they don't do anything. They are rules to build files named game, zombie, and main, and since you never ask to build those files and nothing else depends on them, they do nothing. You might as well delete them.
You also ask "How do I make it rebuild if the header file changes?" Well, if you add a rule with no actions (just target and dependencies) it will just add those dependencies to another rule (built-in in this case) that does have an action. So if you add a line like:
main.o: pairing_heap.h
(with no action), make will add this dependency to the built-in rule that know how to build main.o from main.cpp and will run that rule (recompiling main.cpp) if either main.cpp or pairing_hep.h is newer than main.o -- which is exactly what you want.
I may have a stupid question but as no question is stupid i'll ask it... let's imagine i have the files matrix.hpp and matrix.cpp. In those files i use assert(...) to make sure that some condition is respected. I compile this file and get a matrix.o file. Now i will use this matrix.o file in many different programs, some of them are only tests and need to check the assert(...) conditions, others are working programs that don't need these checks.
My question is : can i compile the matrix.o without the -DNDEBUG flag, thus in general, the assert(...) condition will be checked. but when i link the .o files for a program which doesn't need the checks, i add this flag without recompiling the matrix.o file.
To be more precise, would this do what i want :
# the test program with the "assert(..)" checks
test:test.o matrix.o
gcc -o $# $^
test.o:test.cpp matrix.hpp
gcc -c $^
# the real program without the "assert(..)" checks
prog:prog.o matrix.o
gcc -o $# $^ -DNDEBUG
prog.o:prog.cpp matrix.hpp
gcc -c -DNDEBUG $^
# the matrix.o that can be either checked or not if the -DNDEBUG flag
# is given when the .o files are linked
matrix.o:matrix.cpp matrix.hpp
gcc -c $^
ok thank you for your answer ! So i can't do that simply using the flags -DNDEBUG. What if each time i use "assert(...)" in the matrix files i add :
#ifdef CHECK
assert(...)
#endif
and now when i compile the "test" program i use a CHECK flag but not with the "prog" program ? I guess it won't work either...
The short answer is no. Depending on your exact circumstances there might be some clever tricks you can pull (e.g. linking in a different "assert failed" function).
Have you considered throwing an exception instead of asserting? Then, 'prog' and 'test' could take different approaches to handling it.
No, not with GCC. I see two options:
compile two versions of matrix.o and link the appropriate version into each program, or
replace assert with a manual check that throws an exception.
The latter option obviously has some runtime cost even in the non-test programs, so use it with care (not inside an inner loop).
I have a makefile in my src directory.
The makefile should build the data structures, which are in DataStructures/, and then iterate over all cpp files in calculations/ and create a corresponding .so file in ../bin/calculations
I tried the following syntax:
DAST = DataStructures/
COMPS = computations/
BIN = ../bin/
OBJECTS = ${DAST}Atom.o ${DAST}Molecule.o
COMPILE = g++ -Wall -g -c -std=c++0x -I/usr/local/include/openbabel-2.0 LINK = g++ -Wall -g -std=c++0x ${OBJECTS} -lopenbabel -I/usr/local/include/openbabel-2.0
all: ${BIN}main ${DAST}Molecule.o ${DAST}Atom.o ${BIN}${COMPS}%.so
${BIN}main: ${OBJECTS} main.cpp
${LINK} main.cpp -o ${BIN}main
${DAST}Molecule.o: ${DAST}Molecule.h ${DAST}Molecule.cpp
${COMPILE} ${DAST}Molecule.cpp -o ${DAST}Molecule.o
${DAST}Atom.o: ${DAST}Atom.h ${DAST}Atom.cpp
${COMPILE} ${DAST}Atom.cpp -o ${DAST}Atom.o
${BIN}${COMPS}%.o: ${COMPS}%.cpp
gcc -Wall -fPIC -c -lopenbabel $< -I/usr/local/include/openbabel-2.0 -std=c++0x
${BIN}${COMPS}%.so: ${COMPS}%.o
gcc -shared -Wl,-soname,libcsmtest.so.1 -o libcsmtest.so $#
clean:
rm -rf ${OBJECTS}
.PHONY: all clean
But it obviously doesn't work, as I get the following output:
shai#ubuntu:~/csm/csm2/src$ make all
make: *** No rule to make target `../bin/computations/%.so', needed by 'all'. Stop.
thanks
You need to specify in the all: target, the prerequisites explicitly.
In Makefile parlance, % is a wildcard that can be used in automatic rules. However, the all: target is a simple target with no such wildcard, thus ${BIN}${COMPS}%.so is wrong in that context.
Please note that when I say 'wildcard' in this context, this wildcard matches the target against the prerequisites, not against the filesystem like * do in glob expressions.
Also, while your hart is in the right place, as a matter of style, your Makefile can be better:
Intermediary objects, should not be prerequisites of the all target, but only the final targets you wish to ship.
There is a mix of automatic and simple rules to specify the creation of objects.
Typically one doesn't write an automatic rule for %.so, because a library is often constructed from more than one object.
The dependencies between an object and header files is a complex issue. In short you need to specify that the resulting object depends on the *.cpp (or .c) as well as all the headers included (directly and indirectly) by the *.cpp file.
By convention, that is well supported by GNU make, instead of using ${COMPILE} as you do, one should use $(CXX) for your C++ compiler, and $(CXXFLAGS) for the standard flags you wish to pass to that compiler.
You need something like
SOBJECTS = ...
all: ${BIN}main ${SOBJECTS}
...
You need a way to gather all the *.so names in the variable SOBJECTS. You can do this manually, or use some of make's internal functions to scan the source directory.
Also notice that I removed the two *.o files as dependencies from the all target. They are not final goals of the build (I assume), so you don't need to mention them there.
Besides this there are other stylistic points which I would do differently, but at the moment they are not causing immediate problems, so I won't digress, but I advise you to have a look at some tutorials to see how things are done generally.
For starters, look at Paul's Rules of Makefiles, and How Not to Use VPATH.