Make targets using % are not working as in "Nothing to be done" - go

I'm trying to compile all my apps from the cmd folder but somehow this makefile is not working.
GO_BUILD_FLAGS =
APPS = my-app another-app stuff
define BUILD_BINARY =
#echo go build $(GO_BUILD_FLAGS) -o $# ./$<
go build $(GO_BUILD_FLAGS) -o $# ./$<
endef
FORCE: ;
bin/%: cmd/% FORCE
$(BUILD_BINARY)
build: $(addprefix bin/,$(APPS))
I'm continously facing following output, no matter I try.
$ make build
make: Nothing to be done for `build'.
$ make bin/my-app
make: Nothing to be done for `bin/my-app'.
$ make bin/another-app
make: Nothing to be done for `bin/another-app'.
$ make bin/stuff
make: Nothing to be done for `bin/stuff'.
Despite FORCE the bin/ targets are not executed. What am I missing?
Running this on MacOS using GNU Make 3.81.
This is how my folder looks like:
$ tree cmd
cmd
├── another-app
│ └── main.go
├── my-app
│ └── main.go
└── stuff
└── main.go
3 directories, 3 files
when running make with -d I get following:
https://pastebin.com/wh6TWxj9 (didn't fit in body as it has a 30000 char limit)

Eventually I found the issue. However I do not understand yet why the define doesn't work.
In the end I just removed:
define BUILD_BINARY =
#echo go build $(GO_BUILD_FLAGS) -o $# ./$<
go build $(GO_BUILD_FLAGS) -o $# ./$<
endef
and replaced the original bin target
bin/%: cmd/% FORCE
$(BUILD_BINARY)
with
bin/%: cmd/% FORCE
go build $(GO_BUILD_FLAGS) -o $# ./$<
Then it starts working.

Related

Reverse-Recursive Makefile - Suppress entering/leaving directory messages

I know there are many discussions here, why don't use recursive Makefiles. But not reverse. Use this concept (Reverse-Recursive) for usability purpose. With this system I only need one open shell for adding new or modified files to git and can also type make in the same path for rebuild the changed source and link them.
Short description to my Reverse-Recursive Makefile implementation. I have the following simplified tree here:
$ tree
.
├── dir
│   ├── Makefile
│   └── subdir
│   ├── Makefile
│   └── subsubdir
│   └── Makefile
└── Makefile
3 directories, 4 files
Content from the Root-Makefile:
all:
#echo 'Makefile-root: all'
arg1:
#echo 'Makefile-root: arg1'
arg2:
#echo 'Makefile-root: arg2'
.PHONY: all arg1 arg2
RR-Makefile: All other Makefiles in the sub-directories have the same content:
%::
make -C .. $#
all:
make -C ..
.PHONY: all
Output when I type make in subsubdir:
$ make
make -C ..
make[1]: Entering directory '/home/krj/projects/XU-Loader/test/dir/subdir'
make -C ..
make[2]: Entering directory '/home/krj/projects/XU-Loader/test/dir'
make -C ..
make[3]: Entering directory '/home/krj/projects/XU-Loader/test'
Makefile-root: all
make[3]: Leaving directory '/home/krj/projects/XU-Loader/test'
make[2]: Leaving directory '/home/krj/projects/XU-Loader/test/dir'
make[1]: Leaving directory '/home/krj/projects/XU-Loader/test/dir/subdir'
Output when I type make with an argument in subsubdir:
$ make arg1
make -C .. arg1
make[1]: Entering directory '/home/krj/projects/XU-Loader/test/dir/subdir'
make -C .. arg1
make[2]: Entering directory '/home/krj/projects/XU-Loader/test/dir'
make -C .. arg1
make[3]: Entering directory '/home/krj/projects/XU-Loader/test'
Makefile-root: arg1
make[3]: Leaving directory '/home/krj/projects/XU-Loader/test'
make[2]: Leaving directory '/home/krj/projects/XU-Loader/test/dir'
make[1]: Leaving directory '/home/krj/projects/XU-Loader/test/dir/subdir'
It's maybe only a cosmetic issue, but how can I suppress Leaving/Entering messages without to invoke make with the argument --no-print-directory in subsubdir?
$ make --no-print-directory
make -C ..
make -C ..
make -C ..
Makefile-root: all
Have tried to add MAKEFLAGS += -no-print-directory in each RR-Makefile but breaks the function of the recursion down to the root Makefile.
It was an usage fault from me. I used -no-print-directory instead of --no-print-directory, because I searched first on SO for a similar question and found this answer. Unfortunately don't investigaed the manual pages from GNU make.
With --no-print-directory this works, without any issues:
MAKEFLAGS += --no-print-directory
%::
make -C .. $#
all:
make -C ..
.PHONY: all

