rules for makefile with flags - makefile

_OBJ = hellomake.o hellofunc.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
I am trying to learn makefile syntax. What is the second line saying? I am clueless. Can I get each operator what it is for in the above please.

It's pattern substitution function call. Here is the link to the manual.
In your case, line2 prefixes all the filenames in _OBJ with $(ODIR)/ and stores the results into variable OBJ.

Related

How to handle directory paths in Makefile directive

I have a makefile directive defined as follows:
OBJ = $(SRC:%.c=$(BUILDDIR)/%.o)
where $SRC is defined as
file1.c file2.c etc..
This works just fine when all files are at the same level as the makefile.
If they are in a directory i.e ./src/file1.c ./src/file2.c it does not.
It fails because it tries to append the source path to the build path i.e
gcc -o ./build/./src/file1.o src/file.c
.
I tried to use the nodir keyword but no luck.
I'm looking for the build command to look like this
gcc -o ./build/file1.o ./src/file.c
Any help is much appreciated
Let's try an experiment:
SRC = ./src/file1.c ./src/file2.c
OBJ = $(notdir $(SRC):%.c=$(BUILDDIR)/%.o)
apps: $(OBJ)
We get:
make: *** No rule to make target `file1.c', needed by `apps'. Stop.
Something's amiss here. Let's look at OBJ:
$(info $(OBJ))
We get:
file1.c %.o
Yikes! We constructed OBJ incorrectly. What if we break it up into smaller steps?
SIMPLE_SRC = $(notdir $(SRC))
OBJ = $(SIMPLE_SRC:%.c=$(BUILDDIR)/%.o)
$(info $(OBJ))
We get:
./build/file1.o ./build/file2.o
It turns out that substitution references of the form $(var:%a=%b) do not allow us to put functions in the var. At this point we should probably forgo them and write the full pattern substitution:
OBJ = $(patsubst %.c,$(BUILDDIR)/%.o,$(notdir $(SRC)))
$(info $(OBJ))
We get:
./build/file1.o ./build/file2.o

Use % twice in a patsubst

I'd like to generate two output words for each input word, that they be consecutive, and apply patsubst to them.
A non-working prototype of what I want:
$(patsubst %.o,%.a.o %.so.o,$(OBJ))
The second apearance of % is not substituted, and instead a plain % appears.
A working version that does not give the desired order:
$(patsubst %.o,%.a.o,$(OBJ)) $(patsubst %.o,%.so.o,$(OBJ))
Example:
Input:
foo.o bar.o
Desired output:
foo.a.o foo.so.o bar.a.o bar.so.o
How can I get the desired output?
The join make function takes two word lists and concatenate them word by word. Not exactly what you want because there would be no space between foo.a.o and foo.so.o, but not far from it.
Assuming you know for sure that some string will never be part of your file names (e.g. !!!) you can combine substitution references (or the equivalent patsubst), join and subst:
$(subst !!!, ,$(join $(OBJ:o=a.o!!!),$(OBJ:o=so.o)))
Or, even simpler, if you know for sure that .a.o cannot be part of your files' basename:
$(subst .a.o,.a.o ,$(join $(OBJ:o=a.o),$(OBJ:o=so.o)))
Two nested foreach loop could be solve your problem. One for the files and the other one for extensions. The below code should solve your problem.
OBJS = foo.o bar.o
EXTS = a.o so.o
OUT = $(foreach file, ${OBJS}, \
$(foreach ext, ${EXTS}, \
$(patsubst %.o, %.${ext}, ${file})))

In a Makefile, use patsubst and wildcard with subfolders and subfolder substitutions

