Makefile에서 프로그램을 호출 할 수 있는지 어떻게 확인할 수 있습니까?
(즉, 프로그램이 경로에 존재하거나 호출 가능해야합니다.)
예를 들어 어떤 컴파일러가 설치되어 있는지 확인하는 데 사용할 수 있습니다.
예를 들어이 질문 과 같지만 기본 쉘이 POSIX와 호환된다고 가정하지 않고.
automake
다양한 전제 조건을 확인하고 적절한 Makefile
.
Makefile에서 프로그램을 호출 할 수 있는지 어떻게 확인할 수 있습니까?
(즉, 프로그램이 경로에 존재하거나 호출 가능해야합니다.)
예를 들어 어떤 컴파일러가 설치되어 있는지 확인하는 데 사용할 수 있습니다.
예를 들어이 질문 과 같지만 기본 쉘이 POSIX와 호환된다고 가정하지 않고.
automake
다양한 전제 조건을 확인하고 적절한 Makefile
.
답변:
때로는 다른 대상 OS에서 실행할 수있는 Makefile이 필요하며, 실패 PATH
하기 전에 오랜 시간 동안 실행하는 것보다 필요한 실행 파일이없는 경우 빌드가 조기에 실패하기를 원합니다 .
engineerchuan 이 제공하는 우수한 솔루션 은 타겟을 만들어야합니다 . 그러나 테스트 할 실행 파일이 많고 Makefile에 각각 테스트가 필요한 여러 독립 대상이있는 경우 각 대상에는 테스트 대상이 종속성으로 필요합니다. 따라서 한 번에 둘 이상의 대상을 만들 때 처리 시간뿐만 아니라 많은 추가 입력이 필요합니다.
0xf에서 제공하는 솔루션 은 대상을 만들지 않고도 실행 파일을 테스트 할 수 있습니다. 이렇게하면 개별적으로 또는 함께 빌드 할 수있는 여러 대상이있을 때 입력 및 실행 시간이 많이 절약됩니다.
후자의 솔루션에 대한 개선 사항 은 새 변수를 정의하는 대신 GNU Make 지시문에 직접 각 실행 파일에 옵션 이 있다는 것에 의존하는 대신 which
실행 파일 ( where
Windows에서) 을 사용하고 GNU Make를 사용하는 것입니다. 필요한 실행 파일이에없는 경우 빌드를 중지하는 함수입니다 . 예를 들어 실행 파일 을 테스트하려면 다음을 수행하십시오 .--version
ifeq
error
${PATH}
lzop
ifeq (, $(shell which lzop))
$(error "No lzop in $(PATH), consider doing apt-get install lzop")
endif
검사 할 실행 파일이 여러 개인 경우 실행 파일 foreach
과 함께 함수 를 사용할 수 있습니다 which
.
EXECUTABLES = ls dd dudu lxop
K := $(foreach exec,$(EXECUTABLES),\
$(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH")))
:=
RHS 표현식을 즉시 평가하기 위해 필요한 할당 연산자 의 사용에 유의하십시오 . Makefile이을 변경하면 PATH
위의 마지막 줄 대신 다음이 필요합니다.
$(if $(shell PATH=$(PATH) which $(exec)),some string,$(error "No $(exec) in PATH")))
그러면 다음과 유사한 출력이 제공됩니다.
ads$ make
Makefile:5: *** "No dudu in PATH. Stop.
where my_exe 2>NUL
대신 which
.
@kenorb와 @ 0xF의 솔루션을 혼합하여 다음을 얻었습니다.
DOT := $(shell command -v dot 2> /dev/null)
all:
ifndef DOT
$(error "dot is not available please install graphviz")
endif
dot -Tpdf -o pres.pdf pres.dot
"command -v"는 실행 파일을 사용할 수없는 경우 아무것도 인쇄하지 않기 때문에 아름답게 작동합니다. 따라서 변수 DOT는 정의되지 않고 코드에서 원할 때마다 확인할 수 있습니다. 이 예에서는 오류가 발생하지만 원하는 경우 더 유용한 작업을 수행 할 수 있습니다.
변수를 사용할 수있는 경우 "command -v"는 DOT 변수를 정의하여 명령 경로를 인쇄하는 저렴한 작업을 수행합니다.
command
더 많은 이식성을 위해 bash 내장형 which
입니까?
command -v
POSIX와 유사한 쉘 환경이 필요합니다. 이것은 cygwin 또는 유사한 에뮬레이션이없는 Windows에서는 작동하지 않습니다.
command
종종 작업을 수행입니다 때문이 아니라 그 부재의 , 그러나 때문에의 독특한 최적화 GNU 제조사가하는 : 명령이 "간단 충분"인 경우 것입니다 쉘 우회; 이것은 불행히도 명령을 약간 조작하지 않으면 내장 기능이 때때로 작동하지 않음을 의미합니다.
이것이 당신이 한 일입니까?
check: PYTHON-exists
PYTHON-exists: ; @which python > /dev/null
mytarget: check
.PHONY: check PYTHON-exists
내 동료에 대한 신용.
이 shell
함수를 사용하여 표준 출력에 무언가를 인쇄하는 방식으로 프로그램을 호출하십시오. 예를 들어 --version
.
GNU Make는에 전달 된 명령의 종료 상태를 무시합니다 shell
. 잠재적 인 "명령을 찾을 수 없음"메시지를 방지하려면 표준 오류를로 리디렉션하십시오 /dev/null
.
그런 다음 사용하여 결과를 확인 할 수 있습니다 ifdef
, ifndef
, $(if)
등
YOUR_PROGRAM_VERSION := $(shell your_program --version 2>/dev/null)
all:
ifdef YOUR_PROGRAM_VERSION
@echo "Found version $(YOUR_PROGRAM_VERSION)"
else
@echo Not found
endif
보너스로 출력 (예 : 프로그램 버전)은 Makefile의 다른 부분에서 유용 할 수 있습니다.
*** missing separator. Stop.
한 후 나는 모든 라인에 탭을 추가하면 all:
내가 오류make: ifdef: Command not found
ifdef
참으로 평가됩니다 . gnu.org/software/make/manual/make.html#Conditional-Syntaxyour_program
ifdef
, else
, endif
라인. @echo
줄이 탭으로 시작 하는지 확인하십시오 .
ifdef
비어 있지 않은 변수 값 을 확인하는 내용이 나와 있습니다. 변수가 비어 있지 않으면 무엇으로 평가됩니까?
ifdef
or ifndef
(허용 된 답변에서와 같이)를 사용 하면 평가되는 변수가 :=
지연 설정 ( =
) 대신 즉시 설정 ( ) 되는 경우에만 작동합니다 . 그러나 즉시 설정 변수를 사용하는 단점은 선언시 평가되는 반면 지연 설정 변수는 호출시 평가된다는 것입니다. 즉 :=
, Make가 해당 변수를 사용하지 않는 규칙 만 실행하는 경우에도 변수에 대한 명령을 실행 하게됩니다! =
with 를 사용하여 이것을 피할 수 있습니다ifneq ($(MY_PROG),)
여기에서 기존 솔루션 중 일부를 정리했습니다 ...
REQUIRED_BINS := composer npm node php npm-shrinkwrap
$(foreach bin,$(REQUIRED_BINS),\
$(if $(shell command -v $(bin) 2> /dev/null),$(info Found `$(bin)`),$(error Please install `$(bin)`)))
는 $(info ...)
이 조용 할하려는 경우는 제외 할 수 있습니다.
이것은 빨리 실패 할 것 입니다. 대상이 필요하지 않습니다.
내 솔루션에는 필요한 모든 명령이있는 경우 플래그 파일을 배치 하는 작은 도우미 스크립트 1 이 포함됩니다 . 이는 필요한 명령에 대한 검사가 모든 make
호출이 아닌 한 번만 수행된다는 장점이 있습니다.
check_cmds.sh
#!/bin/bash
NEEDED_COMMANDS="jlex byaccj ant javac"
for cmd in ${NEEDED_COMMANDS} ; do
if ! command -v ${cmd} &> /dev/null ; then
echo Please install ${cmd}!
exit 1
fi
done
touch .cmd_ok
Makefile
.cmd_ok:
./check_cmds.sh
build: .cmd_ok target1 target2
if
문 에서 "예기치 않은 파일 끝"이 나타납니다 .
나에게 위의 모든 답변은 Linux를 기반으로하며 Windows에서 작동하지 않습니다. 나는 새로 만들었으므로 내 접근 방식이 이상적이지 않을 수 있습니다. 그러나 Linux와 Windows 모두에서 나를 위해 작동하는 완전한 예는 다음과 같습니다.
# detect what shell is used
ifeq ($(findstring cmd.exe,$(SHELL)),cmd.exe)
$(info "shell Windows cmd.exe")
DEVNUL := NUL
WHICH := where
else
$(info "shell Bash")
DEVNUL := /dev/null
WHICH := which
endif
# detect platform independently if gcc is installed
ifeq ($(shell ${WHICH} gcc 2>${DEVNUL}),)
$(error "gcc is not in your system PATH")
else
$(info "gcc found")
endif
선택적으로 더 많은 도구를 검색해야 할 때 사용할 수 있습니다.
EXECUTABLES = ls dd
K := $(foreach myTestCommand,$(EXECUTABLES),\
$(if $(shell ${WHICH} $(myTestCommand) 2>${DEVNUL} ),\
$(myTestCommand) found,\
$(error "No $(myTestCommand) in PATH)))
$(info ${K})
당신은 같은 bash는 내장 명령을 사용할 수 있습니다 type foo
또는 command -v foo
아래로를 :
SHELL := /bin/bash
all: check
check:
@type foo
foo
프로그램 / 명령은 어디에 있습니까 ? 로 리디렉션 > /dev/null
당신이 침묵합니다.
나는 개인적으로 require
다른 모든 것보다 먼저 실행 되는 목표를 정의 하고 있습니다. 이 대상은 모든 요구 사항의 버전 명령을 한 번에 하나씩 실행하고 명령이 유효하지 않은 경우 적절한 오류 메시지를 인쇄합니다.
all: require validate test etc
require:
@echo "Checking the programs required for the build are installed..."
@shellcheck --version >/dev/null 2>&1 || (echo "ERROR: shellcheck is required."; exit 1)
@derplerp --version >/dev/null 2>&1 || (echo "ERROR: derplerp is required."; exit 1)
# And the rest of your makefile below.
아래 스크립트의 출력은
Checking the programs required for the build are installed...
ERROR: derplerp is required.
makefile:X: recipe for target 'prerequisites' failed
make: *** [prerequisites] Error 1
내가 찾던 런타임 항목을 확인하는 것이 유일한 목적인 다른 메이크 파일 대상에서 특별한 작은 프로그램을 컴파일하여 해결되었습니다.
그런 다음이 프로그램을 또 다른 메이크 파일 대상에서 호출했습니다.
올바르게 기억하면 다음과 같습니다.
real: checker real.c
cc -o real real.c `./checker`
checker: checker.c
cc -o checker checker.c
의 STDERR
출력을 확인하는 솔루션 --version
은 STDOUT
대신 버전을 인쇄하는 프로그램에서는 작동하지 않습니다 STDERR
. STDERR
또는에 대한 출력을 확인하는 대신 STDOUT
프로그램 리턴 코드를 확인하십시오. 프로그램이 존재하지 않으면 종료 코드는 항상 0이 아닙니다.
#!/usr/bin/make -f
# /programming/7123241/makefile-as-an-executable-script-with-shebang
ECHOCMD:=/bin/echo -e
SHELL := /bin/bash
RESULT := $(shell python --version >/dev/null 2>&1 || (echo "Your command failed with $$?"))
ifeq (,${RESULT})
EXISTS := true
else
EXISTS := false
endif
all:
echo EXISTS: ${EXISTS}
echo RESULT: ${RESULT}