"रन बनाने" के लिए तर्क पारित करना


354

मैं Makefiles का उपयोग करें।

मेरे पास एक लक्ष्य है जिसे runबिल्ड लक्ष्य कहा जाता है । सरलीकृत, यह निम्न की तरह दिखता है:

prog: ....
  ...

run: prog
  ./prog

क्या तर्कों को पारित करने का कोई तरीका है? इसलिए कि

make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat

धन्यवाद!


जवाबों:


264

मुझे ऐसा करने का तरीका नहीं पता है कि आप क्या चाहते हैं, लेकिन एक समाधान हो सकता है:

run: ./prog
    ./prog $(ARGS)

फिर:

make ARGS="asdf" run
# or
make run ARGS="asdf"

27
@Rob: $ () अधिक पोर्टेबल है, यह Nmake के साथ-साथ बनाने में भी काम आता है।
जॉन न्युएलर

7
@ रब: निमेक ने स्थूल विस्तार के लिए कभी भी $ {} का समर्थन नहीं किया है, और यह अब एक पुरातन रूप प्रतीत होता है। $ () की सिफारिश हर ऑनलाइन ट्यूटोरियल द्वारा की जाती है जिसे मैंने देखा है। $ () भी अन्य उपकरणों जैसे बैश के साथ अधिक सुसंगत है।
जॉन नॉवेलर

10
शायद यह पुरातन है। मैंने हमेशा $ {} का उपयोग किया है, लेकिन GNU मेक के लिए मैनुअल कहता है "किसी वैरिएबल के मान को बदलने के लिए, कोष्ठक या ब्रेसिज़ में वैरिएबल के नाम के बाद एक डॉलर का चिह्न लिखें: या तो $(foo)' or $ {foo} 'का एक वैध संदर्भ है चर 'फू'। " और उदाहरण देने के लिए आय जहां केवल $ () का उपयोग किया जाता है। ठीक है।
जेकब बोर्ग

