क्या GLOB या प्रत्येक फ़ाइल को CMake में व्यक्तिगत रूप से स्रोत फ़ाइलों को निर्दिष्ट करना बेहतर है?


157

CMake एक लक्ष्य के लिए स्रोत फ़ाइलों को निर्दिष्ट करने के कई तरीके प्रदान करता है। उदाहरण के लिए ग्लोबिंग ( प्रलेखन ) का उपयोग करना है :

FILE(GLOB MY_SRCS dir/*)

एक अन्य विधि प्रत्येक फ़ाइल को व्यक्तिगत रूप से निर्दिष्ट करना है।

कौन सा तरीका पसंद किया जाता है? ग्लोबिंग आसान लगता है, लेकिन मैंने सुना है कि इसमें कुछ गिरावट है।

जवाबों:


185

पूर्ण प्रकटीकरण: मैंने मूल रूप से इसकी सादगी के लिए ग्लोबिंग दृष्टिकोण को प्राथमिकता दी, लेकिन वर्षों से मैं यह मानता आया हूं कि बड़ी, मल्टी-डेवलपर परियोजनाओं के लिए फाइलों को स्पष्ट रूप से सूचीबद्ध करना कम त्रुटि वाला है।

मूल उत्तर:


ग्लोबिंग के फायदे हैं:

  • नई फ़ाइलों को जोड़ना आसान है क्योंकि वे केवल एक ही स्थान पर सूचीबद्ध हैं: डिस्क पर। ग्लोबिंग नहीं दोहराव पैदा करता है।

  • आपकी CMakeLists.txt फ़ाइल छोटी होगी। यदि आपके पास बहुत सारी फाइलें हैं तो यह एक बड़ा प्लस है। ग्लोबिंग के कारण आप फाइलों की विशाल सूची के बीच सीएमके तर्क को नहीं खो सकते हैं।

हार्डकोड फ़ाइल सूची का उपयोग करने के फायदे हैं:

  • CMake डिस्क पर एक नई फ़ाइल की निर्भरता को सही ढंग से ट्रैक करेगा - अगर हम ग्लोब का उपयोग करते हैं तो पहली बार राउंड में ग्लोबेड नहीं की गई फाइलें जब आप रन करेंगे तो सीमेक को उठाया नहीं जाएगा

  • आप यह सुनिश्चित करते हैं कि केवल वही फाइलें जो आप चाहते हैं, जोड़ी गई हैं। ग्लोबिंग आवारा फाइलें उठा सकता है जो आप नहीं चाहते हैं।

पहले अंक के आसपास काम करने के लिए, आप बस CMakeLists.txt को "टच" कर सकते हैं जो ग्लोब को करता है, या तो टच कमांड का उपयोग करके या बिना किसी बदलाव के फाइल को लिखकर। यह सीएमके को नई फाइल को फिर से चलाने और लेने के लिए मजबूर करेगा।

दूसरी समस्या को ठीक करने के लिए आप अपने कोड को ध्यान से निर्देशिकाओं में व्यवस्थित कर सकते हैं, जो कि आप शायद वैसे भी करते हैं। सबसे खराब स्थिति में, आप list(REMOVE_ITEM)फ़ाइलों की ग्लॉब्ड सूची को साफ करने के लिए कमांड का उपयोग कर सकते हैं :

file(GLOB to_remove file_to_remove.cpp)
list(REMOVE_ITEM list ${to_remove})

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


1
ग्लोबिंग के साथ भी बुरा है: गिट के डिफॉल्ट फाइल को $ बेसन के रूप में संग्रहीत किया जाता है। $ ext। $ ext $ $ pid। $ ext जो एक मर्ज रिज़ॉल्यूशन के बाद संकलित करने का प्रयास करते समय मजेदार त्रुटियों का कारण बन सकता है।
मैथ्सटफ

9
मुझे लगता है कि नई फाइलों के गुम होने की कमियों के बारे में यह उत्तर स्पष्ट है, Simply "touch" the CMakeLists.txtयदि आप डेवलपर हैं तो ठीक है, लेकिन दूसरों के लिए अपने सॉफ़्टवेयर का निर्माण करना वास्तव में एक दर्द-बिंदु हो सकता है जो अपडेट करने के बाद आपका निर्माण विफल हो जाता है और बोझ उनकी जांच करने के लिए है क्यों।
विचारमान42

36
आपको पता है कि? 6 साल पहले यह जवाब लिखने के बाद से , मैंने अपना दिमाग थोड़ा बदल दिया है और अब स्पष्ट रूप से फाइलों को सूचीबद्ध करना पसंद करता हूं। यह केवल वास्तविक नुकसान है "यह एक फ़ाइल जोड़ने के लिए थोड़ा और काम है", लेकिन यह आपको सभी प्रकार के सिरदर्द से बचाता है। और बहुत से तरीकों से स्पष्ट रूप से निहित से बेहतर है।
ऋचीक

1
क्या आप इस वर्तमान स्थिति पर पुनर्विचार करेंगे? :)
एंटोनियो

8
जैसा कि एंटोनियो कहते हैं, वोट "ग्लोबिंग" दृष्टिकोण की वकालत के लिए दिए गए थे। उत्तर की प्रकृति को बदलना उन मतदाताओं के लिए एक चारा और स्विच बात है। एक समझौता के रूप में, मैंने अपनी बदली हुई राय को दर्शाने के लिए एक एड किया है। मैं इंटरनेट पर माफी माँगता हूँ कि इस तरह के एक
तूफ़ानी

113

सीएमके में सोर्सफाइल्स को निर्दिष्ट करने का सबसे अच्छा तरीका उन्हें स्पष्ट रूप से सूचीबद्ध करना है

खुद CMake के निर्माता ग्लोबिंग का उपयोग नहीं करने की सलाह देते हैं

देखें: https://cmake.org/cmake/help/v3.15/command/file.html?highlight=glob#file

(हम आपके स्रोत वृक्ष से स्रोत फ़ाइलों की सूची एकत्र करने के लिए GLOB का उपयोग करने की अनुशंसा नहीं करते हैं। यदि कोई स्रोत जोड़ा या हटाए जाने पर कोई CMakeLists.txt फ़ाइल परिवर्तित नहीं होती है, तो उत्पन्न बिल्ड सिस्टम को पता नहीं चल सकता है कि CMake को पुन: उत्पन्न करने के लिए कब कहा जाए।)

बेशक, आप जानना चाहते होंगे कि डाउनसाइड क्या हैं - पर पढ़ें!


जब ग्लोबिंग विफल होता है:

ग्लोबिंग के लिए बड़ा नुकसान यह है कि फ़ाइलों को बनाना / हटाना स्वचालित रूप से बिल्ड-सिस्टम को अपडेट नहीं करेगा।

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

मामलों को बदतर बनाने के लिए, विफलता आमतौर पर कुछ लिंकिंग त्रुटि देती है जो समस्या के कारण को कोई संकेत नहीं देती है और समय की समस्या का निवारण नहीं होता है।

जिस प्रोजेक्ट में मैंने काम किया था, उसमें हमने ग्लोबिंग शुरू कर दिया था, लेकिन जब नई फाइलें जोड़ी गईं, तो इतनी शिकायतें मिलीं कि ग्लोबिंग के बजाय फाइलों को स्पष्ट रूप से सूचीबद्ध करना पर्याप्त कारण था।

यह आम गिट वर्क-फ्लो
( git bisectऔर फीचर शाखाओं के बीच स्विच) को भी तोड़ता है ।

इसलिए मैं इसकी सिफारिश नहीं कर सकता, इससे जो समस्याएँ दूर होती हैं, वे सुविधा से बाहर हो जाती हैं, जब कोई व्यक्ति आपके सॉफ़्टवेयर का निर्माण नहीं कर सकता है, क्योंकि वे समस्या को ट्रैक करने के लिए या बस हार मानने में बहुत समय लगा सकते हैं।

और एक और ध्यान दें, बस याद रखना CMakeLists.txtहमेशा पर्याप्त नहीं होता है, स्वचालित बिल्ड के साथ जो ग्लोबिंग का उपयोग करता है, मुझे हर बिल्ड से cmakeपहले दौड़ना पड़ता था क्योंकि फाइलें पिछले बिल्डिंग के बाद से जोड़ी / हटा दी गई हो सकती हैं।

नियम के अपवाद:

ऐसे समय होते हैं जब ग्लोबिंग बेहतर होता है:

  • CMakeLists.txtमौजूदा परियोजनाओं के लिए एक फाइल स्थापित करने के लिए जो CMake का उपयोग नहीं करते हैं।
    इसका सभी स्रोत को संदर्भित करने का एक तेज़ तरीका है (एक बार बिल्ड सिस्टम के चलने पर - स्पष्ट फ़ाइल सूचियों के साथ ग्लोबिंग को बदलें)।
  • जब CMake का उपयोग प्राथमिक बिल्ड-सिस्टम के रूप में नहीं किया जाता है, उदाहरण के लिए यदि आप एक प्रोजेक्ट का उपयोग कर रहे हैं जो CMake का उपयोग नहीं कर रहे हैं, और आप इसके लिए अपना स्वयं का बिल्ड-सिस्टम बनाए रखना चाहते हैं।
  • किसी भी स्थिति के लिए जहां फ़ाइल सूची इतनी बार बदलती है कि इसे बनाए रखना अव्यावहारिक हो जाता है। इस मामले में यह उपयोगी हो सकता है, लेकिन फिर आपको एक विश्वसनीय / सही निर्माण (जो सीएमके के इरादे के खिलाफ जाता है - भवन से कॉन्फ़िगरेशन को विभाजित करने की क्षमता) प्राप्त करने के लिए हर बारcmake बिल्ड-फाइल्स को चलाने के लिए चलना स्वीकार करना होगा ।

* हां, मैं अपडेट के पहले और बाद में डिस्क पर फ़ाइलों के पेड़ की तुलना करने के लिए एक कोड लिख सकता था, लेकिन यह इतना अच्छा वर्कअराउंड नहीं है और बिल्ड-सिस्टम के लिए कुछ बेहतर है।


9
"ग्लोबिंग का बड़ा नुकसान यह है कि नई फाइलें बनाने से स्वचालित रूप से बिल्ड-सिस्टम अपडेट नहीं होगा।" लेकिन क्या यह सच नहीं है कि यदि आप ग्लोब नहीं करते हैं, तो आपको अभी भी CMakeLists.txt को मैन्युअल रूप से अपडेट करना होगा, अर्थात cmake अभी भी अपने आप बिल्ड सिस्टम को अपडेट नहीं कर रहा है? ऐसा लगता है कि नई फ़ाइलों के निर्माण के लिए मैन्युअल रूप से कुछ करने के लिए आपको याद रखना चाहिए। CMakeLists.txt को छूना नई फ़ाइल को जोड़ने के लिए इसे खोलने और इसे संपादित करने से अधिक आसान लगता है।
डैन

17
@ अपने सिस्टम के लिए - यकीन है, अगर आप केवल अकेले विकसित करते हैं तो यह ठीक है, लेकिन बाकी सभी के बारे में जो आपकी परियोजना का निर्माण करता है? क्या आप उन्हें जाने के लिए ईमेल करने जा रहे हैं और मैन्युअल रूप से CMake फ़ाइल को स्पर्श करेंगे? हर बार किसी फ़ाइल को जोड़ा या हटाया जाता है? - फ़ाइल सूची को CMake में संग्रहीत करना सुनिश्चित करता है कि बिल्ड हमेशा उसी फ़ाइलों का उपयोग कर रहा है जिनके बारे में vcs को पता है। मेरा विश्वास करो - यह सिर्फ कुछ सूक्ष्म विवरण नहीं है - जब आपका निर्माण कई देवों के लिए विफल हो जाता है - वे सूचियों को मेल करते हैं और आईआरसी से पूछते हैं कि कोड टूट गया है। नोट: (यहां तक ​​कि अपने स्वयं के सिस्टम पर आप उदाहरण के लिए git इतिहास में वापस जा सकते हैं, और
सीएमके

2
आह मैंने उस केस के बारे में नहीं सोचा था। यह सबसे अच्छा कारण है जो मैंने ग्लोबिंग के खिलाफ सुना है। मैं चाहता हूँ कि लोगों को ग्लोबिंग से बचने की सलाह देते हुए सीमेक डॉक्स का विस्तार किया जाए।
दान

1
मैं फ़ाइल में अंतिम cmake निष्पादन के टाइमस्टैम्प लिखने के समाधान के बारे में सोच रहा हूं। केवल समस्याएं हैं: 1) यह शायद cmake द्वारा किया जा रहा है crossplatform है और इसलिए हम cmake से बचने के लिए खुद को दूसरी बार किसी भी तरह से बचने की जरूरत है। 2) संभवतः अधिक मर्ज संघर्ष (जो अभी भी फ़ाइल सूची btw के साथ होता है) वे वास्तव में बाद में टाइमस्टैम्प ले कर इस मामले में तुच्छ रूप से हल किया जा सकता है।
प्रेडेलनिक

2
@ टिम-एमबी, "लेकिन यह अच्छा होगा यदि सीएमके ने एक फ़ाइल-निर्मित फ़ाइल बनाई जिसे आप चेक कर सकते हैं, जो कि अद्यतन की गई फ़ाइलों के ग्लोब को हर बार स्वचालित रूप से बदल देगा।" - आपने अभी-अभी वर्णन किया है कि मेरा उत्तर क्या करता है।
ग्लेन नोल्स

21

3.12 सीएमके में , file(GLOB ...)औरfile(GLOB_RECURSE ...) कमांड ने एक CONFIGURE_DEPENDSविकल्प प्राप्त किया जो ग्लोब के मान में परिवर्तन होने पर सीमेकिंग करता है। जैसा कि स्रोत फ़ाइलों के लिए ग्लोबिंग का प्राथमिक नुकसान था, ऐसा करना अब ठीक है:

# Whenever this glob's value changes, cmake will rerun and update the build with the
# new/removed files.
file(GLOB_RECURSE sources CONFIGURE_DEPENDS "*.cpp")

add_executable(my_target ${sources})

हालांकि, कुछ लोग अभी भी स्रोतों के लिए ग्लोबिंग से बचने की सलाह देते हैं। दरअसल, दस्तावेज में कहा गया है:

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

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


यदि आपकी बिल्ड सिस्टम पूरी तरह से cmake और build cycle (डिलीट डायरेक्टरी को डिलीट करती है, वहां से cmake चलाती है और फिर मेकफाइल को इनवॉइस करती है), बशर्ते वे अनचाहे फाइलों में न खिंचें, तो निश्चित रूप से GLOBbed स्रोतों का उपयोग करने में कोई कमियां नहीं हैं? मेरे अनुभव में cmake हिस्सा बिल्ड की तुलना में बहुत तेज़ी से चलता है, इसलिए यह वैसे भी बहुत ज्यादा नहीं है
Den-Jason

9

आप निर्भरता रखने के लिए एक अतिरिक्त फ़ाइल की कीमत पर सुरक्षित रूप से (और शायद चाहिए) ग्लोब कर सकते हैं।

इन जैसे कार्यों को कहीं जोड़ें:

# Compare the new contents with the existing file, if it exists and is the 
# same we don't want to trigger a make by changing its timestamp.
function(update_file path content)
    set(old_content "")
    if(EXISTS "${path}")
        file(READ "${path}" old_content)
    endif()
    if(NOT old_content STREQUAL content)
        file(WRITE "${path}" "${content}")
    endif()
endfunction(update_file)

# Creates a file called CMakeDeps.cmake next to your CMakeLists.txt with
# the list of dependencies in it - this file should be treated as part of 
# CMakeLists.txt (source controlled, etc.).
function(update_deps_file deps)
    set(deps_file "CMakeDeps.cmake")
    # Normalize the list so it's the same on every machine
    list(REMOVE_DUPLICATES deps)
    foreach(dep IN LISTS deps)
        file(RELATIVE_PATH rel_dep ${CMAKE_CURRENT_SOURCE_DIR} ${dep})
        list(APPEND rel_deps ${rel_dep})
    endforeach(dep)
    list(SORT rel_deps)
    # Update the deps file
    set(content "# generated by make process\nset(sources ${rel_deps})\n")
    update_file(${deps_file} "${content}")
    # Include the file so it's tracked as a generation dependency we don't
    # need the content.
    include(${deps_file})
endfunction(update_deps_file)

और फिर ग्लोबिंग करें:

file(GLOB_RECURSE sources LIST_DIRECTORIES false *.h *.cpp)
update_deps_file("${sources}")
add_executable(test ${sources})

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

नई फ़ाइल बनाने के बाद प्रक्रिया में एकमात्र परिवर्तन है। यदि आप ग्लोब नहीं करते हैं, तो विजुअल स्टूडियो के अंदर से CMakeLists.txt को संशोधित करना और पुनर्निर्माण करना है, यदि आप ग्लोब करते हैं तो आप cmake को स्पष्ट रूप से चलाते हैं - या CMakeLists.txt को स्पर्श करें।


सबसे पहले मैंने सोचा था कि यह एक ऐसा उपकरण था जो स्रोत फ़ाइल को जोड़ने पर स्वचालित रूप से मेकफ़ाइल्स को अपडेट कर देगा, लेकिन मैं अब देख रहा हूं कि इसका मूल्य क्या है। अच्छा! यह किसी को रिपॉजिटरी से अपडेट करने और makeअजीब लिंकर त्रुटियों को देने की चिंता को हल करता है ।
क्राइस लुएंगो

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

1
यह तब काम नहीं करेगा जब आपकी परियोजना में सशर्त रूप से फ़ाइलें शामिल हों (जैसे, कुछ फाइलें जो केवल तब सक्षम होती हैं, जब कोई सुविधा सक्षम होती है, या केवल किसी विशेष ऑपरेटिंग-सिस्टम के लिए उपयोग की जाती है)। यह पोर्टेबल सॉफ्टवेयर के लिए पर्याप्त है कि कुछ फाइलें केवल चंचल प्लेटफार्मों के लिए उपयोग की जाती हैं।
ideasman42

0

प्रत्येक फ़ाइल को व्यक्तिगत रूप से निर्दिष्ट करें!

मैं इसे अपडेट करने के लिए एक पारंपरिक CMakeLists.txt और एक पायथन स्क्रिप्ट का उपयोग करता हूं। मैं फ़ाइलों को जोड़ने के बाद मैन्युअल रूप से अजगर स्क्रिप्ट चलाता हूं।

मेरा उत्तर यहाँ देखें: https://stackoverflow.com/a/48318388/3929196

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.