2012-06-21 5 views
17

मैं project/build में सीएमके को निर्देशिका 'बिल्ड' में बनाने की कोशिश कर रहा हूं, जहां CMakeLists.txt project/ में है।स्क्रिप्ट लपेटने के बिना स्रोत से बाहर बनाने के लिए cmake प्राप्त करना?

मैं जानता हूँ कि मैं कर सकते हैं:

mkdir build 
cd build 
cmake ../ 

लेकिन यह बोझिल है। मैं इसे एक स्क्रिप्ट में डाल सकता हूं और इसे कॉल कर सकता हूं, लेकिन फिर सेमेक (जैसे -जी "एमएसवाईएस मेकफ़ाइल") के लिए अलग-अलग तर्क प्रदान करना अप्रिय है, या मुझे प्रत्येक प्लेटफ़ॉर्म पर इस फ़ाइल को संपादित करने की आवश्यकता होगी।

अधिमानतः मैं मुख्य CMakeLists.txt में एसईटी (CMAKE_OUTPUT_DIR बिल्ड) जैसे कुछ करता हूं। कृपया मुझे बताएं कि यह संभव है, और यदि हां, तो कैसे? या कुछ अन्य स्रोत निर्माण विधि से बाहर है जो विभिन्न तर्कों को निर्दिष्ट करना आसान बनाता है?

+0

मेरे पास आपके जैसा ही प्रोजेक्ट आर्किटेक्चर है। मेरा "निर्माण" डीआईआर हमेशा यहाँ है। मैं व्यक्तिगत रूप से यह कहता हूं कि टाइपिंग _cmake .._ इतना बड़ा सौदा नहीं है। – Offirmo

उत्तर

26

आप गैर-दस्तावेजी CMake विकल्पों -H और -Bcmake लागू पर स्रोत और बाइनरी निर्देशिका निर्दिष्ट करने के लिए उपयोग कर सकते हैं:

cmake -H. -Bbuild -G "MSYS Makefiles" 

यह वर्तमान फ़ोल्डर में CMakeLists.txt के लिए देखो और एक build फ़ोल्डर बना देगा (अगर यह इसमें अभी तक मौजूद नहीं है) इसमें।

+3

अच्छा विकल्प। लेकिन मैक्स ने कहा "सेमीकेक को अलग-अलग तर्क प्रदान करना अप्रिय है"। वह इसे सीएमकेलिस्ट में चाहता है। – Offirmo

4

एक समाधान जिसे मैंने हाल ही में पाया है, मेकफ़ाइल रैपर के साथ आउट-ऑफ-सोर्स बिल्ड अवधारणा को गठबंधन करना है।

अपने शीर्ष स्तर CMakeLists.txt फ़ाइल में, मैं में स्रोत को रोकने के लिए निम्न शामिल हैं बनाता है:

if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) 
    message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt.") 
endif() 

फिर, मैं एक उच्च-स्तरीय Makefile बनाते हैं, और इस प्रकार हैं:

# ----------------------------------------------------------------------------- 
# CMake project wrapper Makefile ---------------------------------------------- 
# ----------------------------------------------------------------------------- 

SHELL := /bin/bash 
RM := rm -rf 
MKDIR := mkdir -p 

all: ./build/Makefile 
    @ $(MAKE) -C build 

./build/Makefile: 
    @ ($(MKDIR) build > /dev/null) 
    @ (cd build > /dev/null 2>&1 && cmake ..) 

