我想执行以下命令:
./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?
当前回答
这并不是对这个问题的纯粹回答,而是一种解决这类问题的聪明方法:
而不是写一个复杂的文件,简单地委托控制,例如一个bash脚本: makefile
foo : bar.cpp baz.h
bash script.sh
script.sh是这样的:
for number in 1 2 3 4
do
./a.out $number
done
其他回答
这个答案,就像@Vroomfondel的答案一样,旨在以优雅的方式规避循环问题。
我的想法是让make生成循环本身作为一个导入的makefile,就像这样:
include Loop.mk
Loop.mk:Loop.sh
Loop.sh > $@
shell脚本可以像你喜欢的那样高级,但可以是一个最小的工作示例
#!/bin/bash
LoopTargets=""
NoTargest=5
for Target in `seq $NoTargest` ; do
File="target_${Target}.dat"
echo $File:data_script.sh
echo $'\t'./data_script.ss $Target
LoopTargets="$LoopTargets $File"
done
echo;echo;echo LoopTargets:=$LoopTargets
生成文件
target_1.dat:data_script.sh
./data_script.ss 1
target_2.dat:data_script.sh
./data_script.ss 2
target_3.dat:data_script.sh
./data_script.ss 3
target_4.dat:data_script.sh
./data_script.ss 4
target_5.dat:data_script.sh
./data_script.ss 5
LoopTargets:= target_1.dat target_2.dat target_3.dat target_4.dat target_5.dat
这样做的好处是make本身可以跟踪已经生成的文件以及需要(重新)生成的文件。同样,这也允许make使用-j标志进行并行化。
如果你使用。/a,下面就可以做到这一点。out,你就在一个unix类型的平台上。
for number in 1 2 3 4 ; do \
./a.out $$number ; \
done
测试如下:
target:
for number in 1 2 3 4 ; do \
echo $$number ; \
done
生产:
1
2
3
4
对于更大的范围,使用:
target:
number=1 ; while [[ $$number -le 10 ]] ; do \
echo $$number ; \
((number = number + 1)) ; \
done
这将输出1到10(包含10),只需将while终止条件从10更改为1000,以获得更大的范围,如您的注释所示。
嵌套循环可以这样完成:
target:
num1=1 ; while [[ $$num1 -le 4 ]] ; do \
num2=1 ; while [[ $$num2 -le 3 ]] ; do \
echo $$num1 $$num2 ; \
((num2 = num2 + 1)) ; \
done ; \
((num1 = num1 + 1)) ; \
done
生产:
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
4 1
4 2
4 3
#I have a bunch of files that follow the naming convention
#soxfile1 soxfile1.o soxfile1.sh soxfile1.ini soxfile1.txt soxfile1.err
#soxfile2 soxfile2.o soxfile2.sh soxfile2.ini soxfile2.txt soxfile2.err
#sox... .... ..... .... .... ....
#in the makefile, only select the soxfile1.. soxfile2... to install dir
#My GNU makefile solution follows:
tgt=/usr/local/bin/ #need to use sudo
tgt2=/backup/myapplication/ #regular backup
install:
for var in $$(ls -f sox* | grep -v '\.' ) ; \
do \
sudo cp -f $$var ${TGT} ; \
cp -f $$var ${TGT2} ; \
done
#The ls command selects all the soxfile* including the *.something
#The grep command rejects names with a dot in it, leaving
#My desired executable files in a list.
如果您正在使用GNU make,您可以尝试一下
NUMBERS = 1 2 3 4 doit: $(foreach var,$(NUMBERS),./a.out $(var);)
哪个将生成并执行
./a.out 1; ./a.out 2; ./a.out 3; ./a.out 4;
为了跨平台支持,让命令分隔符(用于在同一行上执行多个命令)成为可配置的。
例如,如果你在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 =;