makefile 레시피에서 변수를 찾을 수 없습니다.

makefile 레시피에서 변수를 찾을 수 없습니다.

이 간단한 레시피가 왜 효과가 없을까요?

.PHONY: test
test:
    foo := $(shell ls | grep makefile) ;\
    echo $(foo)

밝혀지다

$> make test
makefile:65: warning: undefined variable 'foo'
foo := makefile ;\
echo 
/bin/sh: 1: foo: not found

그럼 제가 아는 바로는 변수 foo에 값이 설정되어 있는데 makefile사용할 수 없다는 건가요? 그러나 동일한 쉘에서 실행되는 단일 행 명령입니까?

그러나 이것은 작동합니다

@$(eval export foo := $(shell ls | grep makefile)) \
echo $(foo)

echo그렇다면 우리가 시도할 때 할당이 아직 평가되지 않았기 때문에 첫 번째 예의 변수에 액세스할 수 없는 것 같습니다.

더 자세히 살펴보면 어떻게 이 작업을 수행할 수 있나요?

.PHONY: test
test:
    @$(eval export files = $(shell ls))
    for f in $(files) ; do \
        t = $(ls | grep $$f) ; \
        echo $$t;\
    done

답변1

나는 당신의 루프를 보았습니다... 인용문은 다음과 같습니다:

.PHONY: test
test:
    @$(eval export files = $(shell ls))
    for f in $(files) ; do \
        t = $(ls | grep $$f) ; \
        echo $$t;\
    done

그럼... $(eval ... )make에서 명령을 실행해 보세요.

$(shell ls)ls셸에서 명령을 실행하고 출력을 바꿉니다.

따라서 실행되는 명령은 $(eval ... )다음과 같습니다 export files = file file2 makefile source.c. 이 명령은 files라는 이름의 make 변수를 생성하고 이를 submake로 내보냅니다. 따라서 내보내기가 필요하지 않을 수도 있습니다.

전체를 $(eval ... )대체하여 사용할 수 있으며 규칙 외부에 배치 files = $(wildcard *) 할 수 있습니다 .:=

for루프(4줄)는 셸에서 실행됩니다. 가장 먼저 할 일은 make 변수와 함수를 바꾸는 것입니다. 이상한 점은 $(ls | grep $$f). ls는 make 함수가 아니기 때문에 정의되지 않은 변수를 확장하려고 시도합니다. 이는 빈 문자열입니다. 이것이 쉘 $(...)연산자라면 $를 두 배로 늘려야 합니다. eval을 기반으로 .Extended $$로 확장됩니다 .$$(files)

이것은 다음과 같습니다(이전 예를 사용하면).

for f in file file2 makefile source.c ; do
    t =
    echo $t;
done

언뜻 보기에 이것은 네 개의 빈 줄을 에코하는 것처럼 보일 수 있지만 사실은 아닙니다. 이 명령은 t =실제로 프로그램을 실행 t하고 등호를 인수로 전달합니다. t아마도 존재하지 않을 것입니다. 따라서 t가 유효한 프로그램이 아니라는 것을 나타내는 4개의 오류가 발생합니다. 각 오류 뒤에는 빈 줄이 옵니다(t가 다른 곳에서 정의되지 않은 경우).

당신이 원하는 것에 더 가까운 것은 다음과 같습니다:

files := $(wildcard *)
.PHONY: test
test:
    for f in $(files) ; do \
        t=$$(ls | grep $$f) ; \
        echo $$t ; \
    done

그러면 다음이 출력됩니다.

file file2
file2
makefile
source.c

첫 번째 줄에는 이름에 "file"이 포함되어 있으므로 두 개의 파일이 나열됩니다. 이것이 원하는 것이 아니라면 다음을 고려해 볼 수 있습니다.

files := $(wildcard *)
.PHONY: test
test:
    for f in $(files) ; do \
        echo $$f ; \
    done

또는 (GNU에만 해당될 수도 있음):

files := $(wildcard *)
.PHONY: test
test:
    $(foreach f, $(files), echo $f ; )

답변2

make target 레시피 내에서 명령은 레시피 외부의 로직과 다르게 처리됩니다(셸 생성).

레시피 외부로 변수를 이동할 수 있습니다.

.PHONY: test
foo := $(shell ls | grep makefile)
test:
    echo $(foo)

아니면 정중하게이 문제, 평가 사용:

.PHONY: test
test:
    $(eval foo=$(shell ls | grep makefile))
    echo $(foo)

둘 다 다음을 출력합니다.

echo makefile
makefile

관련 정보