2012-10-08 21 views
11

मैं इस तरह से है कि मैं इस तरह के रूप में अपने Makefile के हर नियम में उपयोग कर सकते हैं, में एक खोल समारोहमेकफ़ाइल में वैश्विक शैल फ़ंक्शंस को कैसे परिभाषित किया जाए?

#!/bin/sh 

test() 
{ 
    do_some_complicated_tests $1 $2; 
    if something; then 
    build_thisway $1 $2; 
    else 
    build_otherway $1 $2; 
    fi 
} 

परिभाषित करना चाहते हैं:

foo: bar 
    test foo baz 

स्पष्ट है कि, मैं खोल चाहते मेकफ़ाइल का हिस्सा बनने के लिए कार्य करें। ऐसा करने का सबसे शानदार तरीका क्या है? बोनस पॉइंट्स यदि आप बिना कॉल किए इसे कॉल कर सकते हैं।


पृष्ठभूमि: मेरे वास्तविक समस्या यह है कि make -n एक बहुत लंबा और अपठनीय उत्पादन उत्पादन होता है। प्रत्येक नियम अपठनीय शैल आदेशों के लगभग समान अनुक्रम का उपयोग करता है, और कई नियम हैं। उपरोक्त समाधान make -n का उत्पादन अधिक उपयोगी बना देगा।

+0

मैंने किया है @JonathanLeffler 'नहीं कर सके कहा -n बनाने टी नहीं किया जा सकता है?मैं कम से कम एक महीने के लिए खुद से प्रसन्नता से प्रसन्न होने जा रहा हूं। – Beta

+0

क्यों न केवल कोड को एक शेल स्क्रिप्ट में डालें और उसे कॉल करें? – reinierpost

उत्तर

7

यह समाधान एक बाहरी अस्थायी फ़ाइल पर निर्भर नहीं करता और SHELL चर के साथ टिंकर करने के लिए आप के लिए मजबूर नहीं है।

TESTTOOL=sh -c '\ 
    do_some_complicated_tests $$1 $$2; \ 
    if something; then 
    build_thisway $$1 $$2; 
    else 
    build_otherway $$1 $$2; 
    fi' TESTTOOL 

ifneq (,$(findstring n,$(MAKEFLAGS))) 
TESTTOOL=: TESTTOOL 
endif 

foo: bar 
    ${TESTTOOL} foo baz 

कमांड लाइन पर -n ध्वज के लिए ifneq…endif ब्लॉक चेक और : TESTTOOL को TESTTOOL के विस्तार जो पढ़ने में आसान और निष्पादित करने के लिए सुरक्षित है निर्धारित करता है।

सबसे अच्छा समाधान शैल फ़ंक्शन को वास्तविक प्रोग्राम में बदलने के लिए हो सकता है यदि यह आपके लिए एक विकल्प है।

3

कुछ मुझसे कहता है आप make -n के उत्पादन को छानने बेहतर होगा, लेकिन क्या आप से पूछना संभव है:

define test 
    @echo do some tests with $(1) and $(2); \ 
    SOMETHING=$(1)_3 ; \ 
    if [ $$SOMETHING == foo_3 ]; then \ 
    echo build this way $(1) $(2); \ 
    else \ 
    echo build another way $(1) $(2) ; \ 
    fi 
endef 

someTarget: 
    $(call test,foo,bar) 

someOtherTarget: 
    $(call test,baz,quartz) 
+0

धन्यवाद! दुर्भाग्यवश, यह समाधान बिल्कुल वही है जिसे मैं टालने की कोशिश कर रहा था। – Holger

+0

@ होल्गर, इसके साथ क्या गलत है? – Beta

+0

यह ठीक काम करता है, लेकिन 'मेक-एन' का आउटपुट अपठनीय हो जाएगा क्योंकि 'स्क्रिप्ट' नामक प्रत्येक लक्ष्य के लिए शेल स्क्रिप्ट फिर से दिखाई देगी। इससे भी बदतर, लिपि एक पंक्ति पर होगी। मैं फ़िल्टर का उपयोग कर सकता था, लेकिन फिर मुझे फ़िल्टर को डीबग करना होगा, जिसे मैं टालना चाहता हूं। – Holger

5

