I've followed the instructions online to set up gcc (actually g++) to generate .d files for dependencies, and now my makefile looks something like this:
CPPFLAGS := ... -MMD -MP
...
OBJECTS := $(shell find *.cpp *.s | sed -e 's/\.cpp/\.o/' -e 's/\.s/\.o/')
all: setupdir $(OBJECTS) link image
And then at the end of the file:
-include $(pathsubst %.d,obj/%.d,$(OBJECTS:.o=.d))
The .d files are being correctly generated, and all show up in the obj directory. The problem is, now, even with the assembly files that don't have .d files generated for them the entire source tree is being rebuilt every time I run make. The project doesn't take long to compile, but still, how would one go about fixing it so that make runs correctly?
It's important to note that -M is not magic bullet for dependencies, in many cases you'll need to specify certain headers so things are re-built appropriately if they change. In fact, the most common problem with letting gcc handle dependencies is things not being re-built that should be (broadly depending on the version of GCC being used by whoever runs make).
That being said, I don't see anything blatantly wrong with what you're doing.
What I recommend doing is eliminating the shell tricks, since it's quite easy to specify exactly what you want. E.g.
foo_SOURCES = \
src/foo.cpp \
src/bar.cpp
foo_OBJECTS = $(foo_SOURCES:.cpp=.o)
foo_DEPS = $(foo_OBJECTS:.o=.d)
%.o : %.cpp
$(CC) $(CFLAGS) ... $< -o $#
$(CC) -M $< > $(#.o=.d)
# lots more rules and targets here
# and finally, at the bottom:
-include $(foo_DEPS)
This is off the top of my head in meta form, so check it to be sure. I believe your problem is actually the dependencies not being included, but I don't see anything obviously wrong with the way you are using pathsubst.
As people have noted in comments, running make with debug on may be helpful, but a good first step would be to specify your objects and dependencies without talking to the shell.
If you get that working, try just storing the results of your shell calls and echoing them to the screen. That's a lot less noisy than make's debug output.
Related
I recently learned how to use Makefiles, and I found out that GCC/G++ generates dependencies for you:
$ g++ -MM file.cpp
file.o: file.cpp file.h
I then thought that the obvious thing to do would be to use this to generate dependencies directly in the file without creating a dependency file:
CXX = g++
SRCS = $(wildcard src/*.cpp)
OBJS = $(SRCS:.cpp=.o)
OCT = $(CXX -MM $(SRCS))
OBJDIR = obj
CPPFLAGS = -Wall -I/usr/local/include -L/usr/local/lib -lGLEW -lglfw -lGL
.PHONY: all
all: $(OBJS)
$(CXX) $(CPPFLAGS) $(OBJS) -o output
$(OCT)
.PHONY: clean
clean:
rm -f obj/*
For some reason, I have never seen anyone else do this; they always generate a dependency file. Is there something wrong with this system? In my case yes -- the objects don't go to OBJDIR, they go to they location of the source file. I'm sure this could be fixed though. If anyone knows how I could fix this and why dependency files are usually generated, please let me know.
Well, the first reason people don't do this is that it's not possible to do: if you try to make your suggestion work in real life you'll see that. Your example, for instance, doesn't do anything at all. This:
OCT = $(CXX -MM $(SRCS))
(I assume you mean $($(CXX) -MM $(SRCS)) but it doesn't matter either way) is putting a reference to the make variable named, literally, CXX -MM $(SRCS) into the variable OCT: you probably are thinking that it's using the shell command invocation syntax $(...) but this is a makefile, not a shell script. So when you write:
$(OCT)
that tries to look up that make variable, which obviously does not exist, and so this expands to the empty string and nothing at all happens. If you actually try to test your makefile by touching a header etc. you'll see nothing gets rebuilt.
How can you do this? You can't do it. You can change your variable assignment like this:
OCT = $(shell $(CXX) -MM $(SRCS))
and that will actually run the compiler, which is moving you in the right direction, but the results of the shell function will change all newlines to whitespace, so this:
$(OCT)
will expand to the entire output of the compiler command on one line, and since it contains multiple colons you'll get a syntax error.
All you can do is redirect the output of the compiler to a file, and using make's include capability to include that file. But now you're basically back to the scenario suggested in the GNU make manual, except your version is less efficient because, as pointed out in the comments above, you're regenerating all the headers for all the source files every time you run make, rather than only regenerating header information for the files that have actually changed.
There are better/more efficient ways to generate headers, such as the one used by most GNU packages.
I seem to be having an issue getting my makefile to build my C++ file correctly. My makefile code is below; the file I am trying to compile is named "avl.cc" (which is working and compiles properly).
CC=g++
CFLAGS=-g -O2
PROGS=avl
all: $(PROGS)
$#:
$(CC) $(CFLAGS) $# $#.cc
.PHONY: clean
clean:
rm $(PROGS)
However, when I enter the command make or make all, I get
c++ avl.cc -o avl
And the debugging symbols I want from the -g flag don't come up. A similar makefile (only changing the PROGS variable) worked for a similar project, so I am not sure what I'm doing wrong. Does anyone have any tips? Thanks!
From Makefile documentation about automatic variables:
It’s very important that you recognize the limited scope in which
automatic variable values are available: they only have values within
the recipe. In particular, you cannot use them anywhere within the
target list of a rule; they have no value there and will expand to the
empty string.
This means you cannot use $# as a rule, which means the default c++ compilation rule of Makefile is used, and since you did not use the correct variable names for c++ compilation, they are also ignored.
You can replace CC by CXX and CFLAGS by CXXFLAGS to work with c++.
You don't have a target for 'avl', so make uses a default rule.
Try changing the makefile to this:
CC=g++
CFLAGS=-g -O2
PROGS=avl
all: $(PROGS)
$(PROGS):
$(CC) $(CFLAGS) -o $# $#.cc
.PHONY: clean
clean:
rm $(PROGS)
I had the exact same question but a much different source of the problem. There were typos or misnamed files in my makefile. Make found no rules for such files but tried to compile targets with the c++ compiler. This made the process seem like it was ignoring my rules and imposing its own, switching compilers since I needed g++. Finally I tried using the -r option, and then the resulting different error messages allowed me to figure out what was really wrong. Below is the entry from the make man page for option -r.
-r, --no-builtin-rules
Eliminate use of the built-in implicit rules. Also clear out the default
list of suffixes for suffix rules.
Actually i have a library 'cryptopp' and what i want is that when i make any change to a file and issue the make command it should take care of the changes made in any file in the source directory. well, the GNUMakefile of cryptoopp takes care of the changes 'if' made in the '.cpp' files but not for the changes made in a '.h' file.
So what changes can i make in the 'GNUMakefile' of cryptopp so that it looks at all the modified header files and recompiles all the files dependent on the 'modified' header file.
If you are building with g++ you can let g++ generate dependancy makefiles.
You can include these in your main makefile.
Use the -M and -M* arguments to use this feature. (see http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Preprocessor-Options.html#Preprocessor-Options)
You have to add all the dependencies to your Makefile:
mycode.o: mycode.cpp mycode.h somelib.h resources.h
$(CXX) -c -o $# $< $(CXXFLAGS) $(INCLUDES)
If you already have a generic pattern matching command line, you don't have to say the command again, you can just list the dependencies:
%o: %.cpp
$(CXX) -c -o $# $< $(CXXFLAGS) $(INCLUDES)
mycode.o: mycode.cpp mycode.h somelib.h resources.h
yourcode.o: yourcode.cpp yourcode.h mycode.h somethingelse.h
# ...
In general, this is a terrible and unscalable mess. You'll almost definitely want a higher-level build system to generate the Makefile for you. Even for very small projects keeping the header dependencies up to date in the Makefile is such a pain that it is simply not worth it.
There are several popular portable build environments. I personally like cmake a lot, which includes discovery if you changed the build settings (say from Debug to Release) and will always build all the necessary files (for example, if you change the cmake master file and type "make" it'll automatically run cmake again for you first).
For a Unix-only solution you could try makedepend, or the infamous autotools, though that's a whole other headache...
You might try 'makedepend' if it's installed on your system. The easiest way is to add a target to your makefile. Something like:
depend:
makedepend *.cc
You might have to replace the '*.cc' with a list of your source files. Then you can regenerate all the dependencies with 'make depend' command. You might want to redirect error messages to /dev/null since it always seems to generate a lot of noise.
To generate dependency files I can use something like this to generate dependency files:
-include $(patsubst %.cpp,build/%.d,$(SRC))
build/%.o: %.cpp
$(CC) $(CXXFLAGS) -c -o $# $<
$(CC) $(CXXFLAGS) -MM -MT $# -MF $(patsubst %.o,%.d,%#) $<
This generates everything and puts both the object and dependency files into the build dir where I want them. But this makes two dependency lines for the <file>.o targets, one from the -include rule and with all the header dependencies, and one which is from the pattern rule. Will this get interpreted correctly, i.e. when a header is modified, the object will be recompiled via the command specified for the pattern rule?
Edit: So this approach does in fact work quite well. I guess I'd like somebody to provide an answer which gives me some insight into what it is exactly that make does in these situations. For instance, what if a different command was given for both rules for the same target? My guess would be that it gives an error since it wouldn't be obvious which command to execute.
You should add one more pattern rule to express the dependency between the .cpp and .d files and use that rule to create the .d files (second line in the pattern rule of your question) instead of creating the .d files unconditionally. It might make sense to introduce another dependency between all .h and .cpp files and all .d files to force re-creating the .d files if a header or source file changes.
Here's the separate rule for .d files (hope I got it right):
-include $(patsubst %.cpp,build/%.d,$(SRC))
build/%.o: %.cpp
$(CC) $(CXXFLAGS) -c -o $# $<
build/%.d: %.cpp
$(CC) $(CXXFLAGS) -MM -MT $# -MF $<
Edit: So this approach does in fact
work quite well. I guess I'd like
somebody to provide an answer which
gives me some insight into what it is
exactly that make does in these
situations.
I'm afraid currently it would only work by chance (or you have not given all relevant pieces from the make file). See, you have not expressed any dependency between .d files and .cpp files. This, however, is needed so that your .d files get updated before inclusion as make file fragment.
For instance, what if a
different command was given for both
rules for the same target? My guess
would be that it gives an error since
it wouldn't be obvious which command
to execute.
With that syntax it wouldn't make a difference. But there are some special cases where splitting the rules into two (though otherwise identical rules) has merit. I strongly recommend you get the book "Managing Projects with GNU Make" to get a grip on the various ways of working with GNU Make. The only other recommendation in connection with GNU Make is to read to read the paper here.
Yes, you can specify several rules for one file, and they get merged into one.
See the GNU Make documentation.
[...] There can only be one recipe to be executed for a file. [...]
An extra rule with just prerequisites can be used to give a few extra prerequisites to many files at once.
And I second that there should be separate rule for .d files. It's names in many projects are deps or depend.
POSIX 7 also says that multiple lines for a given target work http://pubs.opengroup.org/onlinepubs/9699919799/
A target that has prerequisites, but does not have any commands, can be used to add to the prerequisite list for that target. Only one target rule for any given target can contain commands.
so long as only one has the commands.
I know I am doing it wrong, but I can't figure out how to organize this makefile. I define my util source files, and use some functions to define the .o files from them here:
UTIL_SRC = utils/src/foo.cpp utils/src/bar.cpp utils/src/baz.cpp
UTIL_OBJS = $(patsubst utils/src/%.cpp,utils/obj/%.o,$(UTIL_SRC))
This is the target that I use these files for:
lib : lib/libutils.a
lib/libutils.a : $(UTIL_OBJS)
rm -f lib/libutils.a
ar -c -q lib/libutils.a $(UTIL_OBJS)
Then, when I get to the rule to compile these babies, I would love to just have one command that would iterate through each UTIL_OBJS file and each UTIL_SRC file. Instead I have resorted to this monstrosity, which defeats the purpose of storing them in variables.
$(UTIL_OBJS) : $(UTIL_SRC)
g++ $(UTIL_FLAGS) utils/src/foo.cpp -o utils/obj/foo.o
g++ $(UTIL_FLAGS) utils/src/bar.cpp -o utils/obj/bar.o
g++ $(UTIL_FLAGS) utils/src/baz.cpp -o utils/obj/baz.o
Can I condense this down to one line? How? Thanks, great ones!
It's usually easier to work with implicit rules. There are a lot of predefined ones, where you'll only need to specify variables.
CXX=g++
CXXFLAGS=$(UTIL_FLAGS)
Then you need to define an executable, like this
myutil: $(UTIL_OBJS)
Since you're not storing your objects in the same directory, you'll need to specify a new implicit rule as well though (otherwise, we'd be done now).
utils/obj/%.o: utils/obj/%.cpp
% is a pattern-match, it'll match the same text on both left and right side, so this rule will make foo.o out of foo.cpp.
Try if that'll work without the command (it might have grabbed that from another rule, I'm not sure), otherwise let it say:
utils/obj/%.o: utils/obj/%.cpp
$(CXX) $(CXXFLAGS) -o $# $^
$# is the target of the rule (e.g. foo.o), and $^ is all files on the right hand side.
I'm writing this off the top of my head, without the possibility to test it, so please let me know how it turned out.. :)
To make it even more elegant, you can include a dependency file
include .depend
If you're running GNU make, it'll try to make the .depend file if it can't find it (with old school make, you need to create it yourself first, it can be just a dummy though, if you'd like to manage it through the makefile)
.depend: $(UTIL_SRC)
$(CXX) -MM -o $# $^
The dependency file will contain lines for each .cpp file, telling make what header files it needs, which will allow make to recompile the necessary files when you change something. This doesn't help with your original question though, just thought it might come in handy.
EDIT:
As a response to your edit. You could probably drop the commands for creating the .a-file as well, that too is already available as an implicit rule. Not sure exactly how it works though, haven't used it much. I do know that there are a bunch of quirks in make for dealing with .a(rchive?)-files.
I think you could use this:
$(UTIL_OBJS) : $(UTIL_SRC)
g++ $(UTIL_FLAGS) $(# : .o = .cpp) -o $#
again, I'm not quite sure... especialy about the $(# : .cpp = .o) part