क्या एक ही पुस्तकालय के स्थिर और साझा दोनों प्रकार के निर्माण के लिए CMake प्राप्त करना संभव है?


141

एक ही स्रोत, यह सब, बस एक स्थिर और साझा संस्करण दोनों चाहते हैं। करने में आसान?

जवाबों:


123

हां, यह मामूली आसान है। बस दो "add_library" कमांड का उपयोग करें:

add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)

यहां तक ​​कि अगर आपके पास कई स्रोत फाइलें हैं, तो आप स्रोतों की सूची को एक सीमेक चर में रख देंगे, इसलिए ऐसा करना अभी भी आसान है।

विंडोज पर आपको संभवतः प्रत्येक लाइब्रेरी को एक अलग नाम देना चाहिए, क्योंकि साझा और स्थिर दोनों के लिए एक ".लिब" फाइल है। लेकिन लिनक्स और मैक पर आप दोनों पुस्तकालयों को एक ही नाम (जैसे libMyLib.aऔर libMyLib.so) दे सकते हैं :

set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)

लेकिन मैं पुस्तकालय के स्थिर और गतिशील दोनों संस्करणों को एक ही नाम देने की सलाह नहीं देता। मैं विभिन्न नामों का उपयोग करना पसंद करता हूं क्योंकि इससे लाइब्रेरी के लिए लिंक करने वाले टूल के लिए संकलन लाइन पर स्थिर बनाम गतिशील लिंकेज चुनना आसान हो जाता है। आमतौर पर मैं libMyLib.so(साझा) और libMyLib_static.a(स्थिर) जैसे नाम चुनता हूं । (वे लिनक्स पर नाम होंगे।)


उनके लिए एक ही नाम की उम्मीद कर रहा था, लेकिन ओह ठीक है। एक और सवाल: क्या आप सीएमके को संभव होने पर स्थिर पुस्तकालयों को साझा पुस्तकालय से जोड़ने के लिए कह सकते हैं?
gct

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

1
मुझे यकीन नहीं है कि मैं स्थिर लाइब्रेरी को साझा लाइब्रेरी में लिंक करने के बारे में आपके प्रश्न को समझता हूं।
क्रिस्टोफर ब्रंस

5
ध्यान दें कि यह अब ऐसा करने का सुझाव नहीं है। गैर-तुच्छ आकार की परियोजनाओं के लिए (जो संकलन करने के लिए मिनट, सेकंड नहीं), संकलन समय को दोगुना करने से परहेज करना चमत्कारिक है। ऑब्जेक्ट लाइब्रेरी उपयोग या डॉक्स के लिए नीचे उपयोगकर्ता 465139 उत्तर देखें: cmake.org/cmake/help/v3.8/command/…
KymikoLoco

3
@KymikoLoco: ऑब्जेक्ट लाइब्रेरी दृष्टिकोण वास्तव में संकलन समय को आधे से कम कर देता है, लेकिन इसके लिए स्थैतिक पुस्तकालयों को स्थिति स्वतंत्र कोड (यानी के साथ -fPIC) के रूप में बनाया जाना चाहिए , जो उन स्थिर पुस्तकालयों का उपयोग करने पर रनटाइम ओवरहेड की एक छोटी राशि जोड़ता है। इसलिए अधिकतम प्रदर्शन के लिए, यह उत्तर अभी भी सबसे अच्छा है।
जॉन Zwinck

95

सीएमके संस्करण 2.8.8 के बाद से, आप ऑब्जेक्ट फ़ाइलों के डुप्लिकेट संकलन से बचने के लिए "ऑब्जेक्ट लाइब्रेरीज़" का उपयोग कर सकते हैं । दो स्रोत फ़ाइलों के साथ एक पुस्तकालय के क्रिस्टोफर ब्रंस के उदाहरण का उपयोग करना:

# list of source files
set(libsrc source1.c source2.c)

# this is the "object library" target: compiles the sources only once
add_library(objlib OBJECT ${libsrc})

# shared libraries need PIC
set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1)

