[makefile] Makefile에서 프로그램이 있는지 확인

Makefile에서 프로그램을 호출 할 수 있는지 어떻게 확인할 수 있습니까?

(즉, 프로그램이 경로에 존재하거나 호출 가능해야합니다.)

예를 들어 어떤 컴파일러가 설치되어 있는지 확인하는 데 사용할 수 있습니다.

예를 들어이 질문 과 같지만 기본 쉘이 POSIX와 호환된다고 가정하지 않고.



답변

때로는 다른 대상 OS에서 실행할 수있는 Makefile이 필요하며, 실패 PATH하기 전에 오랜 시간 동안 실행하는 것보다 필요한 실행 파일이없는 경우 빌드가 조기에 실패하기를 원합니다 .

engineerchuan 이 제공하는 우수한 솔루션 은 타겟을 만들어야합니다 . 그러나 테스트 할 실행 파일이 많고 Makefile에 각각 테스트가 필요한 여러 독립 대상이있는 경우 각 대상에는 테스트 대상이 종속성으로 필요합니다. 따라서 한 번에 둘 이상의 대상을 만들 때 처리 시간뿐만 아니라 많은 추가 입력이 필요합니다.

0xf에서 제공하는 솔루션 은 대상을 만들지 않고도 실행 파일을 테스트 할 수 있습니다. 이렇게하면 개별적으로 또는 함께 빌드 할 수있는 여러 대상이있을 때 입력 및 실행 시간이 많이 절약됩니다.

후자의 솔루션에 대한 개선 사항 은 새 변수를 정의하는 대신 GNU Make 지시문에 직접 각 실행 파일에 옵션 이 있다는 것에 의존하는 대신 which실행 파일 ( whereWindows에서) 을 사용하고 GNU Make를 사용하는 것입니다. 필요한 실행 파일이에없는 경우 빌드를 중지하는 함수입니다 . 예를 들어 실행 파일 을 테스트하려면 다음을 수행하십시오 .--versionifeqerror${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.


답변

@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 변수를 정의하여 명령 경로를 인쇄하는 저렴한 작업을 수행합니다.


답변

이것이 당신이 한 일입니까?

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의 다른 부분에서 유용 할 수 있습니다.


답변

여기에서 기존 솔루션 중 일부를 정리했습니다 …

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

1command -v 기술 에 대한 자세한 내용은 여기 에서 찾을 수 있습니다 .


답변

나에게 위의 모든 답변은 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})