जवाबों:
हां, यह मामूली आसान है। बस दो "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
(स्थिर) जैसे नाम चुनता हूं । (वे लिनक्स पर नाम होंगे।)
-fPIC
) के रूप में बनाया जाना चाहिए , जो उन स्थिर पुस्तकालयों का उपयोग करने पर रनटाइम ओवरहेड की एक छोटी राशि जोड़ता है। इसलिए अधिकतम प्रदर्शन के लिए, यह उत्तर अभी भी सबसे अच्छा है।
सीएमके संस्करण 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
फाइलों को संकलित करने में काफी लंबा समय लग सकता है; ऑब्जेक्ट लाइब्रेरीज़ के साथ आप उन्हें केवल एक बार संकलित करते हैं।
आपके द्वारा भुगतान किया जाने वाला मूल्य यह है कि ऑब्जेक्ट फ़ाइलों को स्थिति-स्वतंत्र कोड के रूप में बनाया जाना चाहिए क्योंकि साझा पुस्तकालयों को इसकी आवश्यकता होती है (स्थिर कामों की परवाह नहीं है)। ध्यान दें कि स्थिति-स्वतंत्र कोड कम कुशल हो सकता है, इसलिए यदि आप अधिकतम प्रदर्शन के लिए लक्ष्य रखते हैं तो आप स्थैतिक पुस्तकालयों के लिए जाएंगे। इसके अलावा, सांख्यिकीय रूप से जुड़े निष्पादनयोग्य वितरित करना आसान है।
target_link_libraries()
कॉलें थीं जो आपके पुस्तकालय पर निर्भर करती हैं ताकि वे लिंक करने के लिए "ऑब्जेक्ट लाइब्रेरी" का उपयोग न कर सकें; उन लोगों को नए साझा या स्थिर पुस्तकालयों (और डुप्लिकेट किया जा सकता है) को लक्षित करना चाहिए। लेकिन पहले टिप्पणीकारों के अनुभव के विपरीत यह काफी उपयोगी था, और मुझे सभी डुप्लिकेट किए गए लक्ष्यों को निकालने की अनुमति दी और मेरी सभी CMakeLists.txt
फ़ाइलों को आधे से काट दिया ।
set_property
केवल तभी काम किया जाता था जब मैं उपयोग करता था objlib
और उपयोग करते समय नहीं ${objlib}
। तो शायद इस जवाब को सही किया जा सकता है?
आमतौर पर 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
दूसरे के साथ।
पिछले संकलन में दिए गए सुझाव के अनुसार, समान संकलन सांस में 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
पुस्तकालय (ऊपर उल्लिखित केवेट के साथ, तो आपको ऐसा करने के लिए एक सम्मोहक कारण की आवश्यकता है) का उपयोग करके संकलन को म्यूट करने का इरादा है , फिर भी आप दो अलग-अलग परियोजनाओं में लगाए गए पुस्तकालयों को समाप्त कर सकते हैं।
यह वास्तव में संभव है। जैसा कि @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 (विंडोज पर) प्राप्त करेंगे।