Makefile में लूप कैसे लिखें?


217

मैं निम्नलिखित आदेशों पर अमल करना चाहता हूं:

./a.out 1
./a.out 2
./a.out 3
./a.out 4
.
.
. and so on

कैसे एक लूप के रूप में इस बात को लिखने के लिए Makefile?


इसी तरह, लेकिन थोड़ा और सामान्य:
मल्टीफिल

जवाबों:


273

यदि ./a.outआप आपके उपयोग के द्वारा मान लेते हैं, तो आप यह करेंगे, यदि आप UNIX- प्रकार प्लेटफ़ॉर्म पर हैं।

for number in 1 2 3 4 ; do \
    ./a.out $$number ; \
done

परीक्षण इस प्रकार है:

target:
    for number in 1 2 3 4 ; do \
        echo $$number ; \
    done

पैदा करता है:

1
2
3
4

बड़ी श्रेणियों के लिए, उपयोग करें:

target:
    number=1 ; while [[ $$number -le 10 ]] ; do \
        echo $$number ; \
        ((number = number + 1)) ; \
    done

यह 10 समावेशी के माध्यम से 1 आउटपुट करता है, बस whileअपनी टिप्पणी में संकेत के रूप में एक बहुत बड़ी रेंज के लिए 10 से 1000 तक समाप्ति स्थिति को बदल दें ।

नेस्टेड छोरों इस प्रकार किया जा सकता है:

target:
    num1=1 ; while [[ $$num1 -le 4 ]] ; do \
        num2=1 ; while [[ $$num2 -le 3 ]] ; do \
            echo $$num1 $$num2 ; \
            ((num2 = num2 + 1)) ; \
        done ; \
        ((num1 = num1 + 1)) ; \
    done

उत्पादन:

1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
4 1
4 2
4 3

1
qwert केवल एक लक्षित नाम है जो वास्तविक फ़ाइल होने की संभावना नहीं है। Makefile नियमों को एक लक्ष्य की आवश्यकता है। सिंटैक्स त्रुटि के रूप में, आपको कुछ सामग्री याद आ रही है - अपडेट देखें।
पैक्सडीब्लो सेप

2
चूँकि आप मान रहे हैं कि उसका खोल पहचानता है (...), तो () (i = 0; i <WHATEVER; ++ i) के लिए ज्यादा सरल का उपयोग क्यों नहीं किया जाता; करना ...; किया हुआ ?
इडेलिक

1
ध्यान दें कि seqजो संख्याओं का एक क्रम उत्पन्न करता है वह अधिकांश (सभी?) यूनिक्स प्रणालियों पर मौजूद होता है, इसलिए आप लिख सकते हैं for number in ``seq 1 1000``; do echo $$number; done(seq कमांड के प्रत्येक पक्ष पर एक सिंगल बैकटिक क्लिक करें, दो नहीं, मुझे नहीं पता कि यह कैसे सही तरीके से प्रारूपित करना है
स्टैकओवरफ्लो

3
धन्यवाद, मुझे लूप चर के संदर्भ में डबल $ $ याद आ रही थी।
लीफ ग्रुएनवोल्ड्ट

1
@ जोन: लाइन कंटिन्यू कैरेक्टर इसलिए है क्योंकि makeआमतौर पर हर लाइन को एक अलग सब-शेल में चलाने की चीज माना जाता है । निरंतरता के बिना, यह for number in 1 2 3 4 ; doलूप के बाकी हिस्सों के बिना, केवल (उदाहरण के लिए) के साथ एक सबस्क्रिप्शन चलाने की कोशिश करेगा । इसके साथ, यह प्रभावी रूप से प्रपत्र की एक पंक्ति बन जाती है while something ; do something ; done, जो एक पूर्ण विवरण है। इस $$सवाल का जवाब यहां दिया गया है: stackoverflow.com/questions/26564825/… , इस बहुत ही उत्तर से निकाले गए कोड के साथ :-)
paxdiablo

265

यदि आप GNU मेक का उपयोग कर रहे हैं, तो आप कोशिश कर सकते हैं

NUMBERS = 1 2 3 4
कर दो:
        $ (foreach var, $ (NUMBERS); / a.out $ (var))

जो उत्पन्न और निष्पादित करेगा

./a.out 1; ./a.out 2; ./a.out 3; ./a.out 4;

