जांचें कि क्या कोई प्रोग्राम मेकफाइल से मौजूद है


115

अगर कोई प्रोग्राम मेकफाइल से कॉल करने योग्य है, तो मैं कैसे जांच सकता हूं?

(अर्थात, प्रोग्राम पथ में मौजूद होना चाहिए या अन्यथा कॉल करने योग्य होना चाहिए।)

उदाहरण के लिए यह संकलित करने के लिए इसका उपयोग किया जा सकता है।

उदाहरण के लिए कुछ इस तरह का सवाल है , लेकिन अंतर्निहित खोल के बिना POSIX संगत है।


1
क्या आप एक POSIX- संगत शेल आह्वान कर सकते हैं ?
रीइनियरियरपोस्ट

शायद नहीं, मुझे लगता है कि मैं एक होने की मांग कर सकता हूं, लेकिन यह बहुत आसान होगा यदि मुझे नहीं करना है।
प्रो। फॉकन

इस बीच, मैंने इसे प्रोजेक्ट में एक प्रोग्राम जोड़कर हल किया, जो पहले बनाया गया है, और जिसका एकमात्र उद्देश्य उस अन्य प्रोग्राम की जांच करना है ... :-)
प्रो। फॉकन

2
पारंपरिक वर्कअराउंड में एक automakeस्क्रिप्ट होती है जो विभिन्न पूर्वापेक्षाओं की जांच करती है और एक उपयुक्त लिखती है Makefile
ट्रिपल

जवाबों:


83

कभी-कभी आपको अलग-अलग लक्ष्य ओएस पर चलने में सक्षम होने के लिए मेकफिल की आवश्यकता होती है और आप चाहते हैं कि बिल्ड जल्दी विफल हो जाए यदि एक आवश्यक निष्पादन योग्य PATHविफल होने से पहले लंबे समय तक चलने के बजाय है।

इंजीनियरचुआन द्वारा प्रदान किए गए उत्कृष्ट समाधान को एक लक्ष्य बनाने की आवश्यकता है । हालांकि, यदि आपके पास परीक्षण करने के लिए कई निष्पादन योग्य हैं और आपके मेकफाइल के पास कई स्वतंत्र लक्ष्य हैं, जिनमें से प्रत्येक को परीक्षणों की आवश्यकता होती है, तो प्रत्येक लक्ष्य को एक निर्भरता के रूप में परीक्षण लक्ष्य की आवश्यकता होती है। जब आप एक समय में एक से अधिक लक्ष्य बनाते हैं, तो बहुत अधिक अतिरिक्त टाइपिंग के साथ-साथ प्रसंस्करण समय भी बनता है।

0xf द्वारा प्रदान किया गया समाधान एक लक्ष्य बनाए बिना एक निष्पादन योग्य के लिए परीक्षण कर सकता है। यह बहुत सारे टाइपिंग और निष्पादन के समय को बचाता है जब कई लक्ष्य होते हैं जिन्हें अलग-अलग या एक साथ बनाया जा सकता है।

बाद के समाधान के लिए मेरा सुधार whichनिष्पादन योग्य ( whereविंडोज में) का उपयोग करना है , बजाय इसके कि --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")))

:=आरएचएस अभिव्यक्ति के तत्काल मूल्यांकन को मजबूर करने के लिए आवश्यक असाइनमेंट ऑपरेटर के उपयोग पर ध्यान दें । यदि आपका मेकफाइल बदलता है PATH, तो ऊपर की अंतिम पंक्ति के बजाय आपको आवश्यकता होगी:

        $(if $(shell PATH=$(PATH) which $(exec)),some string,$(error "No $(exec) in PATH")))

यह आपको इसके समान आउटपुट देना चाहिए:

ads$ make
Makefile:5: *** "No dudu in PATH.  Stop.

2
यदि आप सभी चर (यानी एलएस सीसी एलडी) का प्रदर्शन करते हैं, और $ ($ (निष्पादन)) का उपयोग करते हैं, तो आप उन्हें पर्यावरण या अन्य मेकफाइल्स से मूल बनाने के लिए पारित कर सकते हैं। क्रॉस-संकलन करते समय उपयोगी।
रिकोफोसुसा