# shared and static libraries built from the same object files
add_library(MyLib_shared SHARED $<TARGET_OBJECTS:objlib>)
add_library(MyLib_static STATIC $<TARGET_OBJECTS:objlib>)

से CMake डॉक्स :

ऑब्जेक्ट लायब्रेरी स्रोत फ़ाइलों को संकलित करती है लेकिन उनकी ऑब्जेक्ट फ़ाइलों को लाइब्रेरी में संग्रहीत या लिंक नहीं करती है। इसके बजाय अन्य लक्ष्यों द्वारा बनाए गए add_library()या स्रोत के रूप में add_executable()अभिव्यक्ति की अभिव्यक्ति का उपयोग करके वस्तुओं का संदर्भ दे सकते हैं $<TARGET_OBJECTS:objlib>, जहां objlib ऑब्जेक्ट लाइब्रेरी नाम है।

सीधे शब्दों में कहें, add_library(objlib OBJECT ${libsrc})कमांड सीएमके को निर्देश देती है कि वह स्रोत फाइलों को *.oऑब्जेक्ट फाइलों में संकलित करें। *.oफ़ाइलों के इस संग्रह को तब $<TARGET_OBJECT:objlib>दो add_library(...)आदेशों के रूप में संदर्भित किया जाता है जो उचित लाइब्रेरी निर्माण कमांड को लागू करते हैं जो ऑब्जेक्ट फ़ाइलों के एक ही सेट से साझा और स्थिर लाइब्रेरी का निर्माण करते हैं । यदि आपके पास बहुत सारी स्रोत फाइलें हैं, तो *.oफाइलों को संकलित करने में काफी लंबा समय लग सकता है; ऑब्जेक्ट लाइब्रेरीज़ के साथ आप उन्हें केवल एक बार संकलित करते हैं।

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


3
यह मेरे लिए एक आकर्षण की तरह काम करता था - केवल कैविएट बाद की target_link_libraries()कॉलें थीं जो आपके पुस्तकालय पर निर्भर करती हैं ताकि वे लिंक करने के लिए "ऑब्जेक्ट लाइब्रेरी" का उपयोग न कर सकें; उन लोगों को नए साझा या स्थिर पुस्तकालयों (और डुप्लिकेट किया जा सकता है) को लक्षित करना चाहिए। लेकिन पहले टिप्पणीकारों के अनुभव के विपरीत यह काफी उपयोगी था, और मुझे सभी डुप्लिकेट किए गए लक्ष्यों को निकालने की अनुमति दी और मेरी सभी CMakeLists.txtफ़ाइलों को आधे से काट दिया ।
फिश

1
लक्ष्य गुण सेट करते समय क्या आपको ओब्ब्लिब से "बचने" की आवश्यकता है? यानी set_property (TARGET $ {objlib} PROPERTY ...) बनाम set_property (TARGET objlib PROPERTY ...)
gnac

1
जिसने भी इसे डाउनवोट किया ... क्या वह व्यक्ति एक स्पष्टीकरण प्रदान कर सकता है कि उसने क्या गलत माना है? सभी और अधिक क्योंकि यह ओपी चाहता है कि सीएमके डॉक्स को करने का अनुशंसित तरीका है।
लेरिक्स डेसीडुआ

1
@ user465139 शायद आपको यह बताना चाहिए कि स्थैतिक और साझा लक्ष्य दोनों के लिए ऑब्जेक्ट फ़ाइलों को फिर से उपयोग करने के लिए क्यों काम करना चाहिए। विशेष रूप से, एसओ में सामान्य ज्ञान अभी भी इसके बारे में बहुत भ्रमित है, पुराने / अभिलेखागार इसे स्पष्ट करने में मदद नहीं करते हैं, जैसे। cmake.org/pipermail/cmake/2008-March/020315.html यथास्थिति की ठोस व्याख्या की आवश्यकता है। ps यह मुझे नहीं था जो
1717 को mloskot नीचे आया