27
यह उत्तर IMHO बेहतर है, क्योंकि इसे किसी भी शेल का उपयोग करने की आवश्यकता नहीं है, यह शुद्ध मेकाइल है (भले ही यह जीएनयू-विशिष्ट है)।
जोसेलिन delalande

7
अर्धविराम महत्वपूर्ण है अन्यथा केवल पहला पुनरावृत्ति निष्पादित होगा
जेरेमी लीपज़िग

7
यह समाधान बाहर निकलने का कोड छुपाता है ./a.out 1./a.out 2परवाह किए बिना निष्पादित किया जाएगा।
बॉबबोगो

1
@ अलेक्जेंडर: क्या आप इस बात पर विस्तार से बता सकते हैं कि आप किस सीमा का उल्लेख कर रहे हैं?
इडेलिक

1
@ इदेल, हाँ। निम्नलिखित मेकफाइल और शेलस्क्रिप्ट के लिए, शेलस्क्रिप्ट काम करता है (एलएस को तर्क पास करता है), जबकि मेकफाइल एक त्रुटि देता है: मेक: एग्वीवप: / बिन / श: तर्क सूची बहुत लंबी मेकफाइल : ix .io/ d5L शेल्स्क्रिप्ट: ix.io / d5M यह एक समस्या है जो मुझे काम करते समय सामने आई थी, जब एक असामान्य रूप से लंबी सूची (लंबे रास्तों के साथ) को कमांड में पारित किया गया था। हमें वर्कअराउंड ढूंढना था।
अलेक्जेंडर

107

करने के लिए इस्तेमाल करते हैं IMHO प्रमुख कारण है -jझंडा। make -j5एक बार में 5 शेल कमांड चलाएगा। यह अच्छा है अगर आपके पास 4 सीपीयू हैं, और किसी भी मेकफाइल का अच्छा परीक्षण है।

मूल रूप से, आप कुछ ऐसा देखना चाहते हैं:

.PHONY: all
all: job1 job2 job3

.PHONY: job1
job1: ; ./a.out 1

.PHONY: job2
job2: ; ./a.out 2

.PHONY: job3
job3: ; ./a.out 3

यह -jअनुकूल (एक अच्छा संकेत) है। क्या आप बॉयलर-प्लेट को स्पॉट कर सकते हैं? हम लिख सकते हैं:

.PHONY: all job1 job2 job3
all: job1 job2 job3
job1 job2 job3: job%:
    ./a.out $*

एक ही प्रभाव के लिए (हाँ, यह पिछले फॉर्मूलेशन के समान है जहां तक मेकअप का संबंध है, बस थोड़ा अधिक कॉम्पैक्ट है)।

एक और बिट पैरामीटर का उपयोग ताकि आप कमांड-लाइन पर एक सीमा निर्दिष्ट कर सकें (थकाऊ जैसा makeकि कोई अच्छा अंकगणित मैक्रोज़ नहीं है, इसलिए मैं यहां धोखा दूंगा और उपयोग करूंगा $(shell ...))

LAST := 1000
NUMBERS := $(shell seq 1 ${LAST})
JOBS := $(addprefix job,${NUMBERS})
.PHONY: all ${JOBS}
all: ${JOBS} ; echo "$@ success"
${JOBS}: job%: ; ./a.out $*

आप के साथ इस चलाने make -j5 LAST=550, के साथ LAST1000 के दोषी।


7
यह निश्चित रूप से सबसे अच्छा जवाब है, कारण यह है कि उल्लेख किया bobbogo (के लिए है -j )।
dbn

इसका कोई विशेष कारण ।PHONY प्रत्यय? क्या उन्हें किसी चीज की आवश्यकता है?
एसईबी

6
@seb: बिना .PHONY: all, मेक नामक एक फाइल की तलाश करेगा all। यदि ऐसी कोई फ़ाइल मौजूद है, तो उस फ़ाइल के अंतिम-परिवर्तित-समय की जांच करें, और मेकफाइल लगभग निश्चित रूप से वह नहीं करेगा जो आपने इरादा किया था। .PHONYघोषणा कि मेकअप बताता है allएक प्रतीकात्मक लक्ष्य है। इसलिए बनाओ allलक्ष्य को हमेशा पुराना मानेंगे। उत्तम। मैनुअल देखें।
बोब्बोगो

