2009-09-29 2 views
154

Я хочу, чтобы выполнить следующие команды:Как написать цикл в Makefile?

Как написать эту вещь как цикл в Makefile?

+0

Аналогичные, но несколько более общие: [Многострочные команды bash в makefile] (http://stackoverflow.com/q/10121182/86967) – nobar

ответ

196

Следующее будет сделано, если, как я полагаю, используя ваше использование ./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 включительно, просто изменить 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 
+0

Но если я хочу дойти до 1000, то не можем ли мы указать предел? – avd

+0

Почему да, вы можете :-) Смотрите мое обновление. – paxdiablo

+0

Одна вещь: что такое использование метки qwert? Другая вещь - вложенные петли. Он показывает синтаксическую ошибку в этом для n1 в 0 1 2; do \ для n2 в 1 2 3; do \ ./a.out $$ n1 $$ n2; \ done done – avd

204

Если вы используете GNU сделать, вы можете попробовать

 
NUMBERS = 1 2 3 4 
doit: 
     $(foreach var,$(NUMBERS),./a.out $(var);) 

, который будет генерировать и выполнить

 
./a.out 1; ./a.out 2; ./a.out 3; ./a.out 4; 
+17

Этот ответ ИМХО лучше, потому что ему не требуется использовать какую-либо оболочку, это чистый makefile (даже если он специфичен для GNU). –

+2

Согласен, @Jocelyn, это определенно лучший ответ. – cvk

+5

ключевое слово с запятой имеет решающее значение, иначе будет выполняться только первая итерация –

81

Основная причина использования make 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 не имеет хорошие арифметические макросов, так что я буду обманывать здесь и использовать $(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.

+7

Это, безусловно, лучший ответ по той причине, что bobbogo упомянул (_-j_). – dbn

+0

Любая конкретная причина, по которой это используется. Суффиксы PHONY? Они нужны для чего-нибудь? – Seb

+5

@seb: Без '.PHONY: all', make будет искать файл под названием' all'. Если такой файл существует, сделайте затем проверку последнего изменения времени файла, и make-файл почти наверняка не сделает то, что вы намеревались. В декларации '.PHONY' говорится, что' all' является символической целью. Поэтому Make будет считать цель «все» всегда устаревшей. Отлично. См. Руководство. – bobbogo

14

Для поддержки кросс-платформенных команд необходимо настроить разделитель команд (для выполнения нескольких команд в одной строке).

Если вы используете 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 = ;.

+0

& работает на unix тоже. – orkoden

18

Я понимаю, что вопрос несколько лет, но этот пост все же может быть полезен для кого-то, поскольку он демонстрирует подход, который отличается от вышеизложенного, и не зависит от операций оболочки или от необходимости Измените жестко закодированную строку числовых значений.

$ (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) и счетчика, аналогичный описанному выше (в моем случае счетчик используется, чтобы гарантировать, что мы не так или иначе перейдите в бесконечный цикл, а также как диагностику, чтобы сообщить, сколько итераций было необходимо).

Что-то еще ничего не стоит, хотя и не имеет значения для Q: $ (eval ...) предоставляет метод обхода внутреннего отвращения make к циклическим ссылкам, что является хорошим и хорошим, чтобы обеспечить, когда переменная является макросом type (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.

3

Это не совсем чистый ответ на этот вопрос, но разумный способ обойти такие проблемы:

вместо того чтобы писать сложный файл, просто делегировать управление, например, Баш скрипт, как: Makefile

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

и script.sh выглядит следующим образом:

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

Я застрял на одном шаге, когда писал Makefile. У меня есть следующий код: set_var: @ NUM = 0; while [[$$ NUM <1]]; do \ эхо "Я здесь"; \ echo $$ NUM dump $$ {NUM} .txt; \ var = "SSA_CORE $$ {NUM} _MAINEXEC"; \ echo $$ var; \ var1 = 'eval echo \ $$ {$ (var)}'; \ echo $$ var1; \ ((NUM = NUM ​​+ 1)); \ done all: set_var здесь SSA_CORE0_MAINEXEC - это переменная среды, которая уже установлена. Поэтому я хочу, чтобы это значение получило оценку или печать с использованием переменной var1. Я попробовал это, как показано выше, но не работал. пожалуйста помоги. –

3

может быть, вы можете использовать:

xxx: 
    for i in `seq 1 4`; do ./a.out $$i; done; 
+0

нет, он не может :-( – zx1986

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. 
1

Вы можете использовать set -e в качестве префикса для петли. Пример:

all: 
    set -e; for a in 1 2 3; do /bin/false; echo $$a; done 

make немедленно выйти с кодом выхода <> 0.

Смежные вопросы