1
मेरे "," जब "ifeq (, $ (शेल जो lzop)) चल रहा है) पर चोक बनाते हैं" = /
mentatkgs

2
विंडोज पर, where my_exe 2>NULइसके बजाय का उपयोग करें which
आरोन कैंपबेल

2
Ifeq के साथ TABS इंडेंटेशन से सावधान रहें जो एक नियम वाक्यविन्यास है! यह TAB के बिना होना चाहिए। उसके साथ एक कठिन समय था। stackoverflow.com/a/21226973/2118777
Pipo

2
यदि आप उपयोग कर रहे हैं Bash, तो बाहरी कॉल करने की कोई आवश्यकता नहीं है whichcommand -vइसके बजाय अंतर्निहित का उपयोग करें । अधिक जानकारी
कुरुचिंस्की २

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 

यह खूबसूरती से काम करता है क्योंकि "कमांड -v" कुछ भी प्रिंट नहीं करता है यदि निष्पादन योग्य उपलब्ध नहीं है, तो चर डॉट को कभी भी परिभाषित नहीं किया जाता है और जब भी आप अपने कोड में चाहते हैं, तब आप इसे जांच सकते हैं। इस उदाहरण में मैं एक त्रुटि फेंक रहा हूं, लेकिन यदि आप चाहते हैं तो आप कुछ अधिक उपयोगी हो सकते हैं।

यदि वैरिएबल उपलब्ध है, तो "कमांड -v" डीओटी वेरिएबल को परिभाषित करते हुए कमांड पथ को प्रिंट करने का सबसे सस्ता संचालन करता है।


5
कम से कम कुछ प्रणालियों में (अर्थात Ubuntu 14.04), के $(shell command -v dot)साथ विफल हो जाता है make: command: Command not found। इसे ठीक करने के लिए, stderr आउटपुट को / dev / null पर रीडायरेक्ट करें $(shell command -v dot 2> /dev/null):। स्पष्टीकरण
J0HN

3
commandएक बैश बिलिन है, अधिक पोर्टेबिलिटी के लिए, उपयोग करने पर विचार करें which?
जुलियन पालार्ड

10
@JulienPalard मैं आपको लगता है कि कर रहे हैं गलत: commandउपयोगिता के लिए आवश्यक है POSIX (सहित -vविकल्प) दूसरी ओर whichकोई मानकीकरण किया गया है bahaviour (है कि मैं के बारे में पता) और कभी कभी एकमुश्त है व्यर्थ
Gyom

3
command -vPOSIX जैसे शेल वातावरण की आवश्यकता है। यह बिना साइबरविन या समान एमुलेशन के विंडोज पर काम नहीं करेगा।
डोलमेन

10
कारण है कि commandअक्सर काम नहीं करता है इसके अभाव की वजह से नहीं है, लेकिन क्योंकि एक की अजीब अनुकूलन कि जीएनयू पड़ता है: अगर एक कमांड "सरल पर्याप्त" है कहीं भी होगी खोल बाईपास; दुर्भाग्यवश इसका मतलब है कि जब तक आप कमांड को थोड़ा सा नहीं करेंगे, तब तक बिल्ट-इन कभी-कभी काम नहीं करेगा।
रफालविंड

33

यह तुमने क्या किया?

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

मेरे सहकर्मी को श्रेय।


नहीं, मैंने एक कार्यक्रम को एक लक्ष्य में संकलित किया और दूसरे में चलाया।
प्रो। फॉकन

21

shellअपने प्रोग्राम को कॉल करने के लिए फ़ंक्शन का उपयोग इस तरह से करें कि यह मानक आउटपुट के लिए कुछ प्रिंट करता है। उदाहरण के लिए, पास --version

GNU मेक पास की गई कमांड की निकास स्थिति को अनदेखा करता है 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

एक बोनस के रूप में, आउटपुट (जैसे प्रोग्राम संस्करण) आपके मेकफाइल के अन्य भागों में उपयोगी हो सकता है।