7
जॉन और शांत की ओर इशारा करते हुए, मैं वापस गया और देखा कि यह सुझाव पहले संस्करण ऑर्ली की किताब "मेकिंग के लिए मैनेजिंग प्रोजेक्ट्स" की मेरी कॉपी से आया था। लेखक अभिलेख प्रतिस्थापन के बारे में नियम बताता है () और मैक्रोज़ दोनों का उपयोग करने में सक्षम है लेकिन भेद करने के लिए {} के उपयोग का सुझाव देता है। लेकिन .... नया संस्करण अब "GNU मेक के साथ प्रबंध परियोजनाओं" () के रूप में उपयोग किया जाता है। जाओ आंकड़ा .... लगता है कि मुझे आधुनिकीकरण करना होगा! (-: मैं अभी भी चकित हूँ कि MS NMake बारफू पर {} के हालांकि।
Rob Wells

1
@xealits यह निश्चित है - वहाँ सवाल पर एक उदाहरण है यहां
helvete

198

यह सवाल लगभग तीन साल पुराना है, लेकिन फिर भी ...

यदि आप GNU मेक का उपयोग कर रहे हैं, तो यह करना आसान है। एकमात्र समस्या यह है कि makeलक्ष्य के रूप में कमांड लाइन में गैर-विकल्प तर्कों की व्याख्या की जाएगी। इसका समाधान उन्हें कुछ भी नहीं करने के लिए करना है, इसलिए makeशिकायत नहीं करेंगे:

# If the first argument is "run"...
ifeq (run,$(firstword $(MAKECMDGOALS)))
  # use the rest as arguments for "run"
  RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
  # ...and turn them into do-nothing targets
  $(eval $(RUN_ARGS):;@:)
endif

prog: # ...
    # ...

.PHONY: run
run : prog
    @echo prog $(RUN_ARGS)

इसे चलाने से यह मिलता है:

$ make run foo bar baz
prog foo bar baz

2
यह बहुत अच्छा है, सिवाय इसके कि यह एक डैश के साथ शुरू होने वाले तर्कों के लिए काम नहीं करता:prog foo bar --baz
ingydotnet

22
यह उस मामले में भी काम करता है, लेकिन आपको कमांड लाइन विकल्प के रूप में makeव्याख्या नहीं करना है :। इसका मतलब है "इस के बाद सब कुछ एक तर्क, एक विकल्प नहीं है"। --bazmake -- prog foo bar --baz--
3

मैं इसका RUN_ARGSउपयोग करने के लिए एक डिफ़ॉल्ट मान कैसे परिभाषित करूंगा ?
बुके

हो सकता है कि एक elseशाखा को इसमें जोड़ें ifeqऔर RUN_ARGSवहाँ सेट करें ?
इडली

1
अच्छी बात है! लेकिन इसके लिए एक समाधान है: 'eval' लाइन को बदलें, जिसमें $(eval $(RUN_ARGS):dummy;@:)कोई डमी लक्ष्य निर्धारित नहीं है।
लुकास किमोन

52

मानक बनाने के लिए आप इस तरह मैक्रोज़ को परिभाषित करके तर्क पारित कर सकते हैं

make run arg1=asdf

तो उन्हें इस तरह का उपयोग करें

run: ./prog $(arg1)
   etc

Microsoft के NMake बनाने के लिए संदर्भ


34

आप नीचे दिए गए बदलाव की तरह चर को पास कर सकते हैं:

run:
    @echo ./prog $$FOO

उपयोग:

$ make run FOO="the dog kicked the cat"
./prog the dog kicked the cat

या:

$ FOO="the dog kicked the cat" make run
./prog the dog kicked the cat

वैकल्पिक रूप से बीटा द्वारा प्रदान किए गए समाधान का उपयोग करें :

run:
    @echo ./prog $(filter-out $@,$(MAKECMDGOALS))
%:
    @:

%:- नियम जो किसी भी कार्य के नाम से मेल खाते हैं; @:- खाली नुस्खा = कुछ न करना

उपयोग:

$ make run the dog kicked the cat
./prog the dog kicked the cat

22

TL; DR ऐसा करने की कोशिश नहीं करते

$ make run arg

इसके बजाय स्क्रिप्ट बनाएँ:

#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"

और यह करो:

$ ./buildandrunprog.sh arg

उक्त प्रश्न का उत्तर:

आप नुस्खा में एक चर का उपयोग कर सकते हैं

run: prog
    ./prog $(var)

फिर बनाने के लिए एक तर्क के रूप में एक चर असाइनमेंट पास करें

$ make run var=arg

यह निष्पादित करेगा ./prog arg

लेकिन नुकसान से सावधान रहें। मैं इस विधि के नुकसान और अन्य तरीकों के बारे में विस्तार से बताऊंगा।


सवाल के पीछे की मंशा का जवाब:

धारणा: आप progकुछ तर्कों के साथ चलना चाहते हैं, लेकिन यदि आवश्यक हो तो चलने से पहले इसका पुनर्निर्माण करें।

उत्तर: एक स्क्रिप्ट बनाएं जो यदि आवश्यक हो तो फिर से आर्ग से चलाता है

#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"

यह स्क्रिप्ट बहुत स्पष्ट है। इसका उपयोग यह करने के लिए करता है कि यह किसके लिए अच्छा है: भवन। यह एक शेल स्क्रिप्ट का उपयोग करता है जो कि इसके लिए अच्छा है: बैच प्रोसेसिंग।

इसके अलावा आप एक और स्क्रिप्ट के सभी लचीलेपन के बिना एक और स्क्रिप्ट के पूर्ण लचीलेपन और स्पष्टता के साथ जो कुछ भी आप की आवश्यकता हो सकती है।

कॉलिंग सिंटैक्स भी अब व्यावहारिक रूप से समान है:

$ ./buildandrunprog.sh foo "bar baz"

से तुलना:

$ ./prog foo "bar baz"

इसके विपरीत

$ make run var="foo bar\ baz"

पृष्ठभूमि:

लक्ष्य के लिए तर्क पारित करने के लिए डिज़ाइन नहीं किया गया है। कमांड लाइन पर सभी तर्कों को एक लक्ष्य (उर्फ लक्ष्य), एक विकल्प के रूप में, या एक चर असाइनमेंट के रूप में व्याख्या की जाती है।

इसलिए यदि आप इसे चलाते हैं:

$ make run foo --wat var=arg

मेकअप की व्याख्या करेगा runऔर fooउनके व्यंजनों के अनुसार लक्ष्यों (लक्ष्य) अद्यतन करने के लिए के रूप में। --watबनाने के लिए एक विकल्प के रूप में। और var=argएक चर असाइनमेंट के रूप में।

अधिक जानकारी के लिए देखें: https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals

शब्दावली के लिए देखें: https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introduction


चर असाइनमेंट विधि के बारे में और मैं इसके खिलाफ क्यों सलाह देता हूं

$ make run var=arg

और नुस्खा में चर

run: prog
    ./prog $(var)

यह एक नुस्खा के लिए तर्कों को पारित करने का सबसे "सही" और सीधा तरीका है। लेकिन जब इसका उपयोग तर्कों के साथ एक कार्यक्रम चलाने के लिए किया जा सकता है तो निश्चित रूप से इसे इस तरह से उपयोग करने के लिए डिज़ाइन नहीं किया गया है। देख https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding

मेरी राय में इसका एक बड़ा नुकसान है: आप जो करना चाहते हैं वह progतर्क से चलाया जाता है arg। लेकिन लिखने के बजाय:

$ ./prog arg

आप लिख रहे हैं:

$ make run var=arg

रिक्त स्थान वाले कई तर्कों या तर्कों को पारित करने का प्रयास करते समय यह और भी अजीब हो जाता है:

$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz

से तुलना:

$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz

इस रिकॉर्ड के लिए मेरे progजैसा दिखता है:

#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
  echo "arg: $arg"
done

यह भी ध्यान दें कि आपको $(var)मेकफाइल में उद्धरण नहीं देना चाहिए :

run: prog
    ./prog "$(var)"

क्योंकि तब progहमेशा सिर्फ एक तर्क मिलेगा:

$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz

यह सब इसलिए है क्योंकि मैं इस मार्ग के खिलाफ सलाह देता हूं।


पूर्णता के लिए यहां "रन बनाने के लिए तर्क पास करें" कुछ अन्य तरीके हैं।

विधि 1:

run: prog
    ./prog $(filter-out $@, $(MAKECMDGOALS))

%:
    @true

सुपर शॉर्ट स्पष्टीकरण: लक्ष्यों की सूची से वर्तमान लक्ष्य को फ़िल्टर करें। कैच %टू ऑल टारगेट ( ) जो अन्य लक्ष्यों को चुपचाप अनदेखा करने के लिए कुछ भी नहीं करता है।

विधि 2:

ifeq (run, $(firstword $(MAKECMDGOALS)))
  runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
  $(eval $(runargs):;@true)
endif

run:
    ./prog $(runargs)

सुपर शॉर्ट स्पष्टीकरण: यदि लक्ष्य runतो पहले लक्ष्य को हटा दें और शेष लक्ष्यों का उपयोग करने के लिए कुछ भी लक्ष्य न बनाएं eval

दोनों आपको कुछ इस तरह लिखने की अनुमति देंगे

$ make run arg1 arg2

विवरण के लिए गहन अध्ययन करें: https://www.gnu.org/software/make/manual/html_node/ind.net.html

विधि 1 की समस्याएं:

  • एक डैश के साथ शुरू होने वाले तर्कों की व्याख्या एक लक्ष्य के रूप में की जाती है और इसे पारित नहीं किया जाता है।

    $ make run --foo --bar
    

    वैकल्पिक हल

    $ make run -- --foo --bar
    
  • समान चिन्ह वाले तर्क की व्याख्या मेक द्वारा की जाएगी और पारित नहीं की जाएगी

    $ make run foo=bar
    

    कोई वर्कअराउंड नहीं

  • रिक्त स्थान के साथ तर्क अजीब है

    $ make run foo "bar\ baz"
    

    कोई वर्कअराउंड नहीं

  • यदि कोई तर्क होता है run(लक्ष्य के बराबर) तो उसे भी हटा दिया जाएगा

    $ make run foo bar run
    

    के ./prog foo barबजाय चलेगा./prog foo bar run

    विधि 2 के साथ संभव समाधान

  • यदि एक तर्क एक वैध लक्ष्य है तो इसे भी चलाया जाएगा।

    $ make run foo bar clean
    

    चलेगा, ./prog foo bar cleanलेकिन लक्ष्य के लिए नुस्खा clean(यह मौजूद है)।

    विधि 2 के साथ संभव समाधान

  • जब आप एक वैध लक्ष्य को गलत करते हैं तो इसे पकड़ के कारण चुपचाप नजरअंदाज कर दिया जाएगा।

    $ make celan
    

    बस चुपचाप उपेक्षा करेंगे celan

    वर्कअराउंड सब कुछ क्रिया करना है। तो आप देखिए क्या होता है। लेकिन यह वैध उत्पादन के लिए बहुत शोर पैदा करता है।

विधि 2 की समस्याएं:

  • यदि किसी तर्क में एक मौजूदा लक्ष्य के समान नाम है, तो मेक एक चेतावनी को मुद्रित करेगा कि यह ओवरराइट किया जा रहा है।

    कोई वर्कअराउंड जिसे मैं जानता हूं

  • समान चिह्न वाले तर्क अभी भी मेक द्वारा पारित किए जाएंगे और पारित नहीं किए जाएंगे

    कोई वर्कअराउंड नहीं

  • रिक्त स्थान के साथ तर्क अभी भी अजीब है

    कोई वर्कअराउंड नहीं

  • स्पेस ब्रेक के साथ तर्क evalकुछ भी लक्ष्य नहीं बनाने की कोशिश कर रहा है।

    वर्कअराउंड: उपरोक्त सभी कुछ भी न करते हुए ग्लोबल कैच को बनाएं। ऊपर के रूप में इस समस्या के साथ कि यह फिर से चुपचाप गलत लक्ष्यों को नजरअंदाज कर देगा।

  • यह evalरनटाइम पर मेकफाइल को संशोधित करने के लिए उपयोग करता है। पठनीयता और दुर्बलता और कम से कम विस्मय के सिद्धांत के संदर्भ में आप कितना बदतर हो सकते हैं ।

    वर्कअराउंड: ऐसा न करें !! 1 के बजाय एक शेल स्क्रिप्ट लिखें जो रन बनाती है और फिर चलती है prog

मैंने केवल ग्नू मेक का उपयोग करके परीक्षण किया है। अन्य तरीकों से अलग व्यवहार हो सकता है।


TL; DR ऐसा करने की कोशिश नहीं करते

$ make run arg

इसके बजाय स्क्रिप्ट बनाएँ:

#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"

और यह करो:

$ ./buildandrunprog.sh arg

12

यहाँ एक और समाधान है जो इन उपयोग मामलों में से कुछ के साथ मदद कर सकता है:

test-%:
    $(PYTHON) run-tests.py $@

दूसरे शब्दों में, कुछ उपसर्ग ( test-इस मामले में) चुनें, और फिर प्रोग्राम / धावक को सीधे लक्ष्य नाम दें। मुझे लगता है कि यह ज्यादातर उपयोगी है अगर इसमें कुछ रनर स्क्रिप्ट शामिल हो जो अंतर्निहित कार्यक्रम के लिए उपयोगी कुछ लक्ष्य नाम को खोल सकती है।


2
आप $*लक्ष्य के उस भाग से भी गुजर सकते हैं जिसका मिलान किया गया था %
मालवीयस

9

जीएनयू बनाने के लिए मैन पेज से वाक्य रचना को देखते हुए

बनाना [-f makefile] [विकल्प] ... [लक्ष्य] ...

आप कई लक्ष्य निर्दिष्ट कर सकते हैं, इसलिए 'नहीं' (आपके द्वारा निर्दिष्ट सटीक तरीके से कम से कम नहीं)।


4

आप कमांड लाइन में प्रत्येक n-वें तर्क को स्पष्ट रूप से निकाल सकते हैं। ऐसा करने के लिए, आप वैरिएबल MAKECMDGOALS का उपयोग कर सकते हैं, यह 'make' को दिए गए कमांड लाइन के तर्कों की सूची रखता है, जो इसे लक्ष्यों की सूची के रूप में व्याख्या करता है। यदि आप n-वें तर्क को निकालना चाहते हैं, तो आप "शब्द" फ़ंक्शन के साथ संयुक्त उस चर का उपयोग कर सकते हैं, उदाहरण के लिए, यदि आप दूसरा तर्क चाहते हैं, तो आप इसे एक चर में निम्नानुसार संग्रहीत कर सकते हैं:

second_argument := $(word 2, $(MAKECMDGOALS) )

यह उस तर्क के लिए मेक कमांड भी चलाता है। make: *** No rule to make target 'arg'. Stop.
थॉमसरैगी

2

एनोन , run: ./progथोड़ा अजीब लगता है, क्योंकि दाहिना हिस्सा एक लक्ष्य होना चाहिए, इसलिए run: progबेहतर दिखता है।

मैं बस सुझाव दूंगा:

.PHONY: run

run:
        prog $(arg1)

और मैं जोड़ना चाहूंगा, कि तर्क पारित किए जा सकते हैं:

  1. तर्क के रूप में: make arg1="asdf" run
  2. या पर्यावरण के रूप में परिभाषित किया जा सकता है: arg1="asdf" make run

2

यहाँ मेरा उदाहरण है। ध्यान दें कि मैं विंडोज 7 के तहत लिख रहा हूं, देव-सीपी के साथ आने वाले mingw32-make.exe का उपयोग कर। (मेरे पास c: \ Windows \ System32 \ make.bat है, इसलिए कमांड को अभी भी "मेक" कहा जाता है। "

clean:
    $(RM) $(OBJ) $(BIN) 
    @echo off
    if "${backup}" NEQ "" ( mkdir ${backup} 2> nul && copy * ${backup} )

नियमित सफाई के लिए उपयोग:

make clean

Mydir में सफाई और एक बैकअप बनाने के लिए उपयोग:

make clean backup=mydir

2

इस पर बहुत गर्व नहीं है, लेकिन मैं पर्यावरण चर में पारित नहीं करना चाहता था इसलिए मैंने डिब्बाबंद कमांड चलाने का तरीका उलटा किया:

run:
    @echo command-you-want

यह उस कमांड को प्रिंट कर देगा जिसे आप चलाना चाहते हैं, इसलिए अभी इसका सबस्क्रिप्शन में मूल्यांकन करें:

$(make run) args to my command

4
दो साल बाद इस जवाब पर गौर करना - मैं कभी इतना जिद्दी क्यों था कि मैं पर्यावरण चर का उपयोग नहीं करना चाहता था और मुझे क्यों लगता है कि एक और कमांड की पीढ़ी को बेहतर बनाना था?
कॉनरैड.डीन

0

मुझे एक समान चिह्न (=) के साथ तर्क प्राप्त करने का एक तरीका मिला! जवाब विशेष रूप से @lesmana के उत्तर के अतिरिक्त है (जैसा कि यह सबसे पूर्ण है और यहां एक समझाया गया है), लेकिन इसे टिप्पणी के रूप में लिखना बहुत बड़ा होगा। फिर से, मैं उनके संदेश को दोहराता हूं: TL, DR ऐसा करने की कोशिश नहीं करते हैं!

मुझे अपने तर्क का इलाज करने का एक तरीका चाहिए था --xyz-enabled=false(चूंकि डिफ़ॉल्ट सत्य है), जिसे हम सभी अब तक जानते हैं कि यह एक लक्ष्य नहीं है और इस तरह इसका हिस्सा नहीं है $(MAKECMDGOALS)

जबकि i के गूंजने से मेक के सभी वेरिएबल्स में$(.VARIABLES) इन दिलचस्प आउटपुट मिले:

[...] -*-command-variables-*- --xyz-enabled [...]

यह हमें दो तरीके से जाने की अनुमति देता है: या तो सभी --(जो आपके मामले पर लागू होता है) के साथ शुरू हो रहा है , या जीएनयू को विशिष्ट बनाने के लिए देखें (शायद हमारे लिए उपयोग करने का इरादा नहीं) चर -*-command-variables-*-। ** अतिरिक्त विकल्पों के लिए पाद देखें ** मेरे मामले में यह चर आयोजित किया गया:

--xyz-enabled=false

इस चर के साथ हम इसे पहले से मौजूद समाधान के साथ जोड़ सकते हैं $(MAKECMDGOALS)और इस प्रकार परिभाषित कर सकते हैं:

# the other technique to invalidate other targets is still required, see linked post
run:
    @echo ./prog $(-*-command-variables-*-) $(filter-out $@,$(MAKECMDGOALS))`

और इसका उपयोग (स्पष्ट रूप से तर्कों के क्रम को मिलाकर):

make run -- config --xyz-enabled=false over=9000 --foo=bar show  isit=alwaysreversed? --help

लौटा हुआ:

./prog isit=alwaysreversed? --foo=bar over=9000 --xyz-enabled=false config show --help

जैसा कि आप देख सकते हैं, हम आर्ग के कुल क्रम को ढीला कर देते हैं। "असाइनमेंट" -ार्ग्स वाला हिस्सा उलट दिया गया लगता है, "लक्ष्य" -ार्ग का क्रम रखा जाता है। मैंने शुरुआत में "असाइनमेंट" रखा, उम्मीद है कि आपका कार्यक्रम इस बात की परवाह नहीं करता कि तर्क कहाँ रखा गया है।


अद्यतन: निम्नलिखित चर के रूप में अच्छी तरह से होनहार देखो:

MAKEFLAGS =  -- isit=alwaysreverse? --foo=bar over=9000 --xyz-enabled=false
MAKEOVERRIDES = isit=alwaysreverse? --foo=bar over=9000 --xyz-enabled=false

-2

मेरे द्वारा उपयोग की जाने वाली एक और चाल -nध्वज है, जो makeसूखा रन करने के लिए कहता है। उदाहरण के लिए,

$ make install -n 
# Outputs the string: helm install stable/airflow --name airflow -f values.yaml
$ eval $(make install -n) --dry-run --debug
# Runs: helm install stable/airflow --name airflow -f values.yaml --dry-run --debug
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.