2
@gnac मैं इसकी पुष्टि नहीं कर सकता। मेरे मामले में, set_propertyकेवल तभी काम किया जाता था जब मैं उपयोग करता था objlibऔर उपयोग करते समय नहीं ${objlib}। तो शायद इस जवाब को सही किया जा सकता है?
जोस

22

आमतौर पर ADD_LIBRARYआपके उद्देश्य के लिए कॉल डुप्लिकेट करने की कोई आवश्यकता नहीं है । बस का उपयोग करें

$> man cmake | grep -A6 '^ *BUILD_SHARED_LIBS$' 
   BUILD_SHARED_LIBS
          Global flag to cause add_library to create shared libraries if on.

          If present and true, this will cause all libraries to be built shared unless the library was
          explicitly added as a static library.  This variable is often added to projects as an OPTION
          so  that each user of a project can decide if they want to build the project using shared or
          static libraries.

निर्माण करते समय, पहले (एक आउट-ऑफ-सोर्स निर्देशिका में) -DBUILD_SHARED_LIBS:BOOL=ONऔर OFFदूसरे के साथ।


43
यह BOTH स्थिर और साझा किए गए संस्करणों का निर्माण नहीं करता है, जो मुझे लगता है कि यह प्रश्न क्या है।
निक डेसुलेनीर्स

0

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

यह स्पष्ट हो सकता है, लेकिन एक विकल्प जिसका पहले उल्लेख नहीं किया गया है, वह पुस्तकालय के प्रकार को एक पैरामीटर बनाने के लिए है:

set( ${PROJECT_NAME}_LIBTYPE CACHE STRING "library type" )
set_property( CACHE ${PROJECT_NAME}_LIBTYPE PROPERTY STRINGS "SHARED;STATIC" )
add_library( ${PROJECT_NAME} ${PROJECT_NAME}_LIBTYPE ${SOURCE_FILES} )

दो अलग-अलग बाइनरी पेड़ों में लाइब्रेरी के साझा और स्थिर संस्करण होने से विभिन्न संकलन विकल्पों को संभालना आसान हो जाता है। मुझे संकलन के पेड़ों को अलग रखने में कोई गंभीर कमी नहीं दिखती, खासकर अगर आपके संकलन स्वचालित हैं।

ध्यान दें कि यदि आप एक मध्यवर्ती OBJECTपुस्तकालय (ऊपर उल्लिखित केवेट के साथ, तो आपको ऐसा करने के लिए एक सम्मोहक कारण की आवश्यकता है) का उपयोग करके संकलन को म्यूट करने का इरादा है , फिर भी आप दो अलग-अलग परियोजनाओं में लगाए गए पुस्तकालयों को समाप्त कर सकते हैं।


-2

यह वास्तव में संभव है। जैसा कि @Christopher Bruns ने अपने जवाब में कहा, आपको लाइब्रेरी के दो संस्करण जोड़ने होंगे:

set(libsrc source1.c source2.c source3.c)
add_library(mylib-static STATIC ${libsrc})
add_library(mylib-shared SHARED ${libsrc})

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

SET_TARGET_PROPERTIES(mylib-static PROPERTIES OUTPUT_NAME mylib CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(mylib-shared PROPERTIES OUTPUT_NAME mylib CLEAN_DIRECT_OUTPUT 1)

इस तरह, आप दोनों libmylib.a और libmylib.so (लिनक्स पर) या mylib.lib और mylib.dll (विंडोज पर) प्राप्त करेंगे।


10
2.8 से ऊपर सीएमके संस्करणों का उपयोग करते समय यह अनावश्यक है। [0?], जैसा कि 2009 में संपत्ति को हटा दिया गया था, और जो व्यवहार प्रदान किया गया था वह अब डिफ़ॉल्ट है। यह 2.8 से नीचे के लोगों के लिए उपयोगी हो सकता है, लेकिन यदि आप अभी भी CMake <2.7 का उपयोग कर रहे हैं, तो मैं आपको अपग्रेड करने के लिए प्रेरित करता हूं। github.com/Kitware/CMake/commit/…
KymikoLoco
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.