इस त्रुटि देता है *** missing separator. Stop.मैं सभी लाइनों पर टैब जोड़ देते हैं तो बाद all:मैं त्रुटि मिलती हैmake: ifdef: Command not found
मथायस 009


1
करने के लिए टैब न जोड़ें ifdef, else, endifलाइनों। बस सुनिश्चित करें कि @echoलाइनें टैब से शुरू होती हैं।
0xF

मैंने विंडोज और लिनक्स पर अपने समाधान का परीक्षण किया। आपके द्वारा लिंक किए गए दस्तावेज़ में कहा गया है कि ifdefगैर-रिक्त चर मान के लिए जाँच करता है। यदि आपका वैरिएबल खाली नहीं है, तो यह किसका मूल्यांकन करता है?
0xF

1
@ Matthias009 जब मैं GNU मेक v4.2.1 का परीक्षण करता हूं, तो ( ifdefया ifndefस्वीकृत उत्तर के रूप में) केवल तभी काम करता है जब मूल्यांकन किए जा रहे चर को तुरंत सेट ( :=) के बजाय lazily set ( =) से किया जाए। हालाँकि, तुरंत सेट चर का उपयोग करने का एक नकारात्मक पहलू यह है कि उन्हें मूल्यांकन के समय पर मूल्यांकन किया जाता है, जबकि आलसी सेट चर का मूल्यांकन तब किया जाता है जब उन्हें बुलाया जाता है। इसका मतलब है कि आप :=तब भी चर के लिए कमांड निष्पादित कर रहे होंगे जब मेक केवल नियम चल रहा हो जो कभी भी उन चर का उपयोग न करें! =ifneq ($(MY_PROG),)
डेनिस

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
मैंने अभी इसका परीक्षण किया है और यह काम करता है और चूंकि आपने इस बारे में कोई संकेत नहीं दिया है कि आपके लिए क्या काम नहीं कर रहा है।
प्रवाह करें

मैं पहले ifबयान पर "फ़ाइल का अप्रत्याशित अंत" प्राप्त कर रहा हूं ।
एडम ग्रांट

6

मेरे लिए उपरोक्त सभी उत्तर लिनक्स पर आधारित हैं और विंडोज़ के साथ काम नहीं कर रहे हैं। मैं नया हूं इसलिए मेरा दृष्टिकोण आदर्श नहीं हो सकता है। लेकिन पूरा उदाहरण जो कि 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 ... "शेल" के साथ GNU मेक का उपयोग करेगा।
जोहान बोले

4

आप नीचे दिए गए type fooया जैसे बैश बिल्ट कमांड का उपयोग कर सकते हैं command -v foo:

SHELL := /bin/bash
all: check

check:
        @type foo

fooआपका प्रोग्राम / कमांड कहां है > /dev/nullयदि आप इसे चुप करना चाहते हैं तो पुनर्निर्देशित करें ।


हां, लेकिन बात यह है कि मैं चाहता था कि यह तब काम करे जब मेरे पास केवल जीएनयू हो लेकिन कोई बैश स्थापित न हो।
प्रो। फॉकन

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

धन्यवाद। लेकिन यह गर्भपात कर देगा, है ना? क्या गर्भपात करने से रोकना संभव है? यदि आवश्यक उपकरण उपलब्ध नहीं है तो मैं एक बिल्ड चरण को छोड़ने की कोशिश कर रहा हूं ..
मार्क-क्रिस्चियन शुल्ज़

@ coding.mof को संपादित किया गया - यह उस तरह अधिक था। कार्यक्रम ने रनटाइम में कुछ जाँच की और बाकी संकलन के अनुसार जानकारी दी।
प्रो। फॉकन

1

STDERRआउटपुट के लिए जाँच करने वाले समाधान --versionउन कार्यक्रमों के लिए काम नहीं करते हैं जो STDOUTइसके बजाय अपने संस्करण को प्रिंट करते हैं STDERR। उनके आउटपुट की जाँच करने के बजाय STDERRया STDOUT, प्रोग्राम रिटर्न कोड की जाँच करें। यदि प्रोग्राम मौजूद नहीं है, तो इसका निकास कोड हमेशा शून्य रहेगा।

#!/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}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.