我想执行以下命令:
./a.out 1
./a.out 2
./a.out 3
./a.out 4
.
.
. and so on
如何写这个东西作为一个循环在Makefile?
我想执行以下命令:
./a.out 1
./a.out 2
./a.out 3
./a.out 4
.
.
. and so on
如何写这个东西作为一个循环在Makefile?
当前回答
使用make的主要原因是-j标志。Make -j5将同时运行5个shell命令。如果你有4个cpu,这是一个很好的makefile测试。
基本上,你想看到的是:
.PHONY: all
all: job1 job2 job3
.PHONY: job1
job1: ; ./a.out 1
.PHONY: job2
job2: ; ./a.out 2
.PHONY: job3
job3: ; ./a.out 3
这是-j友好的(一个好迹象)。你能认出那个锅炉盘吗?我们可以写成:
.PHONY: all job1 job2 job3
all: job1 job2 job3
job1 job2 job3: job%:
./a.out $*
为了达到同样的效果(是的,就make而言,这与前面的公式相同,只是更紧凑一点)。
进一步的参数化,这样你就可以在命令行上指定一个限制(因为make没有任何好的算术宏,所以我在这里作弊,使用$(shell…)))
LAST := 1000
NUMBERS := $(shell seq 1 ${LAST})
JOBS := $(addprefix job,${NUMBERS})
.PHONY: all ${JOBS}
all: ${JOBS} ; echo "$@ success"
${JOBS}: job%: ; ./a.out $*
您可以使用make -j5 LAST=550运行该命令,其中LAST默认为1000。
其他回答
为了跨平台支持,让命令分隔符(用于在同一行上执行多个命令)成为可配置的。
例如,如果你在Windows平台上使用MinGW,命令分隔符是&:
NUMBERS = 1 2 3 4
CMDSEP = &
doit:
$(foreach number,$(NUMBERS),./a.out $(number) $(CMDSEP))
这将在一行中执行连接的命令:
./a.out 1 & ./a.out 2 & ./a.out 3 & ./a.out 4 &
正如前面提到的,在*nix平台上使用CMDSEP =;
尽管GNUmake表工具包有一个真正的while循环(不管这在GNUmake编程中意味着什么,它有两个或三个执行阶段),如果需要的是一个迭代列表,有一个简单的解决方案,即interval。为了好玩,我们把数字也转换成十六进制:
include gmtt/gmtt.mk
# generate a list of 20 numbers, starting at 3 with an increment of 5
NUMBER_LIST := $(call interval,3,20,5)
# convert the numbers in hexadecimal (0x0 as first operand forces arithmetic result to hex) and strip '0x'
NUMBER_LIST_IN_HEX := $(foreach n,$(NUMBER_LIST),$(call lstrip,$(call add,0x0,$(n)),0x))
# finally create the filenames with a simple patsubst
FILE_LIST := $(patsubst %,./a%.out,$(NUMBER_LIST_IN_HEX))
$(info $(FILE_LIST))
输出:
./a3.out ./a8.out ./ad.out ./a12.out ./a17.out ./a1c.out ./a21.out ./a26.out ./a2b.out ./a30.out ./a35.out ./a3a.out ./a3f.out ./a44.out ./a49.out ./a4e.out ./a53.out ./a58.out ./a5d.out ./a62.out
在循环中动态地分配变量
1 2 3 4中for数的问题;做…-solution是,在循环中没有变量可以赋值。$(eval VAR=…)只能在目标执行开始时已知赋值内容的情况下使用。如果赋值依赖于循环变量,VAR将为空。
为了避免这个问题,可以使用目标功能对循环建模。下面的例子从SRC / OBJ获取第n个文件,并将它们一起处理。使用这种结构,您甚至可以使用$(eval…)来处理循环变量,如VAR3所示。
makefile
SRC = f1.c f2.cpp f3.cpp
OBJ = f1.o f2.o f3.o
SRC2 = $(addsuffix _,$(SRC))
JOIN = $(join $(SRC2),$(OBJ))
PHONY: all
all : info loop
loop : $(JOIN)
$(JOIN) :
@# LOOP - CONTENT
@echo "TARGET: $@"
$(eval VAR1=$(word 1,$(subst _, ,$@)))
@echo "VAR1: "$(VAR1)
$(eval VAR2=$(word 2,$(subst _, ,$@)))
@echo "VAR2: "$(VAR2)
$(eval VAR3=$(subst .o,.x,$(VAR2)))
@echo "You can even substitute you loop variable VAR3: "$(VAR3)
#g++ -o $(VAR2) $(VAR1)
@echo
PHONY: info
info:
@printf "\n"
@echo "JOIN: "$(JOIN)
@printf "\n"
输出
$ make
JOIN: f1.c_f1.o f2.cpp_f2.o f3.cpp_f3.o
TARGET: f1.c_f1.o
VAR1: f1.c
VAR2: f1.o
You can even substitute you loop variable VAR3: f1.x
#g++ -o f1.o f1.c
TARGET: f2.cpp_f2.o
VAR1: f2.cpp
VAR2: f2.o
You can even substitute you loop variable VAR3: f2.x
#g++ -o f2.o f2.cpp
TARGET: f3.cpp_f3.o
VAR1: f3.cpp
VAR2: f3.o
You can even substitute you loop variable VAR3: f3.x
#g++ -o f3.o f3.cpp
一个简单的、独立于shell/平台的纯宏解决方案是…
# GNU make (`gmake`) compatible; ref: <https://www.gnu.org/software/make/manual>
define EOL
$()
endef
%sequence = $(if $(word ${1},${2}),$(wordlist 1,${1},${2}),$(call %sequence,${1},${2} $(words _ ${2})))
.PHONY: target
target:
$(foreach i,$(call %sequence,10),./a.out ${i}${EOL})
使用make的主要原因是-j标志。Make -j5将同时运行5个shell命令。如果你有4个cpu,这是一个很好的makefile测试。
基本上,你想看到的是:
.PHONY: all
all: job1 job2 job3
.PHONY: job1
job1: ; ./a.out 1
.PHONY: job2
job2: ; ./a.out 2
.PHONY: job3
job3: ; ./a.out 3
这是-j友好的(一个好迹象)。你能认出那个锅炉盘吗?我们可以写成:
.PHONY: all job1 job2 job3
all: job1 job2 job3
job1 job2 job3: job%:
./a.out $*
为了达到同样的效果(是的,就make而言,这与前面的公式相同,只是更紧凑一点)。
进一步的参数化,这样你就可以在命令行上指定一个限制(因为make没有任何好的算术宏,所以我在这里作弊,使用$(shell…)))
LAST := 1000
NUMBERS := $(shell seq 1 ${LAST})
JOBS := $(addprefix job,${NUMBERS})
.PHONY: all ${JOBS}
all: ${JOBS} ; echo "$@ success"
${JOBS}: job%: ; ./a.out $*
您可以使用make -j5 LAST=550运行该命令,其中LAST默认为1000。