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
Related
I have the following files in my proj2 directories and need to compile them together to have one executable file.
proj2/main.cpp
proj2/model/Player.cpp
proj2/model/gameBoard.cpp
proj2/controller/TTTController.cpp
proj2/Makefile
I'm using the following command inside my makefile, but it is not working.
all:
g++ /project2_p1/main.cpp /project2_p1/controller/TTTController.cpp /model/gameBoard.cpp /model/Player.cpp -o ttt
clean:
-rm ttt
Can anybody help me please.Thank you
I strongly recommend you start learning make as it is one of the fundamental tools that programmers use. And, if you can learn C++, you can definitely learn make.
In your project you have source files buried in their own subdirectories so in order to find them all you can use the $(shell find...) command. Same with any header files in your project.
By making all: the direct target it gets executed unconditionally and you lose the benefits of using make - only compile when you change something.
Having said that the basic template I am providing here could be improved to recompile only those source files that have changed but that's an exercise for the reader.
I think this should work in your case:
# set non-optional compiler flags here
CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic-errors
# set non-optional preprocessor flags here
# eg. project specific include directories
CPPFLAGS +=
# find cpp files in subdirectories
SOURCES := $(shell find . -name '*.cpp')
# find headers
HEADERS := $(shell find . -name '*.h')
OUTPUT := ttt
# Everything depends on the output
all: $(OUTPUT)
# The output depends on sources and headers
$(OUTPUT): $(SOURCES) $(HEADERS)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $(OUTPUT) $(SOURCES)
clean:
$(RM) $(OUTPUT)
thats my minGW project's makefile codes:
hepsi: derle calistir
Nesneler := ./lib/Hata.o ./lib/Hatalar.o ./lib/Dugum.o ./lib/ListeGezici.o ./lib/BagilListe.o
derle:
g++ -I ./include/ -o ./lib/Hata.o -c ./src/Hata.cpp
g++ -I ./include/ -o ./lib/Hatalar.o -c ./src/Hatalar.cpp
g++ -I ./include/ -o ./lib/Dugum.o -c ./src/Dugum.cpp
g++ -I ./include/ -o ./lib/ListeGezici.o -c ./src/ListeGezici.cpp
g++ -I ./include/ -o ./lib/BagilListe.o -c ./src/BagilListe.cpp
g++ -I ./include/ -o ./bin/test $(Nesneler) ./src/test.cpp
calistir:
./bin/test
In your project I think this will work;
all: compile run
Objects := ./lib/Player.o ./lib/gameBoard.o ./lib/TTTController.o
compile:
g++ -I ./include/ -o ./lib/Player.o -c ./model/Player.cpp
g++ -I ./include/ -o ./lib/gameBoard.o -c ./model/gameBoard.cpp
g++ -I ./include/ -o ./lib/TTTController.o -c .controller/TTTController.cpp
g++ -I ./include/ -o ./bin/main $(Objects) ./main.cpp
run:
./bin/main
lib folder contains .o files. You can chance it if you want.
include folder refers your header .h or .hpp files. You can change every one of them according to your headers location.
bin folder contains your .exe file called main.exe. You can change or remove it like that
run:
./main
I hope it'll work.
#Galik has right. if you want to learn C++, you should definitely learn make.
I am working on a makefile for a C++ project that needs to support a few configurations, i.e. debug , release and maybe a few more customized ones in the future.
Currently, my naming convention for generated .o files is $(SOURCE_FULLPATH).$(CONFIGURATION).o. For instance, ABC.cpp generates ABC.cpp.debug.o in debug mode.
Now I would like to write the pattern rule for generating those object files in a configuration-independent way. What I did was: from each XX.o filename, I strip the .debug or .release suffix from XX, and use the remaining part of XX as the source filename.
%.o: $$(basename %)
$(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $# $<
With this trick, I can build the executable correctly, except that I get one warning message from make:
make: Circular makefile.o <- makefile dependency dropped.
I am puzzled because I do not list makefile or makefile.o as a target or dependency anywhere in my makefile. I did a search on SO, but most questions about Circular dependency is on a specific user source file, rather than the makefile itself. Can anyone help me understand what causes the circular dependency, and how to get rid of this warning message?
A sample makefile that can reproduce this issue is listed below.
.SECONDEXPANSION:
PROJECT := helloworld
CC := clang++
BUILD_FOLDER := Build
OBJ_FILE_SUFFIX := .o
# Source
CPP_FILES :=\
Source/hello.cpp \
Source/mysqrt.cpp \
INCLUDE_FOLDERS := \
-IInclude
# MMD outputs the dependency files (".d" files). These files will be used by
# this makefile to allow for dependency checking on .h files.
CC_FLAGS += -MMD
EXISTING_OBJ_FILES = $(wildcard $(addsuffix *.o, $(basename $(CPP_FILES))))
##--------------------
## Targets definition
##--------------------
.PHONY:default
default: all
.PHONY:all
all: debug release
.PHONY:debug release
# Add a 'debug'/'release' suffix to the name of the object file
# e.g. hello.cpp -> hello.cpp.debug.o
debug release: OBJ_FILES=$(addsuffix .$#$(OBJ_FILE_SUFFIX), $(CPP_FILES))
debug release: $${OBJ_FILES} # Use Secondary Expansion to get the obj names
$(CC) $^ -o $(BUILD_FOLDER)/$(PROJECT)_$#
# Strip configuration name from the end of the object file name
%.o: $$(basename %)
$(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $# $<
## clean: remove executable, all object files, and all dependency files
.PHONY:clean
clean:
-rm -f $(BUILD_FOLDER)/$(PROJECT) $(EXISTING_OBJ_FILES) $(EXISTING_OBJ_FILES:.o=.d)
# Include the dependent files so that in later builds, modified .h files
# will cause all .cpp dependent on them to rebuild
-include $(OBJ_FILES:.o=.d)
The folder structure is
makefile
Source
- hello.cpp
- mysqrt.cpp
Include
- mysqrt.h
The full output of make debug is
make: Circular makefile.o <- makefile dependency dropped.
clang++ -MMD -IInclude -c -o Source/hello.cpp.debug.o Source/hello.cpp
clang++ -MMD -IInclude -c -o Source/mysqrt.cpp.debug.o Source/mysqrt.cpp
clang++ Source/hello.cpp.debug.o Source/mysqrt.cpp.debug.o -o Build/helloworld_debug
Everything is good except for the first line.
I would also really appreciate it if anyone can point to me if there is any bad practice in my makefile (I am still a newbie in makefile). Thank you in advance!
GNU Make always attempts to update the makefile(s) it has read before
making anything else. If it finds rules and prerequisites that tell it
to update makefile(s), then it does so and then starts again from scratch -
including attempting to update the makefile(s). See 3.5 How Makefiles Are Remade.
In your recipe:
%.o: $$(basename %)
$(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $# $<
you have provided make with a rule for making makefile.o from makefile.
It is also the inverse of the rule in the builtin recipe
%: %.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
which makes an executable from a single object file. So your recipe has introduced the circularity:
makefile.o <- makefile <- makefile.o
when make is considering makefile itself as a target.
You could suppress the circularity by expressly deleting the builtin inverse rule,
by writing the empty rule:
%: %.o
in the makefile. Then you could observe the following confusion on the part of the
compiler:
$ make makefile.o
clang++ -c -o makefile.o makefile
clang: warning: makefile: 'linker' input unused
And the same would occur if you attempted to make any target that depended
on makefile.o.
It is probably safe to assume that you will have no targets that depend on
makefile.o. Nevertheless a rule that would attempt to
compile foo.o from any existing file foo is clearly more sweeping that you
want or need. For the particular pattern of dependency that you wish to capture:
foo.cpp.{debug|release}.o: foo.cpp
You'd be better off with:
%.o: $$(basename $$(basename %)).cpp
$(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $# $<
Note, BTW, that in GNU Make conventions - the conventions that are
assumed by GNU Make's builtin rules - CC denotes your C compiler while
CXX denotes your C++ compiler. Likewise flags for the C compiler are
denoted CFLAGS and flags for the C++ compiler are denoted CXXFLAGS.
Flags for the preprocessor are denoted CPPFLAGS, and -Ipath options
- which are preprocessor options - are conventionally be passed through CPPFLAGS.
My Makefile is located in the current working directory. I am trying to put all my object files in the directory ./bin/obj and my executable in the directory ./bin. However, when I follow the method described here: How to place object files in separate subdirectory and in several other StackOverflow questions, I'm unable to get my *.o files to be written to the desired directory; they're created in the directory containing my Makefile. Below is an excerpt from my Makefile (the dots are just rules for many more source files, omitted for brevity). Please note that the Makefile worked until I tried to change the output directory.
CXX=g++
CXXFLAGS=-O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3
LINKFLAGS=-O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3
SRC=src
BIN=bin
OBJ=$(BIN)/obj
BAREBONES=$(SRC)/universal.h $(SRC)/parameters.h
HEADERS=$(wildcard *.h)
ALLOBJS=$(OBJ)/assignDomain.o $(OBJ)/assignDomains.o ...
all: $(BIN)/ngl.x
$(OBJ)/assignDomain.o: $(BAREBONES) $(SRC)/assignDomain.cpp $(SRC)/Domain.h $(OBJ)/Domain.o $(SRC)/Kingdom.h $(OBJ)/Kingdom.o $(SRC)/Sp.h $(OBJ)/Sp.o
$(CXX) $(CXXFLAGS) -c $(SRC)/assignDomain.cpp
$(OBJ)/assignDomains.o: $(BAREBONES) $(OBJ)/assignDomain.o $(SRC)/assignDomains.cpp $(SRC)/Domain.h $(OBJ)/Domain.o $(SRC)/Kingdom.h $(SRC)/Sp.h $(OBJ)/Sp.o
$(CXX) $(CXXFLAGS) -c $(SRC)/assignDomains.cpp
#...more rules...
$(BIN)/ngl.x: $(BAREBONES) $(ALLOBJS) $(wildcard *.h)
$(CXX) $(ALLOBJS) $(LINKFLAGS) -o $(BIN)/ngl.x
#...more rules...
clean:
rm -f $(OBJ)/*.o $(OBJ)/*.gch $(BIN)/ngl.x
.phony: all clean
The output is as follows:
/usr/local/include/eigen3 -c ./src/assignDomain.cpp
g++ -O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3 -c ./src/assignDomains.cpp
g++ -O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3 -c ./src/evict.cpp
g++ ./bin/obj/assignDomain.o ./bin/obj/assignDomains.o /usr/local/include/eigen3 -o ./bin/ngl.x
g++: error: ./bin/obj/assignDomain.o: No such file or directory
g++: error: ./bin/obj/assignDomains.o: No such file or directory
#...same error, for the other rules...
g++: fatal error: no input files
compilation terminated.
Makefile:94: recipe for target 'bin/ngl.x' failed
make: *** [bin/ngl.x] Error 1
Just to be clear: there is no built-in rule in make which knows how to compile a source file in one directory and put the object file into a different directory. If you want to do that, you have to write your own rule. When you write your own rule you have to provide the -o option: there's no way for the compiler to know that in your makefile you specified a different output directory, unless you tell it with the -o flag. The compiler doesn't parse your makefile!
You can write a pattern rule like this:
$(OBJ)/%.o : $(SRC)/%.c
$(CXX) $(CXXFLAGS) -c $< -o $#
Then you don't need any explicit rules, although you do need to define the prerequisites. Other notes about your makefile:
It's never correct to have .o files depend on other .o files.
It's never correct to have executable files depend on header files.
Object files list source and header files as prerequisites. Executable files list object files (and libraries, if you have any) as prerequisites. You should write your prerequisites like this:
$(OBJ)/assignDomain.o: $(SRC)/assignDomain.cpp $(BAREBONES) $(SRC)/Domain.h $(SRC)/Kingdom.h $(SRC)/Sp.h
$(OBJ)/assignDomains.o: $(SRC)/assignDomains.cpp $(BAREBONES) $(SRC)/Domain.h $(SRC)/Kingdom.h $(SRC)/Sp.h
...other prerequisites...
$(BIN)/ngl.x: $(ALLOBJS)
$(CXX) $^ $(LINKFLAGS) -o $#
Your explicit compilation rule is disabling Make's knowledge of how to compile files in subdirectories, and so you get exactly what your rule says, and nothing else. You don't specify an -o option, so you are not telling g++ where to put the output file; so it follows its built-in default, and simply creates a file ./a.out (!).
The most straightforward solution is to not override the built-in rules. Make already knows how to create an .o file from a .cpp file with the same base name; you only need to declare the dependencies and flags in your Makefile.
For legibility, I have refactored the shared dependencies into a separate variable.
SHAREDDEPS := $(SRC)/Domain.h $(OBJ)/Domain.o \
$(SRC)/Kingdom.h \
$(SRC)/Sp.h $(OBJ)/Sp.o
$(OBJ)/assignDomain.o: $(BAREBONES) $(SRC)/assignDomain.cpp \
$(SHAREDDEPS) $(OBJ)/Kingdom.o
# No $(CXX) anything here!
$(OBJ)/assignDomains.o: $(BAREBONES) $(OBJ)/assignDomain.o \
$(SRC)/assignDomains.cpp $(SHAREDDEPS)
# Here either!
I wrapped the dependencies across multiple lines for legibility (notice the final backslash on the first line) but you should notice that they are a single logical line, and only specify dependencies, not how to actually compile anything.
It's not clear how the depended *.o files are supposed to figure into this; my speculation, based on your explicit rules which I am removing, is that these are not actually used in compilation, and so are not actually true dependencies.
I'm new to makefiles, and they puzzle me. I have the following folder hierarchy:
A folder named lib contains tow folders: include (with file mylib.h) and src (with file mylib.cpp). It also contains a Makefile, which, for some reason, gives me an error.
The full makefile is:
CFLAGS = -Wall -fPIC
OBJECTS = mylib.o
all: libmine.so
libmine.so: $(OBJECTS)
g++ -shared $(CFLAGS) \
-o libmine.so \
$(OBJECTS)
%.o: src/%.cpp include/%.h
g++ $(CFLAGS) \
-I include \
-o %.o \
-c src/%.cpp
clean:
rm src/*.o
rm libmine.so
The error is
mr209#Quantum:~/Desktop/hw1/lib$ make
g++ -Wall -fPIC \
-I include \
-o %.o \
-c src/%.cpp
g++: error: src/%.cpp: No such file or directory
g++: fatal error: no input files
compilation terminated.
make: *** [mylib.o] Error 4
But the file is present. Thus, make is doing weird things, causing it not to be able to find the .cpp file.
In order to make libmine.so, g++ will have to do something with mylib.o, and for a generic .o file I have written some lines of code.
Here is what I was thinking: in order to make libmine.so, g++ will have to do something with mylib.o. Thus, in lib, a file named mylib.o has to appear. Using the generic %.0 rule, this file is made from mylib.cpp in src and mylib.h in include (hence the first line of the %.o rule). The file is made using g++, which has to look in include for additional headers, produces mylib.o as output, and compiles src/mylib.cpp, but -c guarantees that a .o file is produced.
Obviously, something goes wrong, and I am unable to figure out what. Only 2 days ago have I learned what Makefiles are and why one should learn how to deal with them, so I'm not that much of an expert.
Your build target %.o is miswritten. You can't use the % in the command section, so the names of the destination file and dependent file won't ever match.
The proper change is to do the following:
%.o: src/%.cpp include/%.h
g++ $(CFLAGS) \
-I include \
-o $# \
-c src/$(#:%.o=%.cpp)
Just to explain the changes, the -o needs the target file, which is pretty much always written as $# in Makefiles, as that's the name of the target.
Secondly, the source file needs to be defined in terms of the target, the operator in question is a pattern replacement operator $(#:%.o=%.cpp), so what that does is take the target - which will match a filename of <blah>.o, then it pattern match replaces .o with .cpp.
So in the case of the target mylib.o, the variable $# is mylib.o, and the result of doing $(#:%.o=%.cpp) is to turn mylib.o into mylib.cpp. As a result it is the expected file that is being compiled, and the expected target is build.
Rules using a % pattern in them are what are referred to as implicit rules, and are used to reduce the complexity of the code being written - if you had a pile of files that shared the target pattern: blah.o: src/blah.cpp src/blah.h, then you use the implicit rule to only have to write the target once, then you need to write the commands in terms of the target.
You must do a variable before put it in g++
like :
FT_C= $(src/%.cpp)
FT_O=$(FT_C:.c=.o)
and
g++ $(CFLAGS) -I include -o $(FT_O) -c $(FT_C)
and don't put your .h in compilation '-I' are here for it.
Look this example if you want understand what i mean:
https://github.com/emericspiroux/wolf3d/blob/master/libft/Makefile
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.