MakeFile:Force all files under directory to include header - c++

My current directory looks as follow:
root
|___src
| |
| |____Makefile
| |____a.cpp
| |____b.cpp
| |____c.h
| |____tests
| |
|______________|____test.cpp
Is there a way from the makefile to force all files under tests directory to include c.h

You haven't answered either of my questions, so I'll have to make some guesses.
This may be what you're looking for:
%.o: %.cpp
#$(CXX) -c $< -o $#
tests/%.o: tests/%.cpp
#$(CXX) -include c.h -c $< -o $#
EDIT:
If you want to insert #include "c.h" at the top of a source file, you can use this sed command:
sed -i "" '1{h;s/.*/#include "c.h"/;G;}' filename
If you want to be sure you don't do so more than once, you can do this:
sed -i "" '1{h;s/.*/#include "c.h"/;G;s/\(.*\)\n\1$/\1/;}' filename
There are several different ways to do this with a makefile. Here is one crude-but-effective approach:
tests/%.o: tests/%.cpp
#sed -i "" '1{h;s/.*/#include "c.h"/;G;s/\(.*\)\n\1$/\1/;}' $<
#$(CXX) -c $< -o $#
But Make will work better if you run sed on each source file only once. This can be done, but it requires more careful thought about priorities.

gcc and clang support -include file command line option.
gcc documentation:
-include file
Process file as if #include "file" appeared as the first line of the primary source file. However, the first directory searched for file is the preprocessor's working directory instead of the directory containing the main source file. If not found there, it is searched for in the remainder of the #include "..." search chain as normal.
Other compilers may have a similar option.

Related

GCC - Multiple precompiled headers and specific paths

