CMake में फंक्शन बनाम मैक्रो


90

सीएमके 2.8.12 के आधिकारिक दस्तावेज के बारे में कहते हैंmacro

जब इसे लागू किया जाता है, तो मैक्रो में दर्ज किए गए आदेशों को पहले पारित किए गए तर्कों के साथ औपचारिक मापदंडों ($ {arg1}) को बदलकर संशोधित किया जाता है, और फिर सामान्य आदेशों के रूप में लागू किया जाता है।

और उस बारे में function

जब इसे लागू किया जाता है, तो फ़ंक्शन में दर्ज किए गए आदेशों को पहले पारित किए गए तर्कों के साथ औपचारिक मापदंडों ($ {arg1}) को बदलकर संशोधित किया जाता है, और फिर सामान्य आदेशों के रूप में आमंत्रित किया जाता है।

जाहिर है, दो उद्धरण लगभग समान हैं लेकिन मुझे भ्रमित कर रहे हैं। मैक्रो की तरह ही किसी फ़ंक्शन को कॉल करते समय पहले पैरामीटर को प्रतिस्थापित करता है?


8
कम से कम एक अन्य महत्वपूर्ण है, यद्यपि के बीच काफी स्पष्ट अंतर है functionऔर macro: का शब्दार्थ return(): जब एक में उपयोग किया जाता है macro, तो आप मैक्रो से वापस नहीं आएंगे लेकिन कॉलिंग फ़ंक्शन से।
जोआचिम डब्ल्यू

1
एक और महत्वपूर्ण नोट, यह है कि किसी मैक्रो में तर्कों पर दो-पास विस्तार चरण होता है जब एक फ़ंक्शन केवल एक होता है। इन मैक्रो और फ़ंक्शन को बनाने का प्रयास करें, और ${ARGV}अंदर से प्रिंट करें : macro(my_macro), function(my_func)। और उन्हें इस्तेमाल: set(a 123), my_macro("\\\${a}\\\\;\\\;;"), my_func(\${a}\\;\;;)। आप आप डबल बच करने के लिए है कि सभी मिल जाएगा $, \ , ;ठीक से पूरी स्ट्रिंग नेस्टेड आदेशों को अपरिवर्तित पारित करने के लिए। में यह वास्तविक है cmake 3.14+
एंड्री

जवाबों:


95

मैंने नीचे एक नमूना कोड लिखा है:

set(var "ABC")

macro(Moo arg)
  message("arg = ${arg}")
  set(arg "abc")
  message("# After change the value of arg.")
  message("arg = ${arg}")
endmacro()
message("=== Call macro ===")
Moo(${var})

function(Foo arg)
  message("arg = ${arg}")
  set(arg "abc")
  message("# After change the value of arg.")
  message("arg = ${arg}")
endfunction()
message("=== Call function ===")
Foo(${var})

और आउटपुट है:

=== Call macro ===
arg = ABC
# After change the value of arg.
arg = ABC
=== Call function ===
arg = ABC
# After change the value of arg.
arg = abc

तो ऐसा लगता है argकी मूल्य असाइन किया गया है varजब बुला Fooऔर ${arg}सिर्फ स्ट्रिंग के साथ बदल दिया है ${var}जब बुला Moo

इसलिए मुझे लगता है कि उपरोक्त दो उद्धरण एक भ्रमित करने के लिए बहुत आसान हैं, हालांकि आधिकारिक दस्तावेजों में यह भी कहा गया है कि :

ध्यान दें कि मानकों को एक स्थूल और करने के लिए मूल्यों को इस तरह के ARGN के रूप में हमेशा की तरह CMake अर्थ में चर नहीं हैं। वे स्ट्रिंग प्रतिस्थापन हैं जैसे कि सी प्रीप्रोसेसर एक मैक्रो के साथ क्या करेंगे। यदि आप सही CMake चर और / या बेहतर CMake गुंजाइश नियंत्रण चाहते हैं, तो आपको फ़ंक्शन कमांड को देखना चाहिए।


मैं यह भूल गया हूं, लेकिन मुझे लगता है कि यह हो सकता है।
यंतो झी जू

2
@robert तुरंत सहायता केंद्र के अनुसार अपने स्वयं के प्रश्न का उत्तर देने की अनुमति देता है (विशेषकर यदि यह दूसरों के लिए सामान्य हित का एक अच्छा, गैर-डुप्लिकेट प्रश्न है)। यह SO को एक बेहतर ज्ञान आधार बनने में मदद करना है। क्या आपने उस सहायता केंद्र विषय से जुड़े ब्लॉग पोस्ट को पढ़ा है? stackoverflow.blog/2011/07/01/…
एमिल कॉर्मियर

1
@robert मैं सिर्फ इसलिए बता रहा हूं कि SO के संस्थापक खुद इस प्रथा के बारे में क्या सोचते हैं। उसे अपने साथ ले जाओ। ;-)
एमिल कॉर्मियर

2
इस तरह के चल रहे उदाहरण cmake --trace-expandज्ञानवर्धक हैं
मार्कह

1
कृपया प्रत्येक कॉल के बाद निम्न कमांड जोड़ने पर विचार करें: message("# arg in main scope = '${arg}'")+ मैक्रो से पहले फ़ंक्शन को कॉल करना।
मार्ख

