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


115

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

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

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

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


1
POSIX 호환 쉘 을 호출 할 수 있습니까 ?
reinierpost 2011

아마 그렇지 않을 것입니다. 내가 거기에있을 것을 요구할 수있을 것 같지만, 내가 할 필요가 없다면 훨씬 쉬울 것입니다.
Prof. Falken 2011

그동안 저는 먼저 빌드 된 프로젝트에 프로그램을 추가하여 문제를 해결했습니다.이 프로그램은 다른 프로그램을 확인하는 것이 유일한 목적입니다 ... :-)
Prof. Falken 2011-04-11

2
전통적인 해결 방법은 automake다양한 전제 조건을 확인하고 적절한 Makefile.
tripleee 2011

답변:


83

때로는 다른 대상 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.

2
EXECUTABLES를 모든 변수 (예 : LS CC LD)로 만들고 $ ($ (exec))를 사용하면 환경 또는 다른 메이크 파일에서 원활하게 만들기 위해 전달할 수 있습니다. 크로스 컴파일 할 때 유용합니다.
rickfoosusa 2015 년

1
은 ","실행 "는 ifeq을 ($ (쉘 lzop))"에서 내 메이크업 초크 = /
mentatkgs

2
Windows에서 사용하는 where my_exe 2>NUL대신 which.
Aaron Campbell

2
규칙 구문 인 ifeq를 사용한 TABS 들여 쓰기에주의하십시오! WITHOUT TAB이어야합니다. 그것으로 힘든 시간을 보냈습니다. stackoverflow.com/a/21226973/2118777
Pipo

2
당신이 사용하는 경우 Bash에 외부 전화를 걸 필요가 없습니다 which. command -v대신 내장을 사용하십시오 . 더 많은 정보 .
kurczynski

48

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


5
일부 시스템 (예 : 우분투 14.04)에서 적어도 $(shell command -v dot)실패합니다 make: command: Command not found. 이 문제를 해결하려면 stderr 출력을 / dev / null :로 리디렉션하십시오 $(shell command -v dot 2> /dev/null). 설명
J0HN

3
command더 많은 이식성을 위해 bash 내장형 which입니까?
줄리앙 Palard

10
난 당신이 생각 @JulienPalard있는 거 잘못 다음 command유틸리티가 필요하지 않습니다 POSIX 합니다 (포함 -v반면에 옵션) which더 bahaviour을 (내가 아는) 표준화하고, 때로는 노골적이다 사용할 수 없게
Gyom

3
command -vPOSIX와 유사한 쉘 환경이 필요합니다. 이것은 cygwin 또는 유사한 에뮬레이션이없는 Windows에서는 작동하지 않습니다.
고인돌

10
이유는 command종종 작업을 수행입니다 때문이 아니라 그 부재의 , 그러나 때문에의 독특한 최적화 GNU 제조사가하는 : 명령이 "간단 충분"인 경우 것입니다 쉘 우회; 이것은 불행히도 명령을 약간 조작하지 않으면 내장 기능이 때때로 작동하지 않음을 의미합니다.
Rufflewind

33

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

check: PYTHON-exists
PYTHON-exists: ; @which python > /dev/null
mytarget: check
.PHONY: check PYTHON-exists

내 동료에 대한 신용.


아니요, 한 대상에서 프로그램을 컴파일하고 다른 대상에서 실행했습니다.
Prof. Falken

21

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
마티아스 009

또한 : 존재하지 않아도 ifdef참으로 평가됩니다 . gnu.org/software/make/manual/make.html#Conditional-Syntaxyour_program
Matthias 009

1
받는 사람 탭을 추가하지 마십시오 ifdef, else, endif라인. @echo줄이 탭으로 시작 하는지 확인하십시오 .
0xF

Windows 및 Linux에서 솔루션을 테스트했습니다. 링크 한 문서에는 ifdef비어 있지 않은 변수 값 을 확인하는 내용이 나와 있습니다. 변수가 비어 있지 않으면 무엇으로 평가됩니까?
0xF 2014 년

1
@ Matthias009 GNU Make v4.2.1을 테스트 할 때 ifdefor ifndef(허용 된 답변에서와 같이)를 사용 하면 평가되는 변수가 :=지연 설정 ( =) 대신 즉시 설정 ( ) 되는 경우에만 작동합니다 . 그러나 즉시 설정 변수를 사용하는 단점은 선언시 평가되는 반면 지연 설정 변수는 호출시 평가된다는 것입니다. 즉 :=, Make가 해당 변수를 사용하지 않는 규칙 만 실행하는 경우에도 변수에 대한 명령을 실행 하게됩니다! =with 를 사용하여 이것을 피할 수 있습니다ifneq ($(MY_PROG),)
Dennis

9

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

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 ...)이 조용 할하려는 경우는 제외 할 수 있습니다.

이것은 빨리 실패 할 것 입니다. 대상이 필요하지 않습니다.


8

내 솔루션에는 필요한 모든 명령이있는 경우 플래그 파일을 배치 하는 작은 도우미 스크립트 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 기술 에 대한 자세한 내용은 여기 에서 찾을 수 있습니다 .


2
방금 테스트했고 작동했으며 작동하지 않는 항목 (bash 스크립트 또는 Makefile 코드) 또는 오류 메시지에 대한 힌트를 제공하지 않았으므로 문제를 찾는 데 도움이되지 않습니다.
흐름

첫 번째 if문 에서 "예기치 않은 파일 끝"이 나타납니다 .
애덤 그랜트

6

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

누군가가 끔찍한 cmd.exe ... "shell"과 함께 GNU Make를 사용할 것이라고는 생각하지 못했습니다.
Johan Boulé 2019

4

당신은 같은 bash는 내장 명령을 사용할 수 있습니다 type foo또는 command -v foo아래로를 :

SHELL := /bin/bash
all: check

check:
        @type foo

foo프로그램 / 명령은 어디에 있습니까 ? 로 리디렉션 > /dev/null당신이 침묵합니다.


예,하지만 GNU make 만 있고 bash가 설치되지 않았을 때 작동하기를 원했습니다.
Prof. Falken 2015 년

3

다른 대상과 빌더가 있고 각각 다른 도구 세트가 필요하다고 가정하십시오. 이러한 도구 목록을 설정하고 해당 도구의 가용성을 강제로 확인하는 대상으로 간주합니다.

예를 들면 :

make_tools := gcc md5sum gzip

$(make_tools):  
    @which $@ > /dev/null

file.txt.gz: file.txt gzip
    gzip -c file.txt > file.txt.gz 

3

나는 개인적으로 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

1

내가 찾던 런타임 항목을 확인하는 것이 유일한 목적인 다른 메이크 파일 대상에서 특별한 작은 프로그램을 컴파일하여 해결되었습니다.

그런 다음이 프로그램을 또 다른 메이크 파일 대상에서 호출했습니다.

올바르게 기억하면 다음과 같습니다.

real: checker real.c
    cc -o real real.c `./checker`

checker: checker.c
    cc -o checker checker.c

감사합니다. 그러나 이것은 만들지 않을 것입니다. make가 중단되는 것을 방지 할 수 있습니까? 필요한 도구를 사용할 수없는 경우 빌드 단계를 건너 뛰려고합니다.
Marc-Christian Schulze

@ coding.mof 편집-더 비슷했습니다. 프로그램은 런타임에서 무언가를 확인하고 나머지 컴파일에 따라 정보를 제공했습니다.
Prof. Falken

1

STDERR출력을 확인하는 솔루션 --versionSTDOUT대신 버전을 인쇄하는 프로그램에서는 작동하지 않습니다 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}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.