development

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

big-blog 2020. 6. 30. 08:03
반응형

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


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

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)

The leading @ sign turns off command echoing and : is the actual command, a shell no-op stub.

Showing target name

The check_defined function can be improved to also output the target name (provided through the $@ variable):

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 `$@')))

So that, now a failed check produces a nicely formatted output:

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

check-defined-MY_FLAG special target

Personally I would use the simple and straightforward solution above. However, for example, this answer suggests using a special target to perform the actual check. One could try to generalize that and define the target as an implicit pattern rule:

# 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 :

Usage:

foo :|check-defined-BAR

Notice that the check-defined-BAR is listed as the order-only (|...) prerequisite.

Pros:

  • (arguably) a more clean syntax

Cons:

I believe, these limitations can be overcome using some eval magic and secondary expansion hacks, although I'm not sure it's worth it.


Use the shell function test:

foo:
    test $(something)

Usage:

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

You can use an IF to test:

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

Result:

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

Use the shell error handling for unset variables (note the 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

If you need a custom error message, add it after the ?:

$ 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

참고URL : https://stackoverflow.com/questions/10858261/abort-makefile-if-variable-not-set

반응형