34

दूसरे शब्दों में, फ़ंक्शन नए चर स्कोप और पॉप को बनाता है (केवल फ़ंक्शन में ही बनाए गए और परिवर्तित किए गए चर), मैक्रो नहीं करता है। हालाँकि, आप कमांड के PARENT_SCOPEपैरामीटर के साथ फ़ंक्शन डिफ़ॉल्ट व्यवहार को ओवरराइड कर सकते हैं set


8

आपके द्वारा उद्धृत cmake प्रलेखन इतना भ्रामक है कि यह मूल रूप से गलत है। इसे इस तरह स्पष्ट किया जाना चाहिए:

  • मैक्रो: जब इसे लागू किया जाता है, तो मैक्रो में दर्ज किए गए आदेशों को पारित किए गए तर्कों के साथ औपचारिक मापदंडों ($ {arg1}) को बदलकर चलाने से पहले सभी को संशोधित किया जाता है।

cmake --trace-expand वास्तव में क्या होता है दिखाता है।

इस संबंध में 2.8.12 की तुलना में cmake 3.13.3 डॉक्टर परिवर्तित नहीं हुआ है।


3

मैक्रो विस्तार, Yantao झी द्वारा उत्तर दिया वास्तव में मेरी आँखों को खोलता है!

मैंने यह भी पाया कि नीचे दिया गया ट्यूटोरियल कुछ ठोस उदाहरणों के साथ आता है, जो चर गुंजाइश अवधारणा को समझने में सहायक है।

15 मिनट में जानें सेमीकिट से उद्धृत :

CMake में, आप फ़ंक्शन को परिभाषित करने के लिए function/ endfunctionकमांड्स की एक जोड़ी का उपयोग कर सकते हैं । यहाँ एक है जो अपने तर्क के संख्यात्मक मूल्य को दोगुना करता है, फिर परिणाम प्रिंट करता है:

function(doubleIt VALUE)
    math(EXPR RESULT "${VALUE} * 2")
    message("${RESULT}")
endfunction()

doubleIt("4")                           # Prints: 8

कार्य अपने स्वयं के दायरे में चलते हैं। फ़ंक्शन में परिभाषित कोई भी चर कॉलर के दायरे को प्रदूषित नहीं करता है। यदि आप कोई मान वापस करना चाहते हैं, तो आप अपने फ़ंक्शन के लिए एक चर का नाम पारित कर सकते हैं, फिर setविशेष तर्क के साथ कमांड को कॉल कर सकते हैं PARENT_SCOPE:

function(doubleIt VARNAME VALUE)
    math(EXPR RESULT "${VALUE} * 2")
    set(${VARNAME} "${RESULT}" PARENT_SCOPE)    # Set the named variable in caller's scope
endfunction()

doubleIt(RESULT "4")                    # Tell the function to set the variable named RESULT
message("${RESULT}")                    # Prints: 8

इसी तरह, एक जोड़ी macro/ endmacroआदेश एक मैक्रो को परिभाषित करता है। फ़ंक्शन के विपरीत, मैक्रोज़ उनके कॉलर के समान दायरे में चलते हैं। इसलिए, मैक्रो के अंदर परिभाषित सभी चर कॉलर के दायरे में सेट किए गए हैं। हम पिछले फ़ंक्शन को निम्नलिखित के साथ बदल सकते हैं:

macro(doubleIt VARNAME VALUE)
    math(EXPR ${VARNAME} "${VALUE} * 2")        # Set the named variable in caller's scope
endmacro()

doubleIt(RESULT "4")                    # Tell the macro to set the variable named RESULT
message("${RESULT}")                    # Prints: 8

दोनों कार्य और मैक्रोज़ एक मनमानी संख्या को स्वीकार करते हैं। तर्क एक विशेष चर नाम के माध्यम से, एक सूची के रूप में कार्य के संपर्क में हैं ARGN

यहां एक ऐसा फ़ंक्शन है जो प्रत्येक तर्क को दोगुना करता है, जो प्रत्येक को एक अलग लाइन पर प्रिंट करता है:

function(doubleEach)
    foreach(ARG ${ARGN})                # Iterate over each argument
        math(EXPR N "${ARG} * 2")       # Double ARG's numeric value; store result in N
        message("${N}")                 # Print N
    endforeach()
endfunction()

doubleEach(5 6 7 8)                     # Prints 10, 12, 14, 16 on separate lines

3

के बीच एक और उल्लेखनीय अंतर function()और macro()के व्यवहार है return()

रिटर्न के cmake प्रलेखन से () :

ध्यान दें कि एक मैक्रो, फ़ंक्शन के विपरीत, जगह में विस्तारित है और इसलिए रिटर्न को संभाल नहीं सकता है ()।

इसलिए क्योंकि यह जगह में विस्तारित है, macro()इसमें कॉलर से रिटर्न होता है। जबकि एक समारोह में यह सिर्फ बाहर निकलता हैfunction()

उदाहरण:

macro(my_macro)
    return()
endmacro()

function(my_function)
    return()
endfunction()

my_function()
message(hello) # is printed
my_macro()
message(hi) # is not printed
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.