प्रश्न टैग है के बाद से gnu-make, आप बीटा समाधान के साथ खुश हो सकता है, लेकिन मुझे लगता है कि सबसे अच्छा समाधान 1 है) test के अलावा फ़ंक्शन का नाम बदलें (ls और cd जैसे नामों से बचें); चर्चा के उद्देश्य के लिए मान लें कि आपने इसका नाम बदलकर foo, 2) बस foo नामक एक स्क्रिप्ट लिखें और इसे मेकफ़ाइल से आमंत्रित करें। क्या तुम सच में Makefile में एक खोल समारोह को परिभाषित करना चाहते हैं, तो बस प्रत्येक नियम के लिए इसे परिभाषित:

F = foo() { \ 
    do_some_complicated_tests $$1 $$2; \ 
    if something; then \ 
    build_thisway $$1 $$2; \ 
    else \ 
    build_otherway $$1 $$2; \ 
    fi \ 
} 

all: bar 
    @$(F); foo baz bar 

ऐसा नहीं है कि आप foo की परिभाषा की प्रत्येक पंक्ति पर लाइन निरंतरता होनी चाहिए और उन्हें $ सब तो भाग निकले कर रहे हैं कि वे खोल के लिए पास कर रहे हैं।

+1

धन्यवाद! प्रत्येक नियम में फ़ंक्शन को परिभाषित करने से समस्या हल नहीं होती है कि 'make -n' का आउटपुट बहुत लंबा है। इस मामले में, मैं बीटा के समाधान को प्राथमिकता दूंगा। हालांकि, निम्नलिखित मेरे लिए काम कर सकता है: मैं निर्भरता 'सब: foo.sh' और एक नियम' foo.sh: 'जोड़ सकता हूं जो कि स्क्रिप्ट को' foo.sh' में आउटपुट करता है। यह धीमा है और मुझे कुछ और सुरुचिपूर्ण खोजने में खुशी होगी, लेकिन मैं वास्तव में सब कुछ एक फाइल में होना चाहता हूं। – Holger

+0

ग्रेट; यह मेरा पसंदीदा है। मुझे जो भी बेहतर लगता है वह निम्नलिखित संक्षेप है: 'F_DEF = foo() {ऊपर के रूप में}', और फिर 'F = @ $ (F_DEF); foo', और फिर आप इसे कहीं भी '$ (एफ) arg1 ... argn' के रूप में पुन: उपयोग कर सकते हैं। –

3

मैं यह नहीं लगता कि के रूप में "सुरुचिपूर्ण" उत्तीर्ण, लेकिन यह तुम क्या चाहते करने के लिए लगता है:

## 
## --- Start of ugly hack 
## 

THIS_FILE := $(lastword $(MAKEFILE_LIST)) 

define shell-functions 
: BEGIN 
    # Shell syntax here 
    f() 
    { 
    echo "Here you define your shell function. This is f(): [email protected]" 
    } 

    g() 
    { 
    echo "Another shell function. This is g(): [email protected]" 
    } 
: END 
endef 

# Generate the file with function declarations for the shell 
$(shell sed -n '/^: BEGIN/,/^: END/p' $(THIS_FILE) > .functions.sh) 

# The -i is necessary to use --init-file 
SHELL := /bin/bash --init-file .functions.sh -i 

## 
## -- End of ugly hack 
## 

all: 
    @f 1 2 3 4 
    @g a b c d 

चल रहा है इस का उत्पादन:

$ make -f hack.mk 
Here you define your shell function. This if f(): 1 2 3 4 
Another shell function. This is g(): a b c d 

-n के साथ चल रहा है पैदा करता है:

$ make -f hack.mk -n 
f 1 2 3 4 
g a b c d 

यह इस तथ्य पर निर्भर करता है कि मैक्रोज़ define और 0 के बीच परिभाषित हैंको make द्वारा तब तक व्याख्या नहीं किया जाता है जब तक वे वास्तव में उपयोग नहीं किए जाते हैं, इसलिए आप सीधे शेल सिंटैक्स का उपयोग कर सकते हैं और आपको बैकस्लैश के साथ प्रत्येक पंक्ति को समाप्त करने की आवश्यकता नहीं है। बेशक, अगर आप shell-functions मैक्रो को कॉल करते हैं तो यह बम होगा।

+0

