In current directory:
.
├── android
├── build
│ └── Makefile
├── device
│ ├── coo
│ │ └── AndroidProducts.mk
│ ├── google
│ │ └── AndroidProducts.mk
│ └── sky
│ └── AndroidProducts.mk
├── kernel
├── product
└── vendor
├── coo
└── sky
└── AndroidProducts.mk
Makefile:
5 define _search-android-products-files-in-dir
6 $(sort $(shell test -d $(1) && find -L $(1) \
7 -maxdepth 6 \
8 -name .git -prune \
9 -o -name AndroidProducts.mk -print))
10 endef
11
12 define _find-android-products-files
13 $(foreach d, device vendor product, $(call _search-android-products-files-in-dir, $(d))) \
14 build/product/AndroidProducts.mk
15 endef
16
17
18 define _get_directories
19 $(foreach f, $(_find-android-products-files), $(patsubst %/,%,$(dir $(f))))
20 endef
21
22 .PHONY: all search find dir
23
24 all: search find
25
26 search:
27 $(call _search-android-products-files-in-dir,device)
28
29
30 find:
31 $(_find-android-products-files)
32
33 dir:
34 $(_get_directories)
make the target find is ok:
$ make -f build/Makefile find
device/coo/AndroidProducts.mk device/google/AndroidProducts.mk device/sky/AndroidProducts.mk vendor/sky/AndroidProducts.mk build/product/AndroidProducts.mk
but make the target dir have error:
$ make -f build/Makefile dir
device/coo device/google device/sky vendor/sky build/product
make: execvp: device/coo: Permission denied
make: *** [dir] Error 127
Why the error:
make: execvp: device/coo: Permission denied
Related
I am trying to use make to build a set of markdown documents from specific and shared files.
PKGS := foo bar baz app
DEFAULT := DEPENDENCIES.md RULES.md
BUILD := .build
VPATH := .:packages
$(BUILD)/%.history.md: $(DEFAULT) $(wildcard %/RULES.*.md) $(foreach f,$(DEFAULT),%/$(f))
echo "!! BUILDING NOW $#"
echo $^
echo
with the following directory structure:
.
├── ABSTRACT.md
├── DEPENDENCIES.md
├── IMPLEMENTATION.md
├── Makefile
├── packages
│ ├── foo
│ │ ├── ABSTRACT.md
│ │ ├── DEPENDENCIES.md
│ │ ├── IMPLEMENTATION.md
│ │ ├── RULES.0.md -> ../COMMON.md
│ │ └── RULES.md
│ ├── COMMON.md
│ ├── bar
│ │ ├── ABSTRACT.md
│ │ ├── DEPENDENCIES.md
│ │ ├── IMPLEMENTATION.md
│ │ └── RULES.md
│ ├── baz
│ │ ├── ABSTRACT.md
│ │ ├── DEPENDENCIES.md
│ │ ├── IMPLEMENTATION.md
│ │ └── RULES.md
│ └── app
│ ├── ABSTRACT.md
│ ├── DEPENDENCIES.md
│ ├── IMPLEMENTATION.md
│ ├── RULES.0.md -> ../COMMON.md
│ └── RULES.md
└── RULES.md
However, $(wildcard %/RULES.*.md) always seems to expand into an empty list.
When executing make .build/foo.history.md I expected it to evaluate the prerequisites as DEPENDENCIES.md RULES.md packages/foo/RULES.0.md packages/foo/DEPENDENCIES.md packages/foo/RULES.md but instead I see this:
make .build/foo.history.md
echo "!! BUILDING NOW .build/foo.history.md"
!! BUILDING NOW .build/foo.history.md
echo DEPENDENCIES.md RULES.md packages/foo/DEPENDENCIES.md packages/foo/RULES.md
DEPENDENCIES.md RULES.md packages/foo/DEPENDENCIES.md packages/foo/RULES.md
echo
I've also tried adding some extra targets to better understand the process:
# Pattern rule with `%` as a directory clearly works.
%.static: %/RULES.0.md
echo $# -> $^
%.semi: %/RULES.*.md
echo $# -> $^
%.x: $(wildcard packages/%/RULES.*.md)
echo $# -> $^
# Wildcards using * also clear work.
app.y: $(wildcard packages/app/RULES.*.md)
echo $# -> $^
# Combination of both fails.
# I expect that if the target is `foo.z` for the prerequisites to expand into `foo/RULES.*.md`,
# searching within the VPATH.
%.z: $(wildcard %/RULES.*.md)
echo $# -> $^
Which results in this:
$ make app.static --just-print
echo app.static -> packages/app/RULES.0.md
$ make app.semi --just-print
make: *** No rule to make target 'app.semi'. Stop.
$ make app.x --just-print
echo app.x ->
$ make app.y --just-print
echo app.y -> packages/app/RULES.0.md
$ make app.z --just-print
echo app.z ->
I've also tried using .SECONDEXPANSION, but I couldn't get it to work with that either and I keep seeing other people recommending against it.
Additionally, it does work for $(foreach f,$(DEFAULT),%/$(f)) expanding correctly into packages/app/DEPENDENCIES.md packages/app/RULES.md which adds confusion as to why it doesn't work in $(wildcard).
The high-level problem is that you're trying to use too many unfamiliar tools at once. Let's take VPATH out of the picture for now.
The wildcard function will work, with secondary expansion:
.SECONDEXPANSION:
$(BUILD)/%.history.md: $$(wildcard packages/%/RULES.*.md)
echo "!! BUILDING NOW $#"
echo $^
echo
Notice that we must escape the $ in the prerequisite list with another $. I don't know why people advised against secondary expansion, but I see no easier way to get the effect you want.
Now about that VPATH. There isn't much need for it, since you want to search only one directory (packages/). Also, it doesn't work well with wildcard because VPATH tells Make where to look for prerequisites; it doesn't tell wildcard where to look for matches. And Make doesn't know what prerequisite to look for until after wildcard has done its work, which it can't because it doesn't know where to look. I advise you to do without it.
This is the structure of my project:
`
.
├── Makefile
├── arch
│ └── riscv
│ ├── Makefile
│ ├── include
│ │ ├── defs.h
│ │ ├── mm.h
│ │ ├── proc.h
│ │ └── sbi.h
│ └── kernel
│ ├── Makefile
│ ├── clock.c
│ ├── entry.S
│ ├── head.S
│ ├── mm.c
│ ├── proc.c
│ ├── sbi.c
│ ├── trap.c
│ ├── vm.c
│ └── vmlinux.lds.S
├── include
│ ├── printk.h
│ ├── rand.h
│ ├── stddef.h
│ ├── string.h
│ └── types.h
├── init
│ ├── Makefile
│ ├── main.c
│ └── test.c
└── lib
├── Makefile
├── printk.c
├── rand.c
└── string.c
7 directories, 28 files
I include ./include/types.h in ./arch/riscv/include/defs.h, and I successfully compiled .o file of all .c file in./arch/riscv/include/kernel, but something goes wrong when compile ./arch/riscv/include/kernel/vmlinux.lds.S`, it says:
make[2]: Entering directory '/home/micheal/courses/zjuos/src/lab4/arch/riscv/kernel'
riscv64-linux-gnu-gcc -E -P -I../include -o vmlinux.lds vmlinux.lds.S
In file included from vmlinux.lds.S:1:
../include/defs.h:3:10: fatal error: types.h: No such file or directory
3 | #include "types.h"
| ^~~~~~~~~
compilation terminated.
How can I fix it? It is really strange that other .c file also include defs.h, but they compiled well, only vmlinux.ld.S goes wrong.
the top level Makefile looks like:
export
CROSS_=riscv64-linux-gnu-
GCC=${CROSS_}gcc
LD=${CROSS_}ld
OBJCOPY=${CROSS_}objcopy
ISA=rv64imafd
ABI=lp64
INCLUDE = -I $(shell pwd)/include -I $(shell pwd)/arch/riscv/include
CF = -march=$(ISA) -mabi=$(ABI) -mcmodel=medany -fno-builtin -ffunction-sections -fdata-sections -nostartfiles -nostdlib -nostdinc -static -lgcc -Wl,--nmagic -Wl,--gc-sections -g
CFLAG = ${CF} ${INCLUDE} -D DSJF
.PHONY:all run debug clean
all:
${MAKE} -C lib all
${MAKE} -C init all
${MAKE} -C arch/riscv all
#echo -e '\n'Build Finished OK
run: all
#echo Launch the qemu ......
#qemu-system-riscv64 -nographic -machine virt -kernel vmlinux -bios ~/opensbi/build/platform/generic/firmware/fw_jump.bin
debug: all
#echo Launch the qemu for debug ......
#qemu-system-riscv64 -nographic -machine virt -kernel vmlinux -bios ~/opensbi/build/platform/generic/firmware/fw_jump.bin -S -s
clean:
${MAKE} -C lib clean
${MAKE} -C init clean
${MAKE} -C arch/riscv clean
$(shell test -f vmlinux && rm vmlinux)
$(shell test -f System.map && rm System.map)
#echo -e '\n'Clean Finished
the trouble making Makefile looks like:
ASM_SRC = $(filter-out vmlinux.lds.S,$(sort $(wildcard *.S)))
C_SRC = $(sort $(wildcard *.c))
OBJ = $(patsubst %.S,%.o,$(ASM_SRC)) $(patsubst %.c,%.o,$(C_SRC))
all:$(OBJ) vmlinux.lds
vmlinux.lds: vmlinux.lds.S
$(GCC) -E -P -I../include -o $# $^
%.o:%.S
${GCC} ${CFLAG} -c $<
%.o:%.c
${GCC} ${CFLAG} -c $<
clean:
$(shell rm *.o vmlinux.lds 2>/dev/null)
I tried to change $(GCC) -E -P -I../include -o $# $^ to $(GCC) -E -P {include} -o $# $^, but it says:
make[2]: Entering directory '/home/micheal/courses/zjuos/src/lab4/arch/riscv/kernel'
riscv64-linux-gnu-gcc -E -P -I /home/micheal/courses/zjuos/src/lab4/include -I /home/micheal/courses/zjuos/src/lab4/arch/riscv/include -o vmlinux.lds vmlinux.lds.S
make[2]: Leaving directory '/home/micheal/courses/zjuos/src/lab4/arch/riscv/kernel'
riscv64-linux-gnu-ld -T kernel/vmlinux.lds kernel/*.o ../../init/*.o ../../lib/*.o -o ../../vmlinux
riscv64-linux-gnu-ld:kernel/vmlinux.lds:1: syntax error
I'm using GNU Make on Arch Linux to generate PDFs from LilyPond source files. I have a directory structure as follows:
scores/
├── makefile
├── out
│ ├── others-songs
│ │ ├── ...
│ │ ├── ...
│ │ └── 失恋阵线联盟
│ │ ├── 失恋阵线联盟.edition.log
│ │ ├── 失恋阵线联盟.oll.log
│ │ └── 失恋阵线联盟.pdf
│ └── ...
├── src
│ ├── others-songs
│ │ ├── ...
│ │ ├── ...
│ │ └── 失恋阵线联盟
│ │ ├── chorus.ily
│ │ ├── verse.ily
│ │ ├── words.ily
│ │ └── 失恋阵线联盟.ly
│ └── ...
The PDFs in the out directory depend on the .ily and .ly files in the corresponding directory in src. The following implicit pattern rule works if the .ly file is modified, but not if any of the other files are:
LY = $(shell find src -iname '*.ly')
PDF = $(subst src,out,$(LY:.ly=.pdf))
pdf: $(PDF)
out/%.pdf: src/%.ly
#mkdir -p $(dir $#)
#lilypond --include=$(lib) \
-dpoint-and-click=\#f \
-o $(basename $#) $<
I tried doing several different things, like appending $(<D)*.ily to the prerequisites, but it wasn't successful. I've looked at the GNU make manual online for help, but I didn't come up with anything that that I was able to apply to my particular situation.
How can I write a pattern rule that makes each PDF depend on all the files in the appropriate corresponding source directory?
EDIT
I may not have been clear enough with my first question. The behavior I want is if any of the files in the source directories are changed, the corresponding PDF is updated. For example, if chorus.ily is changed, then 失恋阵线联盟.ly is made.
A working example:
LY := $(shell find src -iname '*.ly')
PDF := ${LY:src/%.ly=out/%.pdf}
pdf: $(PDF)
define pdf_deps
$(1:src/%.ly=out/%.pdf) : $(wildcard $(dir ${1})*)
endef
# Make each pdf depend on all the files in its src directory.
$(foreach ly,${LY},$(eval $(call pdf_deps,${ly})))
out/%.pdf:
#echo "making $# from $^"
Usage:
$ ls -1R
.:
Makefile
out
src
./out:
./src:
A
B
./src/A:
a.ly
./src/B:
b.1
b.ly
$ make
making out/B/b.pdf from src/B/b.ly src/B/b.1
mkdir -p out/B
touch out/B/b.pdf
making out/A/a.pdf from src/A/a.ly
mkdir -p out/A
touch out/A/a.pdf
$ make
make: Nothing to be done for 'pdf'.
$ touch src/B/b.ly
$ make
making out/B/b.pdf from src/B/b.ly src/B/b.1
mkdir -p out/B
touch out/B/b.pdf
$ make
make: Nothing to be done for 'pdf'.
$ touch src/B/b.1
$ make
making out/B/b.pdf from src/B/b.ly src/B/b.1
mkdir -p out/B
touch out/B/b.pdf
$ make
make: Nothing to be done for 'pdf'.
I have a directory structure as follows:
.
├── one
│ ├── one_one
│ │ └── one_one_one
│ │ ├── Makefile
│ │ └── one_one_oneTest.cpp
│ └── one_two
│ ├── Makefile
│ └── one_twoTest.cpp
├── three
│ ├── Makefile
│ └── threeTest.cpp
└── two
└── two_one
├── Makefile
└── two_oneTest.cpp
I want to run the make command where ever I find the Makefile. So, I have written a shell script as follows.
#!/bin/bash
find . -type f -name Makefile -exec make \;
But it gives error saying make: *** No targets specified and no makefile found. Stop.
If I just run find . -type f -name Makefile, I get
./two/two_one/Makefile
./three/Makefile
./one/one_two/Makefile
./one/one_one/one_one_one/Makefile
which is the correct output I expected.
If I run the Makefile using make command, it runs properly, so I think the Makefile is correct.
What can be wrong with the shell script?
Just for reference, one of my Makefiles is as follows:
all: TestTwoOne
TestTwoOne: two_oneTest.cpp
g++ two_oneTest.cpp -o TestTwoOne
Your "current directory" is not being changed to the appropriate subdirectories for running the make. Do this instead:
find . -type f -name Makefile -execdir make \;
I have a directory tree like this:
├── dir_a
│ └── file_1.txt
├── dir_b
│ └── dir_c
│ ├── file_2.txt
| └── file_3.txt
└── file_4.txt
I want to mirror this directory structure to hold the results of a command that processes each text file. I.e., the output would look like this:
├── build
│ ├── dir_a
│ │ └── processed_file_1.txt
│ ├── dir_b
│ │ └── dir_c
│ │ ├── processed_file_2.txt
│ | └── processed_file_3.txt
│ └── processed_file_4.txt
├── dir_a
│ └── file_1.txt
├── dir_b
│ └── dir_c
│ ├── file_2.txt
| └── file_3.txt
└── file_4.txt
I'm not very adept with Makefiles, so my question is: how can I get a Makefile to recreate the directory structure and recursively process all text files to place them into the right place inside the build directory? I'll be running this repeatedly as the input files change, so a Makefile that doesn't process unchanged files seems like the right way to go.
Update:
I should also mention that new input files will be added frequently, so I don't want the Makefile to name them explicitly.
It would be easier if you used stems with different suffixes rather than inserting that "processed_" string, but here's an example that works for me here:
OUTPUTS := build/dir_a/processed_file_1.txt \
build/dir_b/dir_c/processed_file_2.txt \
build/dir_b/dir_c/processed_file_3.txt \
build/processed_file_4.txt
all: $(OUTPUTS)
.SECONDEXPANSION:
$(OUTPUTS): build/% : $$(subst processed_file_,file_,%)
mkdir -p $(dir $#)
cp $< $#
clean:
rm -rf build
You could remove the complication of .SECONDEXPANSION by changing the end of the filename instead of the beginning:
OUTPUTS := build/dir_a/file_1.out \
build/dir_b/dir_c/file_2.out \
build/dir_b/dir_c/file_3.out \
build/file_4.out
all: $(OUTPUTS)
$(OUTPUTS) : build/%.out : %.txt
mkdir -p $(dir $#)
cp $< $#
clean:
rm -rf build
As Carl suggested, you could use secondary expansion, but in conjunction with order-only prerequisites.
BUILD_DIR = build
IN_FILES := dir_a/file_1.out \
dir_b/dir_c/file_2.out \
dir_b/dir_c/file_3.out \
file_4.out
OUT_FILES := $(IN_FILES:%=$(BUILD_DIR)/%)
all: $(OUT_FILES)
.SECONDEXPANSION:
$(OUT_FILES) : $(BUILD_DIR)/%.out : %.txt | $$(#D)/.
# your text processing rule here...
%/. :
mkdir -p $*
| $$(#D) means:
during the secondary expansion calculate the value of $(#D) automatic variable (which is the directory part of the target), and
add the order-only dependency on it, that is ensure that the directory exists, but don't consider remaking the target if it is older than the directory (which is an often case)