Я хочу выполнить следующие команды:
./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.