我想执行以下命令:

./a.out 1
./a.out 2
./a.out 3
./a.out 4
.
.
. and so on

如何写这个东西作为一个循环在Makefile?


当前回答

在循环中动态地分配变量

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

其他回答

如果你使用。/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

我意识到这个问题已经是几年前的问题了,但是这篇文章可能仍然对某些人有用,因为它演示了一种不同于上面的方法,它既不依赖于shell操作,也不需要开发人员提取硬编码的数值字符串。

$(eval ....)内置宏是你的朋友。或者至少可以这样。

define ITERATE
$(eval ITERATE_COUNT :=)\
$(if $(filter ${1},0),,\
  $(call ITERATE_DO,${1},${2})\
)
endef

define ITERATE_DO
$(if $(word ${1}, ${ITERATE_COUNT}),,\
  $(eval ITERATE_COUNT+=.)\
  $(info ${2} $(words ${ITERATE_COUNT}))\
  $(call ITERATE_DO,${1},${2})\
)
endef

default:
  $(call ITERATE,5,somecmd)
  $(call ITERATE,0,nocmd)
  $(info $(call ITERATE,8,someothercmd)

That's a simplistic example. It won't scale pretty for large values -- it works, but as the ITERATE_COUNT string will increase by 2 characters (space and dot) for each iteration, as you get up into the thousands, it takes progressively longer to count the words. As written, it doesn't handle nested iteration (you'd need a separate iteration function and counter to do so). This is purely gnu make, no shell requirement (though obviously the OP was looking to run a program each time -- here, I'm merely displaying a message). The if within ITERATE is intended to catch the value 0, because $(word...) will error out otherwise.

注意,使用增长字符串作为计数器是因为内置的$(words…)可以提供阿拉伯计数,但make不支持数学运算(你不能将1+1赋值给某物并得到2,除非你从shell中调用某物来为你完成它,或者使用同样复杂的宏操作)。这适用于INCREMENTAL计数器,但不适用于DECREMENT计数器。

I don't use this myself, but recently, I had need to write a recursive function to evaluate library dependencies across a multi-binary, multi-library build environment where you need to know to bring in OTHER libraries when you include some library which itself has other dependencies (some of which vary depending on build parameters), and I use an $(eval) and counter method similar to the above (in my case, the counter is used to ensure we don't somehow go into an endless loop, and also as a diagnostic to report how much iteration was necessary).

Something else worth nothing, though not significant to the OP's Q: $(eval...) provides a method to circumvent make's internal abhorrence to circular references, which is all good and fine to enforce when a variable is a macro type (intialized with =), versus an immediate assignment (initialized with :=). There are times you want to be able to use a variable within its own assignment, and $(eval...) will enable you to do that. The important thing to consider here is that at the time you run the eval, the variable gets resolved, and that part which is resolved is no longer treated as a macro. If you know what you're doing and you're trying to use a variable on the RHS of an assignment to itself, this is generally what you want to happen anyway.

  SOMESTRING = foo

  # will error.  Comment out and re-run
  SOMESTRING = pre-${SOMESTRING}

  # works
  $(eval SOMESTRING = pre${SOMESTRING}

default:
  @echo ${SOMESTRING}

快乐的制作。

一个简单的、独立于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})

这招对我很管用:

NUM=4

a-out:
    for (( i=1; i<=${NUM}; i++ )) \
    do \
        ./a.out $$i ; \
    done

这并不是对这个问题的纯粹回答,而是一种解决这类问题的聪明方法:

而不是写一个复杂的文件,简单地委托控制,例如一个bash脚本: makefile

foo : bar.cpp baz.h
    bash script.sh

script.sh是这样的:

for number in 1 2 3 4
do
    ./a.out $number
done