What approach do C++ programmers on Unix platform use to create and manage Makefiles?
I was using hand made Makefiles for my projects but they don't handle header file changes and other dependencies. I googled around and found a good solution here.
But I ran into a problem here in the sed command -
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
The problem is with the 3rd expression "-e 's/ *\$$//'.
It doesn't work. Its supposed to remove trailing backslashes. I understand that there has to be double dollar there since this is part of a Makefile. Can someone tell me what wrong here?
Here's the complete Makefile -
CC=g++
CFLAGS=-g -Wall
LIBS=-lpthread
OBJS=file1.o file2.o
TARGET=testProg
$(TARGET) : $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
%.o : %.cpp
$(CC) -MMD -c -o $# $< $(CFLAGS)
#cp $*.d $*.P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
rm -f $*.d
-include $(OBJS:%.o=%.P)
clean :
rm -f $(TARGET) $(OBJS)
all : $(TARGET)
Apart from the solution to this problem, I would also like some tips/pointers to my 1st question.
gcc/g++ can generate dependencies for you with the -M family of options.
The following works by specifying how to generate .depends files given a source file. By doing -include $(DEPS) $(DEPS) is recognized as a target and will be built/rebuilt when the source files change.
CXX = g++
CXXFLAGS = -Wall -O3
LDFLAGS =
TARGET = testcpp
SRCS = main.cc x.cc foo.cc
OBJS = $(SRCS:.cc=.o)
DEPS = $(SRCS:.cc=.depends)
.PHONY: clean all
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)
.cc.o:
$(CXX) $(CXXFLAGS) -c $< -o $#
%.depends: %.cc
$(CXX) -M $(CXXFLAGS) $< > $#
clean:
rm -f $(OBJS) $(DEPS) $(TARGET)
-include $(DEPS)
I use that approach too and can't praise it highly enough. And I write my makefiles by hand and reuse them a lot on new projects.
.The expression "s/ *\\$//" will work outside the context of Make. Within a makefile it doesn't work because Make tries to interpret "$/" before handing the result to the shell. So you must use "s/ *\\$$//" (note the extra $) within the makefile, but this won't work outside the context of Make (so testing it is a slight pain).
EDIT:
I've tried your makefile, and that sed statement seems to remove trailing backslashes just fine. Try something simpler, like this:
backslash:
#echo " \\" > $#
test: backslash
#echo without sed:
#cat backslash
#echo with sed:
#sed -e 's/ *\\$$//' < backslash
EDIT:
All right, now I'm hooked. Could you try these experiments and tell us the results?
Change the last character to 'z' : s/.$/z/
Change a trailing backslash to 'z' : s/\\$/z/
Change a trailing backslash to 'z' : sm\\$mzm
Delete a trailing backslash : s/\\$//
Delete spaces and a trailing backslash: s/ *\\$//
Try all of these inside and outside of Make, with '$' and '$$'.
In a make file anything you list on the dependency line is a dependency header files or other files included.
BSD tutorial on make Note: you can auto generate header dependency info with the -MM switch of GCC.
I must be missing something. Why doesn't generating dependency files work for you?
I prefer to use CMake, even though it's not strictly the solution to your problem.
It's a project description language that'll generate your Makefiles, Visual Studio Project, Eclipse Project, KDevelop, etc for you. All the dependencies are done for you:
CMakeLists.txt
add_executable(my_exe file1.c file2.c)
target_link_libraries(my_exe my_library)
add_subdirectory(lib)
In lib/CMakeLists.txt
add_library(my_library file3.c file4.c)
This creates a my_exe from file1.c file2.c linked against my_library. I find this much simpler. It also has things like package discovery:
find_package(Qt4)
The makedepend utility is installed on many systems and can be quite useful for generating dependency information.
Here is an example Makefile that uses the include directive (plus a little Perl magic) to incorporate the output from makedepend:
# the name of the executable that we'll build
TARGET = foo_prog
# our .cc source files
SRCS = foo.cc main.cc
# the .o versions of our source files
OBJS := $(patsubst %.cc, %.o, $(filter %.cc, $(SRCS)))
# some flags for compiling
CXXFLAGS = -Wall -Werror
# In order to build $(TARGET), we first build each of the $(OBJS).
# Then we use the given command to link those $(OBJS) into our
# $(TARGET) executable. $^ is a shortcut for $(OBJS). $# is a
# shortcut for $(TARGET).
#
# The default compile rule will compile each of the $(OBJS) for us.
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $^ -o $#
# Use "make clean" to remove all of the support files.
clean:
rm -f $(OBJS) $(TARGET) Makefile.depend *~
# This automatically uses the 'makedepend' utility to add any
# dependencies that our source files have, namely .h files. This way,
# if the .h files change, the code will be re-compiled.
include Makefile.depend
Makefile.depend: $(SRCS)
makedepend -f- -Y $(SRCS) 2> /dev/null | \
perl -p -e "s/(^.*?:)/Makefile.depend \1/" > Makefile.depend
If both foo.cc and main.cc depend on foo.h, then the contents of Makefile.depend would be:
Makefile.depend foo.o: foo.h
Makefile.depend main.o: foo.h
The end result is that the dependency information from makedepend is injected into the Makefile as a series of rules. It's similar to the approach of using a .d file for each .cc file, but keeps the dependency information in one file instead of scattered all over the place.
In Mozilla's build system, we use GCC's -MD switch to generate the dependency files:
http://mxr.mozilla.org/mozilla-central/source/configure.in#7134
and then we use a script called mddepend.pl to check for removed header files, such that
removing a header simply causes a rebuild, not an error:
http://mxr.mozilla.org/mozilla-central/source/config/rules.mk#2066
http://mxr.mozilla.org/mozilla-central/source/build/unix/mddepend.pl
That script generates an .all.pp file containing all the dependencies, with extra foo.o: FORCE dependencies stuck in for missing header files. We then simply -include the .all.pp file in rules.mk right below there.
You can use qmake to generate Makefiles for a project even if that project is not using Qt.
I use BSD make (pmake?) which does lot of work for me (my lang is C, but I think no difference here). This is my common 'local.prog.mk', I never change it:
.PHONY: tags .depend
# .depend depends only on $(SRCS) in bsd.dep.mk, so we can't track changes of
# header's own dependencies properly. so .depend is .PHONY target here.
CSTD ?=c99
WARNS ?=9
.if !empty(PC_LIST)
PC_CF !=pkg-config --cflags $(PC_LIST)
PC_LD !=pkg-config --libs $(PC_LIST)
.endif
CFLAGS +=$(PC_CF) -fgnu89-inline
.if !defined(NO_DEBUG)
CFLAGS +=-O0 -ggdb3
.endif
LDFLAGS +=$(PC_LD)
CTAGS =exctags
NO_MAN=
NO_OBJ=
CLEANFILES+=$(PROG).core
.include <bsd.prog.mk>
$(PROG): $(SUBDIR)
build: clean cleandepend depend all
run: $(PROG)
./$(PROG)
Note 'bsd.prog.mk' inclusion -- this handles all, build, depend, clean targets. Project-specific BSDmakefiles are simple:
.SILENT:
PROG =hello
SRCS =hello.c world.c
PC_LIST =gtk+-2.0 gnet-2.0
.include "../local.prog.mk"
proto:
cproto -siv `pkg-config --cflags $(PC_LIST)` $(SRCS) > prototypes
CLEANFILES+=prototypes
I just make depend every time I insert/remove any #include directives.
Instead of the sed scripts, use gcc's -MT option to modify the target of the generated dependency rules. This blog post has more info.
With a more modern version of GCC, you can add the -MP flag to have GCC generate empty rules for the headers itself.
I top tip that I have found useful when building dependency files is to include the dependency file as a target in the generated rule:
file.d file.o : file.c header.h header2.h ...
Thus make will regenerate the dependencies if the source or any of the headers change. Including phony targets for the headers (GCC -MP) should then allow stable builds when headers are removed - the absense of required header remains a compilation error, not a make dependency error.
Assuming that dependency files are generated into the same directory as the object files, the following should work for GCC on Unix:
-include $(OBJ:.o=.d)
$(OBJDIR)/%d : $(SRCDIR)/%.cpp
mkdir -p $(#D)
echo -n "$# " > $#.tmp
$(CXX) $(CPPFLAGS) -MM -MP -MT $(#:.d=.o) $< >> $#.tmp
mv $#.tmp $#
(from memory)
Related
I have the following makefile that I use to build a program (a kernel, actually) that I'm working on. Its from scratch and I'm learning about the process, so its not perfect, but I think its powerful enough at this point for my level of experience writing makefiles.
AS = nasm
CC = gcc
LD = ld
TARGET = core
BUILD = build
SOURCES = source
INCLUDE = include
ASM = assembly
VPATH = $(SOURCES)
CFLAGS = -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \
-nostdinc -fno-builtin -I $(INCLUDE)
ASFLAGS = -f elf
#CFILES = core.c consoleio.c system.c
CFILES = $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
SFILES = assembly/start.asm
SOBJS = $(SFILES:.asm=.o)
COBJS = $(CFILES:.c=.o)
OBJS = $(SOBJS) $(COBJS)
build : $(TARGET).img
$(TARGET).img : $(TARGET).elf
c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img
$(TARGET).elf : $(OBJS)
$(LD) -T link.ld -o $# $^
$(SOBJS) : $(SFILES)
$(AS) $(ASFLAGS) $< -o $#
%.o: %.c
#echo Compiling $<...
$(CC) $(CFLAGS) -c -o $# $<
#Clean Script - Should clear out all .o files everywhere and all that.
clean:
-del *.img
-del *.o
-del assembly\*.o
-del core.elf
My main issue with this makefile is that when I modify a header file that one or more C files include, the C files aren't rebuilt. I can fix this quite easily by having all of my header files be dependencies for all of my C files, but that would effectively cause a complete rebuild of the project any time I changed/added a header file, which would not be very graceful.
What I want is for only the C files that include the header file I change to be rebuilt, and for the entire project to be linked again. I can do the linking by causing all header files to be dependencies of the target, but I cannot figure out how to make the C files be invalidated when their included header files are newer.
I've heard that GCC has some commands to make this possible (so the makefile can somehow figure out which files need to be rebuilt) but I can't for the life of me find an actual implementation example to look at. Can someone post a solution that will enable this behavior in a makefile?
EDIT: I should clarify, I'm familiar with the concept of putting the individual targets in and having each target.o require the header files. That requires me to be editing the makefile every time I include a header file somewhere, which is a bit of a pain. I'm looking for a solution that can derive the header file dependencies on its own, which I'm fairly certain I've seen in other projects.
As already pointed out elsewhere on this site, see this page:
Auto-Dependency Generation
In short, gcc can automatically create .d dependency files for you, which are mini makefile fragments containing the dependencies of the .c file you compiled.
Every time you change the .c file and compile it, the .d file will be updated.
Besides adding the -M flag to gcc, you'll need to include the .d files in the makefile (like Chris wrote above).
There are some more complicated issues in the page which are solved using sed, but you can ignore them and do a "make clean" to clear away the .d files whenever make complains about not being able to build a header file that no longer exists.
You could add a 'make depend' command as others have stated but why not get gcc to create dependencies and compile at the same time:
DEPS := $(COBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$#) -o $# $<
The '-MF' parameter specifies a file to store the dependencies in.
The dash at the start of '-include' tells Make to continue when the .d file doesn't exist (e.g. on first compilation).
Note there seems to be a bug in gcc regarding the -o option. If you set the object filename to say obj/_file__c.o then the generated _file_.d will still contain _file_.o, not obj/_file_c.o.
This is equivalent to Chris Dodd's answer, but uses a different naming convention (and coincidentally doesn't require the sed magic. Copied from a later duplicate.
If you are using a GNU compiler, the compiler can assemble a list of dependencies for you. Makefile fragment:
depend: .depend
.depend: $(SOURCES)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^>>./.depend;
include .depend
There is also the tool makedepend, but I never liked it as much as gcc -MM
You'll have to make individual targets for each C file, and then list the header file as a dependency. You can still use your generic targets, and just place the .h dependencies afterwards, like so:
%.o: %.c
#echo Compiling $<...
$(CC) $(CFLAGS) -c -o $# $<
foo.c: bar.h
# And so on...
Basically, you need to dynamically create the makefile rules to rebuild the object files when the header files change. If you use gcc and gnumake, this is fairly easy; just put something like:
$(OBJDIR)/%.d: %.c
$(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(#D)/\1.o $(#D)/\1.d:,' >$#
ifneq ($(MAKECMDGOALS),clean)
include $(SRCS:%.c=$(OBJDIR)/%.d)
endif
in your makefile.
Over and above what #mipadi said, you can also explore the use of the '-M' option to generate a record of the dependencies. You might even generate those into a separate file (perhaps 'depend.mk') which you then include in the makefile. Or you can find a 'make depend' rule which edits the makefile with the correct dependencies (Google terms: "do not remove this line" and depend).
Simpler solution: Just use the Makefile to have the .c to .o compilation rule be dependent on the header file(s) and whatever else is relevant in your project as a dependency.
E.g., in the Makefile somewhere:
DEPENDENCIES=mydefs.h yourdefs.h Makefile GameOfThrones.S07E01.mkv
::: (your other Makefile statements like rules
::: for constructing executables or libraries)
# Compile any .c to the corresponding .o file:
%.o: %.c $(DEPENDENCIES)
$(CC) $(CFLAGS) -c -o $# $<
None of the answers worked for me. E.g. Martin Fido's answer suggests gcc can create dependency file, but when I tried that it was generating empty (zero bytes) object files for me without any warnings or errors. It might be a gcc bug. I am on
$ gcc --version gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)
So here's my complete Makefile that works for me; it's a combination of solutions + something that wasn't mentioned by anyone else (e.g. "suffix replacement rule" specified as .cc.o:):
CC = g++
CFLAGS = -Wall -g -std=c++0x
INCLUDES = -I./includes/
# LFLAGS = -L../lib
# LIBS = -lmylib -lm
# List of all source files
SRCS = main.cc cache.cc
# Object files defined from source files
OBJS = $(SRCS:.cc=.o)
# # define the executable file
MAIN = cache_test
#List of non-file based targets:
.PHONY: depend clean all
## .DEFAULT_GOAL := all
# List of dependencies defined from list of object files
DEPS := $(OBJS:.o=.d)
all: $(MAIN)
-include $(DEPS)
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
#suffix replacement rule for building .o's from .cc's
#build dependency files first, second line actually compiles into .o
.cc.o:
$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$#) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $# $<
clean:
$(RM) *.o *~ $(MAIN) *.d
Notice I used .cc .. The above Makefile is easy to adjust for .c files.
Also notice importance of these two lines :
$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$#) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $# $<
so gcc is called once to build a dependency file first, and then actually compiles a .cc file. And so on for each source file.
I believe the mkdep command is what you want. It actually scans .c files for #include lines and creates a dependency tree for them. I believe Automake/Autoconf projects use this by default.
I have couple of cpp and hpp files in directory ./src. I compile all cpp files in one binary file, say ./bin/run. I want to re-compile only if I need i.e it or one of its header was changed.
I, probably, can create Makefile where file will be recompiled if and only if it was changed, but it's quite uncomfortable because big part of my code is in the headers. (It's not going to be changed, because the product is header itself and cpp files are tests).
I want to store temporary .o files in ./build
I know about g++ -MM function but I'm not sure how to use it.
I'll glad to see solutions that use not necessary make but any other system possible if they are easy enough.
UPD
I'll try to clarify, what's the problem is:
New cpp's maybe created, includes may be added or gone, etc. I don't want to edit my makefile each time.
To solve the problem I mentioned (-include is not a good solution), I use something like this:
build/%.o: %.cpp
#$(CC) -MD -c -Wall -o $# $<
#cp build/$*.d build/$*.P
#sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < build/$*.P >> build/$*.d
#rm build/$*.P
-include build/*.d
No `%.d rule is needed.
EDIT:
#JackKelly has [*cough*, *choke*] shown me a better way to get effectively the same dependency file:
build/%.o: %.cpp
#$(CC) -MD -c -Wall -o $# $<
#$(CC) -MM -MP -Wall -o $*.d $<
-include build/*.d
Ye, you can have multiple rules for the same target, as long as only one of them has commands; the prerequisites accumulate. The idea is to get a file like this:
file.o: file.cpp headerfile.h
headerfile.h:
The second line (headerfile.h:) is a rule for headerfile.h that has no prerequisites or commands. It does nothing, but it's a rule, so if headerfile.h is missing, Make is satisfied.
You mention g++ -MM, which can do what you're trying to do:
include $(ALLOBJ:%.o=%.d)
%.d: %.cxx
#echo making dependencies for $<
#g++ -MM -MP $(CXXFLAGS) $< -o $#
#sed -i 's,$*\.o,& $# ,g' $#
Basically this defines a rule that creates .d files from .cxx files. The .d files are, in turn, required by the include statement, which requires one for each .o file in ALLOBJ.
The last line in the dependency rule is the 'sed magic' that makes the dependency files regenerate themselves. If you think regular expressions are hacks at best, and evil more often than not, you can use the -MT flag.
The outline of a solution is as follows:
Use auxiliary dependency files for each source file (that is, create foo.dep for foo.c, bar.dep for bar.c etc)
Use gcc -MM to create the dependency files
In order to force make to do this automatically, use foo.c as a prerequisite for foo.dep and foo.o; this requires some minor sed magic on the output of gcc -MM
Include all the dependency files in your main makefile; this is a key step that makes this approach possible.
The last step is written as follows:
-include $(dependency_files)
This is very tricky but possible; see the GNU make manual for more information.
You can do this with Make, you just need to specify the headers in your rule's sensitivity list. For example
myfile.o: myfile.cpp
gcc -c myfile.o myfile.cpp ${LDFLAGS} # This is optional. make can infer this line.
Turns into
myfile.o: myfile.cpp myfile.h
gcc -c myfile.o myfile.cpp ${LDFLAGS} # Again, optional.
Now, whenever myfile.h changes, myfile.cpp will be rebuild. More headers can be chained in a similar way.
I have a list of library folders that I'm specifying in a make file:
LIBRARIES = Ethernet \
SPI \
SD
I also have a number of rules for compiling each one into a local obj folder of my project:
obj/SPI/%.cpp.o: $(LIBS_DIR)/SPI/%.cpp
#echo "Compiling $<"
obj/SD/%.cpp.o: $(LIBS_DIR)/SD/%.cpp
#echo "Compiling $<"
obj/Ethernet/%.cpp.o: $(LIBS_DIR)/Ethernet/%.cpp
#echo "Compiling $<"
(Note that each one uses it's own sub-folder). How can I generate these rules from $(LIBRARIES) automatically so that I don't have to duplicate them like this?
You can just do:
obj/%.cpp.o : $(LIBS_DIR)/%.cpp
g++ -c -o $# ${CPPFLAGS} ${CXXFLAGS} $<
In the above % captures dir/src part.
If you'd like the output directories to be created automatically it can be done with secondary expansion make feature:
.SECONDEXPANSION:
obj/%.cpp.o : $(LIBS_DIR)/%.cpp | $${#D} # object file depends on its directory
g++ -c -o $# ${CPPFLAGS} ${CXXFLAGS} $<
obj/% : # directory creation rule
mkdir -p $#
Sufficiently new versions of GNU make support the eval function. You can use it like this:
define SUBDIR_RULE
obj/$1/%.cpp.o: $(LIBS_DIR)/$1/%.cpp
#echo "Compiling $$<"
enddef
$(foreach D,$(LIBRARIES),$(eval $(call SUBDIR_RULE,$D)))
If you don't want to rely on that you can use auto-generated makefiles, which have been a feature of GNU make for much much longer. But this method is slightly trickier to use.
Sometimes I need my project to use plain makefile, although it's a dated building technology not recommended for any use, but since make is available almost everywhere it sometimes makes sense.
However I want my Makefile to look something like
Include "../buildexec.mk"
TARG = my_exec
CPPFILES = file1.cpp \
file2.cpp \
and have all the generic (and horrible) dependency tracking code being in buildexec.mk.
Is there such a "Make library"?
In Go, there's a standard Makefile you can include, and your Makefile looks as beautiful like this:
include $(GOROOT)/src/Make.inc
TARG=irc
GOFILES=irc.go irc_struct.go irc_callback.go
include $(GOROOT)/src/Make.pkg
Anything similar for C++?
clarification: I know of tup, cmake and scons/ I know of waf and bjam and so on/ but I want my deps to so small/ so that compilation is no trouble at all. I specifically asked for Make support, not for Make alternative.
I would suggest generating the makefile with automake instead. Cmake also generates makefiles, while also being able to generate project files for several IDEs.
The problem is there is no one make. The very basic syntax is always the same, but anything slightly more complex (which you need for such includes) is not compatible even between GNU make and BSD make (not trying to mention nmake). Automake can however deal with several versions of make and provide automatic dependency rules where available (only some compilers support them).
You probably want to look at CMake or Premake.
With large C/C++ projects you tend to have additional requirements such as platform specific APIs or libraries that need customization.
This will do what you're asking for (at least in GNUMake).
makelib.mk:
$(TARG): $(CPPFILES:.cc=.o)
$(CC) $^ -o $#
%.o : %.cc
$(CC) -MD -o $# $<
#cp $*.d $*.P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
rm -f $*.d
-include $(CPPFILES:.cc=.P)
Makefile:
CPPFILES = foo.cc bar.cc
TARG = someTarget
include makelib.mk # Note lower-case "i"
CPPFILES = baz.cc quartz.cc quince.cc
TARG = anotherTarget
include makelib.mk
...
But a word of advice: don't curse your tools so much. It's energy you could be using to either learn how to use them or switch to ones you like better.
There's a googlecode project doing exactly what I wanted:
http://code.google.com/p/nonrec-make/
There is none of my knowledge. There are really a lot of problems with make, but it is still the most available tool around, and once you get it running properly you should just focus on your development.
Until there, you will have to write makefiles. But instead of looking for a 'make library', a really simple solution (if you're actually initiated in Make language), often overlooked for being too obvious, is to implement your own. Create a make script containing a set of default pattern rules and variables for communication with the project makefile, and just include this script in every project's makefile. It's not hard, maybe a little time-consuming, but it often pays off really well, specially if you have lots of small projects to manage.
I work with such a design. I have a couple of GNU make scripts carefully designed to offer an almost trivial mechanism to create rather complex build systems: automatic dependency generation, handling of different languages, generation of language parsers, different build configurations (debug or release), build log generation, and so on. And the script is not cumbersome: the current version contains just about 250 lines of makefile code, excluding comments.
I will leave you with a sample of an older version of such system, handling C source code only, which contained a few features. It should handle the compilation of binaries and libraries (both static and dynamic). It also should help you track inter-project dependencies through the DEPS variable.
Call this $(ROOT)/project.mk:
# Remove the default suffix rules.
.SUFFIXES:
# Turn on the delete-on-error feature.
.DELETE_ON_ERROR:
# Set up additional command variables.
STRIP ?= strip
# Set up a global search path to locate prerequisites.
VPATH := $(VPATH) $(shell find -type d)
# Locate all source files from the default locations in the project tree.
SRC := $(SRC) $(shell find src -name '*.c')
# Set up the default dependency files.
DEP := $(DEP) $(addprefix dep/,$(addsuffix .d,$(basename $(notdir $(filter %.c,$(SRC))))))
# Set up the default object files.
OBJ := $(OBJ) $(addprefix obj/,$(addsuffix .o,$(basename $(notdir $(filter %.c,$(SRC))))))
# Set up a set of default flags for all commands used.
STRIPFLAGS ?= -p
CPPFLAGS ?= -DNDEBUG
CFLAGS ?= -Wall -Wextra -Werror -pedantic -O3 -march=native -fomit-frame-pointer -ffast-math
LDFLAGS ?= --as-needed -O1
ARFLAGS ?= -scr
# Set up the default include and library search paths.
override INCLUDES := \
$(addprefix $(ROOT)/,$(addsuffix /include,$(DEPS))) \
$(INCLUDES)
override LIBRARIES := \
$(addprefix $(ROOT)/,$(addsuffix /lib,$(DEPS))) \
$(LIBRARIES) lib
# The default rule to build every target in the project.
.PHONY: all
all: deps $(DEP) $(OBJ) $(BIN) $(LIB)
# Phony rule to recursively build the library dependencies.
.PHONY: deps
deps:
#for dep in $(DEPS); do cd $(ROOT)/lib/$$dep && $(MAKE); done
# Secondary expansion is used to properly locate prerequisites.
.SECONDEXPANSION:
# Rule for dependency file generation.
%.d: $$(notdir $$*).c
$(CC) -M $(CPPFLAGS) $(CFLAGS) -iquote include $(addprefix -I ,$(INCLUDES)) $< -MM -MG -MP -MT '$# $(filter %/$(notdir $*).o,$(OBJ))' > $#
# Rule for compiling object files.
%.o: $$(notdir $$*).c
$(CC) -c $(CPPFLAGS) $(CFLAGS) -iquote include $(addprefix -I ,$(INCLUDES)) $< -o $#
# Rule for linking binaries.
%: $$(notdir $$*).c
$(CC) $(CPPFLAGS) $(CFLAGS) $(addprefix -Xlinker ,$(LDFLAGS)) -iquote include $(addprefix -I ,$(INCLUDES)) $(addprefix -L ,$(LIBRARIES)) $(filter-out $<,$^) -o $# $(addprefix -l,$(LDLIBS))
$(STRIP) $(STRIPFLAGS) $#
# Rule for linking shared libraries.
%.so: $$(notdir $$*).c
$(CC) $(CPPFLAGS) $(CFLAGS) $(addprefix -Xlinker ,$(LDFLAGS)) -iquote include $(addprefix -I ,$(INCLUDES)) $(addprefix -L ,$(LIBRARIES)) $(filter-out $<,$^) -o $# -fpic -shared -Wl,-h,$(notdir $#) $(addprefix -l,$(LDLIBS))
$(STRIP) $(STRIPFLAGS) $#
# Rule for generating static libraries.
%.a:
$(AR) $(ARFLAGS) $# $?
# Include all dependency files and remake them if necessary.
ifneq ($(MAKECMDGOALS),clean)
include $(DEP)
endif
# Phony rule to clean the entire build tree.
.PHONY: clean
clean:
#for dep in $(DEPS); do cd $(ROOT)/lib/$$dep && $(MAKE) clean; done
$(RM) $(DEP) $(OBJ) $(BIN) $(LIB) $(CLEAN)
ROOT contains the path for your projects' directory (working copy of repository, for example), typically exported as an environment variable. You will also need a couple of directories (bin, dep, obj and src) in your projects.
An example Makefile using this system could be:
DEPS := mylib
BIN := bin/test
LIB := lib/libtest.a
include $(ROOT)/project.mk
bin/test: $(OBJ)
lib/libtest.a: obj/test1.o obj/test2.o
That is, you just write the minimum necessary about your project, and let the build system do the rest. You can always explicitly specify the value for a given variable (SRC, for example, or CFLAGS), but if you don't, then it gets a reasonable default.
The above was tailored to my needs, but it should be simple to adapt to yours, while keep things as easy as the examples you've mentioned.
I want a build rule to be triggered by an include directive if the target of the include is out of date or doesn't exist.
Currently the makefile looks like this:
program_NAME := wget++
program_H_SRCS := $(wildcard *.h)
program_CXX_SRCS := $(wildcard *.cpp)
program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
program_OBJS := $(program_CXX_OBJS)
DEPS = make.deps
.PHONY: all clean distclean
all: $(program_NAME) $(DEPS)
$(program_NAME): $(program_OBJS)
$(LINK.cc) $(program_OBJS) -o $(program_NAME)
clean:
#- $(RM) $(program_NAME)
#- $(RM) $(program_OBJS)
#- $(RM) make.deps
distclean: clean
make.deps: $(program_CXX_SRCS) $(program_H_SRCS)
$(CXX) $(CPPFLAGS) -MM $(program_CXX_SRCS) > make.deps
include $(DEPS)
The problem is that it seems like the include directive is executing before the rule to build make.deps which effectively means that make is either getting no dependency list if make.deps doesn't exist or always getting the make.deps from the previous build and not the current one.
For example:
$ make clean
$ make
makefile:32: make.deps: No such file or directory
g++ -MM addrCache.cpp connCache.cpp httpClient.cpp wget++.cpp > make.deps
g++ -c -o addrCache.o addrCache.cpp
g++ -c -o connCache.o connCache.cpp
g++ -c -o httpClient.o httpClient.cpp
g++ -c -o wget++.o wget++.cpp
g++ addrCache.o connCache.o httpClient.o wget++.o -o wget++
Edit
I read the docs for the include directive, and it sounds like if the include target doesn't exist it will continue processing the parent makefile try and build the target, but it's not completely clear to me how this works:
If an included makefile cannot be
found in any of these directories, a
warning message is generated, but it
is not an immediately fatal error;
processing of the makefile containing
the include continues. Once it has
finished reading makefiles, make will
try to remake any that are out of date
or don't exist. See section How
Makefiles Are Remade. Only after it
has tried to find a way to remake a
makefile and failed, will make
diagnose the missing makefile as a
fatal error.
ANSWER
This is a modification of the answer I accepted. The one thing missing was that the dependency files also depend on the sources, and won't get regenerated unless they are added to the deps files which are being included:
%.d: $(program_CXX_SRCS)
# $(CXX) $(CPPFLAGS) -MM $*.cpp | sed -e 's#^\(.*\)\.o:#\1.d \1.o:#' > $#
sed adds the name of the .d file to the beginning of each dependency line like so:
foo.d foo.o: foo.cpp foo.h bar.h baz.h
I got the idea from this amazing paper on the dangers of recursive make:
Recursive Make Considered Harmful
I also add the following to the makefile:
clean_list += ${program_SRCS:.c=.d}
# At the end of the makefile
# Include the list of dependancies generated for each object file
# unless make was called with target clean
ifneq "$(MAKECMDGOALS)" "clean"
-include ${program_SRCS:.c=.d}
endif
You are relying on an implicit rule to compile your .cpp files. You have to redefine it to use the -MM and -MF flags that will create the dependency file.
%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $# -MM -MF $#.d
Then, you have to include these dependencies files in the Makefile, using -include that will not error when the dependencies files do not exist yet (on the first time, or after a clean).
program_DEPS := $(program_OBJS:.o=.o.d)
-include $(program_DEPS)
And remember to add the rm command for the dependencies files in the clean rule.
An important point that it took me a while to grasp is that the make.deps from the previous build are good enough. Think about it: for a given object file, the only way the list of dependency files can change is if... one of the old dependency files has been altered. And if that's the case, then the old make.deps will cause that object file to be rebuilt, and if rebuilding the object file also rebuilds make.deps, then everything will be up to date. You don't have to rebuild make.deps before checking to see which objects must be rebuilt.
The include directives work like they do in C and C++ - they are processed before anything else happens, to build the "real" makefile that make then processes. Specifically, they are processed before any rules are fired.