I have a project with this toy structure:
src:
obj1.cpp
obj2.cpp
obj:
(empty folder)
which I want to compile into a library using make. What I want to write in my makefile is something along the lines of:
mylib.a: obj1.o obj2.o
ar $# $^
And this works, however it leaves the folder messy, as it results in this structure:
obj1.o
obj2.o
mylib.a
src:
obj1.cpp
obj2.cpp
obj:
(empty folder)
What I would prefer is that the result of the call would be something like this:
mylib.a
src:
obj1.cpp
obj2.cpp
obj:
obj1.o
obj2.o
where both obj sources are compiled into .o objects in obj. I tried doing this in my makefile:
vpath %.o obj
mylib.a: obj1.o obj2.o
but this has the same result as above. So, I figures, well sure, the implicit rule for obj1.o doesn't know where to output, right? OK, so I added this rule:
%.o: %.cpp
g++ $^ -o obj/$#
to ensure that I am compiling into obj, however, now, the make command fails, and I understand why it fails. It fails because mylib finds obj1.o, as in it finds the rule for it, it executes the rule, but the rule does not result in the existence of obj1.o, but rather in the existence of obj/obj1.o, and so when mylib is composed, its rule says ar obj1.o obj2.o and it fails.
So, my question is: is there a simple and elegant way to avoid this problem?
One solution I see is to always have some file, empty if need be, named obj1.o in obj, but that seems ugly to me. Another would be to add
"obj/" to every object going to mylib.a, but that means duplicating code and is even uglier. So, what would be the best way to solve this?
vpath and VPATH are not intended for targets, they are for sources. Using them to tell make where the object files should go is not a good idea. The easiest solution is probably a pattern rule:
obj/%.o: src/%.c
<your compilation rule>
Based on this you can elaborate a bit:
SRCDIR := src
OBJDIR := obj
SRCS := $(wildcard $(SRCDIR)/*.c)
OBJS := $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SRCS))
mylib.a: $(OBJS)
<your library building recipe>
$(OBJDIR)/%.o: $(SRCDIR)/%.c
<your compilation recipe>
clean:
rm -f $(OBJS) mylib.a
And of course, in your recipes, do not hesitate to use the automatic variables and the variables you declared yourself like OBJS, for instance. Examples:
mylib.a: $(OBJS)
$(AR) $# $^
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
Related
I need help, simply because I need help:
SRC=src/main.c
OBJ_PATH=bin
OBJS := $(addprefix $(OBJ_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
all:$(OBJ_PATH)/target.exe
$(OBJ_PATH)/target.exe: $(OBJ_PATH) $(OBJS)
$(CC) $(OBJS) -o $(OBJ_PATH)/target.exe
$(OBJ_PATH):
mkdir -p bin
$(OBJ_PATH)/%.o:%.c
mkdir -p bin
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
.PHONY: clean
clean:
rm -f $(OBJ_PATH)/*
when running it gives this:
make: *** No rule to make target 'bin/main.o', needed by 'bin/target.exe'. Stop.
If I leave the objects in the same folder as the c files, it works.
I just need some help, maybe it is something simple that I am not seeing.
Thanks guys.
This is wrong:
$(OBJ_PATH)/%.o: %.c
When make wants to build a file bin/main.o. It matches the target pattern bin/%.o, with a stem of main (the part that matches the %). After replacing the prerequisite pattern %.c with main, make will try to find the prerequisite main.c.
But, that file doesn't exist and make has no idea how to create it. So, that pattern doesn't match and make tries to find a different pattern that will build bin/main.o, but there isn't one, so make says there's no way to build that target.
You need to make your pattern rule:
$(OBJ_PATH)/%.o: src/%.c
so that when make replaces % in the prerequisite pattern it yields src/main.c, which exists, and this will work.
There are other problems with your makefile; for example this is a bad idea:
$(OBJ_PATH)/target.exe: $(OBJ_PATH) $(OBJS)
You never(*) want to use a directory like $(OBJ_PATH) as a simple prerequisite.
Also, this:
OBJS := $(addprefix $(OBJ_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
can be more easily written:
OBJS := $(patsubst src/%.c,$(OBJ_PATH)/%.o,$(SRC))
(*) There can indeed be very specific situations where having a directory as a prerequisite can be useful but they are rare and you shouldn't do it unless you fully understand why it's usually not what you want.
I've ha makefile with following entries. Will the first rule depend on the secon rule ? So that it builds all the .o files from second files ?
all:$(PROG)
$(PROG): *.o
$(LD) -o $(PROG) -c $< $(LFLAGS)
%.o : %.c
$(CC) $(CFLAGS) -o $# -c $<
To be specific if i invoke 'make all' will it invoke the second rule if no *.o files were found ?
All other Variables have usual meaning .
No, that will not work. When you run your makefile for the first time, are there any .o files? No. So the expression *.o will expand to nothing.
Of course, your recipe for $(PROG) doesn't actually use any of the object files anyway, as written.
You can do something like this (although personally I prefer to simply list the files out by hand; it's not very common to create all new files so it's not much effort, and it's safer than just trying to grab every file in the directory):
SOURCES := $(wildcard *.c)
OBJECTS := $(SOURCES:%.c=%.o)
$(PROG): $(OBJECTS)
I wanted to build some C++ code. I've already had a magic Makefile that could calculate dependencies automaticaly, but I wanted to keep object files in separate directory. So the structure looks like:
Makefile
source/a/
source/b/
source/c/
obj/
I was able to run Makefile that converted sources into objects using obj/ prefix, but things got messy when I wanted to backport dependency calculation.
The problem is that is almost all Makefile examples this is done in one step, creating .d from .cpp (%.d: %.cpp). I spent some time trying to understand Makefile and fix it with trials and errors. Finally I've got a working script:
DIRS := a b c
SOURCES := $(foreach dir,$(DIRS),$(wildcard source/$(dir)/*.cpp))
OBJECTS := $(patsubst %.cpp,obj/%.o,$(SOURCES))
obj/%.d: %.cpp
#mkdir -p $(#D)
#$(CXX) -E $(CXXFLAGS) -MM -MP -MF $# -MQ $(#:.d=.o) -MQ $# $<
obj/%.o: %.cpp obj/%.d
#$(CXX) $(CXXFLAGS) -o $# -c $<
project: $(OBJECTS)
...
-include $(OBJECTS:.o=.d)
But I'm still not sure why do I need to have separate steps for cpp->d and cpp&d -> o (or maybe I understand - but then I have no idea why most examples don't need this).
Suppose the source files are foo.cpp and bar.cpp, and the headers are foo.h and bar.h, such that foo.cpp includes foo.h and bar.h, and bar.cpp includes bar.h.
You can have a simple makefile that does not involve dependency files at all:
project: $(OBJECTS)
...
%.o: %.cpp
...
Now if you modify foo.cpp, Make will rebuild foo.o (and project). If you modify bar.cpp, Make will rebuild bar.o (and project). If you modify a header, Make will do nothing, because Make doesn't know that the objects depend in any way upon the headers.
You can put in a rule for dependency files:
project: $(OBJECTS)
...
%.o: %.cpp
...
%.d:
...
-include *.d
Now Make will build and use the dependency files-- if you remember to tell it to. If you do that, Make will know that when you modify foo.h it must rebuild foo.o, and when you modify bar.h it must rebuild foo.o and bar.o.
Remembering to rebuild dependency files is a pain. It would be better to let Make do it. When must foo.d be rebuilt? Well, when foo.cpp is modified, certainly:
project: $(OBJECTS)
...
%.o: %.cpp
...
%.d: %.cpp
...
-include *.d
But foo.d must also be rebuilt when any of the other prerequisites of foo.o (i.e. foo.h or bar.h) has been modified. I haven't spelled out the commands in the rules (and I can't make much sense of the command in your %.d rule), but a simple rule will build a foo.d that looks like this:
foo.o: foo.cpp foo.h bar.h
It is possible to write a command that will produce a foo.d that looks like this:
foo.o: foo.cpp foo.h bar.h
foo.d: foo.cpp foo.h bar.h
There are more sophisticated methods, but this is enough for today.
As to why many example makefiles share a certain sub-optimal feature, it's because people copy each others' makefiles without rigorously examining or understanding every feature.
I am doing some Makefile refactoring and trying to figure out the most concise way to implement a Makefile that does the following:
Has one variable that has all the source files listed (can be both C and C++ files)
All object files are generated in OBJ_DIR
The object directory is created if it does not exist
Here is what I have so far:
...
OBJ_DIR = obj/
BIN_DIR = bin/
PROGRAM = program
SRCS = test1.cpp test2.c
OBJS = $(addprefix $(OBJ_DIR), \
$(patsubst %.cpp, %.o, \
$(patsubst %.c, %.o, $(SRCS))))
$(BIN_DIR)$(PROGRAM) : $(OBJS)
$(CREATE_OUT_DIR)
$(LINK)
$(OBJ_DIR)%.o : %.c
$(CREATE_OBJ_DIR)
$(CCOMPILE)
$(OBJ_DIR)%.o : %.cpp
$(CREATE_OBJ_DIR)
$(CPPCOMPILE)
...
I'd like to eliminate the call to $(CREATE_OBJ_DIR) for every .o compile. Anyone know how to do this? I tried adding this, but then it would not build the object files:
$(OBJS): | $(OBJ_DIR)
$(OBJ_DIR):
$(CREATE_OBJ_DIR)
You already seem to have solved your first point: Have them all in one variable (I shouldn't think you actually need to to separate them into TEMP1 and TEMP2 like you have, just have different build rules)
For the second point, you can tell the compiler where to output the object files (for g++ its like this:
g++ -c MySourceFile.cpp -o obj/MySourceFile.o
The make rule for this would look like:
obj/%.o: %.cpp
g++ -c $*.cpp -o obj/$*.o
And your third point is also easily solved, as you can have a build rule for it (Just put the directory name in the dependency list for the target, before all of the objects are listed), and the build rule would look like this
obj:
mkdir obj
Edit: or following your code examples:
$(BIN_DIR)$(PROGRAM) : $(BIN_DIR) $(OBJS)
$(LINK)
$(BIN_DIR):
$(CREATE_OUT_DIR)
As for your 3rd point: This question has been asked here before. Unfortunately there is no really good answer for this, and you need to find the least ugly hack from the answer. Personally, I vote for the marker file solution.
This is what I do:
$(OBJ_LOC)/%.o: $(SRC_LOC)/%.c
#[ -d $(OBJ_LOC) ] || mkdir -p $(OBJ_LOC)
g++ ...
But, I am looking at these other answers with great interest.
Our make file compiles .c source files with a static pattern rule like this:
OBJECTS = foo.o bar.o baz.o
$(OBJECTS): %.o: %.c
$(CC) $< $(C_OPTIONS) -c -o $#
I need to change one of the .c files to an Objective-C .m file. Invoking the compiler is the same for both source types, so I'd like to use the same rule and just tweak it to be more flexible. I'd rather not change the OPTIONS variable because it's also used for the linking step, etc.
Is there a way to make the rule above more flexible to accommodate both .c and .m files?
Thanks
We can add this either-or behavior to the list of things Make should be able to do easily, but isn't. Here's a way to do it, using "eval" to create a seperate rule for each object.
define RULE_template
$(1): $(wildcard $(basename $(1)).[cm])
endef
OBJECTS = foo.o bar.o baz.o
$(foreach obj,$(OBJECTS),$(eval $(call RULE_template,$(obj))))
$(OBJECTS):
$(CC) $< $(C_OPTIONS) -c -o $#
Note that this depends on the source files already existing before you run Make (foo.c or foo.m, but not both). If you're generating those sources in the same step, this won't work.
Here's a less clever, more robust method.
CPP_OBJECTS = foo.o bar.o
OBJECTIVE_OBJECTS = baz.o
OBJECTS = $(CPP_OBJECTS) $(OBJECTIVE_OBJECTS)
$(CPP_OBJECTS): %.o: %.c
$(OBJECTIVE_OBJECTS): %.o: %.m
$(OBJECTS):
$(CC) $< $(C_OPTIONS) -c -o $#
EDIT: corrected OBJECTS assignment, thanks to Jonathan Leffler.
Not really just copy to
$(OBJECTS): %.o: %.m
$(CC) $< $(C_OPTIONS) -c -o $#
The call to the same compiler is just a happy occasion. Normally you do not compile objective-c code with $(CC). That just feels strange.
But since you go in a harsh way, I won't post do-it-right solution, where you separate objective-C targets from C targets into two different $(OBJECTS)-like variables and make two rules (which you should really do). Too boring. Instead, take a hack!
OBJC_FILES:=$(subst $(wildcard *.m))
real_name = `(test -h $(1) && readlink $(1) ) || echo $(1)`
$(OBJECTS): %.o: %.c
$(GCC) $< $(C_OPTIONS) -c -o $(call real_name,$#)
$(OBJC_FILES): %.c: %.m
ln -s $< $#
And God help those who maintains it!
Btw, this obviously won't work if your m-files are generated.