So, I'm trying to understand makefiles. At this moment I have a project with some modules, which are more or less non-dependent on each others.
My directory tree is like this:
root/
- Source/ <-- referenced as $(INPUTPATH)
- Build/ <-- referenced as $(BUILDPATH)
- Release/ <-- referenced as $(OUTPUTPATH)
- Makefile
I want to have the source (.cpp/.h) on the Source/, the objects on the Build/, and the executable on the Release/*.
So, my idea was to have several different targets, and use them like this:
all: maps auxiliars methods
#echo "linking...";\
$(CC) $(CFLAGS) $(OBJS) $(CLIBS) -o ${OUTPUTPATH}/MainProgram
dependency1: $(INPUTPATH)/foo.cpp
#echo "compiling ArbPrecision...";\
cd ${BUILDPATH};\
$(CC) $(CFLAGS) $(CINCLUDE) -c ../$?
dependency2: dependency1 $(INPUTPATH)/bar.cpp
#echo "compiling saddleConstructor...";\
cd ${BUILDPATH};\
$(CC) $(CFLAGS) $(CINCLUDE) -c ../$(INPUTPATH)/bar.cpp
maps: dependency2 $(INPUTPATH)/*Map.cpp
#echo "compiling maps...";\
cd ${BUILDPATH};\
$(CC) $(CFLAGS) $(CINCLUDE) -c ../$(INPUTPATH)/*Map.cpp
... (auxiliars and methods)
The $CINCLUDE and CFLAGS are just compiler stuff like headers and external libs.
Everything works almost perfect: on every target, it asks for other target's dependencies, and for the *cpp on the source. If this does not exist, it calls the target and compiles the *cpp. The executable is created without errors.
However, if I call the "make" twice, the time it takes to compile is the same for the first and second time, even if I don't make any changes on the source. So, apparently, I'm not putting the dependencies right.
Can anyone point me the right direction to perform this compilation? I'm doing something wrong and I'm not getting what it is.
Thanks,
Jorge
Make expects to operate off of files. For each rule, it checks to see if the target file named by that rule (1) exists and (2) is up to date (i.e., modified after any of its dependencies). If the file is not up to date, then it executes the rule to bring it up to date.
Therefore, as your makefile is currently written, when you run make, Make does the following:
all is the first rule, so if you don't specify any arguments, make processes the all rule.
No file named all exists, so the all rule needs to be executed.
all depends on the dependency1 rule. No file named dependency1 exists, so the dependency1 rule needs to be executed.
dependency1 depends on the dependency2 rule. No file named dependency2 exists, so the dependency2 rule needs to be executed.
What you instead want is something similar to the following:
OBJS := foo.o bar.o Map.o
all: $(OUTPUTPATH)/MainProgram
$(OUTPUTPATH)/MainProgram: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) $(CLIBS) -o $(OUTPUTPATH)/MainProgram
%.o: %.cpp
$(CC) $(CFLAGS) $(CINCLUDE) $< -c $#
.PHONY: all
Note the following:
Since Make operates on files, rules' targets and dependencies are listed by filename wherever possible.
Rather than listing the .cpp files individually, an pattern rule is used to build each .o file. Within the pattern rule, the $< and $# automatic variables are used to specify the first prerequisite (file) and the target (file), respectively.
Make echoes its commands by default, so there's no need to echo yourself.
For GNU Make, all is listed as a phony target, to keep Make from looking for a file named all.
Related
I am creating a custom Makefile to to build a C++ Linux application. I have my cpp source files in a folder called src on the same level as the Makefile. So far I have been able to build my object files with the following :
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
Now my project is starting to get a bit more complicated and I want subdirectories within src , such as src/common , and also, not every file is a cpp file now but also a c file.
I guess having a separate Makefile for each subdirectory is the best way but I am trying to keep this simple for now with just one Makefile.
I tried the following but doesn't work
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(SRC_DIR)/common/%.cpp $(SRC_DIR)/common/%.c | $(OBJ_DIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
I could have the Makefile do a shell find to find all cpp and c files but also trying to avoid this.
I'd appreciate any recommendations.
This:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(SRC_DIR)/common/%.cpp $(SRC_DIR)/common/%.c | $(OBJ_DIR)
cannot work; what it says that if make wants to build some file $(OBJ_DIR)/XXX.o and there is no explicit rule, then if and only if ALL the prerequisites $(SRC_DIR)/XXX.cpp, $(SRC_DIR)/common/XXX.cpp, and $(SRC_DIR)/common/XXX.c exist or can be created by make, then the rule will match.
If the same target could be built from multiple different prerequisites you must create multiple rules, one per prerequisite.
Also, it doesn't make sense to compile both C files (.c) and C++ files (.cpp) using the same recipe. C++ compilers use the variables CXX and CXXFLAGS and C compilers use the variables CC and CFLAGS.
As for avoiding find, you can't avoid informing make what files you want to be compiled, in some manner. You either have to list them in your makefile explicitly, or else use some method to generate them dynamically. There's no way around this. You don't have to use find if you don't want to; for example if you know that all the files will be either one or two directories down you could use wildcard, like:
SRCS := $(wildcard $(SRC_DIR)/*.cpp $(SRC_DIR)/*.c $(SRC_DIR)/*/*.cpp $(SRC_DIR)/*/*.c)
Abstract:
I have a .c file and a .cpp file with the same name in the same parent folder. I no longer wish to compile the .c file but doesn't want to remove it from the folder too.
Even though I explicitly specify to compile the .cpp file, the makefile was making use of the .c file. How can I fix this issue?
On renaming file3.c to another name, file3.cpp gets compiled.
Details:
The files present in 'src' folder are:
file1.c
file2.c
file3.c
file3.cpp
file4.cpp
Important extracts from the makefile:
SOURCE_FILES := ./src/file1.c \
./src/file2.c \
./src/file3.cpp \
./src/file4.cpp
OBJS = $(patsubst %.cpp,%.o,$(filter %.cpp, $(SOURCE_FILES))) \
$(patsubst %.c,%.o,$(filter %.c, $(SOURCE_FILES)))
all : $(OBJS)
$(CXX) $(CFLAGS) $(INCLUDES) -o $(PROJECT).bin $(OBJS) $(LDFLAGS) $(LIBRARIES)
.cpp.o:
$(CXX) $(CFLAGS) $(INCLUDES) -c $< -o $#
#echo 'CPP FILE : ' $<
.c.o:
$(CXX) $(CFLAGS) $(INCLUDES) -c $< -o $#
#echo 'C FILE : ' $<
On doing 'make', the log of the echo command gives:
C FILE : ./src/file1.c
C FILE : ./src/file2.c
C FILE : ./src/file3.c
CPP FILE : ./src/file4.cpp
Questions:
How can the above issue be solved?
Is there an easier way to fetch values for my OBJS variable?
The method make uses to pick which of two possible matching rules gets used depends on which version of make you are using. (It changed between 3.81 and 3.82 and I believe got tweaked slightly for 4.0+ but am not certain about that.)
I believe make 3.81 used the last matching rule and make 3.82+ uses the matching rule with the shortest stem (the bit that matches the %) and then the first matching rule between rules that have similar stem lengths.
So it would seem like you are using make 3.81 currently.
In that case it should be possible to simply swap the order of your two rules to get the behavior you want (assuming you always want .cpp files to "win").
Alternatively you could try giving make an explicit prerequisite for the file3.o target instead of letting it guess. (i.e. file3.o: file3.cpp)
That said neither of your explicit suffix rules is necessary as make already contains default rules to build .o files from both .c and .cpp files. (I don't know the relative ordering between them so you likely will need the explicit prerequisite, assuming that works, for the built-in rules to work correctly.)
Also you might want to look at using Pattern Rules instead of Old-Fashioned Suffix Rules just as a point of current practice.
The only improvement to your populating the OBJS variable that I can see, offhand, is to filter on the results and so just filter once.
OBJS = $(filter %.o,$(patsubst %.cpp,%.o,$(SOURCE_FILES)) \
$(patsubst %.c,%.o,$(SOURCE_FILES)))
That said you could also use Substitution References instead of explicit calls to $(patsubst) to shorten that a bit.
OBJS = $(filter %.o,$(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o))
You have rules for both .c ==> .o and .cpp ==> .o.
In your case the rule for file3.c is run first since the newly created file3.o file now exists. Since the target file3.o file exists, there is no reason to compile file3.cpp.
Looking at the make manual, if there are 2 rules for the same target, the last rule is used.
I have the following Makefile in a directory full of .cpp and .h files:
CFLAGS=-g -std=c++0x -Wall -pedantic -Wextra -D __STDC_LIMIT_MACROS -D __STDC_FORMAT_MACROS -O0
CXX=g++
LDFLAGS=-lgmp -lmathsat -lz3
all: Foo.o Bar.o
$(CXX) $(CFLAGS) -o myexe Foo.o Bar.o $(LDFLAGS)
depend: .depend
.depend: $(wildcard *.cpp)
rm -f ./.depend
$(CXX) $(CFLAGS) -MM $^ > ./.depend
include .depend
%.o: %.cpp
$(CXX) $(CFLAGS) $(INCLUDE) $< -c
clean:
rm -f *.o myexe
When I hit make, it invariably executes the last step (linking) even when none of the .o files have changed. How can I prevent make from doing that? I'd expect make to output Everything up-to-date or something similar.
I'm on a i686 GNU/Linux machine with GNU Make 3.82 and g++ version 4.8.2.
Make relinks your project because it tries to build all. The rule for all does not create any file named all. Instead it produces myexe. Next time you run make, it will see that there's no all, but there's a rule to build one, so it dutifully executes that rule which happens to link myexe every time you run make.
In order to fix your problem you need to change your makefile to look roughly like this:
all: myexe
echo Build done
myexe: <myexe dependencies go here>
$(CXX) $(CFLAGS) -o myexe $(wildcard *.o) $(LDFLAGS)
Make always tries to build the top rule. For you, this is all. Since your all rule doesn't actually make an all file it will always be run.
Your probably want your all rule to be a myexe rule and, if you want an explicit all rule, have a dependency only rule: all: myexe.
(With GNU Make, you might want to explicitly declare those targets which aren't supposed to generate a real file with a .PHONY rule. e.g. .PHONY: all depend clean.)
make is a rule-based expert system.
You give it a heap of rules and a target (default target is the first one listed), and then it builds a complete dependency tree.
All parts are rebuilt iff they are non-existent resp. older than their dependencies, recursively.
The rule you are stumbling over is this: Because the target all does not create an output file all, make invokes the non-existent-or-outdated rule.
You can correct this by making the target all not do any work but instead just depend on the output file. Marking it .PHONY is also a good idea.
I have a makefile that's been working pretty great for the past couple weeks. However, now that I've added another target to my project with "main", it starts to flip out a bit.
CC=g++
CCOPTS=-g -w
OBJS = $(BINDIR)/manager.o $(BINDIR)/rtngnode.o
TARGETS = $(BINDIR)/manager $(BINDIR)/rtngnode
BINDIR = build
all: $(TARGETS) $(OBJS)
clean:
rm -f $(TARGETS) $(OBJS)
.PHONY: all clean
$(TARGETS): $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
$(BINDIR)/%.o: %.cpp
$(CC) -c $(CCOPTS) -o $# $<
I don't quite understand makefiles still... so I'm not sure what's going on. I get these two errors:
build/rtngnode.o: In function `__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<int const, Node> > >::new_allocator()':
/home/caleb/Documents/dev/tote2/mp2/rtngnode.cpp:5: multiple definition of `main'
build/manager.o:/home/caleb/Documents/dev/tote2/mp2/manager.cpp:161: first defined here
build/manager.o: In function `main':
manager.cpp:(.text+0xefb): undefined reference to `NetworkConnection::NetworkConnection(char const*, char const*)'
In my rtngnode target, I have dependancies on the tcpcon class... and my manager target also has a main() reference. I'm pretty confused... so not even sure if I'm asking the right question.
I guess my question is:
For OBJS and TARGETS, what goes there? All of my .cpp files? All of my executables?
How do I like the two together?
The other answers are all accurate, but I think the key thing to understand is this rule:
$(TARGETS): $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
doesn't do what you seem to think that it does. This expands to:
$(BINDIR)/manager $(BINDIR)/rtngnode : $(BINDIR)/manager.o $(BINDIR)/rtngnode.o
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
Make doesn't try to infer some magical matching up of targets to prerequisites here; instead make repeats the entire rule again for each target, but with all the prerequisites. The rule above is identical to writing this:
$(BINDIR)/manager : $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
$(BINDIR)/rtngnode : $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
Given this you can see what the problem is: you're trying to link ALL the objects into EACH executable.
Since your programs are built from a single object file with the same prefix as the program name, you actually don't need to write a rule for them at all; you can rely on make's built-in rule for building the programs. Just take the above rule out completely and it should work.
You should bind your executable with exactly one source file containing the "main" function.
As linker tells you, both manager.cpp and rtngnode.cpp have the definition of main function there. You probably do not want to combine them together. I advice you to start from manually building your code using the gcc commands (using gcc -c to produce object files and gcc -o to produce the executable). Once you understand the logic there - proceed writing makefiles.
By the way, if you can choose your build environment - start with cmake which is less cryptic than makefiles.
The most important thing here has nothing to do with your Makefile (which looks reasonably good except for the somewhat lacking use of compiler warnings):
You may have only one main() in your project, across all source files.
So basically, TARGETS should contain your source files (.cpp) which are then compiled to create object files, which should be in the OBJS variable so they are then passed to the linker to create the executable file.
As of right now your Makefile seems correct, the error tells you that you have 2 main() functions declared, one in the rtngnode.cpp file and again in the manager.cpp, this cannot happen or else the machine would not know which one to call when the program is executed.
Also undefined reference errors are most of the time due to a linker error, happening most of the time when you include a library to the compiler with #include but not to the linker usually using the LIBS variable in your makefile.
HERE is a small tutorial on Makefiles, which could also be a good read.
[SOLVED]
I'm having trouble getting this simple makefile to work properly.
This should build the three source files NeonAs1.cpp NeonAs2.cpp NeonAs3.cpp to object files in the 'obj' folder.
This works but it only ever attempts to build NeonAs1.cpp and then completes without error.
Any ideas?
WORKSPACE=../../workspace/
SRC_FOLDER=$(WORKSPACE)/ProjectNeon/
LOCAL_SRC_FILES=NeonAs1.cpp NeonAs2.cpp NeonAs3.cpp
vpath %.cpp $(SRC_FOLDER)
OBJECTS = $(patsubst %.cpp,obj/%.o,$(LOCAL_SRC_FILES))
$(OBJECTS): | obj
obj:
#mkdir -p $#
obj/%.o : %.cpp
#echo $<
#$(CXX) $(CXXFLAGS) -c $< -o $#
clean:
-rm -f $(LIBRARY) obj/*.o
Update 1: if I add a explicit all target like:
all: $(OBJECTS)
Then if I do an explicit:
make all
It works fine.. How can I make it work when I just do a make with no 'all' target
Update 2: Solved, I just needed to move my all target above the $(OBJECTS) target.
The default behavior of make is to only build the first target listed in your Makefile. I don't see any target listed earlier than $(OBJECTS): | obj. Therefore, the "first target rule" will build the first thing listed in $(OBJECTS).
To get all of your $(OBJECTS) built, you need a target for your final executable that depends on $(OBJECTS).
To make your Makefile meet common convention, you'll want to list a target named all early in your Makefile that depends on your executable as well. That way, when you type make or make all, it will build your $(OBJECTS) and your executable.
For debugging purposes, you might add a target named debugvars: that just executes #echo OBJECTS=$(OBJECTS) to make sure $(OBJECTS) is set as you expect. To run that target, you can then type make debugvars. That's a handy trick I've used many times to debug variables in a Makefile.