[makefile] Makefile에서 루프를 작성하는 방법?

다음 명령을 실행하고 싶습니다.

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

이 것을 루프에서 루프로 쓰는 방법은 Makefile무엇입니까?



답변

을 사용하여 가정 한 것처럼 ./a.outUNIX 유형 플랫폼을 사용하는 경우 다음이 수행 됩니다.

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


답변

GNU make를 사용하고 있다면 시도해 볼 수 있습니다.

숫자 = 12 34
해:
        $ (for var, $ (NUMBERS),. / a.out $ (var);)

생성하고 실행할 것입니다

./a.out 1; ./a.out 2; 3 번; ./a.out 4;


답변

사용 메이크업 이럴에 대한 주요 이유는이다 -j플래그. make -j5한 번에 5 개의 셸 명령을 실행합니다. CPU가 4 개인 경우, makefile을 잘 테스트하면 좋습니다.

기본적으로 다음과 같은 내용을보고 싶습니다.

.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 "$@ success"
${JOBS}: job%: ; ./a.out $*

당신은 이것을 실행 make -j5 LAST=550에, LAST1000 디폴트.


답변

나는 질문이 몇 살이라는 것을 알고 있지만,이 게시물은 위와 다른 접근법을 보여 주므로 누군가에게 유용 할 수 있으며 쉘 작업이나 개발자가 하드 코드 된 코드를 작성해야 할 필요성에 의존하지 않습니다 숫자 값의 문자열.

$ (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는 매번 프로그램을 실행하려고했습니다. 여기서는 메시지를 표시하고 있습니다). $ (word …)는 그렇지 않으면 오류가 발생하기 때문에 ITERATE 내의 if는 값 0을 포착하기위한 것입니다.

$ (words …) 내장은 아라비아 숫자를 제공 할 수 있기 때문에 카운터로 사용할 문자열이 증가한다는 점에 유의하십시오. 쉘에서 무언가를 호출하여 그것을 달성하거나 동등하게 복잡한 매크로 작업을 사용하지 않는 한). 이것은 INCREMENTAL 카운터에 효과적이지만 DECREMENT 카운터에는 적합하지 않습니다.

나는 이것을 직접 사용하지 않지만 최근에는 라이브러리를 포함 할 때 다른 라이브러리를 가져올 때 알아야 할 다중 이진 다중 라이브러리 빌드 환경에서 라이브러리 종속성을 평가하기 위해 재귀 함수를 작성해야했습니다. 자체에는 다른 종속성 (일부는 빌드 매개 변수에 따라 다름)이 있으며 위와 비슷한 $ (eval) 및 카운터 방법을 사용합니다 (제 경우에는 카운터가 어떻게 든 끝없이 가지 않도록합니다. 얼마나 많은 반복이 필요한지보고하는 진단으로도 사용됩니다.

OP의 Q에 중요하지는 않지만 다른 가치가있는 것 : $ (eval …)은 순환 참조에 대한 make의 내부 혐오를 피하는 방법을 제공합니다. 이는 변수가 매크로 유형 ( =) 대 즉시 할당 (: =로 초기화) 자체 할당 내에서 변수를 사용하고 싶을 때가 있으며 $ (eval …)을 사용하면 그렇게 할 수 있습니다. 여기서 고려해야 할 중요한 것은 eval을 실행할 때 변수가 해석되고 해석되는 부분이 더 이상 매크로로 처리되지 않는다는 것입니다. 당신이하고있는 일을 알고 있고 RHS에 변수를 사용하려고한다면, 이것은 일반적으로 어쨌든 일어나고 싶습니다.

  SOMESTRING = foo

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

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

default:
  @echo ${SOMESTRING}

행복합니다.


답변

플랫폼 간 지원을 위해 명령 구분 기호 (같은 줄에서 여러 명령을 실행하기 위해)를 구성 할 수있게하십시오.

예를 들어 Windows 플랫폼에서 MinGW를 사용하는 경우 명령 구분 기호는 &다음과 같습니다.

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 = ;.


답변

이것은 실제로 질문에 대한 순수한 대답이 아니라 그러한 문제를 해결하는 지능적인 방법입니다.

복잡한 파일을 작성하는 대신 makefile과 같은 bash 스크립트에 제어를 위임하십시오.

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;