How can I create the necessary out-directories for targets with make? - makefile

Say, in a Makefile, I have the following targets:
EXES=dir1/subdir1/abc dir1/subdir1/def dir1/subdir2/ghi dir1/subdir2/jkl dir2/subdir3/mno dir2/subdir3/pqr
Each item in $(EXES) represents a binary to be created. I want to make sure that the necessary directories (in the example: dir1/subdir1, dir1/subdir2, dir2/subdir3) are created if they are not existent.
How would I achieve this with gnu-make?

Use order-only prerequisites:
target: prerequisites | order-only-prerequisites
order-only-prerequisites:
recipe
Their recipe is executed only if they do not exist yet. Example:
$(BUILDDIR)/foo.o: src/foo.c | $(BUILDDIR)
$(CC) $(CFLAGS) -o $# $<
$(BUILDDIR):
mkdir -p $#
And if you want to extract the list of directories to create from the definition of your EXES variable:
$(EXES): | $(dir $(EXES))
$(dir $(EXES)):
mkdir -p $#
Or, to instantiate exactly one rule per target:
define DIR_rule
$(1): | $$(dir $(1))
endef
$(foreach e,$(EXES),$(eval $(call DIR_rule,$(e))))
$(dir $(EXES)):
mkdir -p $#

I finally found a solution with $(dir ...)
EXE_DIRS=$(dir $(EXES))
EXE_DIRS_UNIQUE=$(shell for DIR in $(EXE_DIRS); do echo $$DIR; done | sort | uniq)
$(shell for DIR in $(EXE_DIRS_UNIQUE); do if [ ! -d $$DIR ]; then mkdir -p $$DIR; fi; done)
all: $(EXES)

Related

Force make to look at files before conclude to a circular dependency