I'm trying to use a makefile to convert some markdown files to html files. I'm trying to accomplish in a few lines that which I previously had a long python script doing.
In the simple example below, I would like to see this code:
build: $(patsubst src/pages/%.md, output/%.html, $(wildcard src/pages/*.md))
%.html: %.md
#echo $< to $#
and this output
src/pages/index.md to output/index.html
src/pages/about.md to output/about.html
src/pages/contact.md to output/contact.html
src/page/foo/bar.md to output/foo/bar.html
Instead, it says:
$ make build
make: *** No rule to make target 'output/index.html', needed by 'build'. Stop.
I'm missing something very basic here.
Consider the target output/index.html. The dependency...
%.html: %.md
will effectively expand to...
output/index.html: output/index.md
with $* equal to output/index. So make looks for output/index.md but can't find it -- hence the error message.
To get the correct pattern stem ($* == index) you need to add the base directories to the pattern rule...
output/%.html: src/pages/%.md
#echo $< to $#
EDIT 1:
If you're concerned about repeated hard-coded strings such as output and src/pages then you can always assign them to parameters...
OUTPUT_DIR := output
SOURCE_DIR := src/pages
build: $(patsubst $(SOURCE_DIR)/%.md, $(OUTPUT_DIR)/%.html, $(wildcard $(SOURCE_DIR)/*.md))
$(OUTPUT_DIR)/%.html: $(SOURCE_DIR)/%.md
#echo $< to $#
(Assuming that's what you meant by `optimization' in your comment.)

Pass argument of call to another function in Makefile

I would like a way to take the argument to a call invocation in a Makefile rule and pass that to a builtin function, in this case wildcard.
This doesn't seem to work:
MODULE_OBJS = $(patsubst %.cc, %.o, $(wildcard $(1)/*.cc))
lib%.a: $(call MODULE_OBJS, %)
#echo $# : $^
In this case I would expect make libfoo.a to print a list of .o files corresponding to the .cc files found under foo/, but nothing is printed. The parameter is getting there because if I append $(1) to the end of MODULE_OBJS the value of % gets printed, but it seems to be lost when getting passed into wildcard.
You need to understand that make will execute $(call MODULE_OBJS, %) before it has even begun building the dependency tree, you cannot accomplish this with a pattern rule. You could use eval hackery but there's a case to made against trying to be too clever with make.
Something like the following is easy enough to maintain
MODULE_OBJS = $(patsubst %.cc, %.o, $(wildcard $(1)/*.cc))
libfoo.a: $(call MODULE_OBJS, foo)
lib%.a:
#echo $#: $^
but after wrestling with clever ways of generating library and binary dependencies I prefer simply listing them explicitly.
I got what I wanted with some hacking of the eval rule:
EXCLUDE_MODULES = obj
MODULES = $(filter-out $(EXCLUDE_MODULES), $(patsubst %/, %, $(wildcard */)))
define MODULE_RULE
lib$(MODULE).a: $(patsubst %.cc, obj/%.o, $(wildcard $(MODULE)/*.cc))
#echo $# : $^
endef
$(foreach MODULE, $(MODULES), $(eval $(MODULE_RULE)))
This allows you to call make libfoo.a and get out a list of all the .o's corresponding with the .cc's in that subdirectory.
For those curious, I uploaded a complete example here.
The Metaprogramming Make articles were a useful resource here.

filter function in Makefile

Is there a way to pick up the target name using automatic variable.
SOURCES = $(wildcard *.c)
dummytgt: $(OBJ)/tier.o
$(GCC) $(CFLAGS) -c $(filter $#,$(SOURCES)).c -o $#
I do not want to mention the filename as input but would want to use the filter function to get the .c file which is same as target name. make throws an error no input files
It's helpful to have a look at how make parses this:
SOURCES = $(wildcard *.c)
dummytgt: $(OBJ)/tier.o
$(GCC) $(CFLAGS) -c $(filter $#,$(SOURCES)).c -o $#
First off,
it will read the makefile, defining and expanding macros as it goes.
SOURCES = $(wildcard *.c) means that ${SOURCES} is a lazy variable with definition $(wildcard *.c).
Lazy? Yes, these recursive variables (as the make manual has it) only expand their right-hand side when they are themselves expanded.
Make needs the dependencies as it reads the file, so $(OBJ) is expanded.
Let's assume that the expansion of ${OBJ} is objs (say).
The shell command block remains as a single lazy variable.
It's important to note that these are not expanded until make decides that it wants to build dmmytgt.
You could have written this to exactly the same effect:
dummytgt: objs/tier.o
$(GCC) $(CFLAGS) -c $(filter $#,$(wildcard *.c)).c -o $#
For this fragment to work,
the file objs/tier.o must already exist.
Let's assume it does.
Make now has all it needs to build dummytgt (according to your makefile),
so now it expands the command block.
$(wildcard *.c) expands to 1.c 2.c (say).
$# is dummytgt
$(filter dummytgt,1.c 2.c) is of course empty (and always will be!)
${GCC} is gcc (say)
${CFLAGS} is empty (say)
Thus the shell gets
gcc -c .c -o dummytgt
Presumably gcc complains that there is no file called .c.
The resulting error stops make's execution.
A few thing not to like here:
$(wildcard ) is only for hacky one-liner makefiles IMHO.
dummytgt requires objs/tier.o, but its build instructions never reference it.
Your $(filter ) always expands to nothing.
$(filter $#.c,$(SOURCES))
But I don't see why you don't use
$#.c
Or better still, make it a prerequisite.

Resources