Yanıtlar:
Evet, orta derecede kolay. Sadece iki "add_library" komutu kullanın:
add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)
Çok sayıda kaynak dosyanız olsa bile, kaynak listesini bir cmake değişkenine yerleştirirsiniz, bu yüzden yine de yapmak kolaydır.
Hem paylaşılan hem de statik için bir ".lib" dosyası olduğundan, Windows'ta muhtemelen her kitaplığa farklı bir ad vermelisiniz. Ancak Linux ve Mac'te her iki kütüphaneye de aynı adı verebilirsiniz (ör. libMyLib.a
Ve libMyLib.so
):
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
Ancak kütüphanenin statik ve dinamik sürümlerinin aynı adı vermesini önermiyorum. Farklı isimler kullanmayı tercih ediyorum çünkü bu, kütüphaneye bağlanan araçlar için derleme satırındaki statik ve dinamik bağlantıyı seçmeyi kolaylaştırıyor. Genellikle libMyLib.so
(paylaşılan) ve libMyLib_static.a
(statik) gibi isimler seçerim . (Bunlar linux üzerindeki isimler olurdu.)
-fPIC
) olarak oluşturulmasını gerektirir, bu da bu statik kitaplıklar kullanıldığında az miktarda çalışma zamanı ek yükü ekler. Maksimum performans için bu cevap hala en iyisidir.
CMake 2.8.8 sürümünden bu yana , nesne dosyalarının yinelenen derlemesini önlemek için "nesne kitaplıkları" kullanabilirsiniz . Christopher Bruns'in iki kaynak dosyası olan bir kütüphane örneğini kullanma:
# 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>)
Gönderen CKağıt docs :
Nesne kitaplığı kaynak dosyaları derler, ancak nesne dosyalarını arşivlemez veya kitaplığa bağlamaz. Bunun yerine , formun bir ifadesini kaynak olarak kullanarak nesneler tarafından oluşturulan
add_library()
veyaadd_executable()
nesnelere$<TARGET_OBJECTS:objlib>
başvurabilir; buradaki objlib, nesne kitaplığı adıdır.
Basitçe söylemek gerekirse, add_library(objlib OBJECT ${libsrc})
komut CMake'e kaynak dosyalarını *.o
nesne dosyalarına derlemesini bildirir . Bu *.o
dosya koleksiyonuna daha sonra aynı nesne kümesi kümesinden paylaşılan ve statik kitaplıkları oluşturan uygun kitaplık oluşturma komutlarını çağıran $<TARGET_OBJECT:objlib>
iki add_library(...)
komutta bahsedilir . Çok sayıda kaynak dosyanız varsa, dosyaları derlemek oldukça uzun sürebilir; nesne kitaplıklarıyla bunları yalnızca bir kez derlersiniz.*.o
Ödediğiniz fiyat, paylaşılan kitaplıkların buna ihtiyacı olduğu için statik dosyaların konumdan bağımsız bir kod olarak oluşturulması gerektiğidir (statik kütüphaneler umursamaz). Konumdan bağımsız kodun daha az verimli olabileceğine dikkat edin, bu nedenle maksimum performans hedefliyorsanız statik kitaplıkları tercih edersiniz. Ayrıca, statik olarak bağlı yürütülebilir dosyaları dağıtmak daha kolaydır.
target_link_libraries()
kitaplığınıza bağlı sonraki çağrılar bağlanmak için "nesne kitaplığı" kullanamazsınız; bunlar yeni paylaşılan veya statik kitaplıkları hedeflemelidir (ve çoğaltılabilir). Ancak ilk yorumcuların deneyiminin aksine, bu oldukça faydalı oldu ve tüm yinelenen hedefleri kaldırmamı ve tüm CMakeLists.txt
dosyalarımı yarıya yakın kesmemi sağladı.
set_property
sadece kullandığımda çalıştım objlib
ve kullanırken değil ${objlib}
. Yani bu cevap düzeltilebilir mi?
Genel olarak ADD_LIBRARY
, amaçlarınız için çağrıları çoğaltmanıza gerek yoktur . Sadece faydalanın
$> 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.
yaparken, önce (kaynak dışı bir dizinde) -DBUILD_SHARED_LIBS:BOOL=ON
ve OFF
diğerinde ile birlikte .
Önceki cevaplarda önerildiği gibi, her şeyi aynı derleme nefesinde paketlemek mümkündür, ama buna karşı tavsiye ederim, çünkü sonunda sadece basit projeler için çalışan bir kesmek. Örneğin, bir noktada kütüphanenin farklı sürümleri için farklı bayraklara ihtiyacınız olabilir (özellikle bayrakların dışa aktarma sembolleri arasında geçiş yapmak için kullanılıp kullanılmadığı Windows'da). Veya yukarıda belirtildiği gibi, .lib
statik veya paylaşılan kitaplıklara karşılık gelmelerine bağlı olarak dosyaları farklı dizinlere koymak isteyebilirsiniz . Bu engellerin her biri için yeni bir saldırı gerekir.
Açık olabilir, ancak daha önce bahsedilmeyen bir alternatif, kütüphane türünü bir parametre yapmaktır:
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} )
Kütüphanenin iki farklı ikili ağaçta paylaşılan ve statik sürümleri olması, farklı derleme seçeneklerinin kullanılmasını kolaylaştırır. Özellikle derlemeleriniz otomatik ise, derleme ağaçlarını ayrı tutmak konusunda ciddi bir dezavantaj görmüyorum.
Bir ara OBJECT
kitaplık (yukarıda belirtilen uyarılarla birlikte) derlemeleri karşılıklılaştırmayı planlasanız bile, bunu yapmak için zorlayıcı bir nedene ihtiyacınız var), yine de iki farklı projede son kitaplıkların olabileceğini unutmayın.
Gerçekten mümkün. @Christopher Bruns'ın cevabında söylediği gibi, kütüphanenin iki versiyonunu eklemeniz gerekir:
set(libsrc source1.c source2.c source3.c)
add_library(mylib-static STATIC ${libsrc})
add_library(mylib-shared SHARED ${libsrc})
Daha sonra, burada açıklandığı gibi , her iki hedefin de aynı çıktı adını kullanması ve birbirlerinin dosyalarının üzerine yazmaması gerektiğini belirtmeniz gerekir:
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)
Bu şekilde, hem libmylib.a hem de libmylib.so (Linux'ta) veya mylib.lib ve mylib.dll (Windows'ta) alırsınız.