I have a circular dependency using make:
CC = gcc
IFLAGS = -Iinclude
CFLAGS = -Wall -g -c -fPIC -pedantic
AFLAGS = -shared
LFLAGS =
VERSION = $(shell cat desc/major).$(shell cat desc/minor).$(shell cat desc/patch)
DFLAGS = -D_XOPEN_SOURCE=700 -DLTKVER=\"$(VERSION)\"
OBJECTS = $(patsubst src/%.c,tmp/%.o, $(shell ls -1 src/*.c))
#OUTPUT = tmp/$(lastword $(subst /, ,$(shell pwd)))
OUT_BIN = install/usr/lib/libLTK.so
OUT_MAN = $(patsubst man/%,install/usr/share/man/%.gz, $(shell find man -type f))
PATH_INCLUDE = install/usr/include/LTK-$(VERSION)
OUT_INCLUDE = $(patsubst %,$(PATH_INCLUDE)/%, $(shell find include -type f -printf "%f\n"))
PC = %
all: $(OUT_BIN) $(OUT_MAN) $(OUT_INCLUDE)
# chmod 755 install/usr/lib/libLTK.so.$(VERSION)
ln -sf install/usr/lib/libLTK.so.$(VERSION) install/usr/lib/libLTK.so
# chmod 755 install/usr/include/LTK-$(VERSION)
# chmod 644 install/usr/include/LTK-$(VERSION)/*
ln -sf install/usr/include/LTK-$(VERSION) install/usr/include/LTK
$(OUT_BIN): $(OBJECTS)
mkdir -p $(shell dirname $#)
$(CC) $(AFLAGS) -o $#.$(VERSION) $^ $(LFLAGS)
tmp/%.o : src/%.c
mkdir -p $(shell dirname $#)
$(CC) $(CFLAGS) -o $# $< $(DFLAGS) $(IFLAGS)
install/usr/share/%.gz : %
mkdir -p $(shell dirname $#)
gzip -c $< > $#
.SECONDEXPANSION:
%.h : $$(patsubst $(PATH_INCLUDE)/$$(PC),include/$$(PC),$$#)
mkdir -p $(shell dirname $$#)
cp $< $$#
clean:
rm -rf tmp install
At second expansion header files, prerequisites are generated from second expansions.
But it's a header that generates another and this new one can be found on the disk.
But make rather prefers to consider a circular dependency and ignore it.
How can I force make to see that the file exists before it searches a target to generate it?
Circular dependences are completely independent of what exists on the disk or doesn't exist on the disk. When make runs it parses the makefile and constructs a graph representing the dependency relationship between targets. This graph must be acyclic, because make will walk the graph looking for whether targets are out of date. If there's a cycle in the graph, then make would recurse forever trying to walk the graph.
For example:
a: b ; touch $#
b: a ; touch $#
It doesn't matter whether these files exist or not: make still needs to be sure that "a" is newer than "b" to satisfy the first dependency, and that "b" is newer than "a" to satisfy the second dependency.
This cannot ever be true, obviously.
Finally resolved by substituing $(OUT_INCLUDE) to %.h.
The goal to auto copy include files is preserved.
Substitued this:
.SECONDEXPANSION:
$(OUT_INCLUDE) : $$(patsubst $(PATH_INCLUDE)/$$(PERCENT),include/$$(PERCENT),$$#)
mkdir -p $(shell dirname $#)
cp $< $#
For this:
.SECONDEXPANSION:
%.h : $$(patsubst $(PATH_INCLUDE)/$$(PC),include/$$(PC),$$#)
mkdir -p $(shell dirname $$#)
cp $< $$#
But I'm still asking myself on "is there anything to force file before dependency".
After looking at the code it looks like no, unless I omit something.

Is it possible to create all missing directory at once with make?

The common pattern is:
obj/%.o : src/%.c
mkdir -p $(dir $#)
$(CC) -c $< -o $#
I am wondering if I can space the call to mkdir for each file. I came across this solution:
CSRC=some/path/here/foo.c another/directory/random/here/bar.c
OBJDIR=obj/
objdirs = $(sort $(foreach path,$(CSRC),$(addprefix $(OBJDIR),$(dir $(path)))))
$(objdirs): %:
mkdir -p $#
obj/%.o : src/%.c | $(objdirs)
$(CC) -c $< -o $#
Is there a better solution?
A simple solution, but not 100% satisfactory, resembles yours:
OBJDIR := obj
CSRC := some/path/here/foo.c another/directory/random/here/bar.c
CSRCDIRS := $(sort $(dir $(CSRC)))
objdirs := $(addprefix $(OBJDIR)/,$(CSRCDIRS))
OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(CSRC))
$(OBJS): $(OBJDIR)/%.o: %.c | $(objdirs)
$(CC) -c $< -o $#
$(objdirs):
mkdir -p $#
It should work but its drawback is that each object file has all object directories as order-only prerequisite, which is overkill. All object directories will be created, even if only one object file is built. They will be created only once because they are order-only, but still, it is not 100% satisfactory.
In order to have only one order-only object directory prerequisite per object file, the only solution I see (but there may be better ones) is something like:
OBJDIR := obj
CSRC := some/path/here/foo.c another/directory/random/here/bar.c
CSRCDIRS := $(sort $(dir $(CSRC)))
objdirs := $(addprefix $(OBJDIR)/,$(CSRCDIRS))
# $(1): source directory
define MY_rule
$(OBJDIR)/$(1)%.o: $(1)%.c | $(OBJDIR)/$(1)
$(CC) -c $$< -o $$#
endef
$(foreach c,$(CSRCDIRS),$(eval $(call MY_rule,$(c))))
$(objdirs):
mkdir -p $#
The iterator explicitly declares each object directory as the only order-only prerequisite of all object files it contains. But it is more difficult to understand (especially the $$). Is it worth the extra complexity?

error in makefile

I am using gnu Make 3.82 and have an annoying problem.
I have a rule setting dependencies between directories.
OBJDIR=../obj
$(objdir)/%.o: %.C
$(COMPILE) -MM -MT$(objdir)/$(notdir $#) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $# ) -c $<
In order to do this, the obj directory must exist.
I want to mkdir the directory as a prerequisite
$(objdir)/%.o: %.C $(objdir)
$(COMPILE) -MM -MT$(objdir)/$(notdir $#) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $# ) -c $<
$(objdir):
mkdir $(objdir)
This doesn't work, because it fails when the directory is there and then the make stops
I tried shell
if [ ! -d $(objdir) ] ; then \
mkdir $(objdir) \
fi
but obviously I've got something wrong. What's the best way of doing this?
One simple way is to use:
mkdir -p ../obj
It doesn't fail when the directory exists.
I usually create a macro, MKPATH, for this:
MKPATH = mkdir -p
and then reference the macro in the rule:
$(objdir):
$(MKPATH) $(objdir)
That way, I can change the behaviour without changing the makefile if it becomes necessary.
Your shell fragment:
if [ ! -d $(objdir) ] ; then
mkdir $(objdir)
fi
does not work as written because make executes each line separately.
You could write (note the added semi-colon):
if [ ! -d $(objdir) ] ; then \
$(MKPATH) $(objdir) ; \
fi
Or:
if [ ! -d $(objdir) ] ; then $(MKPATH) $(objdir); fi
Or:
[ -d $(objdir) ] || $(MKPATH) $(objdir)
Note that the command line must be successful overall, so do not try:
[ ! -d $(objdir) ] && $(MKPATH) $(objdir)
If the directory exists, the first alternative fails, but the shell exits with a non-zero status, thus failing...and causing the build to fail.
mkdir
"mkdir -p"
Change:
$(objdir): mkdir $(objdir)
to =>
$(objdir):
mkdir -p $(objdir)
If that particular mkdir does not have -p then:
$(objdir):
test -d $(objdir) || mkdir $(objdir)
Makefiles
Keep the target: and the comands (mkdir, etc) on seperate lines.
Also, in make, to ignore failed commands, prefix command with minus:
$(objdir):
-mkdir $(objdir)
Commands (if-then-else; for loops, etc) with multiple lines require adding `\;' to represent newlines to the shell:
$(objdir):
if [ ! -d $(objdir) ] ; then \
mkdir $(objdir) ; \
fi
This particular usage of if-then-else can also written as:
$(objdir):
if [ ! -d $(objdir) ] ; then mkdir $(objdir) ; fi
The following Makefile that demonstrates each point above
all: setup dirs report
# Create an intefering dir1
# Remove dir2. It is work to be done later.
setup:
#mkdir -p dir1
#if test -d dir2 ; then rmdir dir2 ; fi
# Continue (with dir2), even though dir1 re-creation fails
dirs:
-mkdir dir1
mkdir -v dir2
# Show we're still running
report:
#echo DIRS:
#for d in dir?; do \
test -d $$d || break ; \
echo -n "$$d " ; \
done
#echo
Output from running running make:
mkdir dir1
mkdir: cannot create directory `dir1': File exists
make: [dirs] Error 1 (ignored)
mkdir -v dir2
mkdir: created directory `dir2'
DIRS:
dir1 dir2

Makefile adds itself as target

I have a Makefile for a C++ program that uses automatic dependency generation. The %.d recipe is taken from the GNU Make manual.
The problem is that somehow "Makefile" is being added as a target and then an implicit rule is causing it to assume it's an executable and using my src/%.cpp rule to try to compile src/Makefile.cpp. When looking at the debug info, this always happens right after the include is executed.
No need to remake target `build/Sprite.d'.
Considering target file `Makefile'.
Looking for an implicit rule for `Makefile'.
...
Trying pattern rule with stem `Makefile'.
Trying implicit prerequisite `Makefile.o'.
Looking for a rule with intermediate file `Makefile.o'.
I know include causes the given Makefiles to be rebuilt if necessary. Does it also try to rebuild the current Makefile? If so how do I stop it, and if not, then why is "Makefile" being added as a target?
Also, the include is executed, causing the .d files to be remade even if I specify a target on the command line, such as make clean. Is there any way to stop that from happening?
# $(call setsuffix,newsuffix,files)
# Replaces all the suffixes of the given list of files.
setsuffix = $(foreach file,$2,$(subst $(suffix $(file)),$1,$(file)))
# $(call twinfile,newdir,newsuffix,oldfile)
# Turns a path to one file into a path to a corresponding file in a different
# directory with a different suffix.
twinfile = $(addprefix $1,$(call setsuffix,$2,$(notdir $3)))
MAIN = main
SOURCE_DIR = src/
INCLUDE_DIR = include/
BUILD_DIR = build/
SOURCES = $(wildcard $(SOURCE_DIR)*.cpp)
OBJECTS = $(call twinfile,$(BUILD_DIR),.o,$(SOURCES))
DEPENDENCIES = $(call twinfile,$(BUILD_DIR),.d,$(SOURCES))
CXX = g++
LIBS = -lpng
CXXFLAGS = -I $(INCLUDE_DIR)
.PHONY: all
all: $(MAIN)
$(MAIN): $(OBJECTS)
$(CXX) $(LIBS) $^ -o $(MAIN)
include $(DEPENDENCIES)
%.o: $(BUILD_DIR)stamp
$(CXX) $(CXXFLAGS) -c $(call twinfile,$(SOURCE_DIR),.cpp,$#) -o $#
$(BUILD_DIR)%.d: $(SOURCE_DIR)%.cpp $(BUILD_DIR)stamp
# echo Generate dependencies for $ $#.$$$$; \
sed 's,\($*\)\.o[ :]*,$(BUILD_DIR)\1.o $# : ,g' $#; \
rm -f $#.$$$$
$(BUILD_DIR)stamp:
mkdir -p $(BUILD_DIR)
touch $#
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
.PHONY: printvars
printvars:
# echo $(SOURCES)
# echo $(OBJECTS)
# echo $(DEPENDENCIES)
Make will always try to remake the Makefile before executing the Makefile. To do so, make will look for rules which can be used to recreate the Makefile. Make will look for quite a few implicit rules and other obscure methods to (re)create the Makefile.
In your case, make somehow decided that the pattern rule %.o: $(BUILD_DIR)/stamp should be used to recreate the Makefile, which failed.
To prevent make from remaking the Makefile you can write a rule with an empty recipe:
Makefile: ;
Read the chapter Remaking Makefiles in the make manual for more explanation.
About the included Makefiles: Included Makefiles will always be included, regardless of the target. If the included makefiles are missing (or older than their prerequisites) then they will first be (re)created. That means a make clean will first generate the .d Makefiles, only to delete them again.
You can prevent the including for specific goals by wraping the include directive in a conditional:
ifneq ($(MAKECMDGOALS),clean)
include $(DEPENDENCIES)
endif
Here is your entire Makefile with some fixes. I marked the places where I changed something.
# Makefile
# $(call setsuffix,newsuffix,files)
# Replaces all the suffixes of the given list of files.
setsuffix = $(foreach file,$2,$(subst $(suffix $(file)),$1,$(file)))
# $(call twinfile,newdir,newsuffix,oldfile)
# Turns a path to one file into a path to a corresponding file in a different
# directory with a different suffix.
twinfile = $(addprefix $1/,$(call setsuffix,$2,$(notdir $3)))
MAIN = main
SOURCE_DIR = src
INCLUDE_DIR = include
BUILD_DIR = build
SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
OBJECTS = $(call twinfile,$(BUILD_DIR),.o,$(SOURCES))
DEPENDENCIES = $(call twinfile,$(BUILD_DIR),.d,$(SOURCES))
CXX = g++
LIBS = -lpng
CXXFLAGS = -I $(INCLUDE_DIR)
.PHONY: all
all: $(MAIN)
$(MAIN): $(OBJECTS)
$(CXX) $(LIBS) $^ -o $(MAIN)
# -------> only include if goal is not clean <---------
ifneq ($(MAKECMDGOALS),clean)
include $(DEPENDENCIES)
endif
# ---------> fixed this target <--------------
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp $(BUILD_DIR)/stamp
$(CXX) $(CXXFLAGS) -c $(call twinfile,$(SOURCE_DIR),.cpp,$#) -o $#
# ---------> and this target <---------------
$(BUILD_DIR)/%.d: $(SOURCE_DIR)/%.cpp $(BUILD_DIR)/stamp
# echo Generate dependencies for $#;
#set -e; rm -f $#; \
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,$(BUILD_DIR)\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
$(BUILD_DIR)/stamp:
mkdir -p $(BUILD_DIR)
touch $#
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
.PHONY: printvars
printvars:
# echo $(SOURCES)
# echo $(OBJECTS)
# echo $(DEPENDENCIES)

Explaining makefile % as well as $< and $#

xpi_built := $(build_dir)/$(install_rdf) \
$(build_dir)/$(chrome_manifest) \
$(chrome_jar_file) \
$(default_prefs)
xpi_built_no_dir := $(subst $(build_dir)/,,$(xpi_built))
$(xpi_file): $(build_dir) $(xpi_built)
#echo "Creating XPI file."
cd $(build_dir); $(ZIP) ../$(xpi_file) $(xpi_built_no_dir)
#echo "Creating XPI file. Done!"
$(build_dir)/%: %
cp -f $< $#
$(build_dir):
#if [ ! -x $(build_dir) ]; \
then \
mkdir $(build_dir); \
fi
can anyone explain me this makefile part? particularly interested in
$(build_dir)/%: % as well as $< and $# directives
two labels $(build_dir) exists, I guess both are executed, but in which order?
$(build_dir)/%: %
cp -f $< $#
This is a static pattern rule which uses automatic variables in its command; $< expands to the leftmost prerequisite, $# expands to the target. If you try to make $(build_dir)/foo (whatever $(build_dir) is), Make will treat this rule as
$(build_dir)/foo: foo
cp -f foo $(build_dir)/foo
The next rule,
$(build_dir):
#if [ ! -x $(build_dir) ]; \
then \
mkdir $(build_dir); \
fi
is for $(build_dir) itself, and is unnecessarily complicated. It says "if $(build_dir) doesn't exist, then mkdir it", and it could be written this way:
$(build_dir):
mkdir $#
It looks as if your primary target is $(xpi_file):
$(xpi_file): $(build_dir) $(xpi_built)
So Make will first make $(build_dir) (if necessary), then the members of the list %(xpi_built), which includes a couple of things of the form $(build_dir)/%. Once those are done, it will execute the commands of this rule: it will cd into $(build_dir), zip some things up, and echo a couple of messages.
See Pattern Rules and Automatic Variables in the GNU make documentation. The first rule matches files inside $(build_dir), not $(build_dir) itself. $< expands to the list of prerequisites of the current rule, $# is the target for the current rule.

Resources