Sumber yang sama, semua itu, hanya menginginkan versi statis dan berbagi keduanya. Mudah untuk dilakukan?
Jawaban:
Ya, ini cukup mudah. Cukup gunakan dua perintah "add_library":
add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)
Meskipun Anda memiliki banyak file sumber, Anda akan menempatkan daftar sumber dalam variabel cmake, jadi masih mudah dilakukan.
Pada Windows Anda mungkin harus memberikan nama yang berbeda untuk setiap perpustakaan, karena ada file ".lib" untuk berbagi dan statis. Tetapi di Linux dan Mac Anda bahkan dapat memberi kedua pustaka nama yang sama (misalnya libMyLib.a
dan libMyLib.so
):
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
Tapi saya tidak merekomendasikan memberikan versi statis dan dinamis dari pustaka nama yang sama. Saya lebih suka menggunakan nama yang berbeda karena itu membuatnya lebih mudah untuk memilih tautan statis vs. dinamis pada baris kompilasi untuk alat yang ditautkan ke perpustakaan. Biasanya saya memilih nama seperti libMyLib.so
(shared) dan libMyLib_static.a
(static). (Itu akan menjadi nama-nama di linux.)
-fPIC
), yang menambahkan sejumlah kecil overhead runtime saat library statis tersebut digunakan. Jadi untuk performa maksimal, jawaban ini tetap yang terbaik.
Sejak CMake versi 2.8.8, Anda dapat menggunakan "perpustakaan objek" untuk menghindari kompilasi file objek yang digandakan . Menggunakan contoh pustaka Christopher Bruns dengan dua file sumber:
# 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>)
Dari dokumen CMake :
Pustaka objek mengompilasi file sumber tetapi tidak mengarsipkan atau menautkan file objeknya ke pustaka. Sebaliknya, target lain yang dibuat oleh
add_library()
atauadd_executable()
mungkin mereferensikan objek menggunakan ekspresi formulir$<TARGET_OBJECTS:objlib>
sebagai sumber, di mana objlib adalah nama pustaka objek.
Sederhananya, add_library(objlib OBJECT ${libsrc})
perintah menginstruksikan CMake untuk mengkompilasi file sumber ke *.o
file objek. Kumpulan *.o
file ini kemudian disebut sebagai $<TARGET_OBJECT:objlib>
dua add_library(...)
perintah yang menjalankan perintah pembuatan perpustakaan yang sesuai yang membangun perpustakaan bersama dan statis dari kumpulan file objek yang sama . Jika Anda memiliki banyak file sumber, maka kompilasi *.o
file bisa memakan waktu cukup lama; dengan pustaka objek Anda mengkompilasinya hanya sekali.
Harga yang Anda bayarkan adalah bahwa file objek harus dibuat sebagai kode yang tidak bergantung pada posisi karena library bersama memerlukan ini (library statis tidak peduli). Perhatikan bahwa kode yang tidak tergantung posisi mungkin kurang efisien, jadi jika Anda bertujuan untuk kinerja maksimal maka Anda akan menggunakan pustaka statis. Selain itu, lebih mudah untuk mendistribusikan file executable yang terhubung secara statis.
target_link_libraries()
panggilan berikutnya yang bergantung pada perpustakaan Anda tidak dapat menggunakan "perpustakaan objek" untuk ditautkan; mereka harus menargetkan pustaka bersama atau statis baru (dan mungkin digandakan). Tetapi bertentangan dengan pengalaman pemberi komentar pertama, ini cukup berguna, dan memungkinkan saya untuk menghapus semua target duplikat dan memotong semua CMakeLists.txt
file saya hampir setengahnya.
set_property
satu - satunya bekerja saat saya digunakan objlib
dan tidak saat menggunakan ${objlib}
. Jadi mungkin jawaban ini bisa diperbaiki?
Biasanya tidak perlu menggandakan ADD_LIBRARY
panggilan untuk tujuan Anda. Manfaatkan saja
$> 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.
saat membangun, pertama (dalam satu direktori di luar sumber) dengan -DBUILD_SHARED_LIBS:BOOL=ON
, dan dengan OFF
di direktori lainnya.
Dimungkinkan untuk mengemas semuanya dalam nafas kompilasi yang sama, seperti yang disarankan dalam jawaban sebelumnya, tetapi saya akan menyarankan agar tidak melakukannya, karena pada akhirnya ini adalah peretasan yang hanya berfungsi untuk proyek-proyek sederhana. Misalnya, Anda mungkin memerlukan flag yang berbeda untuk versi library yang berbeda (khususnya pada Windows di mana flag biasanya digunakan untuk beralih antara mengekspor simbol atau tidak). Atau seperti yang disebutkan di atas, Anda mungkin ingin memasukkan .lib
file ke direktori yang berbeda tergantung pada apakah mereka sesuai dengan pustaka statis atau bersama. Masing-masing rintangan itu membutuhkan peretasan baru.
Mungkin sudah jelas, tetapi satu alternatif yang belum disebutkan sebelumnya adalah membuat tipe pustaka sebagai parameter:
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} )
Memiliki versi bersama dan statis pustaka dalam dua pohon biner berbeda membuatnya lebih mudah untuk menangani opsi kompilasi yang berbeda. Saya tidak melihat kekurangan serius dalam menjaga struktur kompilasi berbeda, terutama jika kompilasi Anda dilakukan secara otomatis.
Perhatikan bahwa meskipun Anda bermaksud untuk saling menguntungkan kompilasi menggunakan OBJECT
pustaka perantara (dengan peringatan yang disebutkan di atas, jadi Anda memerlukan alasan kuat untuk melakukannya), Anda masih bisa memiliki pustaka akhir yang dimasukkan ke dalam dua proyek berbeda.
Itu memang mungkin. Seperti yang dikatakan @Christopher Bruns dalam jawabannya, Anda perlu menambahkan dua versi perpustakaan:
set(libsrc source1.c source2.c source3.c)
add_library(mylib-static STATIC ${libsrc})
add_library(mylib-shared SHARED ${libsrc})
Kemudian, seperti yang dijelaskan di sini , Anda perlu menentukan bahwa kedua target harus menggunakan nama keluaran yang sama dan tidak menimpa file satu sama lain:
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)
Dengan cara ini, Anda akan mendapatkan libmylib.a dan libmylib.so (di Linux) atau mylib.lib dan mylib.dll (di Windows).