"만들기"에 대한 인수 전달


354

나는 Makefiles를 사용합니다.

나는라는 대상이 run빌드 대상을 실행합니다. 단순화하면 다음과 같습니다.

prog: ....
  ...

run: prog
  ./prog

인수를 전달할 방법이 있습니까? 그래서

make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat

감사!


답변:


264

원하는 것을 정확하게 수행하는 방법을 모르지만 해결 방법은 다음과 같습니다.

run: ./prog
    ./prog $(ARGS)

그때:

make ARGS="asdf" run
# or
make run ARGS="asdf"

27
@Rob : $ ()는 이식성이 뛰어나 Nmake와 make에서도 작동합니다.
John Knoeller

7
@Rob : Nmake는 매크로 확장을 위해 $ {}을 지원 한 적이 없으며, 현재는 구식 인 것으로 보입니다. 내가 본 모든 온라인 자습서에서 $ ()을 권장합니다. $ ()는 bash와 같은 다른 도구와 더 일관성이 있습니다.
John Knoeller

10
어쩌면 그것은 구식입니다. 저는 항상 $ {}을 사용했지만 GNU Make 매뉴얼에 "변수의 값을 대치하려면 달러 기호 다음에 변수 이름을 괄호 나 괄호로 묶습니다. $(foo)' or $ {foo} '는 유효한 참조입니다. 변수 'foo'. " $ () 만 사용되는 예제를 제공합니다. 아 잘
Jakob Borg

