Makefile to compile files that begin with a pattern - makefile

My makefile has this line:
OBJS = Test.o Test1.o Test2.o Test3.o ...
Is there a way to make this automatic by matching patterns?

If you are using gmake - you can use the shell command to ls the source files, then patsubst command to convert the list of source files to the list of object files.
SRC=$(shell ls *.cc)
OBJS=$(patsubst %.cc,%.o, $(SRC))
all:
#echo $(OBJS)

I doubt that what you're asking for is what you really want, but here goes:
NUMS := 1 2 3 4 5
OBJS := Test.o $(patsubst %,Test%.o,$(NUMS))
(There is a way to generate a sequence like 1 2 3 4 5 without spelling it out, but it's really ugly and not worth the effort.)

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

collect all .o in subdirectories - makefile

I have the following hierarchy:
+ makefile
|
+ TT_Project1
| obj/
| makefile
+ TT_Project2
| obj/
| makefile
+ TT_Project3
| obj/
| makefile
The top level makefile calls recursively all makefiles below it, each compiles the .cpp to .o and places it under /obj
I would like to collect all .o in the top level to create a static library. And failing as my output library is too small...
TT := libTT.a
SUBDIRS := $(wildcard */.)
OBJECTS := $(wildcard $(addsuffix *.o,$(SUBDIRS)/obj))
all: $(TT) $(OBJECTS)
$(TT) : $(OBJECTS)
ar rcs $(TT) $(OBJECTS)
$(SUBDIRS):
$(MAKE) -C $#
I can clearly see that it's running the makefiles beneath it, and they are placing the *.o under their /obj as expected. But I am failing to grab all the .o I guess... any help is appreciated.
First, this is wrong:
OBJECTS := $(wildcard $(addsuffix *.o,$(SUBDIRS)/obj))
Not only are you missing a / between the obj and *.o, but you need to put the /obj in the first argument to addsuffix. Suppose SUBDIRS ends up as foo/. bar/. baz/.. Then the addsuffix will expand to:
$(addsuffix *.o,foo/. bar/. baz/./obj)
which gives:
foo/.*o bar/.*.o baz/./obj*.o
which is clearly wrong. You want this:
OBJECTS := $(wildcard $(addsuffix /obj/*.o,$(SUBDIRS)))
However, that isn't what you want. It won't work because these variables are expanded when the makefile is read, before any actions have been taken. Before the makefile actually builds anything, there will be no .o files existing, which means the wildcard function will match nothing.
In your case that's a good thing, because if it did match anything you'll get errors because make doesn't know how to build those objects: they're built by the sub-makes.
But, since you have nothing that depends on the SUBDIRS target they won't get built anyway: those recipes will never run.
The easiest thing you can do is something like this:
TT := libTT.a
SUBDIRS := $(wildcard */.)
all: $(TT)
$(TT) : $(SUBDIRS)
ar rcs $(TT) $(addsuffix /obj/*.o,$(SUBDIRS))
$(SUBDIRS):
$(MAKE) -C $#
.PHONY: $(SUBDIRS)
The downside of this is that it will rebuild the library every time you run make even if no objects have been changed. To fix that you'll have to add some complexity.

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.)

Gnu make: is it possible to delay include directive to secondary expansion?

I need to delay inclusion of dependency fragments until second expansion time because the make file I'm editing is itself an include file and I will not have a list of source files to generate the includes until secondary expansion.
.SECONDEXPANSION:
AUTO_DEPENDENCY_FILES = $(patsubst %.cc, depend/%.d, $(CC_SRC_FILES))
# the following does the work because the include argument is not a rule
# prerequisite therefore no secondary expansion occurs
include $$(AUTO_DEPENDENCY_FILES)
depend:
-mkdir depend
all: autodepend
autodepend: depend autodepend_include
autodepend_include: $$(AUTO_DEPENDENCY_FILES)
#echo \"$^\"
$$(AUTO_DEPENDENCY_FILES): depend
depend/%.d: | %.cc
# generate .d files that do not exist
$(COMPILE.cc) -E $*.cc > /dev/null
%.o: %.cc
# update .d files that exist
$(COMPILE.cc) -o $# $<
Note the COMPILE.cc is a very long string that includes -MP -MMD -MFdepend/$*.d flags for auto dependency generation.
I don't know that there's a clean solution to this problem but with a bit of a hack you can get you what you want.
Given a main Makefile of:
$(info main one)
include depend.mk
$(info main two)
CC_SRC_FILES := $(addsuffix .c,a b c d e f)
$(info main three)
and a depend.mk of:
$(info depend one)
AUTO_DEPENDENCY_FILES = $(patsubst %.c,%.d,$(CC_SRC_FILES))
$(info AUTO_DEPENDENCY_FILES := $(AUTO_DEPENDENCY_FILES))
$(info MAKE_RESTARTS := $(MAKE_RESTARTS))
$(info CC_SRC_FILES := $(CC_SRC_FILES))
$(info depend two)
you get the following output when you run make:
main one
depend one
AUTO_DEPENDENCY_FILES :=
MAKE_RESTARTS :=
CC_SRC_FILES :=
depend two
main two
main three
make: `all' is up to date.
Which isn't surprising given the order of assignment and inclusion of files, etc.
Here's where the horrible hack comes in.
When make encounters an include directive that references a file that doesn't exist make sticks the file in a list of "missing include files" and continues parsing the makefile.
When it gets to the end of the makefile(s) it then tries to treat each entry in that list as a potential goal target1 and attempts to make the file.
Once the makefiles have been built make restarts itself and tries again.
You can use this to capture the value of CC_SRC_FILES in an built makefile that your makefile includes and have it be visible when you need it.
If we make depend.mk look like this:
$(info depend one)
include hack.mk
AUTO_DEPENDENCY_FILES = $(patsubst %.c,%.d,$(CC_SRC_FILES))
$(info AUTO_DEPENDENCY_FILES := $(AUTO_DEPENDENCY_FILES))
$(info MAKE_RESTARTS := $(MAKE_RESTARTS))
$(info CC_SRC_FILES := $(CC_SRC_FILES))
$(info depend two)
hack.mk: $(if $(MAKE_RESTARTS),,force)
#echo creating hack.mk
#echo 'CC_SRC_FILES := $(CC_SRC_FILES)' > '$#'
force: ;
Then our output from make becomes:
main one
depend one
depend.mk:3: hack.mk: No such file or directory
AUTO_DEPENDENCY_FILES :=
MAKE_RESTARTS :=
CC_SRC_FILES :=
depend two
main two
main three
creating hack.mk
main one
depend one
AUTO_DEPENDENCY_FILES := a.d b.d c.d d.d e.d f.d
MAKE_RESTARTS := 1
CC_SRC_FILES := a.c b.c c.c d.c e.c f.c
depend two
main two
main three
make: `all' is up to date.
Which gives us the value where we want it.
This isn't pretty but it does work.

No rule to make target consoleio.c

In a recent issue, I've found that DJGPP can only accept the DOS command line character limit. To work around this limitation, I've decided to try to write a makefile to allow me to pass longer strings. In the process of hacking together a makefile and testing it, I've come across a strange error. The makefile is as follows:
AS := nasm
CC := gcc
LD := ld
TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source
CFLAGS := -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \
-nostdinc -fno-builtin -I./include
ASFLAGS := -f aout
export OUTPUT := $(CURDIR)/$(TARGET)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
SOBJS := $(SFILES:.s=.o)
COBJS := $(CFILES:.c=.o)
OBJS := $(SOBJS) $(COBJS)
build : $(TARGET).img
$(TARGET).img : $(TARGET).bin
concat.py
$(TARGET).bin : $(OBJS)
$(LD) -T link.ld -o $# $^
$(SOBJS) : %.o : %.asm
$(AS) $(ASFLAGS) $< -o $#
$(COBJS) : %.o : %.c
$(CC) -c $< $(CFLAGS) -o $#
When attempting to run it, I receive this error:
make: *** No rule to make target `consoleio.c', needed by `consoleio.o'. Stop.
What I don't understand is why it's trying to find a rule for .c files. From what I understand, if the file is there, it should just use it. How do I make make not need a rule for .c files?
What you are trying to do will not work without VPATH, and since you are still learning makefiles, I would avoid using VPATH.
The rule is looking for "consoleio.c", which if I understood your makefile correctly does not exist; what exists is "source/consoleio.c". You probably should change it to something like "$(SOURCES)/%.c" instead of "%c".
I didn't check your syntax for that rule, however. If it's incorrect, the builtin "%.o: %.c" rule will be used instead, which would have the same problem.
The way you are doing is not the usual way I've seen, however. The usual way is to:
Create an implicit rule "%.o: %.c" (or in your case "%.o: $(SOURCES)/%.c")
Explicit list the dependencies for each file: "foo.o: foo.c bar.h baz.h" (with no command, the implicit rule has the command)
Let's try a non-comment answer...
Possibility A:
Your macro for SFILES is looking for files ending in '.s'.
Your rule for compiling SOBJS is looking for files ending in '.asm'.
Possibility B:
Your rule for SOBJS and COBJS is in a notation I don't recognize.
According to the GNU Make manual, you can write implicit rules as:
%.o : %.c ; command
You seem to have a list of targets $(SOBJS) that depends on '%.o : %.asm'.
I'm not sure how make will interpret that.
Personally, I would not trust wild-cards in build rules. I'd much rather spend the time listing exactly which source files are needed to build the code. I don't often run into this problem as a result.
#CesarB seems to have nailed the issue, I'll just add a couple of observations.
I'd strongly recommend against using wildcards in build rules. The build rules should clearly define exactly what is being built, and not depend on what files happen to be in the directory.
I'd also recommend against using VPATH unless you are (1) building in a separate build directory, or (2) have your source files spread out over a large number of directories. If all your sources are in a single directory, using VPATH is only going to confuse.
The := assignment form is usually only used when the variable evaluation is known to take long time, such as when using a $(shell ...). Otherwise, "=" is preferrable.
Using "export" to propagate OUTDIR to concat.py (which I presume it is, since concat.py doesn't take any parameters) is a code smell. If possible, pass it as a parameter instead.

Resources