명령 출력을 Makefile 변수에 지정하는 방법


225

설치된 Python이 특정 버전 (예 : 2.5)보다 큰 경우에만 일부 make 규칙을 조건부로 실행해야합니다.

나는 실행과 같은 것을 할 수 있다고 생각했다.

python -c 'import sys; print int(sys.version_info >= (2,5))'

그런 다음 ifeqmake 문 에서 출력 (확인 인 경우 '1', 그렇지 않으면 '0')을 사용합니다.

간단한 bash 쉘 스크립트에서는 다음과 같습니다.

MY_VAR=`python -c 'import sys; print int(sys.version_info >= (2,5))'`

그러나 그것은 Makefile에서 작동하지 않습니다.

어떤 제안? 나는 이것을 달성하기 위해 다른 합리적인 해결책을 사용할 수 있습니다.


Makefile에서 다른 스크립트를 실행하기 위해 명령 작업에 이상한 틱이 표시됩니다. 다른 것일 수도 있습니다.
Leif Gruenwoldt

답변:


346

다음 shell과 같이 Make 내장 기능을 사용하십시오.MY_VAR=$(shell echo whatever)

me@Zack:~$make
MY_VAR IS whatever

me@Zack:~$ cat Makefile 
MY_VAR := $(shell echo whatever)

all:
    @echo MY_VAR IS $(MY_VAR)

34
shell은 표준 Make 내장 명령이 아닙니다. 이것은 GNU Make 내장입니다.
Dereckson

12
stackoverflow.com/a/2373111/12916 은 이스케이프에 대한 중요한 메모를 추가합니다 $.
Jesse Glick

6
이 간단한 예제가 작동합니다. 쉘 명령 파이프 라인에서도 작동합니다. 쉘 명령에서 $를 나타내려면 $$를 사용해야합니다.
Sergey P. aka azure azure

28
질문이 약간 오래되었지만 MY_VAR : = $ (shell ...)을 수행하는 것이 가장 좋습니다. 그렇지 않으면 MY_VAR을 평가할 때마다 $ (shell ...)이 다시 실행됩니다.
Russ Schultz

쉘과 여는 괄호 사이에 공백이 있었고 공백을 제거한 후에 만 ​​내 makefile 텍스트가 출력되었습니다
peterchaula

29

과제를 포장하는 eval것이 나를 위해 일하고 있습니다.

# dependency on .PHONY prevents Make from 
# thinking there's `nothing to be done`
set_opts: .PHONY
  $(eval DOCKER_OPTS = -v $(shell mktemp -d -p /scratch):/output)

6
"참고 : 여기서 @true는 Make가 수행 할 작업이 없다고 생각하지 못하게합니다." 음, 그게 다야 .PHONY always make these targets.
underscore_d

감사합니다! 이 메이크에서 "이상한 bash는"바이 패스 나에게 도움이
남 G VU에게

19

다음은 레시피 내부에 배관 및 변수 할당을 사용하는 좀 더 복잡한 예입니다.

getpodname:
    # Getting pod name
    @eval $$(minikube docker-env) ;\
    $(eval PODNAME=$(shell sh -c "kubectl get pods | grep profile-posts-api | grep Running" | awk '{print $$1}'))
    echo $(PODNAME)

2
그것이 편리한 경우에 나는 PODNAME배치 이름 을 얻기 위해 약간 비슷한 접근법을 사용하고 있습니다 :$(eval PODNAME=$(shell sh -c "kubectl get pod -l app=sqlproxy -o jsonpath='{.items[0].metadata.name}'"))
Jan Richter

쉘 내장 eval (docker-env 줄)과 make 함수 eval (다음 줄) 을 모두 사용하고 있음을 알 때까지 구문이 혼란 스러웠습니다 .
브라이언 고든

17

문제를 해결하는 실제 구문에 대한 가시성을 높이는 답변을 작성 중입니다. 불행히도, 누군가가 사소한 것으로 볼 수있는 것은 합리적인 질문에 대한 간단한 답변을 찾는 사람에게는 매우 심각한 두통이 될 수 있습니다.

다음을 "Makefile"파일에 넣으십시오.

MY_VAR := $(shell python -c 'import sys; print int(sys.version_info >= (2,5))')

all:
    @echo MY_VAR IS $(MY_VAR)

보고 싶은 동작은 다음과 같습니다 (최근에 파이썬이 설치되어 있다고 가정).

make
MY_VAR IS 1

위의 텍스트를 복사하여 Makefile에 붙여 넣으면 얻을 수 있습니까? 아마 아닙니다. 여기에보고 된 것과 같은 오류가 발생할 수 있습니다.

makefile : 4 : *** 구분 기호가 없습니다. 중지

