I'm new to makefiles , recently I was looking at a makefile and could not understand what this means
OBJS := $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
where
PROJECT_ROOT=.
EXTERNAL_ROOT=$(PROJECT_ROOT)/external
SRCDIR = $(PROJECT_ROOT)/src
OBJDIR = $(PROJECT_ROOT)/myobjs
BINDIR = $(PROJECT_ROOT)/mybins
DOCDIR = $(PROJECT_ROOT)/doc
what does it represent? Also i wish to make static library consistly of all files in in the myobjs folder or $(OBJS) except main.o a file in it how to write the command
ar -cvq mylibs/libCS296test.a $(OBJS); for such a case?
Please create different SO requests for very different questions.
For your first question, that is equivalent to this function:
$(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SOURCES))
which basically says "look through the value of the $(SOURCES) variable and for every word matching the pattern $(SRCDIR)/%.cpp, replace it with the pattern $(OBJDIR)/%.o. So, if SOURCES contained a word ./external/src/foo/bar/biz.cpp that would be replaced with ./external/myobjs/foo/bar/biz.o.
Related
I have the following source files:
% ls
data_lexicon.c data_lexicon.h lex.l makefile
And the following makefile:
% cat makefile
CC = cc
CFLAGS = -Wall -std=c89
LDFLAGS = -ll
OBJFILES = lex.o data_lexicon.o
TARGET = lexical_analyzer_1
all: $(TARGET) lex.c
lex.c: lex.l data_lexicon.h
lex -olex.c lex.l
$(TARGET): $(OBJFILES)
$(CC) $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LDFLAGS)
clean:
rm -f $(OBJFILES) lex.c $(TARGET)
If I do make all I get:
% ls
data_lexicon.c data_lexicon.o lex.l
lexical_analyzer_1 data_lexicon.h lex.c
lex.o makefile
So far so good.
However, I would like to move the source files (data_lexicon.c, data_lexicon.h, lex.l) to a folder src and generate the intermediate files (data_lexicon.o lex.c, lex.o) into a obj folder.
I create both folders but I do not understand how the makefile file shall be configured.
I am using FreeBSD make, so the more portable the solution given the better.
However, I would like to move the source files (data_lexicon.c,
data_lexicon.h, lex.l) to a folder src and generate the intermediate
files (data_lexicon.o lex.c, lex.o) into a obj folder.
It never ceases to amaze me how people insist on making extra work for themselves. You can certainly do what you describe, but it will require writing explicit rules for the object files.
First of all, however, you need to understand that make itself doesn't really know anything about directories. (Traditional make doesn't, anyway. GNU make and perhaps others know a little about them.) That is, it doesn't have any sense of varying directories against which it resolves file names. Rather, every target name is resolved against make's working directory. If you want to refer to something in a subdirectory, then you must say so. To begin with:
OBJFILES = obj/lex.o obj/data_lexicon.o
Similar goes for target and prerequisite names in rules:
obj/lex.c: src/lex.l src/data_lexicon.h
lex -o$# src/lex.l
That's also one reason to favor make's automatic variables, such as the $# in the above rule representing the name of the target being built.
Your makefile presently relies on make's built-in rule for building object files from corresponding C source files, but "corresponding" means target and prerequisite names are identical, including any path components, except for the suffixes (.c vs .o). You will no longer have that correspondence for data_lexicon.o, so you will need to write an explicit rule for it building it. This part is left as an exercise.
Motivation:
I have a C project in which multiple .o files are to be generated from a common file. This main file uses preprocessor directives to conditionally include other .h files as needed, depending on target-specific variables defined in the makefile.
I've written this rule below, but depending on the order in which I apply my variable references I get different outcomes.
One small(ish) change, two different outputs
Consider two versions of code from my Makefile. In version A we have the following snippets:
MAIN_OBJ:= $(MAIN_1) $(MAIN_2) $(MAIN_3) $(MAIN_4)
... omitted non-relevant rules (including an all: rule)
$(OBJECT_DIR)/$(MAIN_1): MFLAG = $(METHOD_1_FLAG)
$(OBJECT_DIR)/$(MAIN_2): MFLAG = $(METHOD_2_FLAG)
$(OBJECT_DIR)/$(MAIN_3): MFLAG = $(METHOD_3_FLAG)
$(OBJECT_DIR)/$(MAIN_4): MFLAG = $(METHOD_4_FLAG)
$(OBJECT_DIR)/$(MAIN_OBJ): $(SOURCE_DIR)/$(DEPENDENT_MAIN)
$(CC) -DUSE_$(MFLAG) $(CFLAGS) -o $# $<
This only successfully builds the first target, $(OBJECT_DIR)/$(MAIN_1). The remaining three never get compiled and make stops there.
Now in version B we redefine MAIN_OBJ so that the directory prefix is included within the target list itself:
MAIN_OBJ:= $(MAIN_1) $(MAIN_2) $(MAIN_3) $(MAIN_4)
MAIN_OBJ:= $(addprefix $(OBJECT_DIR)/,$(MAIN_OBJ)
... omitted non-relevant rules (again)
$(OBJECT_DIR)/$(MAIN_1): MFLAG = $(METHOD_1_FLAG)
$(OBJECT_DIR)/$(MAIN_2): MFLAG = $(METHOD_2_FLAG)
$(OBJECT_DIR)/$(MAIN_3): MFLAG = $(METHOD_3_FLAG)
$(OBJECT_DIR)/$(MAIN_4): MFLAG = $(METHOD_4_FLAG)
$(MAIN_OBJ): $(SOURCE_DIR)/$(DEPENDENT_MAIN)
$(CC) -DUSE_$(MFLAG) $(CFLAGS) -o $# $<
This solution works, and compiles all 4 .o files, each with the proper $(MFLAG) value.
What's happening here?
This is probably a dumb question, but why does Version A only compile one .o file? I recognize version B is a generally better way to write rules.
Let me provide one more example that will perhaps illustrate my confusion.
Say we want to write a much more common type of rule: compiling targets from a list with a pattern rule for finding dependencies.
Doing something similar to Version A wouldn't result in a single .o being successfully generated:
MY_FILES:= $(wildcard $(SOURCE_DIR)/*.c))
MY_OBJ:= $(patsubst $(SOURCE_DIR)/%.c, %.o, $(MY_FILES))
...
$(OBJECT_DIR)/$(MY_OBJ): $(OBJECT_DIR)/%.o: $(SOURCE_DIR)/%.c
$(CC) $(CFLAGS) -o $# $<
Clearly the above is a bad idea, and you should write something like this instead:
MY_FILES:= $(wildcard $(SOURCE_DIR)/*.c))
MY_OBJ:= $(patsubst $(SOURCE_DIR)/%.c, $(OBJECT_DIR)/%.o, $(MY_FILES))
...
$(MY_OBJ): $(OBJECT_DIR)/%.o: $(SOURCE_DIR)/%.c
$(CC) $(CFLAGS) -o $# $<
But my question is this:
Why in this case does adding the directory prefix in the rule itself result in nothing being built, while in version A of my makefile the first target was successfully made?
"Version A" fails because make is just expanding things like you asked it to. A variable reference like this:
$(OBJECT_DIR)/$(MAIN_OBJ): ...
says "expand the variable OBJECT_DIR, then add a "/", then expand the variable MAIN_OBJ". So you get:
$(OBJECT_DIR)/$(MAIN_1) $(MAIN_2) $(MAIN_3) $(MAIN_4): ...
So, only the first one is actually prefixed by the OBJECT_DIR value, not all of them (since you didn't show what the values were for all these variables I didn't complete the expansion).
Secondly, make always builds just the first target that it finds in the makefile (unless you override that with the command line or .DEFAULT). You don't say what the "non-relevant rules" are that you omitted, but unless one of them was an all target or similar that depends on all the MAIN_* targets, make will only build the first one which is the behavior you saw.
ETA Prepending to all words is trivial using various methods; see the GNU make manual.
One option:
$(addprefix $(OBJECT_DIR)/,$(MAIN_OBJ)): ...
Another option:
$(MAIN_OBJ:%=$(OBJECT_DIR)/%): ...
Another option:
$(patsubst %,$(OBJECT_DIR)/%,$(MAIN_OBJ)): ...
I am currently have an Android.mk file. For some requirement I need to write a standard GNU make file to build the same program.
As you know in Android native build, we simply put all source files together like
LOCAL_SRC_FILES := a.c b.c d.cpp e.cpp
Now I want to do something in Makefile like:
OBJ = $(LOCAL_SRC_FILES: .c=.o)
This will only transform .c files with .o object targets. How can I combine the condition ".c or .cpp" together?
I think I am too busy to forget that I can just achieve this target by execute this function twice.
TMP_OBJ = $(LOCAL_SRC_FILES: .c=.o)
OBJ = $(TMP_OBJ: .cpp=.o)
Sorry for this silly question.
You could use basename:
OBJ := $(addsuffix .o,$(basename $(LOCAL_SRC_FILES)))
(strips off the suffix of each file in LOCAL_SRC_FILES then adds .o to the end)
Doing it in two steps:
SRC := main.c hello.cpp
OBJ := $(SRC:.c=.o)
OBJ := $(OBJ:.cpp=.o)
I am trying to do this:
From a directory, pick all the C (.c) files, generate .o and add it to
my final target executable. The C files can be added or removed at anytime, so when I
run make for my target, the available C files from the directory has to be picked
to compile and link with my target.
So far, I have the following:
define test_tgt =
DIR = full/path/to/dir
FILES = $(wildcard $(DIR)/*.c)
OBJS = <rule-to-convert-C-to-O>
endef
get_new_files:
$(eval $(test_tgt))
final-target: get_new_files
$(CC) <other-objs> $(OBJS)
Somehow this doesn't seem to work. I see a lot of similar examples, but not sure what
is wrong here. If this approach is not correct, can anyone suggest a better way to
accomplish this.
TIA.
You are trying to program a check that make does by itself.
Just list $(OBJS) as dependencies of final-target.
Something like this should work under GNU make:
DIR = full/path/to/dir
FILES = $(wildcard $(DIR)/*.c)
OBJS = $(subst .c,.o,$(FILES))
final-target: $(OBJS)
$(LD) -o $# $+ # or similar
Full documentation is here: https://www.gnu.org/software/make/manual/html_node/Text-Functions.html
A common type of makefile has a line like this:
OBJS=something.o other.o third.o progname.o
progname: $(OBJS)
Then you would run make progname. But GNU Make can also generate the list of o-files itself from all the c-files it sees in the current directory. How is this done?
Basically, I want to be able to add C files to the directory without having to change the makefile.
(Is it for instance through some shell-magic, or is there is a built-in function for this?)
It can also be done like this:
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
progname: $(OBJS)
Which works just fine if the object file with main() in it is "progname.o".
To view all the defined rules (include the implicit ones), issue make -p.
However the fact that make knows how to generate object files from source files, does not mean that it should do this. Make will try to do the bare minimum in order to satisfy the target you ask it to build.
If you want make to compile all the sources into object in the current directory you will need a rule that will depend on all the objects, e.g.:
all: $(patsubst %.c,%.o,$(wildcard *.c))
You can expand a shell command to give you a list of files. You can also use implicit rules.
It can be done like this:
$(ODIR)/%.o: %.cpp
$(CC) -c $(CFLAGS) -o $# $<
make generates .o file names from .cpp file names it found in the current directory.