distclean: 
    @ ($(MKDIR) build > /dev/null) 
    @ (cd build > /dev/null 2>&1 && cmake .. > /dev/null 2>&1) 
    @- $(MAKE) --silent -C build clean || true 
    @- $(RM) ./build/Makefile 
    @- $(RM) ./build/src 
    @- $(RM) ./build/test 
    @- $(RM) ./build/CMake* 
    @- $(RM) ./build/cmake.* 
    @- $(RM) ./build/*.cmake 
    @- $(RM) ./build/*.txt 

ifeq ($(findstring distclean,$(MAKECMDGOALS)),) 
    $(MAKECMDGOALS): ./build/Makefile 
    @ $(MAKE) -C build $(MAKECMDGOALS) 
endif 

डिफ़ॉल्ट लक्ष्य all को make टाइप करके बुलाया जाता है, और लक्ष्य ./build/Makefile को आमंत्रित करता है।

पहली बात यह है लक्ष्य ./build/Makefile करता है जो mkdir -p के लिए एक चर रहा है build निर्देशिका $(MKDIR) का उपयोग कर, तैयार करना है। निर्देशिका build वह जगह है जहां हम अपना आउट-ऑफ-सोर्स बिल्ड करेंगे। mkdir यह सुनिश्चित करने के लिए हम -p तर्क प्रदान करते हैं जो कि पहले से मौजूद निर्देशिका बनाने की कोशिश करने के लिए चिल्ला नहीं रहा है।

दूसरी बात लक्ष्य ./build/Makefile निर्देशिका को build निर्देशिका में बदलना है और cmake को आमंत्रित करना है।

all लक्ष्य पर वापस, हम $(MAKE) -C build, जहां $(MAKE) एक Makefile चर स्वचालित रूप से make के लिए उत्पन्न है आह्वान। make -C कुछ भी करने से पहले निर्देशिका को बदलता है। इसलिए, $(MAKE) -C build का उपयोग cd build; make करने के बराबर है।

संक्षेप में, के साथ make all या make कर के बराबर है इस Makefile आवरण बुला:

mkdir build 
cd build 
cmake .. 
make 

लक्ष्य distclean invokes cmake .., तो make -C build clean, और अंत में, build निर्देशिका से सभी सामग्री को निकाल देता है। मेरा मानना ​​है कि यह वही है जो आपने अपने प्रश्न में अनुरोध किया था।

मेकफ़ाइल का अंतिम भाग मूल्यांकन करता है कि उपयोगकर्ता द्वारा प्रदान किया गया लक्ष्य distclean है या नहीं। यदि नहीं, तो यह इसे आमंत्रित करने से पहले निर्देशिका को build में बदल देगा। यह बहुत शक्तिशाली है क्योंकि उपयोगकर्ता टाइप कर सकते हैं, उदाहरण के लिए, make clean, और मेकफ़ाइल इसे cd build; make clean के समतुल्य रूप में बदल देगा।

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

पीएस मेकफ़ाइल में, हम शेल कमांड से आउटपुट को दबाने के लिए उपसर्ग @ का उपयोग करते हैं, और शेल कमांड से त्रुटियों को अनदेखा करने के लिए उपसर्ग @- का उपयोग करते हैं। लक्ष्य के हिस्से के रूप में rm का उपयोग करते समय, यदि फ़ाइलें मौजूद नहीं हैं तो आदेश एक त्रुटि लौटाएगा (वे पहले से ही rm -rf build के साथ कमांड लाइन का उपयोग कर हटा दिए गए हैं, या वे पहले स्थान पर कभी नहीं जेनरेट किए गए थे)। यह वापसी त्रुटि हमारे मेकफ़ाइल को बाहर निकलने के लिए मजबूर करेगी। हम इसे रोकने के लिए उपसर्ग @- का उपयोग करते हैं। यह स्वीकार्य है कि फ़ाइल को पहले ही हटा दिया गया था; हम चाहते हैं कि हमारे मेकफ़ाइल को जारी रखें और बाकी को हटा दें।

ध्यान देने योग्य एक और बात: यदि आप अपनी परियोजना बनाने के लिए सीएमके चर के चर संख्या का उपयोग करते हैं, तो यह मेकफ़ाइल काम नहीं कर सकता है, उदाहरण के लिए, cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"। यह मेकफ़ाइल मानता है कि आप cmake .. टाइप करके या cmake को लगातार संख्या में तर्क (जिसे आप अपने मेकफ़ाइल में शामिल कर सकते हैं) प्रदान करके, सीएमके को लगातार तरीके से आमंत्रित करते हैं।

अंत में, क्रेडिट जहां क्रेडिट देय है। यह मेकफ़ाइल रैपर C++ Application Project Template द्वारा प्रदान की गई मेकफ़ाइल से अनुकूलित किया गया था।

यह उत्तर मूल रूप से here पोस्ट किया गया था। मैंने सोचा कि यह आपकी स्थिति पर भी लागू होता है।

1

पिछले उत्तरों के आधार पर, मैंने निम्न मॉड्यूल लिखा है जिसमें आप आउट-ऑफ-सोर्स बिल्ड को लागू करने के लिए शामिल कर सकते हैं।

  • जब उपयोगकर्ता आलसी है और बस cmake . चलाता है, वे हमेशा एक FATAL_ERROR देखेंगे:

    set(DEFAULT_OUT_OF_SOURCE_FOLDER "cmake_output") 
    
    if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) 
        message(WARNING "In-source builds not allowed. CMake will now be run with arguments: 
         cmake -H. -B${DEFAULT_OUT_OF_SOURCE_FOLDER} 
    ") 
    
        # Run CMake with out of source flag 
        execute_process(
          COMMAND ${CMAKE_COMMAND} -H. -B${DEFAULT_OUT_OF_SOURCE_FOLDER} 
          WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) 
    
        # Cause fatal error to stop the script from further execution 
        message(FATAL_ERROR "CMake has been ran to create an out of source build. 
    This error prevents CMake from running an in-source build.") 
    endif() 
    

    यह काम करता है, लेकिन मैं पहले से ही दो कमियां देखा। मुझे सीएमके को किसी भी अन्य परिचालन करने से रोकने और जल्दी से बाहर निकलने के लिए एक और तरीका नहीं मिला।

  • cmake पर मूल कॉल को पास किए गए किसी भी कमांड लाइन तर्क "आउट-ऑफ-सोर्स बिल्ड कॉल" को पास नहीं किए जाएंगे।

इस मॉड्यूल को बेहतर बनाने के लिए सुझाव स्वागत है।