Background
I have a large Makefile project I'm working on which I'd like to tidy up a bit. It builds several dozen sub-projects, each of which contains roughly 100 .cpp and .h files. I've set it up so that it's able to build debug and release builds for multiple operating systems (Linux, OSX/Mac, QNX, etc) and for multiple architectures (x86/i386, x64/amd64, armhf, arm64/aarch64) in parallel. This is because it's a massive project, and the only way to make it build quickly is in parallel with multiple tool chains.
I have a master rule that all projects obey that stores the intermediate objects (ie: .o files) in temporary directories when building. So, building test.c for Linux, arm64, release mode; would build the object file in the following sub-directory in the present working directory:
.tmp/Linux/arm64/release
Issues
This feature works without issue in my builds, but with this setup, I can't seem to properly use pre-compiled headers (ie: .GCH files) with GCC. With my setup, I have a stdafx.h/stdafx.cpp pair. Using GCC, I can create a stdafx.h.gch file easily enough. However, the project only seems to use it (which accelerates the build) if the file is in the same path as the source files. If the precompiled header is inn the intermediate object path (ie: .tmp/Linux/arm64/release) it doesn't get detected or used. Even if I explicitly add the include path to the intermediate objects path which would contain the gch file, it fails. Including the full path to the file name itself results in it being treated as an invalid linker script, and is ignored.
So, my first workaround was to make a rule to force all OS/arch builds to wait on initial pre-compiled header generation, rather than build a gch on a per-OS/arch basis. However, if I build the gch with release mode settings and attempt to make a debug build, I get the following warning:
warning: stdafx.h.gch: created with -gnone, but used with -gdwarf-2
First, I don't know if that has severe consequences for my build, and second, different operating systems might pass different compile time define flags for the gch generation, so this isn't a "one size fits all" use case, as far as I can see.
Question
How can I work around this so that the precompiled header is in a location other than the $PWD and it can be detected by GCC? I'm currently using gcc v5.3.1.
Thank you.
Here is an MVCE for your problem
scenario:
main.c
#include <hw.h>
#include <stdio.h>
int main(void)
{
puts(HW);
return 0;
}
hw.h
#ifndef HW_H
#define HW_H
#define HW "Hello World"
#endif
Makefile
srcs := main.c
objs := $(addprefix tmp/,$(srcs:.c=.o))
pch := tmp/hw.h.gch
CPPFLAGS += -I.
.PHONY: all clean
all: hw
tmp:
mkdir -p tmp
tmp/%.o: %.c | $(pch)
gcc -c $(CPPFLAGS) -o $# $<
$(pch): hw.h | tmp
gcc -c $(CPPFLAGS) -o $# $<
ifdef ENFORCE_PCH
echo "#error Debug." >> $^
endif
hw: $(objs)
gcc -o $# $^
clean:
sed -i '/^#error/d' hw.h
rm -fr hw tmp
This project outputs its intermediate files in tmp. The .o files go there
and so does the PCH hw.h.gch.
Build and run it:
$ make && ./hw
mkdir -p tmp
gcc -c -I. -o tmp/hw.h.gch hw.h
gcc -c -I. -o tmp/main.o main.c
gcc -o hw tmp/main.o
Hello World
So far so good. But did it actually use the PCH? Let's see:
$ make clean
sed -i '/^#error/d' hw.h
rm -fr hw tmp
$ make ENFORCE_PCH=true
mkdir -p tmp
gcc -c -I. -o tmp/hw.h.gch hw.h
echo "#error Debug." >> hw.h
gcc -c -I. -o tmp/main.o main.c
In file included from main.c:1:0:
./hw.h:5:2: error: #error Debug.
#error Debug.
^
Makefile:15: recipe for target 'tmp/main.o' failed
make: *** [tmp/main.o] Error 1
No it didn't. We know that because, with ENFORCE_PCH defined, we have
tacked an #error directive to the end of hw.h after generating the
good tmp/hw.h.gch. So if the former is subsequently #include-ed anywhere
instead of the latter, the build breaks. Which it just did.
And that is just as it should be. GCC manual 3.21 Using Precompiled Headers,
para. 3:
A precompiled header file is searched for when #include is seen in the compilation.
As it searches for the included file (see Search Path) the compiler looks for a
precompiled header in each directory just before it looks for the include file in
that directory. The name searched for is the name specified in the #include with ‘.gch’
appended. If the precompiled header file can't be used, it is ignored.
So, given include search path ., the directive #include <hw.h> will cause
gcc to check for the PCH ./hw.h.gch before using ./hw.h, and as there is
no ./hw.h.gch, it will use ./hw.h.
It might appear, from the documentation just quoted, that adding tmp to the include search path - CPPFLAGS += -Itmp -I. - should cause
tmp/hw.h.gch to be used in preference to./hw.h. But in fact it makes no difference.
The documentation omits a crucial qualification. The second sentence ought to read:
As it searches for the included file (see Search Path) the compiler looks for a
precompiled header in each directory just before it looks for the include file in
that directory and will use the precompiled header for preference if the include file
is found.
To be found and used, a PCH has to be a sibling of the matching header. And on consideration
this is what you'd want. Otherwise, a a/foo.h.gch without a matching sibling header might be
found and used thanks to -Ia when there is a b/foo.h.gch, with a matching b/foo.h, that
could be found and used thanks to a later -Ib. Clearly, the latter is the sounder choice.
With this insight it's not hard to see a solution: if you really want to compile and use
a PCH that's not a sibling of its source header, make sure to give it a phony matching header
that is a sibling. You can arrange this as you see fit, e.g.
Makefile (fixed)
srcs := main.c
objs := $(addprefix tmp/,$(srcs:.c=.o))
pch := tmp/hw.h.gch
# Seek headers in tmp first...
CPPFLAGS += -Itmp -I.
.PHONY: all clean
all: hw
tmp:
mkdir -p tmp
tmp/%.o: %.c | $(pch)
gcc -c $(CPPFLAGS) -o $# $<
$(pch): hw.h | tmp
# Make phony header in tmp...
echo "#error You should not be here" > $(basename $#)
gcc -c $(CPPFLAGS) -o $# $<
ifdef ENFORCE_PCH
echo "#error Debug." >> $^
endif
hw: $(objs)
gcc -o $# $^
clean:
sed -i '/^#error/d' hw.h
rm -fr hw tmp
See that the PCH is used from tmp:
$ make clean
sed -i '/^#error/d' hw.h
rm -fr hw tmp
$ make ENFORCE_PCH=true && ./hw
mkdir -p tmp
# Make phony header in tmp...
echo "#error You should not be here" > tmp/hw.h
gcc -c -Itmp -I. -o tmp/hw.h.gch hw.h
echo "#error Debug." >> hw.h
gcc -c -Itmp -I. -o tmp/main.o main.c
gcc -o hw tmp/main.o
Hello World
If you force the compiler to -include tmp/pch.h or -include-pch tmp/pch.h.gch, the guard block in pch.h will prevent it from being included again.
# Makefile
SOURCES := main.cpp
OBJECTS := $(SOURCES:%.cpp=tmp/%.o)
PCH_H := tmp/pch.h
PCH := $(PCH_H).gch
$(PCH) : *.h
$(COMPILE.cpp) -x c++-header src/pch.h -o $#
$(OBJECTS) : tmp/%.o : src/%.cpp $(PCH)
$(COMPILE.cpp) -include $(PCH_H) $< -o $#
Notes:
gcc searches for precompiled header called pch.h.gch
clang searches for precompiled header called pch.h.pch or .gch
clang requires either -include pch.h or -include-pch pch.h.pch
gcc always searches for precompiled headers and does not support -include-pch

Makefile: How to correctly include header file and its directory?

I have the following makefile:
CC=g++
INC_DIR = ../StdCUtil
CFLAGS=-c -Wall -I$(INC_DIR)
DEPS = split.h
all: Lock.o DBC.o Trace.o
%.o: %.cpp $(DEPS)
$(CC) -o $# $< $(CFLAGS)
clean:
rm -rf *o all
This makefile and all three source files Lock.cpp, DBC.cpp, Trace.cpp are located in the current directory called Core. One of the source file Trace.cpp contains a line that includes a header file outside the current directory:
//in Trace.cpp
#include "StdCUtil/split.h"
The header file split.h is located at one level above the current directory and then in the subdirectory called StdCUtil. So that's why I added INC_DIR = ../StdCUtil in the makefile. The overall directory structure looks like the following:
root
|___Core
| |
| |____Makefile
| |____DBC.cpp
| |____Lock.cpp
| |____Trace.cpp
|
|___StdCUtil
|___split.h
But when I make it, it gives me the error:
Trace.cpp:8:28: fatal error: StdCUtil/split.h: No such file or directory
#include "StdCUtil/split.h"
^
compilation terminated.
<builtin>: recipe for target 'Trace.o' failed
Why this doesn't find the header file split.h even if I specify the INC_DIR in the makefile? How to correct this?
These lines in your makefile,
INC_DIR = ../StdCUtil
CFLAGS=-c -Wall -I$(INC_DIR)
DEPS = split.h
and this line in your .cpp file,
#include "StdCUtil/split.h"
are in conflict.
With your makefile in your source directory and with that -I option you should be using #include "split.h" in your source file, and your dependency should be ../StdCUtil/split.h.
Another option:
INC_DIR = ../StdCUtil
CFLAGS=-c -Wall -I$(INC_DIR)/.. # Ugly!
DEPS = $(INC_DIR)/split.h
With this your #include directive would remain as #include "StdCUtil/split.h".
Yet another option is to place your makefile in the parent directory:
root
|____Makefile
|
|___Core
| |____DBC.cpp
| |____Lock.cpp
| |____Trace.cpp
|
|___StdCUtil
|___split.h
With this layout it is common to put the object files (and possibly the executable) in a subdirectory that is parallel to your Core and StdCUtil directories. Object, for example. With this, your makefile becomes:
INC_DIR = StdCUtil
SRC_DIR = Core
OBJ_DIR = Object
CFLAGS = -c -Wall -I.
SRCS = $(SRC_DIR)/Lock.cpp $(SRC_DIR)/DBC.cpp $(SRC_DIR)/Trace.cpp
OBJS = $(OBJ_DIR)/Lock.o $(OBJ_DIR)/DBC.o $(OBJ_DIR)/Trace.o
# Note: The above will soon get unwieldy.
# The wildcard and patsubt commands will come to your rescue.
DEPS = $(INC_DIR)/split.h
# Note: The above will soon get unwieldy.
# You will soon want to use an automatic dependency generator.
all: $(OBJS)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CC) $(CFLAGS) -c $< -o $#
$(OBJ_DIR)/Trace.o: $(DEPS)
The preprocessor is looking for StdCUtil/split.h in
./ (i.e. /root/Core/, the directory that contains the #include statement). So ./ + StdCUtil/split.h = ./StdCUtil/split.h and the file is missing
and in
$INC_DIR (i.e. ../StdCUtil/ = /root/Core/../StdCUtil/ = /root/StdCUtil/). So ../StdCUtil/ + StdCUtil/split.h = ../StdCUtil/StdCUtil/split.h and the file is missing
You can fix the error changing the $INC_DIR variable (best solution):
$INC_DIR = ../
or the include directive:
#include "split.h"
but in this way you lost the "path syntax" that makes it very clear what namespace or module the header file belongs to.
Reference:
C++ #include semantics
EDIT/UPDATE
It should also be
CXX = g++
CXXFLAGS = -c -Wall -I$(INC_DIR)
...
%.o: %.cpp $(DEPS)
$(CXX) -o $# $< $(CXXFLAGS)
This is not a question about make, it is a question about the semantic of the #include directive.
The problem is, that there is no file at the path "../StdCUtil/StdCUtil/split.h". This is the path that results when the compiler combines the include path "../StdCUtil" with the relative path from the #include directive "StdCUtil/split.h".
To fix this, just use -I.. instead of -I../StdCUtil.
Try INC_DIR=../ ../StdCUtil.
Then, set CCFLAGS=-c -Wall $(addprefix -I,$(INC_DIR))
EDIT: Also, modify your #include to be #include <StdCUtil/split.h> so that the compiler knows to use -I rather than local path of the .cpp using the #include.

Can I search directory and subdirectories for header files?

Is is possible to instruct g++ to search a folder recursively for header files? In my example I would like g++ to search
/ARDrone_SDK_2_0_1/ARDroneLib/Soft/
and all subdirectories for header files. Can this be done? Here's a simple Makefile example:
C=g++
CFLAGS=-c -Wall
LDFLAGS=
INC1=/ARDrone_SDK_2_0_1/ARDroneLib/Soft/ <- can this be recursive?
INCDIRS= -I${INC1}
SOURCES=src/dronevid.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=build/dronevid
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $(INCDIRS) $< -o $#
The question is a little confusing because you're conflating two different tools, make and g++.
There is no way to get g++ search all subdirectories of a given directory. Every directory you want to use to find an included file must be individually specified on the command line with a -I flag.
If you want to, you can get make to construct those arguments and put them on your command line. Assuming you're using GNU make, and a UNIX-like system that supports the find command, you can do something like this:
INCDIRS := $(addprefix -I,$(shell find /ARDrone_SDK_2_0_1/ARDroneLib/Soft -type d -print))
I should just say up-front, this is not really a good idea. You don't know what order those directories will show up in, and you don't know if there are multiple copies of the same header file in different directories that might cause problems.
Generally the way headers in subdirectories are expected to work is that you add the top-level directory to the compile line, then use relative paths in the #include line in your code. Something like:
#include <subdir/subsubdir/header.h>
Then add:
-I/top/level/dir
to the g++ compile line.

Compile files only if needing

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.

Gnu Makefile - Handling dependencies

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/ *\\$$//' &lt 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)