I want to execute the following commands:
./a.out 1
./a.out 2
./a.out 3
./a.out 4
.
.
. and so on
How to write this thing as a loop in a
A simple, shell/platform-independent, pure macro solution is ...
# 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})
The promblem with the for number in 1 2 3 4 ; do \ ...
-solution is, that no variables can be assigned within the loop. $(eval VAR=...)
can only be used, if the content of the assignment is known at the beginning of the target execution. If the assignment depends on the loop-variable, VAR
will be empty.
To circumvent this issue, one can use the target functionality to model a loop. The following example takes the n-th file from SRC / OBJ and processes them together. Using this construction you can even use $(eval ...)
to process the loop variable, as demonstrated with 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"
output
$ 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
#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.
You can use set -e
as a prefix for the for-loop. Example:
all:
set -e; for a in 1 2 3; do /bin/false; echo $$a; done
make
will exit immediately with an exit code <> 0
.
Maybe you can use:
xxx:
for i in `seq 1 4`; do ./a.out $$i; done;
For cross-platform support, make the command separator (for executing multiple commands on the same line) configurable.
If you're using MinGW on a Windows platform for example, the command separator is &
:
NUMBERS = 1 2 3 4
CMDSEP = &
doit:
$(foreach number,$(NUMBERS),./a.out $(number) $(CMDSEP))
This executes the concatenated commands in one line:
./a.out 1 & ./a.out 2 & ./a.out 3 & ./a.out 4 &
As mentioned elsewhere, on a *nix platform use CMDSEP = ;
.