Я хочу выполнить следующие команды:
./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
?
Следующее будет выполнено, если, как я полагаю, используя ваш ./a.out
, вы находитесь на платформе типа UNIX.
for number in 1 2 3 4 ; do \
./a.out $$number ; \
done
Проверьте следующее:
qwert:
for number in 1 2 3 4 ; do \
echo $$number ; \
done
дает:
1
2
3
4
Для больших диапазонов используйте:
qwert:
number=1 ; while [[ $$number -le 10 ]] ; do \
echo $$number ; \
((number = number + 1)) ; \
done
Это выводит от 1 до 10 включительно, просто измените условие завершения while
с 10 до 1000 для гораздо большего диапазона, как указано в вашем комментарии.
Вложенные петли могут быть выполнены таким образом:
qwert:
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
Если вы используете 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;
Основной причиной использования IMHO является флаг -j
. make -j5
будет запускать сразу 5 команд оболочки. Это хорошо, если у вас есть 4 процессора, и хороший тест любого make файла.
В принципе, вы хотите сделать что-то вроде:
.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 "[email protected] success"
${JOBS}: job%: ; ./a.out $*
Вы запускаете это с помощью make -j5 LAST=550
, с LAST
по умолчанию 1000.
Я понимаю, что вопрос несколько лет, но этот пост может по-прежнему быть полезен для кого-то, поскольку он демонстрирует подход, который отличается от вышеизложенного, и не зависит от операций оболочки или от необходимости расширять возможности разработчика из строковой строки числовых значений.
встроенный макрос $(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)
Это упрощенный пример. Он не будет масштабироваться довольно для больших значений - он работает, но по мере того, как строка ITERATE_COUNT будет увеличиваться на 2 символа (пробел и точка) для каждой итерации, когда вы встанете на тысячи, для подсчета слов требуется более продолжительное время. Как написано, он не обрабатывает вложенную итерацию (вам понадобится отдельная итерационная функция и счетчик для этого). Это чисто gnu make, без требования оболочки (хотя очевидно, что OP каждый раз запускал программу - здесь я просто показываю сообщение). Если внутри ITERATE предполагается уловить значение 0, потому что $(word...) в противном случае будет ошибочно.
Обратите внимание, что растущая строка, служащая в качестве счетчика, используется потому, что встроенный $(words...) может обеспечивать арабский счет, но этот make не поддерживает другие математические операции (вы не можете присваивать 1 + 1 чему-либо и получите 2, если вы не вызываете что-то из оболочки, чтобы выполнить его для вас, или используя операцию с одинаковой степенью макросов). Это отлично работает для счетчика INCREMENTAL, но не так хорошо для DECREMENT. Однако.
Я не использую это сам, но в последнее время мне пришлось написать рекурсивную функцию для оценки зависимостей библиотек в многобиблиотечной, многобиблиотечной среде сборки, где вам нужно знать, чтобы вносить в ДРУГИЕ библиотеки, когда вы включаете некоторая библиотека, которая сама имеет другие зависимости (некоторые из которых различаются в зависимости от параметров сборки), и я использую метод $(eval) и счетчика, аналогичный описанному выше (в моем случае счетчик используется, чтобы гарантировать, что мы не так или иначе в бесконечный цикл, а также как диагностику, чтобы сообщить, сколько итераций было необходимо).
Что-то еще ничего не стоит, хотя и не имеет значения для OP Q: $(eval...), дает метод обхода сделать внутреннее отвращение к циклическим ссылкам, что все хорошо и прекрасно, чтобы обеспечить, когда переменная является типом макроса (intialized with =), по сравнению с непосредственным назначением (инициализируется с помощью = =). Иногда вы хотите иметь возможность использовать переменную в пределах своего собственного назначения, а $(eval...) позволит вам это сделать. Важно рассмотреть здесь, что в то время, когда вы запускаете eval, переменная становится разрешенной, и эта часть, которая разрешена, больше не рассматривается как макрос. Если вы знаете, что делаете, и вы пытаетесь использовать переменную в RHS для присваивания себе, это вообще то, что вы хотите в любом случае.
SOMESTRING = foo
# will error. Comment out and re-run
SOMESTRING = pre-${SOMESTRING}
# works
$(eval SOMESTRING = pre${SOMESTRING}
default:
@echo ${SOMESTRING}
Счастливый make'ing.
Для кросс-платформенной поддержки сделайте разделитель команд (для выполнения нескольких команд в одной строке).
Если вы используете MinGW на платформе Windows, например, разделитель команд &
:
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 = ;
.
Это не совсем чистый ответ на вопрос, но разумный способ обойти такие проблемы:
вместо написания сложного файла просто делегируйте элемент управления, например, bash script, например: Makefile
foo : bar.cpp baz.h
bash script.sh
и script.sh выглядит так:
for number in 1 2 3 4
do
./a.out $number
done
Возможно, вы можете использовать:
xxx:
for i in `seq 1 4`; do ./a.out $$i; done;
Вы можете использовать set -e
в качестве префикса для цикла for. Пример:
all:
set -e; for a in 1 2 3; do /bin/false; echo $$a; done
make
немедленно выйдет с кодом выхода <> 0
.
#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.