4
यह पंक्ति कैसे काम करती है: $ {JOBS}: नौकरी%: दूसरा अर्धविराम किसके लिए है? मैंने gnu.org/software/make/manual/make.htm
जो

2
@JoeS gnu.org/software/make/manual/make.html#Static-Pattern (मुझे लगता है कि आपका मतलब क्या 2 * कोलन * है )। उन्हें अन-नाइस (IMHO) पैटर्न नियमों के साथ भ्रमित न करें । स्टेटिक पैटर्न नियम वास्तव में उपयोगी होते हैं जब भी लक्ष्यों की सूची मेक इन नोड्स पैटर्न में से एक से मेल खाती हो सकती है (यह निर्भरता पर लागू होता है)। यहाँ मैं सुविधा के लिए एक का उपयोग करता हूं कि जो कुछ भी %नियम में मेल खाता $*है वह नुस्खा के रूप में उपलब्ध है ।
बॉबबोगो

22

मुझे एहसास है कि प्रश्न कई साल पुराना है, लेकिन यह पोस्ट अभी भी किसी के लिए उपयोग की जा सकती है क्योंकि यह एक दृष्टिकोण का प्रदर्शन करता है जो ऊपर से अलग है, और शेल ऑपरेशनों पर निर्भर नहीं है और न ही डेवलपर को एक हार्डकोड को स्काइप करने की आवश्यकता है। संख्यात्मक मूल्यों की स्ट्रिंग।

$ (eval ....) बिलियन मैक्रो आपका दोस्त है। या कम से कम हो सकता है।

define ITERATE
$(eval ITERATE_COUNT :=)\
$(if $(filter ${1},0),,\
  $(call ITERATE_DO,${1},${2})\
)
endef

define ITERATE_DO
$(if $(word ${1}, ${ITERATE_COUNT}),,\
  $(eval ITERATE_COUNT+=.)\
  $(info ${2} $(words ${ITERATE_COUNT}))\
  $(call ITERATE_DO,${1},${2})\
)
endef

default:
  $(call ITERATE,5,somecmd)
  $(call ITERATE,0,nocmd)
  $(info $(call ITERATE,8,someothercmd)

यह एक सरल उदाहरण है। यह बड़े मूल्यों के लिए बहुत अधिक पैमाने पर नहीं होगा - यह काम करता है, लेकिन जैसा कि ITERATE_COUNT स्ट्रिंग प्रत्येक पुनरावृत्ति के लिए 2 वर्णों (स्थान और डॉट) से बढ़ेगा, जैसा कि आप हजारों में उठते हैं, शब्दों को गिनने में उत्तरोत्तर अधिक समय लगता है। जैसा कि लिखा गया है, यह नेस्टेड पुनरावृत्ति को संभालता नहीं है (आपको ऐसा करने के लिए एक अलग पुनरावृत्ति फ़ंक्शन और काउंटर की आवश्यकता होगी)। यह विशुद्ध रूप से ग्नू मेक है, कोई शेल आवश्यकता नहीं है (हालांकि स्पष्ट रूप से ओपी हर बार एक कार्यक्रम चलाने के लिए देख रहा था - यहां, मैं केवल एक संदेश प्रदर्शित कर रहा हूं)। अगर ITERATE के भीतर मान 0 को पकड़ने का इरादा है, क्योंकि $ (शब्द ...) अन्यथा त्रुटि होगी।

ध्यान दें कि काउंटर के रूप में सेवा करने के लिए बढ़ते हुए तार को नियोजित किया जाता है क्योंकि $ (शब्द ...) बिलिन एक अरबी गिनती प्रदान कर सकता है, लेकिन यह अन्यथा गणित के संचालन का समर्थन नहीं करता है (आप 1 + 1 को किसी चीज़ को असाइन नहीं कर सकते हैं और 2 प्राप्त कर सकते हैं) जब तक आप शेल से किसी चीज़ को आपके लिए पूरा करने के लिए, या समान रूप से जटिल मैक्रो ऑपरेशन का उपयोग कर रहे हैं)। हालांकि यह एक काउंटर के लिए बहुत अच्छा काम करता है, लेकिन एक निर्णय के लिए इतना अच्छा नहीं है।