GNU Make how to make a static pattern rule for files that are not in the same directory?

I want to use make and create a static pattern rule that has the target in a output directory, and the prerequisite files are in the preceeding directory, and it has to work recursively.
I have a minimal example here:
.
├── anotherdir
│   ├── output
│   │   ├── source3.md
│   │   └── source4.md
│   ├── source3.json
│   └── source4.json
├── output
│   ├── source1.md
│   └── source2.md
├── source1.json
└── source2.json
I want to generate the output directories if they do not exist, and I want to generate *.md files from the *.json using make if they do not exist, or *.json is updated.
So far, I have the following Makefile:
SOURCE_FILES := $(shell find ./ -name "*.json")
OUTPUT_FILES := $(join $(addsuffix output/,$(dir $(SOURCE_FILES))), $(addsuffix .md,$(basename $(notdir $(SOURCE_FILES)))))
.PHONY: all
all: $(OUTPUT_FILES)
$(OUTPUT_FILES): %.md: %.json
mkdir -p $(dir $#)
# Command to create MD file from json file into the output directory here
The actual command to create the MD file from the json file doesn't matter here, because I have a script that I will call that will do this for me. The problem here, is that when I try to even run this at all, I get the following output:
> make all
make: *** No rule to make target 'anotherdir/output/source4.json', needed by 'anotherdir/output/source4.md'. Stop.
Obviously, source4.json is not in anotherdir/output, but rather, it's in the preceeding directory, which is just anotherdir. I don't know how to make it so that the pattern $(OUTPUT_FILES): %.md: %.json will match it properly.
Or is a static pattern rule not good here? I'm not sure what to do to fit my scenario.
EDIT: I tried to do something like this:
$(OUTPUT_FILES): %.md: $(join $(subst output,,$(dir %)), $(addsuffix .json,$(basename $(notdir %))))
and this doesn't work, I still get:
> make all
make: *** No rule to make target 'anotherdir/output/source4.json', needed by 'anotherdir/output/source4.md'. Stop.
Edit 2: to clarify, i start with the following files
.
├── anotherdir
│ ├── source3.json
│ └── source4.json
├── source1.json
└── source2.json
And then when i run make, i want it to generate the output folders like this
.
├── anotherdir
│ ├── output
│ │ ├── source3.md
│ │ └── source4.md
│ ├── source3.json
│ └── source4.json
├── output
│ ├── source1.md
│ └── source2.md
├── source1.json
└── source2.json
I want to use some kind of smart makefile syntax to pick up these files names without me hard coding it in myself. Hence, i looked at the documentation and saw that static pattern rules might be the solution that i want, except that i can't get the right prerequisite pattern down.
I would do it this way:
First, find the source files just as you did (with a small change to prevent the unsightly double-slash):
SOURCE_FILES := $(shell find . -name "*.json")
A pattern file would be nice, if we could use two wildcards at once, but Make can't quite do that. So I recommend using a template:
define template
TDIR := $(dir $(1))output
TARG := $$(TDIR)/$(notdir $(basename $(1))).md
$$(TARG): $(1)
mkdir -p $$#
#echo building $$# from $$<
# Command to create MD file from json file into the output directory here
endef
$(foreach SOURCE,$(SOURCE_FILES),$(eval $(call template,$(SOURCE))))
If this works, all that's left is to construct a list of output files, and a default rule that has all of them as prerequisites:
define template
TDIR := $(dir $(1))output
TARG := $$(TDIR)/$(notdir $(basename $(1))).md
OUTPUT_FILES += $$(TARG)
$$(TARG): $(1)
mkdir -p $$#
#echo building $$# from $$<
# Command to create MD file from json file into the output directory here
endef
all:
$(foreach SOURCE,$(SOURCE_FILES),$(eval $(call template,$(SOURCE))))
all: $(OUTPUT_FILES)
It isn't pretty, but it seems to work.
If it had not been proposed already in another answer I would have suggested foreach-eval-call. For completeness here are different solutions for GNU make (they may work also with other versions of make but I did not check):
Creating the output directories beforehand
If the output directories exist already you can refer to ../%.json in your pattern rule:
SOURCE_FILES := $(shell find . -name "*.json")
OUTPUT_FILES := $(join $(dir $(SOURCE_FILES)),\
$(patsubst %.json,output/%.md,$(notdir $(SOURCE_FILES))))
$(shell mkdir -p $(dir $(OUTPUT_FILES)))
.PHONY: all
all: $(OUTPUT_FILES)
%.md: ../%.json
: json2md $< -o $#
This may look strange but if you read carefully the Pattern match section of the GNU make manual you should quickly understand. The only constraint for this to work is that the output directories exist before make searches pattern rules that match the targets. If one does not exist make will complain that there is no eligible rule to build the target. This is the reason for the:
$(shell mkdir -p $(dir $(OUTPUT_FILES)))
at the beginning of the Makefile. Demonstration:
$ make
: json2md output/../source2.json -o output/source2.md
: json2md output/../source1.json -o output/source1.md
: json2md anotherdir/output/../source4.json -o anotherdir/output/source4.md
: json2md anotherdir/output/../source3.json -o anotherdir/output/source3.md
Using the secondary expansion
Secondary expansion gives you the possibility to use automatic variables in the list of prerequisites. The $$ are needed to escape the first expansion by make.
SOURCE_FILES := $(shell find . -name "*.json")
OUTPUT_FILES := $(join $(dir $(SOURCE_FILES)),\
$(patsubst %.json,output/%.md,$(notdir $(SOURCE_FILES))))
.PHONY: all
all: $(OUTPUT_FILES)
$(sort $(dir $(OUTPUT_FILES))):
mkdir -p $#
.SECONDEXPANSION:
$(OUTPUT_FILES): $$(patsubst %output,%,$$(#D))$$(basename $$(#F)).json | $$(dir $$#)
: json2md $< -o $#
Demonstration:
$ make
mkdir -p output/
mkdir -p anotherdir/output/
: json2md source2.json -o output/source2.md
: json2md source1.json -o output/source1.md
: json2md anotherdir/source4.json -o anotherdir/output/source4.md
: json2md anotherdir/source3.json -o anotherdir/output/source3.md
Note: instead of creating the output directories in the json-to-md rule (which has the drawback of creating them several times), I added them as order-only prerequisites and added a specific rule to create them.
Note: the sort function also removes duplicates.
Using recursive make
Here we invoke make (with always the same Makefile) recursively in each sub-directory (except output, of course). Each invocation handles only the local json files, which makes the paths of prerequisites and targets much simpler.
MF := $(realpath $(lastword $(MAKEFILE_LIST)))
SUB_DIRS := $(filter-out . ./output,$(shell find . -maxdepth 1 -type d))
SOURCE_FILES := $(filter-out $(SUB_DIRS),$(wildcard *.json))
OUTPUT_FILES := $(patsubst %.json,output/%.md,$(SOURCE_FILES))
.PHONY: $(SUB_DIRS) all
all: $(SUB_DIRS) $(OUTPUT_FILES)
$(OUTPUT_FILES): output/%.md: %.json | output
: json2md $< -o $#
output:
mkdir -p $#
$(SUB_DIRS):
$(MAKE) -C $# -f $(MF)
Demonstration:
$ make
make -C anotherdir -f /home/doe/json2md/Makefile
make[1]: Entering directory '/home/doe/json2md/anotherdir'
mkdir -p output
: json2md source4.json -o output/source4.md
: json2md source3.json -o output/source3.md
make[1]: Leaving directory '/home/doe/json2md/anotherdir'
mkdir -p output
: json2md source2.json -o output/source2.md
: json2md source1.json -o output/source1.md

Makefile: explicit entry works, wildcard % not working

I have this rule in my makefile, but make didn't find it:
$(BUILDDIR)%.o : $(BUILDDIR)%.bin
#echo
$(OBJCOPY) -I binary -O elf32-avr --redefine-sym _binary_$*_bin_start=$* --redefine-sym _binary_$*_bin_end=$*_end $< $#
If I make it explicit, make will use them (called for build/rom1.o and build/rom2.o; BUILDDIR=build/)
$(BUILDDIR)rom1.o : $(BUILDDIR)rom1.bin
#echo
$(OBJCOPY) -I binary -O elf32-avr --redefine-sym _binary_rom1_bin_start=rom1 --redefine-sym _binary_rom1_bin_end=rom1_end $< $#
$(BUILDDIR)rom2.o : $(BUILDDIR)rom2.bin
#echo
$(OBJCOPY) -I binary -O elf32-avr --redefine-sym _binary_rom2_bin_start=rom2 --redefine-sym _binary_rom2_bin_end=rom2_end $< $#
Does anyone has a hint whats wrong with the wildcard in my first try?
Edit:
The version of make is 4.1 running on Ubuntu 16.04.
This is the error message from make when trying to run with the wildcard:
make: *** No rule to make target 'build/rom1.o', needed by 'build/rom1.elf'. Stop.
Let's simplify the problem…
If this is your file structure…
.
├── Makefile
└── build
├── rom1.bin
└── rom2.bin
and this is your Makefile…
BUILDDIR := build/
$(BUILDDIR)%.o: $(BUILDDIR)%.bin
touch $#
and you run $ make build/rom{1,2}.o, your resulting file structure will be…
.
├── Makefile
└── build
├── rom1.bin
├── rom1.o
├── rom2.bin
└── rom2.o

Make multiple targets for all subdirectories

My directory structure is the following (of course the src/ subdirectories also contain files, but these are not important right now):
examples/
├───testprog1/
│ ├───bin/
│ ├───obj/
│ ├───src/
│ └───Makefile
├───testprog2/
│ ├───bin/
│ ├───obj/
│ ├───src/
│ └───Makefile
└───Makefile
The Makefile's in testprog1/ and testprog2/ look similar to this one:
OBJECTS_FILES=$(subst .cpp,.o,$(subst src/,obj/,$(wildcard src/*.cpp)))
bin/testprog1.exe: $(OBJECTS_FILES)
g++ -o $# $^
obj/%.o: src/%.cpp
g++ -c -o $# $^
clean:
rm -f obj/*.o
rm -f bin/meanTest.exe
They work perfectly fine alone, but if I want to build all examples at once, it would be better to use the Makefile in examples/ for that. What should it look like? Of course, it has to have the targets all and clean it will execute for all subdirectories. I also would like to avoid for-loops because I heard that they prevent make from using parallel processing.
You can make a recipe run in the background by appending an & to the end, which would allow you to build in parallel, but that's messy as your target could complete before the background tasks have finished running, which could cause dependency issues, so we'll steer clear of that.
A better solution would be to create a new rule for each subdir:
.PHONY: testprog1 testprog2
testprog1 testprog2:
$(MAKE) -C $# $(MAKECMDGOALS)
all clean: testprog1 testprog2
If you do a make clean, then $(MAKECMDGOALS) will be clean. It will build both testprog1 and testprog2 with this target. Notice that because testprog1 and testprog2 are directory names, you have to declare them as phonies, as their timestamp will change when you build them.
You could also specify the target as %: testprog1 testprog2 if you wanted any command (save testprog1 or testprog2) to be passed down to the submakes.

How to tell make to watch dependencies of a sub-make target?

I was investigating on the same question here, but I was not very clear of what I was asking, even for myself. Sorry for those who spent time answering my unclear question.
So let's try again with a more realistic example. We consider this structure:
.
├── Makefile
└── src/
├── bar
├── foo
└── Makefile
Where the main Makefile is:
all: src/foobar
src/foobar:
make -C $(dir $#)
And the sub-makefile is:
foobar: foo bar
join $^ > $#
If I run make for the first time (from ./) everything works as expected, foobar is produced.
$ make
make -C src/
make[1]: Entering directory '/project/src'
join foo bar > foobar
make[1]: Leaving directory '/project/src'
$ make
make: Nothing to be done for 'all'.
However if I touch any of the foobar dependencies. The parent Makefile will not regenerate the target. Here, I perfectly understand the behavior of Make, but I want to tell it to be aware of foobar' dependencies.
$ touch src/foo
$ make
make: Nothing to be done for 'all'.
My current solution which is not very neat is to ask for the dependencies. So the src/Makefile become:
src=foo bar
foobar: $(src)
#echo "Joining"
join $^ > $#
files: $(src)
#echo $^
And the ./Makefile:
all: src/foobar
src=$(addprefix src/,$(shell make --no-print-directory -C src files | tr '\n' ' '))
src/foobar: $(src)
make -C $(dir $#)
I must also say that this particular example could be simplified using a single Makefile only. My real example is quite more complex. The src/Makefile generate an executable while the parent Makefile do lots of other things (packing in a specific format, generate the documentation, build other sub-makefiles and so on). Thus, I want to keep these tasks well separated and I need to different Makefiles.
In the main Makefile create a dependency for the child target or directory that is always in need of building, and let the child Make then do the real work.
There is a good example here: http://owen.sj.ca.us/~rk/howto/slides/make/slides/makerecurs.html.
To translate for your case, change your main Makefile to be:
all: src/foobar
src/foobar: force
$(MAKE) $(MFLAGS) -C src
force:
true
I also added $(MFLAGS) which will pass same flags from parent to child make.

Resources