이유 : 개인적으로 정품 탭을 사용했지만 스택 오버플로 (도움이 되려고 시도 함)는 탭을 여러 공백으로 변환합니다. 좌절 한 인터넷 시민 여러분, 이제 여러분이 제가 사용한 것과 같은 텍스트를 가지고 있다고 생각하면서 이것을 복사하십시오. make 명령은 이제 공백을 읽고 "all"명령의 형식이 잘못되었음을 발견합니다. 따라서 위의 텍스트를 복사하여 붙여 넣은 다음 "@echo"앞의 공백을 탭으로 변환하면이 예제가 도움이 될 것입니다.


붙여 넣는 편집기에 따라 다릅니다. 방금 Eclipse Makefile 편집기에 복사하여 붙여 넣었으며 필요한 경우 선행 탭을 얻었습니다.
Technophile

아, 나는 그것을 생각하지 않았다. 여기 원자.
AlanSE

11

이와 같은 요리법을 조심하십시오

target:
    MY_ID=$(GENERATE_ID);
    echo $MY_ID;

두 가지가 잘못되었습니다. 레시피의 첫 번째 라인은 두 번째 라인과 별도의 쉘 인스턴스에서 실행됩니다. 그 동안 변수가 손실됩니다. 두 번째로 잘못된 것은 $이스케이프되지 않는다는 것입니다.

target:
    MY_ID=$(GENERATE_ID); \
    echo $$MY_ID;

두 가지 문제가 해결되었으며 변수를 사용할 수 있습니다. 백 슬래시는 두 줄을 결합하여 하나의 단일 셸에서 실행되므로 변수 설정과 변수 뒷문 읽기가 작동합니다.

원래 게시물이 쉘 명령의 결과를 MAKE 변수로 가져 오는 방법을 말 했으며이 답변은 쉘 변수로 가져 오는 방법을 보여줍니다. 그러나 다른 독자들도 도움이 될 수 있습니다.

소비자가 "환경 변수"가 설정 될 것으로 기대하는 경우 최종 개선 사항 중 하나를 내 보내야합니다.

my_shell_script
    echo $MY_ID

makefile에서 이것을 필요로 할 것입니다

target:
    export MY_ID=$(GENERATE_ID); \
    ./my_shell_script;

누군가에게 도움이되기를 바랍니다. 일반적으로 누군가가 '--dry-run'옵션과 함께 makefile을 사용하여 수행 할 작업 만 볼 경우 바람직하지 않은 부작용이 없기 때문에 레시피 이외의 실제 작업은 피해야합니다. 모든 $(shell)호출은 컴파일 타임에 평가되며 실수로 실수가 발생할 수 있습니다. 가능한 경우 ID 생성과 같은 실제 작업을 레시피 내부에 두는 것이 좋습니다.


9

GNU의 메이크업으로, 당신은 사용할 수 있습니다 shelleval임의의 명령 행 호출에서 저장, 실행 및 할당 출력. 아래 예제와 사용하는 것의 차이점 :=:=할당이 한 번만 발생한다는 것입니다. 로 재귀 적으로 확장 된 변수 =는 조금 더 "게으르다"; 다른 변수에 대한 참조는 변수 자체가 참조 될 때까지 유지되며, 변수가 참조 될 때 마다 후속 재귀 확장이 발생 하며 이는 "일관되고 호출 가능하며 스 니펫"을 만드는 데 바람직합니다. 자세한 정보는 변수 설정에 대한 매뉴얼을 참조하십시오 .

# Generate a random number.
# This is not run initially.
GENERATE_ID = $(shell od -vAn -N2 -tu2 < /dev/urandom)

# Generate a random number, and assign it to MY_ID
# This is not run initially.
SET_ID = $(eval MY_ID=$(GENERATE_ID))

# You can use .PHONY to tell make that we aren't building a target output file
.PHONY: mytarget
mytarget:
# This is empty when we begin
    @echo $(MY_ID)
# This recursively expands SET_ID, which calls the shell command and sets MY_ID
    $(SET_ID)
# This will now be a random number
    @echo $(MY_ID)
# Recursively expand SET_ID again, which calls the shell command (again) and sets MY_ID (again)
    $(SET_ID)
# This will now be a different random number
    @echo $(MY_ID)

내가 처음 접한 좋은 설명이 있습니다. 감사합니다. 추가해야 할 한 가지 사항 $(SET_ID)if조항의 내부에 거짓 인 경우 여전히 호출 됩니다.
로마

if stmts가 런타임이 아닌 makefile 컴파일 타임에 평가되므로 여전히 호출됩니다. 런타임 특정 지침의 경우 레시피에 넣으십시오. 조건부 인 경우 레시피의 일부로 bash / shell로 작성된 stmts를 추가하십시오.
Juraj December

0

아래 예제에서 Makefile 폴더 경로를 저장 LOCAL_PKG_DIR한 다음 LOCAL_PKG_DIR대상에서 변수 를 사용 했습니다.

메이크 파일 :

LOCAL_PKG_DIR := $(shell eval pwd)

.PHONY: print
print:
    @echo $(LOCAL_PKG_DIR)

터미널 출력 :

$ make print
/home/amrit/folder
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.