मैं स्वयं इसका उपयोग नहीं करता हूं, लेकिन हाल ही में, मुझे एक बहु-बाइनरी, मल्टी-लाइब्रेरी बिल्ड वातावरण में लाइब्रेरी निर्भरता का मूल्यांकन करने के लिए एक पुनरावर्ती फ़ंक्शन लिखने की आवश्यकता थी, जहां आपको कुछ लाइब्रेरी शामिल करने के लिए अन्य पुस्तकालयों में लाने के लिए जानने की आवश्यकता है अपने आप में अन्य निर्भरताएं हैं (जिनमें से कुछ बिल्ड मापदंडों के आधार पर भिन्न होती हैं), और मैं ऊपर दिए गए समान $ (eval) और काउंटर विधि का उपयोग करता हूं (मेरे मामले में, काउंटर का उपयोग यह सुनिश्चित करने के लिए किया जाता है कि हम किसी तरह अंतहीन में न जाएं लूप, और यह भी एक निदान के रूप में रिपोर्ट करने के लिए कि कितना चलना आवश्यक था)।

ओपी के क्यू: $ (eval ...) के लिए महत्वपूर्ण नहीं है, हालांकि कुछ और लायक है, परिपत्र संदर्भों के लिए आंतरिक घृणा को दरकिनार करने के लिए एक विधि प्रदान करता है, जो एक चर प्रकार के साथ एक गहन प्रकार के साथ लागू करने के लिए अच्छा और ठीक है =), बनाम एक तत्काल असाइनमेंट (=: के साथ प्रारंभ)। कई बार आप अपने स्वयं के असाइनमेंट के भीतर एक चर का उपयोग करने में सक्षम होना चाहते हैं, और $ (eval ...) आपको ऐसा करने में सक्षम करेगा। यहाँ पर विचार करने के लिए महत्वपूर्ण बात यह है कि जिस समय आप निष्कासन चलाते हैं, चर हल हो जाता है, और जो भाग हल हो जाता है वह अब स्थूल के रूप में नहीं माना जाता है। यदि आप जानते हैं कि आप क्या कर रहे हैं और आप अपने आप को असाइनमेंट के आरएचएस पर एक चर का उपयोग करने की कोशिश कर रहे हैं, तो यह आम तौर पर आप वैसे भी होना चाहते हैं।

  SOMESTRING = foo

  # will error.  Comment out and re-run
  SOMESTRING = pre-${SOMESTRING}

  # works
  $(eval SOMESTRING = pre${SOMESTRING}

default:
  @echo ${SOMESTRING}

हैप्पी मेकिंग।


20

क्रॉस-प्लेटफ़ॉर्म समर्थन के लिए, कमांड विभाजक बनाएं (एक ही पंक्ति पर कई कमांड निष्पादित करने के लिए) कॉन्फ़िगर करने योग्य।

यदि आप उदाहरण के लिए Windows प्लेटफ़ॉर्म पर MinGW का उपयोग कर रहे हैं, तो कमांड विभाजक है &:

NUMBERS = 1 2 3 4
CMDSEP = &
doit:
    $(foreach number,$(NUMBERS),./a.out $(number) $(CMDSEP))

यह एक पंक्ति में समाप्‍त आदेशों को कार्यान्वित करता है:

./a.out 1 & ./a.out 2 & ./a.out 3 & ./a.out 4 &

जैसा कि कहीं और उल्लेख किया गया है, एक * निक्स मंच उपयोग पर CMDSEP = ;


7

यह वास्तव में सवाल का शुद्ध जवाब नहीं है, लेकिन इस तरह की समस्याओं के आसपास काम करने का एक बुद्धिमान तरीका है:

एक जटिल फ़ाइल लिखने के बजाय, उदाहरण के लिए एक बैश स्क्रिप्ट जैसे: मेकफाइल को नियंत्रित करना

foo : bar.cpp baz.h
    bash script.sh

और script.sh ऐसा दिखता है:

for number in 1 2 3 4
do
    ./a.out $number
done

मैं मेकफाइल लिखते हुए एक कदम पर अटक गया हूं। मेरे पास निम्नलिखित कोड हैं: set_var: @ NUM = 0; जबकि [[$ $ NUM <1]]; do \ echo "मैं यहाँ हूँ"; \ echo $$ NUM डंप $ $ {NUM} .txt; \ var = "SSA_CORE $$ {NUM} _MAINEXEC"; \ echo $$ var; \ var1 = eval echo \$${$(var)}; \ echo $$ var1; \ ((NUM = NUM ​​+ 1)); सभी किया: set_var यहाँ SSA_CORE0_MAINEXEC एक पर्यावरण चर है जो पहले से ही सेट है। इसलिए मैं चाहता हूं कि वैरिएबल var1 का उपयोग करके मूल्यांकन या मुद्रित हो। मैंने इसे ऊपर दिखाए अनुसार काम नहीं किया था। कृपया मदद कीजिए।
XYZ_Linux

2
यह वास्तव में एक आसान समाधान है, हालांकि यह आपको समानांतर में चलने वाली प्रक्रियाओं के लिए अच्छे "मेक -j 4" विकल्प का उपयोग करने से रोकता है।
TabeaKischka

1
@TabeaKischka: वास्तव में। यह " अनुशंसित " तरीका नहीं था , लेकिन यह अधिक मतलब है कि अगर किसी को कुछ सुविधाओं की आवश्यकता होती है जो मेकफाइल द्वारा पेश नहीं की जाती हैं, तो कोई कार्यान्वयन में वापस आ सकता है bashऔर इस प्रकार सुविधाओं का उपयोग कर सकता है। लूप उन विशेषताओं में से एक है जिनके लिए यह प्रदर्शित किया जा सकता है।
विल्म वान ओन्सेम

4

शायद आप उपयोग कर सकते हैं:

xxx:
    for i in `seq 1 4`; do ./a.out $$i; done;

3

आप set -eफॉर-लूप के लिए उपसर्ग के रूप में उपयोग कर सकते हैं । उदाहरण:

all:
    set -e; for a in 1 2 3; do /bin/false; echo $$a; done

makeएक निकास कोड के साथ तुरंत बाहर निकल जाएगा <> 0


0

यद्यपि GNUmake टेबल टूलकिट में एक सच्चा whileलूप होता है (जो कि GNUmake प्रोग्रामिंग में इसका मतलब है कि इसके दो या तीन चरणों में निष्पादन के साथ), अगर जरूरत वाली चीज एक पुनरावृत्त सूची है, तो इसके साथ एक सरल समाधान है interval। इसके मज़े के लिए, हम संख्याओं को हेक्स में भी बदलते हैं:

include gmtt/gmtt.mk

# generate a list of 20 numbers, starting at 3 with an increment of 5
NUMBER_LIST := $(call interval,3,20,5)

# convert the numbers in hexadecimal (0x0 as first operand forces arithmetic result to hex) and strip '0x'
NUMBER_LIST_IN_HEX := $(foreach n,$(NUMBER_LIST),$(call lstrip,$(call add,0x0,$(n)),0x))

# finally create the filenames with a simple patsubst
FILE_LIST := $(patsubst %,./a%.out,$(NUMBER_LIST_IN_HEX))

$(info $(FILE_LIST))

आउटपुट:

./a3.out ./a8.out ./ad.out ./a12.out ./a17.out ./a1c.out ./a21.out ./a26.out ./a2b.out ./a30.out ./a35.out ./a3a.out ./a3f.out ./a44.out ./a49.out ./a4e.out ./a53.out ./a58.out ./a5d.out ./a62.out

0

एक सरल, शेल / प्लेटफ़ॉर्म-स्वतंत्र, शुद्ध मैक्रो समाधान है ...

%sequence = $(if $(word ${1},${2}),$(wordlist 1,${1},${2}),$(call %sequence,${1},${2} $(words _ ${2})))

$(foreach i,$(call %sequence,10),$(info ./a.out ${i}))

-1
#I have a bunch of files that follow the naming convention
#soxfile1  soxfile1.o  soxfile1.sh   soxfile1.ini soxfile1.txt soxfile1.err
#soxfile2  soxfile2.o   soxfile2.sh  soxfile2.ini soxfile2.txt soxfile2.err
#sox...        ....        .....         ....         ....        ....
#in the makefile, only select the soxfile1.. soxfile2... to install dir
#My GNU makefile solution follows:
tgt=/usr/local/bin/          #need to use sudo
tgt2=/backup/myapplication/  #regular backup 

install:
        for var in $$(ls -f sox* | grep -v '\.' ) ; \
        do \
                sudo  cp -f $$var ${TGT} ;     \
                      cp -f  $$var ${TGT2} ;  \
        done


#The ls command selects all the soxfile* including the *.something
#The grep command rejects names with a dot in it, leaving  
#My desired executable files in a list. 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.