변수가 설정되지 않은 경우 makefile 중단


151

makefile의 변수가 설정 / 값 지정되지 않은 상태에서 make / makefile 실행을 어떻게 중단 할 수 있습니까?

나는 이것을 생각해 냈지만 호출자가 대상을 명시 적으로 실행하지 않으면 (즉, 실행 make만) 작동 합니다.

ifeq ($(MY_FLAG),)
abort:   ## This MUST be the first target :( ugly
    @echo Variable MY_FLAG not set && false
endif

all:
    @echo MY_FLAG=$(MY_FLAG)

나는 이것과 같은 것이 좋은 생각이라고 생각하지만 make 매뉴얼에서 아무것도 찾지 못했습니다 :

ifndef MY_FLAG
.ABORT
endif

답변:


271

TL; DR : error기능 사용 :

ifndef MY_FLAG
$(error MY_FLAG is not set)
endif

줄을 들여 쓰면 안됩니다. 보다 정확하게는이 행 앞에 탭이 없어야합니다.


일반적인 솔루션

많은 변수를 테스트하려는 경우 보조 함수를 정의하는 것이 좋습니다.

# Check that given variables are set and all have non-empty values,
# die with an error otherwise.
#
# Params:
#   1. Variable name(s) to test.
#   2. (optional) Error message to print.
check_defined = \
    $(strip $(foreach 1,$1, \
        $(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
    $(if $(value $1),, \
      $(error Undefined $1$(if $2, ($2))))

사용 방법은 다음과 같습니다.

$(call check_defined, MY_FLAG)

$(call check_defined, OUT_DIR, build directory)
$(call check_defined, BIN_DIR, where to put binary artifacts)
$(call check_defined, \
            LIB_INCLUDE_DIR \
            LIB_SOURCE_DIR, \
        library path)


다음과 같은 오류가 출력됩니다.

Makefile:17: *** Undefined OUT_DIR (build directory).  Stop.

노트:

실제 확인은 다음과 같습니다.

$(if $(value $1),,$(error ...))

이는 ifndef빈 값으로 정의 된 변수도 "정의되지 않은"것으로 간주되도록 조건부 동작을 반영합니다 . 그러나 이것은 간단한 변수와 명시 적으로 빈 재귀 변수에 대해서만 적용됩니다.

# ifndef and check_defined consider these UNDEFINED:
explicitly_empty =
simple_empty := $(explicitly_empty)

# ifndef and check_defined consider it OK (defined):
recursive_empty = $(explicitly_empty)

의견에서 @VictorSergienko가 제안한 것처럼 약간 다른 동작이 필요할 수 있습니다.

$(if $(value $1)값이 비어 있지 않은지 테스트합니다. 변수가 빈 값으로 정의되어 있으면 때때로 괜찮습니다 . 나는 사용할 것이다$(if $(filter undefined,$(origin $1)) ...

과:

또한 디렉토리이고 검사가 실행될 때 존재 해야하는 경우을 사용 $(if $(wildcard $1))합니다. 그러나 다른 기능이 될 것입니다.

대상별 점검

특정 대상이 호출 된 경우에만 변수를 요구할 수 있도록 솔루션을 확장 할 수도 있습니다.

$(call check_defined, ...) 레시피 내부에서

수표를 레시피로 옮기십시오.

foo :
    @:$(call check_defined, BAR, baz value)

선행 @부호는 명령 에코를 끄고 :실제 명령, 쉘 no-op 스텁 입니다.

대상 이름 표시

check_defined함수는 출력 (스루 제공 대상 이름을 향상시킬 수있다 $@변수)

check_defined = \
    $(strip $(foreach 1,$1, \
        $(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
    $(if $(value $1),, \
        $(error Undefined $1$(if $2, ($2))$(if $(value @), \
                required by target `$@')))

따라서 실패한 검사는 형식이 좋은 출력을 생성합니다.

Makefile:7: *** Undefined BAR (baz value) required by target `foo'.  Stop.

check-defined-MY_FLAG 특별한 목표

개인적으로 위의 간단하고 간단한 솔루션을 사용합니다. 그러나 예를 들어, 이 답변 은 실제 확인을 수행하기 위해 특수 대상을 사용하도록 제안합니다. 이를 일반화하고 대상을 암시 적 패턴 규칙으로 정의하려고 시도 할 수 있습니다.

# Check that a variable specified through the stem is defined and has
# a non-empty value, die with an error otherwise.
#
#   %: The name of the variable to test.
#   
check-defined-% : __check_defined_FORCE
    @:$(call check_defined, $*, target-specific)

# Since pattern rules can't be listed as prerequisites of .PHONY,
# we use the old-school and hackish FORCE workaround.
# You could go without this, but otherwise a check can be missed
# in case a file named like `check-defined-...` exists in the root 
# directory, e.g. left by an accidental `make -t` invocation.
.PHONY : __check_defined_FORCE
__check_defined_FORCE :

용법:

foo :|check-defined-BAR

는 것을 알 수 check-defined-BAR로 표시됩니다 위해 전용 ( |...) 필수.

장점 :

  • (논쟁 적으로) 더 깨끗한 문법

단점 :

나는 가치가 확실하지 않지만 eval마법과 보조 확장 핵을 사용하여 이러한 제한을 극복 할 수 있다고 생각 합니다.


정확히 무엇? Mac을 사용하지는 않았지만 기본적으로 다른 Make 구현이 설치되어 있다고 생각합니다 (예 : GNU Make 대신 BSD Make). make --version첫 단계 로 확인하시기 바랍니다 .
Eldar Abusalimov

1
이것은 make 3.81에서 작동하지 않는 것 같습니다. 변수가 정의되어 있고 에코 될 수있는 경우에도 항상 오류가 발생합니다.
OrangeDog

아, 당신은 연결된 복제본에서와 같이 정확하게 구성해야합니다.
OrangeDog

1
@bibstha 생각 나는 옵션을 추가했습니다. 업데이트 된 답변을 읽으십시오.
Eldar Abusalimov 1

2
ifndef를 들여 쓰기 할 필요가없는 (누구 같은) 멍청한 설명을 추가하고 싶습니다. :) 다른 곳에서 갑자기 모든 오류가 의미가 있음을 알았습니다.
helios

40

쉘 기능을 사용하십시오 test:

foo:
    test $(something)

용법:

$ make foo
test 
Makefile:2: recipe for target 'foo' failed
make: *** [foo] Error 1
$ make foo something=x
test x

3
이것은 같은 문제에 직면했을 때 사용한 것입니다-감사합니다, 메사! 나는 두 가지 약간의 수정을했다 : 1) 그 안에있는 checkforsomething대상 만 만들고 test그것에 foo의존 하게 만들었고 , 2) @if test -z "$(something)"; then echo "helpful error here"; exit 1; fi대신 수표를 대신 변경 했다. 이로 인해 유용한 오류를 추가 할 수있게되었고, 새로운 대상의 이름을 무엇이 잘못되었는지를 조금 더 나타낼 수있게되었습니다.
브라이언 제라드

이것으로 내가 얻는Makefile:5: *** missing separator. Stop.
silgon

7
압축 test -n "$(something) || (echo "message" ; exit 1)을 위해 나는 명시적인 것을 피하기 위해 사용 했다 if.
user295691

@silgon 아마도 탭 대신 공백을 사용하여 들여 쓰기 할 것입니다.
eweb 2016 년

9

IF를 사용하여 다음을 테스트 할 수 있습니다.

check:
        @[ "${var}" ] || ( echo ">> var is not set"; exit 1 )

결과:

$ make check
>> var is not set
Makefile:2: recipe for target 'check' failed
make: *** [check] Error 1

[는 명령의 별칭 test이므로 위의 @Messa와 같은 대답입니다. 그러나 이것은 더 간결하며 오류 메시지 생성을 포함합니다.
user295691

6

설정되지 않은 변수에 대해 쉘 오류 처리를 사용하십시오 (double 참조 $).

$ cat Makefile
foo:
        echo "something is set to $${something:?}"

$ make foo
echo "something is set to ${something:?}"
/bin/sh: something: parameter null or not set
make: *** [foo] Error 127


$ make foo something=x
echo "something is set to ${something:?}"
something is set to x

사용자 정의 오류 메시지가 필요한 경우 다음 뒤에 추가하십시오 ?.

$ cat Makefile
hello:
        echo "hello $${name:?please tell me who you are via \$$name}"

$ make hello
echo "hello ${name:?please tell me who you are via \$name}"
/bin/sh: name: please tell me who you are via $name
make: *** [hello] Error 127

$ make hello name=jesus
echo "hello ${name:?please tell me who you are via \$name}"
hello jesus

2

단순성과 간결성을 위해 :

$ cat Makefile
check-%:
        @: $(if $(value $*),,$(error $* is undefined))

bar:| check-foo
        echo "foo is $$foo"

출력 :

$ make bar
Makefile:2: *** foo is undefined. Stop.
$ make bar foo="something"
echo "foo is $$foo"
foo is something
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.