I have a list of directories BUILDS := $(wildcard */), each as a Dockerfile.
How do I build each docker file? Obviously, this does not work, but I'm looking for something along the same lines:
build: $(BUILDS)
$(DOCKERCMD) $# -t $(DOCKER_REPO_URL):$(subst /,,$^) --force-rm $^
Details aside, you probably want something on these lines:
Makefile
BUILDS := a b c
define build_it =
$(1):
#echo "Building $$#"
touch $$#
endef
.PHONY: all clean
all: $(BUILDS)
$(foreach build,$(BUILDS),$(eval $(call build_it,$(build))))
clean:
rm -f $(BUILDS)
Which runs like:
$ make
Building a
touch a
Building b
touch b
Building c
touch c
See 8.5 The foreach Function and
8.9 The eval Function
Related
Here's my Makefile:
dist/%.js: src/%.js node_modules
$(NM)/babel $< -o $#
build: $(patsubst src/%,dist/%,$(wildcard src/**/*.js))
It runs a command like this:
node_modules/.bin/babel src/deep/foo.js -o dist/deep/foo.js
The problem is that if dist/deep doesn't exist, it errors:
Error: ENOENT: no such file or directory, open 'dist/deep/foo.js'
So what I want to do is add an extra dependency on the directory, which I was hoping I could do with something like this:
dist/%.js: src/%.js $(dir dist/%) node_modules
$(NM)/babel $< -o $#
dist/%/:
mkdir -p $#
build: $(patsubst src/%,dist/%,$(wildcard src/**/*.js))
But it doesn't work. $(dir dist/%) isn't filling in that % like I hoped. Running make --trace yields:
Makefile:10: update target 'dist/deep/foo.js' due to: src/deep/foo.js dist/ node_modules
i.e., you can see it has a dependency on dist/, but I was hoping it'd depend on dist/deep/ so that I could mkdir -p it.
Is there a way to achieve what I want?
First a subsidiary snag. Judging from:
$(wildcard src/**/*.js)
it seems you want this function to perform recursive globbing,
returning all *.js files that exist in src or any subdirectory
thereof.
I don't know what shell you've got, but they don't all do that by
default. The linux bash shell doesn't, though as of bash 4.0
it will do it if the shell option globstar is set.
And anyway, $(wildcard ...) won't do it (unless, possibly, the
operative shell does it by default, which I'm not in a position to
check out). So you can't dependably use $(wildcard ...) for that
purpose. You need make to be invoking a shell in which recursive
** globbing is enabled, and then call:
$(shell ls src/**/*.js)
So that's what I'll do now in showing how to solve your problem with
a simple example. I've got:
src/
one.js
a/
two.js
c/
four.js
b/
three.js
and I just want to each *.js file copied from beneath src to the
same relative name under dist, ensuring that dist and all
necessary subdirectories exist when required to. (Of course, this
could all be done at once with cp). Here is a makefile:
SHELL := /bin/bash
.SHELLFLAGS := -O globstar -c
SRCS := $(shell ls src/**/*.js)
DISTS := $(patsubst src/%,dist/%,$(SRCS))
DESTDIRS := $(dir $(DISTS))
.PHONY: all clean
all: $(DISTS)
dist/%.js: src/%.js | $(DESTDIRS)
cp $< $#
$(DESTDIRS):
mkdir -p $#
clean:
rm -fr dist
which runs like:
$ make
mkdir -p dist/a/c/
mkdir -p dist/b/
cp src/a/c/four.js dist/a/c/four.js
cp src/a/two.js dist/a/two.js
cp src/b/three.js dist/b/three.js
cp src/one.js dist/one.js
In that makefile,
| $(DESTDIRS)
makes each of the $(DESTDIRS) an order-only prerequisite
of any target dist/%.js. An order-only prequisite is not considered in determining whether its
target shall be made, but if it is determined that the target shall be made, then the
order-only prequisite will be made first.
I am using Makefiles in a project to automate workflows. In order to keep them readable, I have one Makefile in each subdirectory. The structure is like the following:
+ a
|- Makefile # with input.txt -> output.txt
|- input.txt
|- output.txt
+ b
|- Makefile # with input.txt -> output.txt
|- input.txt
Now, there is a complication: The rule that converts input.txt to output.txt in b also needs output.txt from a.
I would like to tell my b/Makefile to use a/Makefile to build a/output.txt. Is there any way to do this?
Here is what I tried, and which issues arose:
Add a rule in b/Makefile that does make -C ../a output.txt: I can't have a pattern rule using %.txt: ../a/%.txt in b/Makefile because otherwise it uses this rule to create a recursive definition mess
Mark a/output.txt as .PHONY in b/Makefile: the target in b is rebuilt every time (it should only if a rebuilds it)
In a/Makefile:
output.txt: input.txt ../b/output.txt
cp $< $#
../b/%:
cd ../b/ && $(MAKE) $*
In b/Makefile:
output.txt: input.txt ../a/output.txt
cp $< $#
../a/%:
cd ../a/ && $(MAKE) $*
That being said, who don't you have a Makefile at the top level (.. in this example) that just handles the whole project properly? This would make it a lot more robust, keep you from repeating yourself, and allow parallel execution and other fancy tricks that makes provides.
To make it simple, say I have the following folders:
./src/ with many .c files
./obj/ with many .obj files
./output/ with my binaries I want to build
My makefile is as follows:
all: init mybin
# init commands
init:
mkdir obj
mkdir output
mybin: project1 project2 project3
$(CC) src/misc.c ... etc
$(LK) obj/first.obj obj/second.obj obj/third.obj obj/four.obj obj/five.obj obj/six.obj obj/seven.obj obj/eight.obj obj/nine.obj -o output/myapp.bin
project1: obj/first.obj obj/second.obj obj/third.obj
obj/first.obj: src/first.c
$(CC) first.c ... etc
obj/second.obj: src/second.c
$(CC) obj/second.c ... etc
obj/third.obj: src/third.c
$(CC) obj/third.c ... etc
project2: obj/four.obj obj/five.obj obj/six.obj
obj/four.obj: src/four.c
$(CC) four.c ... etc
obj/five.obj: src/five.c
$(CC) obj/five.c ... etc
obj/six.obj: src/six.c
$(CC) obj/six.c ... etc
project3: obj/seven.obj obj/eight.obj obj/nine.obj
obj/seven.obj: src/seven.c
$(CC) seven.c ... etc
obj/eight.obj: src/eight.c
$(CC) obj/eight.c ... etc
obj/nine.obj: src/nine.c
$(CC) obj/nine.c ... etc
The first time I ran make all, everything compiled find. Then I did:
$ touch src/four.c
$ make all
$
But make exits without compiling anything. I guess it did not detect that one of the .c files had changed, however I don't see what's wrong with my dependencies.
What I expected:
touching src/four.c should have marked obj/four.obj obsolete, and project2 aswell, hence marking mybin obsolete too. This chain should trigger a new compilation of src/four.c to obj/four.obj and then a new linkage of the whole project.
Did you specify the output file of compilation (likely the -o option)? By default (for most toolchains), compiling a .c file produces an .o file, not an .obj one.
UPD.
To get Make updating targets when some prerequisites change you have to provide an exact dependencies between files as far as Make use timestamps to determine whether a file has been changed.
That is, all and init could remain as so-called .PHONY targets, but it is a good practice to make the rest targets to be files.
OUT_DIR := ./output
SRC_DIR := ./src
OBJ_DIR := ./obj
MYBIN := $(OUT_DIR)/myapp.bin
OBJS := $(addprefix $(OBJ_DIR)/, \
first.obj \
second.obj \
third.obj \
four.obj \
five.obj \
six.obj \
seven.obj \
eight.obj \
nine.obj)
.PHONY : all mkdir-output mkdir-obj
all : $(MYBIN)
mkdir-output :
#mkdir -p $(OUT_DIR)
mkdir-obj :
#mkdir -p $(OBJ_DIR)
$(MYBIN) : $(OBJS) | mkdir-output
$(LK) $^ -o $#
$(OBJS) : | mkdir-out
$(OBJS) : $(OBJ_DIR)/%.obj : $(SRC_DIR)/%.c
$(CC) $< -object=$# $(CC_OPT)
The last rule is GNU Make's static pattern rule. And the mkdir-xxx prerequisites after a pipe sign | are order-only ones.
I'm trying my hand at using recursive make to eliminate things like having multiple CFLAGS variables, one for each target. There is only one level of recursion, there is no crazy directory tree traversal happening here. I just want to dump my object files into their target specific folders.
So far I have come up with something that is really elegant (edit: alright it's more elegant than the single-makefile solution i had from before. Which had way too much repetition!) but unfortunately does not work.
I think that by posting the format here it will be apparent what it is that I am trying to do.
# ./makefile
.PHONY: all clean
export CC = g++
export INCLUDE = -I ../include/
export SRC = Main.cpp Graphics.cpp Thread.cpp Net.cpp Otherstuff.cpp
export LINKEROPT = -lglew32 -lopengl32 -lsdl -lws2_32 -lglu32 -lmorelibraries
test:
$(MAKE) -f make.unittest
all:
$(MAKE) -f make.unittest
$(MAKE) -f make.debug
$(MAKE) -f make.release
clean:
-rm -rf build_* *.exe
# I am on windows so the targets are .exe's
Here is the file make.debug:
### sub-makefile for the debug build target. Contains target specific build settings.
DIRNAME = build_debug
TARGETNAME = program_debug
TARGETDESCR = DEBUG
CFLAGS = -Wextra -Wall -O0 -g3 -DDEBUG
### EVERYTHING AFTER THIS POINT IS A TEMPLATE
# my goal is to have as much of my makefile code being "reusable" as possible
# so that I can easily add targets.
OBJ = $(patsubst %.cpp,$(DIRNAME)/%.o,$(SRC))
DEPS = $(patsubst %.cpp,$(DIRNAME)/%.d,$(SRC))
-include $(DEPS)
# default behavior. Set up the build directory. Then build the debug target.
all: $(DIRNAME) $(TARGETNAME)
# this is the build dir
$(DIRNAME):
mkdir $(DIRNAME)
$(DIRNAME)/%.o: %.cpp
#echo -e "Compiling for $(TARGETDESCR): $< --> $#"
$(CC) $(CFLAGS) $(INCLUDE) -c $< -o $#
#echo -e "Generating dependencies: $< --> $(patsubst %.o,%.d,$#)"
$(CC) $(CFLAGS) $(INCLUDE) -MM -MT $# -MF $(patsubst %.o,%.d,$#) $<
# I realize there is a way to generate the deps while compiling in one pass
# but I'll figure it out later
$(TARGETNAME): $(OBJ)
#echo -e "Linking $(TARGETDESCR): $#.exe"
$(CC) -L ../lib/win32/ -o $# $(OBJ) $(LINKEROPT)
As you can see, I can very quickly add a new build target with its own set of CFLAGS by copying over the sub-makefile and lightly modifying it, and then adding a few entries to the main makefile.
So the problem here is that it doesn't recognize changes in files. Only when I edit Main.cpp will it recompile build_debug/Main.o. I'm really unsure about where I can start to figure out what's incorrect.
I've created a monster.
When I suggested recursive make in that other post it was to deal with a specific -- and very strange -- problem of inclusion. I do not subscribe to the dogma that recursive make is pure evil, but it does have disadvantages, and should not be used as a cure-all.
First, let's eliminate a bad (and ongoing) source of redundancy. In you main makefile, instead of
$(MAKE) -f make.debug
use
$(MAKE) -f makefile.sub DIRNAME = build_debug TARGETNAME = program_debug TARGETDESCR = DEBUG CFLAGS = -Wextra -Wall -O0 -g3 -DDEBUG
where makefile.sub is the "template" part of your various sub-makefiles. I know that doesn't look like an improvement, but this way you have only one sub-makefile, not N. (I also think you're using too many target-specific variables, but we can discuss that later.)
Once you're comfortable with this, you can use target-specific variables within makefile.sub, so that in the main makefile you can replace
all:
$(MAKE) -f makefile.sub DIRNAME=build_unittest ...
$(MAKE) -f makefile.sub DIRNAME=build_debug ...
$(MAKE) -f makefile.sub DIRNAME=build_release ...
with
all:
$(MAKE) -f makefile.sub unittest debug release
It's not clear to me what problem you're having with recognizing changes in files (when should Make rebuild build_debug/Main.o, if Main.cc hasn't changed?), but it's probably a direct consequence of using make recursively (see "disadvantages", above) and we can probably fix it without too much grief.
EDIT:
In your sub-makefile, put the all rule before the -include line, so that it will be the default rule. When you call $(MAKE), you don't specify a target, so Make chooses the default target, which is (usually) whichever one comes first. The contents of the %.d files have the form of rules, so if you include them first, one of them (i.e. build_debug/Main.o: Main.cpp) will win.
(disclaimer: I am used to scons ... I am somewhat unexperienced with make)
Context: I am using Eclipse CDT which generates makefiles.
Let's say I have a project directory 'lib' and 2 build configurations 'Debug' and 'Release'. Eclipse CDT gracefully generates a makefile for each build configuration. The said makefiles end-up residing in 'Debug' and 'Release' folders.
Now, what I want to do is have a makefile in the folder 'lib' which calls the makefiles 'Debug/makefile' and 'Release/makefile'.
How do I do that?
I want to be able to launch 'make' in the folder 'lib' and both configurations would be called with the specified target(s).
Solution
Based on all the great input gathered here, I devised the following:
MAKE=make
BUILDS=Release Debug
TARGETS=all clean
$(TARGETS):
#for b in $(BUILDS) ; do $(MAKE) -C $$b $# ; done
$(BUILDS):
#for t in $(TARGETS) ; do $(MAKE) -C $# $$t ; done
%:
#for b in $(BUILDS) ; do $(MAKE) -C $$b $# ; done
depends on what is "calls". You want to either
include $(BUILD)/Makefile
or
$(MAKE) -C $(BUILD) $#
or some such. I'd guess you want the latter. Maybe something like
release debug:
$(MAKE) -C $#
You get the idea.
More examples:
BUILDS=release debug
TARGETS=all clean
$(TARGETS):
for b in $(BUILDS) ; do $(MAKE) -C $$b $# ; done
$(BUILDS):
for t in $(TARGETS) ; do $(MAKE) -C $# $$t ; done
Since you mention "the specified target(s)", I suggest:
%:
$(MAKE) -C Debug $#
$(MAKE) -C Release $#
If that's too general, you can replace the % with $(TARGETS), where TARGETS is something you define, a list of all the things you'd ever want to do this with.
all: release debug
release:
$(MAKE) -C ../Release
debug:
$(MAKE) -C ../Debug
I'm assuming they're all on the same level. The path must be from where you call Make.
Have different targets that invoke the makefile in the two directories.
all: debug product
debug:
$(MAKE) -f debug/Makefile
product:
$(MAKE) -f product/Makefile