7
존과 평온함을 환호하고, 나는 되돌아 가서 제 1 판 OReilly 책 "Managing Projects with Make"의 사본에서 그 제안이 나온 것을 보았습니다. 저자는 ()와 매크로를 모두 사용하여 아카이브 대체에 관한 규칙을 설명하지만 {}를 사용하여 구별 할 것을 제안합니다. 그러나 .... 새로운 판은 이제 "GNU Make로 프로젝트 관리하기"라는 제목이 사용되었습니다. 가서 그림을 .... 현대화해야 할 것 같아! (-: 그래도 MS NMake barfs가 {}에도 놀랐습니다.
Rob Wells

1
@xealits 확실히- 여기
helvete

198

이 질문은 거의 3 살이지만 어쨌든 ...

GNU make를 사용한다면 쉽게 할 수 있습니다. 유일한 문제는 make명령 행에서 비 옵션 인수를 대상으로 해석 한다는 것입니다. 해결책은 그것들을 아무것도하지 않는 목표로 바꾸는 것이므로 make불평하지 않을 것입니다.

# If the first argument is "run"...
ifeq (run,$(firstword $(MAKECMDGOALS)))
  # use the rest as arguments for "run"
  RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
  # ...and turn them into do-nothing targets
  $(eval $(RUN_ARGS):;@:)
endif

prog: # ...
    # ...

.PHONY: run
run : prog
    @echo prog $(RUN_ARGS)

이것을 실행하면 다음이 제공됩니다.

$ make run foo bar baz
prog foo bar baz

2
대시로 시작하는 인수에서 작동하지 않는 것 외에는이 방법이 훌륭합니다.prog foo bar --baz
ingydotnet

22
이 경우에도 작동하지만 명령 행 옵션 make으로 해석하지 말아야합니다 . 수단 "이 후 모든 인수가 아닌 옵션입니다." --bazmake -- prog foo bar --baz--
Idelic

RUN_ARGS이것을 사용하기 위해 기본값을 어떻게 정의 합니까?
Bouke

else지점을 추가하고 거기에 ifeq설정할 RUN_ARGS수 있습니까?
Idelic

1
좋은 점은 blueyed! 그러나 $(eval $(RUN_ARGS):dummy;@:)더미 대상이 정의되지 않은 상태 에서 'eval'행을로 대체하십시오 .
Lucas Cimon

52

표준 적으로 다음과 같은 매크로를 정의하여 인수를 전달할 수 있습니다.

make run arg1=asdf

다음과 같이 사용하십시오

run: ./prog $(arg1)
   etc

Microsoft NMake만들기 위한 참고 자료


34

아래와 같이 변수를 Makefile에 전달할 수 있습니다.

run:
    @echo ./prog $$FOO

용법:

$ make run FOO="the dog kicked the cat"
./prog the dog kicked the cat

또는:

$ FOO="the dog kicked the cat" make run
./prog the dog kicked the cat

또는 베타에서 제공하는 솔루션을 사용하십시오 .

run:
    @echo ./prog $(filter-out $@,$(MAKECMDGOALS))
%:
    @:

%:-모든 작업 이름과 일치하는 규칙; @:-빈 레시피 = 아무것도하지 마십시오

용법:

$ make run the dog kicked the cat
./prog the dog kicked the cat

22

TL; DR은이 작업을 시도하지 않습니다

$ make run arg

대신 스크립트를 작성하십시오.

#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"

그리고 이것을하십시오 :

$ ./buildandrunprog.sh arg

명시된 질문에 대한 답변 :

레시피에서 변수를 사용할 수 있습니다

run: prog
    ./prog $(var)

그런 다음 변수 할당을 인수로 전달하여

$ make run var=arg

이것은 실행될 것이다 ./prog arg 됩니다.

함정에주의하십시오. 이 방법과 다른 방법의 함정에 대해 자세히 설명하겠습니다.


질문 뒤에 의도 된 의도에 대한 답변 :

가정 : 당신은 실행하고 싶어 prog 일부 인수 하고 싶지만 필요한 경우 실행하기 전에 다시 작성해야합니다.

대답 : 필요한 경우 다시 작성하고 args로 prog를 실행하는 스크립트를 작성하십시오.

#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"

이 스크립트는 의도를 매우 명확하게합니다. 그것은 make를 사용하여 좋은 일을합니다 : 건물. 셸 스크립트를 사용하여 일괄 처리에 적합한 작업을 수행합니다.

또한 makefile의 모든 경고없이 쉘 스크립트의 전체 유연성과 표현력으로 필요한 다른 작업을 수행 할 수 있습니다.

또한 호출 구문은 실제로 동일합니다.

$ ./buildandrunprog.sh foo "bar baz"

다음과 비교하십시오 :

$ ./prog foo "bar baz"

대조하다

$ make run var="foo bar\ baz"

배경:

make는 인수를 대상에 전달하도록 설계되지 않았습니다. 명령 행의 모든 ​​인수는 목표 (일명 대상), 옵션 또는 변수 지정으로 해석됩니다.

따라서 이것을 실행하면 :

$ make run foo --wat var=arg

make는 그들의 레시피에 따라 업데이트 할 목표 (목표)로 해석 run하고 해석 foo합니다. --watmake 옵션으로. 그리고 var=arg변수 할당으로.

자세한 내용은 https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals를 참조하십시오.

용어는 https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introduction을 참조하십시오.


변수 할당 방법에 대해 그리고 내가 그것을 추천하는 이유

$ make run var=arg

레시피의 변수

run: prog
    ./prog $(var)

이것은 레시피에 인수를 전달하는 가장 "올 바르고"직접적인 방법입니다. 그러나 인수로 프로그램을 실행하는 데 사용할 수는 있지만 그런 식으로 사용되도록 설계되지는 않았습니다. 참조 https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding를

내 의견으로는 이것은 하나의 큰 단점이 있습니다 : 당신이하고 싶은 것은 progargument 으로 실행 하는 것 arg입니다. 그러나 쓰는 대신 :

$ ./prog arg

글 쓰고 있구나:

$ make run var=arg

공백을 포함하는 여러 인수 또는 인수를 전달하려고하면 훨씬 더 어색합니다.

$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz

다음과 비교하십시오 :

$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz

기록을 위해 이것은 prog다음과 같습니다.

#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
  echo "arg: $arg"
done

또한 $(var)makefile에 따옴표를 넣지 않아야합니다 .

run: prog
    ./prog "$(var)"

그런 다음 prog항상 하나의 인수 만 얻습니다.

$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz

이 모든 것이 내가이 경로에 대해 추천하는 이유입니다.


완성도를 높이기 위해 "실행할 인수를 전달하는"다른 방법이 있습니다.

방법 1 :

run: prog
    ./prog $(filter-out $@, $(MAKECMDGOALS))

%:
    @true

매우 간단한 설명 : 목표 목록에서 현재 목표를 걸러냅니다. %다른 목표를 조용히 무시하지 않는 모든 대상 ( )을 잡으십시오 .

방법 2 :

ifeq (run, $(firstword $(MAKECMDGOALS)))
  runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
  $(eval $(runargs):;@true)
endif

run:
    ./prog $(runargs)

슈퍼 간단한 설명 : 대상이 run첫 번째 목표를 제거하고을 사용하여 나머지 목표에 대한 대상을 만들지 않는 경우 eval.

둘 다 이런 식으로 쓸 수 있습니다

$ make run arg1 arg2

더 자세한 설명은 make 매뉴얼을 참고 하십시오 : https://www.gnu.org/software/make/manual/html_node/index.html

방법 1의 문제점 :

  • 대시로 시작하는 인수는 make로 해석되며 목표로 전달되지 않습니다.

    $ make run --foo --bar
    

    해결 방법

    $ make run -- --foo --bar
    
  • 등호가있는 인수는 make로 해석되며 전달되지 않습니다.

    $ make run foo=bar
    

    해결 방법 없음

  • 공백이있는 인수는 어색합니다

    $ make run foo "bar\ baz"
    

    해결 방법 없음

  • 인수가 run(대상과 같음) 발생하면 제거됩니다

    $ make run foo bar run
    

    ./prog foo bar대신에 실행 됩니다./prog foo bar run

    방법 2로 가능한 해결 방법

  • 인수가 정당한 대상이면 실행됩니다.

    $ make run foo bar clean
    

    ./prog foo bar clean대상의 레시피도 실행됩니다 clean(존재한다고 가정).

    방법 2로 가능한 해결 방법

  • 합법적 인 대상을 잘못 입력하면 모든 대상을 잡기 때문에 자동으로 무시됩니다.

    $ make celan
    

    그냥 조용히 무시할 것이다 celan 합니다.

    해결 방법은 모든 것을 장황하게 만드는 것입니다. 무슨 일이 일어나는지 알 수 있습니다. 그러나 이는 합법적 인 출력에 많은 노이즈를 발생시킵니다.

방법 2의 문제 :

  • 인수가 기존 대상과 이름이 같은 경우 make는 덮어 쓰고 있다는 경고를 인쇄합니다.

    내가 아는 해결 방법이 없습니다.

  • 등호가있는 인수는 여전히 make로 해석되며 전달되지 않습니다.

    해결 방법 없음

  • 공백이있는 인수는 여전히 어색합니다

    해결 방법 없음

  • 공백이있는 인수 eval 을 만들려는 대상을 수행하지 않습니다.

    해결 방법 : 위와 같이 아무 것도 수행하지 않는 전역 캐치 모든 대상을 작성하십시오. 위와 같은 문제로 잘못 입력 된 합법적 인 목표를 다시 자동으로 무시합니다.

  • eval런타임에 makefile을 수정하는 데 사용 됩니다. 가독성과 디버깅 가능성, 그리고 놀랍게도 적은 원리로 얼마나 더 나빠질 수 있습니까? ?

    해결 방법 :이 작업을 수행하지 마십시오 !! 1 대신 make를 실행 한 다음 실행하는 쉘 스크립트를 작성하십시오 prog.

나는 gnu make 만 사용하여 테스트했습니다. 다른 제조사들은 다른 행동을 할 수 있습니다.


TL; DR은이 작업을 시도하지 않습니다

$ make run arg

대신 스크립트를 작성하십시오.

#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"

그리고 이것을하십시오 :

$ ./buildandrunprog.sh arg

12

다음은 이러한 사용 사례 중 일부에 도움이되는 다른 솔루션입니다.

test-%:
    $(PYTHON) run-tests.py $@

즉, 접두사 ( test-이 경우)를 선택한 다음 대상 이름을 프로그램 / 러너로 직접 전달하십시오. 대상 이름을 기본 프로그램에 유용한 것으로 풀 수있는 러너 스크립트가있는 경우 이것이 대부분 유용하다고 생각합니다.


2
을 ( $*를) 일치하는 대상의 일부만 전달 하는 데 사용할 수도 있습니다 %.
Malvineous

9

아니요. GNU make의 맨 페이지에서 구문을 보면

[-f makefile] [옵션] ... [대상] ...

여러 개의 대상을 지정할 수 있으므로 '아니오'(지정한 정확한 방식으로는 아니오)입니다.


4

명령 행에서 각 n 번째 인수를 명시 적으로 추출 할 수 있습니다. 이를 위해 변수 MAKECMDGOALS를 사용할 수 있으며 'make'에 제공된 명령 행 인수 목록을 보유하며 이는 대상 목록으로 해석됩니다. n 번째 인수를 추출하려면 "word"함수와 함께 해당 변수를 사용할 수 있습니다. 예를 들어 두 번째 인수를 원하는 경우 다음과 같이 변수에 변수를 저장할 수 있습니다.

second_argument := $(word 2, $(MAKECMDGOALS) )

또한 해당 인수에 대해 make 명령을 실행합니다. make: *** No rule to make target 'arg'. Stop.
ThomasReggi 2016 년

2

곧이 , run: ./prog오른쪽 부분이 대상이되어야 정도로, 조금 이상한 보인다run: prog 더 나은 보인다.

나는 간단하게 제안 할 것이다 :

.PHONY: run

run:
        prog $(arg1)

그리고 나는 인수가 전달 될 수 있다고 덧붙이고 싶습니다.

  1. 인수로 : make arg1="asdf" run
  2. 또는 환경으로 정의하십시오. arg1="asdf" make run

2

여기 내 예가 있습니다. Dev-Cpp와 함께 제공되는 mingw32-make.exe를 사용하여 Windows 7에서 작성하고 있습니다. (c : \ Windows \ System32 \ make.bat가 있으므로 명령은 여전히 ​​"make"입니다.)

clean:
    $(RM) $(OBJ) $(BIN) 
    @echo off
    if "${backup}" NEQ "" ( mkdir ${backup} 2> nul && copy * ${backup} )

정기적 인 청소 사용법 :

make clean

mydir /에서 백업 정리 및 백업 사용법 :

make clean backup=mydir

2

이것을 자랑스럽게 생각하지는 않지만 환경 변수를 전달하고 싶지 않아 미리 준비된 명령을 실행하는 방법을 뒤집 었습니다.

run:
    @echo command-you-want

실행하려는 명령이 인쇄되므로 서브 쉘에서 평가하십시오.

$(make run) args to my command

4
2 년 후이 답변을 되돌아 보았습니다. 왜 환경 변수를 사용하고 싶지 않아서 다른 명령의 생성을 인라인하는 것이 더 좋을까요?
Conrad.Dean

0

등호 (=)로 인수를 얻는 방법을 찾았습니다! 대답은 특히 @lesmana의 답변에 추가 된 것입니다. (여기에서 가장 완전하고 설명되어 있기 때문에) 주석으로 작성하기에는 너무 큽니다. 다시, 나는 그의 메시지를 반복합니다 : TL; DR이 작업을 시도하지 마십시오!

내 주장을 다룰 수있는 방법이 필요했습니다 --xyz-enabled=false(기본값은 true이므로). 이것은 make 대상이 아니므로의 일부가 아니라는 것을 모두 알고 $(MAKECMDGOALS)있습니다.

에코를 통해 make의 모든 변수를 살펴보면서 $(.VARIABLES)다음과 같은 흥미로운 결과를 얻었습니다.

[...] -*-command-variables-*- --xyz-enabled [...]

이를 통해 두 가지 방법으로 갈 수 있습니다. 모든 것이 --(귀하의 경우에 해당되는 경우) 시작하거나 GNU에서 특정 변수 ( 사용하지 않을 수도 있음 )를 살펴보십시오 -*-command-variables-*-. ** 추가 옵션은 바닥 글을 참조하십시오. ** 제 경우에는이 변수가 다음과 같습니다.

--xyz-enabled=false

이 변수를 사용 $(MAKECMDGOALS)하여 다음을 정의하여 기존 솔루션과 결합 할 수 있습니다 .

# the other technique to invalidate other targets is still required, see linked post
run:
    @echo ./prog $(-*-command-variables-*-) $(filter-out $@,$(MAKECMDGOALS))`

그리고 그것을 다음과 함께 사용 (명확하게 인수 순서를 섞음) :

make run -- config --xyz-enabled=false over=9000 --foo=bar show  isit=alwaysreversed? --help

반환 :

./prog isit=alwaysreversed? --foo=bar over=9000 --xyz-enabled=false config show --help

보시다시피, 우리는 인수의 총 순서를 느슨하게합니다. "할당"인수가있는 부분이 반전 된 것처럼 보이고 "대상"인수의 순서가 유지됩니다. 처음에 "할당"-args를 배치 했으므로 프로그램이 인수 위치를 신경 쓰지 않기를 바랍니다.


업데이트 : 다음은 변수를 유망하게 보이게합니다.

MAKEFLAGS =  -- isit=alwaysreverse? --foo=bar over=9000 --xyz-enabled=false
MAKEOVERRIDES = isit=alwaysreverse? --foo=bar over=9000 --xyz-enabled=false

-2

내가 사용하는 또 다른 트릭 은 건식 실행 -n을 지시 하는 플래그 make입니다. 예를 들어

$ make install -n 
# Outputs the string: helm install stable/airflow --name airflow -f values.yaml
$ eval $(make install -n) --dry-run --debug
# Runs: helm install stable/airflow --name airflow -f values.yaml --dry-run --debug
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.