.sh फ़ाइल निकालने की आपकी विधि बहुत उपयोगी है, धन्यवाद। यह मेरी इच्छा के करीब है। अगर मैं एक अस्थायी .sh फ़ाइल लिख रहा हूं, तो मुझे कोई परवाह नहीं है कि मैं एफ और जी को शैल फ़ंक्शंस के रूप में उपयोग कर रहा हूं; मैं इसके बजाए f.sh और g.sh का उपयोग करूंगा। तो यह लगभग बदसूरत नहीं है क्योंकि '$ (SHELL) 'को फिर से परिभाषित करने की कोई आवश्यकता नहीं है। – Holger

+0

'SHELL' चाल का उपयोग करने का लाभ यह है कि सबकुछ स्वचालित रूप से और पारदर्शी रूप से होता है। आपको '.sh' फ़ाइलों को खोल में स्पष्ट रूप से हर बार लोड करने की ज़रूरत नहीं है। – Idelic

+0

मैंने सोचा कि हर कमांड के लिए $ (SHELL) को पुनरारंभ करें? तो उपरोक्त सभी 'प्रभावी' बनाएं, $ (SHELL) चलाएं और पाइप "एफ 1 2 3 4" अपने stdin में चलाएं। अगली पंक्ति पर, $ (SHELL) और पाइप "g a b c d" का एक नया उदाहरण अपने stdin में शुरू करें। क्या यह सच है? यदि ऐसा है, तो मुझे अलग-अलग फ़ाइलों का उपयोग करने पर लाभ दिखाई नहीं देता है (क्योंकि 'bash --init-file ...' को .sh-file को फिर से पढ़ना है)। [स्पष्ट होने के लिए, मेरा प्रस्तावित विकल्प '@।/F.sh 1 2 3 4' '@f 1 2 3 4' के बजाय' @।/F.sh 1 2 3 4' का उपयोग करना है।] – Holger

3

यह वास्तव में यहूदी है, लेकिन जो भी हो। मैं zsh का उपयोग करता हूं, लेकिन मुझे यकीन है कि बैश और श समकक्ष हैं।

Makefile:

export ZDOTDIR := ./ 

SHELL := /usr/bin/env zsh 

default: 
    f 

।zshenv, Makefile रूप में एक ही निर्देशिका:

f() { echo 'CHECK OUT THIS AWESOME FUNCTION!' } 

ZDOTDIR चर बनाता dotfiles के लिए मौजूदा निर्देशिका में zsh देखो। फिर आप .zshenv में जो चाहते हैं उसे बस चिपकाएं।

$ make 
f 
CHECK OUT THIS AWESOME FUNCTION! 
1

टी एल; डॉ:

अपने makefile में:

SHELL=bash 
BASH_FUNC_command%%=() { ... } 
export BASH_FUNC_command%% 

लांग जवाब

मैं एक संदर्भ गैर बनाने के जो यहाँ काम करता है में पार्टी के साथ कुछ ऐसा ही किया है ।

मैं पार्टी में अपने खोल कार्यों की घोषणा की और फिर उन्हें साथ निर्यात:

export -f function-name 

वे तो अगर एक ही खोल, आपके मामले में, एक उप प्रक्रिया के रूप में शुरू हो जाती है मेकअप से स्वाभाविक रूप से उपलब्ध हैं।

उदाहरण:

$ # define the function 
$ something() { echo do something here ; } 
$ export -f something 

$ # the Makefile 
$ cat > Makefile <<END 
SHELL=bash 
all: ; something 
END 
$ 

इसे आजमाएं

$ make 
something 
do something here 
$ 

कैसे वातावरण में इस दिखता है?

$ env | grep something 
BASH_FUNC_something%%=() { echo do something here 

तो आपके लिए सवाल मेकफ़ाइल के भीतर से पर्यावरण चर सेट करने का तरीका होगा। पैटर्न BASH_FUNC_ किया जा रहा है समारोह-नाम %% =() {समारोह शरीर}

सीधे भीतर

तो कैसे करता है आप के लिए यह काम करता है? इस makefile

SHELL=bash 
define BASH_FUNC_something-else%% 
() { 
    echo something else 
} 
endef 
export BASH_FUNC_something-else%% 

all: ; something-else 

की कोशिश करो और कोशिश यह:

$ make 
something-else 
something else 

यह थोड़ा Makefile में बदसूरत है, लेकिन प्रस्तुत के लिए कोई कुरूपता कुछ

संबंधित मुद्दे