Buat tautan ke perpustakaan eksternal

126

Bagaimana cara agar CMake menautkan file yang dapat dieksekusi ke pustaka bersama eksternal yang tidak dibuat dalam proyek CMake yang sama?

Melakukan saja sudah target_link_libraries(GLBall ${CMAKE_BINARY_DIR}/res/mylib.so)memberikan kesalahan

make[2]: *** No rule to make target `res/mylib.so', needed by `GLBall'.  Stop.
make[1]: *** [CMakeFiles/GLBall.dir/all] Error 2
make: *** [all] Error 2
(GLBall is the executable)

setelah saya menyalin perpustakaan ke dir biner bin/res.

Saya mencoba menggunakan find_library(RESULT mylib.so PATHS ${CMAKE_BINARY_DIR}/res)

Yang gagal dengan RESULT-NOTFOUND.

Utama
sumber

Jawaban:

101

Setel jalur pencarian perpustakaan terlebih dahulu:

LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/res)

Dan kemudian lakukan saja

TARGET_LINK_LIBRARIES(GLBall mylib)
panahd
sumber
44
Penggunaannya link_directoriestidak disarankan, bahkan dalam dokumentasinya sendiri. Saya pikir akan lebih baik di sini untuk menyelesaikan find_librarypanggilan gagal di pertanyaan awal, atau menggunakan solusi @ Andre.
Fraser
4
Saya menemukan target perpustakaan "diimpor" menjadi lebih kuat, karena menargetkan lokasi perpustakaan tertentu, alih-alih hanya memberikan jalur pencarian global. Lihat jawaban Andre.
Mark Lakata
1
Anda harus selalu menggunakan find_librarydan menggunakan jalur ini alih-alih melakukan hard coding, lih. jawabanku .
usr1234567
121

Jawaban arrowdodger benar dan disukai di banyak kesempatan. Saya hanya ingin menambahkan alternatif untuk jawabannya:

Anda dapat menambahkan target perpustakaan "diimpor", sebagai ganti direktori tautan. Sesuatu seperti:

# Your-external "mylib", add GLOBAL if the imported library is located in directories above the current.
add_library( mylib SHARED IMPORTED )
# You can define two import-locations: one for debug and one for release.
set_target_properties( mylib PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/res/mylib.so )

Lalu tautkan seolah-olah pustaka ini dibuat oleh proyek Anda:

TARGET_LINK_LIBRARIES(GLBall mylib)

Pendekatan seperti itu akan memberi Anda sedikit lebih banyak fleksibilitas: Lihatlah perintah add_library () dan banyak properti target yang terkait dengan pustaka yang diimpor .

Saya tidak tahu apakah ini akan menyelesaikan masalah Anda dengan "versi terbaru dari libs".

André
sumber
2
Itu mungkin akan terjadi add_library( mylib SHARED IMPORTED )atau Anda mendapatkan add_library called with IMPORTED argument but no library typekesalahan
Marvin
4
@ Andre: Saya pikir setelah IMPORTED_LOCATIONbraket pembukaan salah
Ela782
5
Anda perlu menambahkan GLOBALsetelah IMPORTEDjika Anda ingin mengakses perpustakaan yang diimpor di direktori di atas saat ini:add_library(breakpad STATIC IMPORTED GLOBAL)
Roman Kruglov
@Andre IMPORTED_LOCATION tampaknya memerlukan jalur ke file alih-alih direktori yang berisi file
SOUser
1
@SOUser: Ya, IMPORTED_LOCATION harus mengarah ke file, bukan ke direktori. Saya telah memperbaikinya, kira penulis tidak akan mengeluh.
Tsyvarev
65

Saya berasumsi Anda ingin menautkan ke pustaka bernama foo , nama filenya biasanya berupa tautan foo.dllatau libfoo.so.

1. Temukan perpustakaan
Anda harus mencari perpustakaan. Ini adalah ide yang bagus, meskipun Anda mengetahui jalur ke perpustakaan Anda. CMake akan error jika perpustakaan menghilang atau mendapat nama baru. Ini membantu untuk menemukan kesalahan lebih awal dan menjelaskan kepada pengguna (mungkin sendiri) apa yang menyebabkan masalah.
Untuk menemukan perpustakaan foo dan menyimpan jalan yang FOO_LIBdigunakan

    find_library(FOO_LIB foo)

CMake akan mengetahui sendiri bagaimana nama file sebenarnya. Ia memeriksa tempat-tempat biasa seperti /usr/lib, /usr/lib64dan jalur masuk PATH.

Anda sudah tahu lokasi perpustakaan Anda. Tambahkan ke CMAKE_PREFIX_PATHsaat Anda memanggil CMake, maka CMake juga akan mencari perpustakaan Anda di jalur yang dilewati.

Terkadang Anda perlu menambahkan petunjuk atau akhiran jalur, lihat dokumentasi untuk mengetahui detailnya: https://cmake.org/cmake/help/latest/command/find_library.html

2. Tautkan perpustakaan Dari 1. Anda memiliki nama perpustakaan lengkap FOO_LIB. Anda menggunakan ini untuk menautkan perpustakaan ke target Anda GLBallseperti pada

  target_link_libraries(GLBall PRIVATE "${FOO_LIB}")

Anda harus menambahkan PRIVATE, PUBLICatau INTERFACEsetelah target, lih dokumentasi: https://cmake.org/cmake/help/latest/command/target_link_libraries.html

Jika Anda tidak menambahkan salah satu penentu visibilitas ini, itu akan berperilaku seperti PRIVATEatau PUBLIC, tergantung pada versi CMake dan kebijakan yang ditetapkan.

3. Tambahkan penyertaan (Langkah ini mungkin tidak wajib.)
Jika Anda juga ingin menyertakan file header, gunakan yang find_pathmirip dengan find_librarydan cari file header. Kemudian tambahkan direktori include yang target_include_directoriesmirip dengan target_link_libraries.

Dokumentasi: https://cmake.org/cmake/help/latest/command/find_path.html dan https://cmake.org/cmake/help/latest/command/target_include_directories.html

Jika tersedia untuk perangkat lunak eksternal, Anda dapat mengganti find_librarydan find_pathdengan find_package.

usr1234567
sumber
5
IMHO ini adalah jawaban terbaik. Namun, saya mengalami masalah karena saya tidak memanggil "find_library" setelah "project" dan "target_link_libraries" setelah "add_executable".
smoothware
1
find_packagejauh lebih sederhana daripada mengikuti langkah-langkah ini
aktif
2
Saya kira saya tidak mengerti langkah 2. Untuk pustaka bersama $ {FOO_LIB} akan seperti /full/path/to/libfoo.dylib. Bagaimana itu berguna? target_link_libraries tidak membuat "-L / full / path / to -lfoo", jadi find_library tidak mengembalikan sesuatu yang berguna, selain memverifikasi bahwa perpustakaan berada di lokasi yang sudah saya ketahui. Apa yang saya lewatkan?
guymac
target_link_libraries(mylib "${FOO_LIB}")? "Targetnya mylibbukan target sebenarnya," katanya GLBall. tidak masuk akal bagi saya
Bersan
5

Satu lagi alternatif, jika Anda bekerja dengan Appstore, memerlukan "Hak" dan karena itu perlu ditautkan dengan Apple-Framework.

Agar Hak dapat bekerja (mis. GameCenter) Anda harus memiliki "Tautan Biner dengan Perpustakaan" -buildstep dan kemudian menautkan dengan "GameKit.framework". CMake "menyuntikkan" pustaka pada "level rendah" ke dalam baris perintah, oleh karena itu Xcode tidak benar - benar mengetahuinya, dan karena itu Anda tidak akan mengaktifkan GameKit di layar Kapabilitas.

Salah satu cara untuk menggunakan CMake dan memiliki "Tautan dengan Binari" -buildstep adalah dengan membuat xcodeproj dengan CMake, lalu gunakan 'sed' untuk 'mencari & mengganti' dan menambahkan GameKit dengan cara yang disukai XCode ...

Skripnya terlihat seperti ini (untuk Xcode 6.3.1).

s#\/\* Begin PBXBuildFile section \*\/#\/\* Begin PBXBuildFile section \*\/\
    26B12AA11C10544700A9A2BA \/\* GameKit.framework in Frameworks \*\/ = {isa = PBXBuildFile; fileRef = 26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/; };#g

s#\/\* Begin PBXFileReference section \*\/#\/\* Begin PBXFileReference section \*\/\
    26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameKit.framework; path = System\/Library\/Frameworks\/GameKit.framework; sourceTree = SDKROOT; };#g

s#\/\* End PBXFileReference section \*\/#\/\* End PBXFileReference section \*\/\
\
\/\* Begin PBXFrameworksBuildPhase section \*\/\
    26B12A9F1C10543B00A9A2BA \/\* Frameworks \*\/ = {\
        isa = PBXFrameworksBuildPhase;\
        buildActionMask = 2147483647;\
        files = (\
            26B12AA11C10544700A9A2BA \/\* GameKit.framework in Frameworks xxx\*\/,\
        );\
        runOnlyForDeploymentPostprocessing = 0;\
    };\
\/\* End PBXFrameworksBuildPhase section \*\/\
#g

s#\/\* CMake PostBuild Rules \*\/,#\/\* CMake PostBuild Rules \*\/,\
            26B12A9F1C10543B00A9A2BA \/\* Frameworks xxx\*\/,#g
s#\/\* Products \*\/,#\/\* Products \*\/,\
            26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/,#g

simpan ini ke "gamecenter.sed" dan kemudian "terapkan" seperti ini (ini mengubah xcodeproj Anda!)

sed -i.pbxprojbak -f gamecenter.sed myproject.xcodeproj/project.pbxproj

Anda mungkin harus mengubah perintah skrip agar sesuai dengan kebutuhan Anda.

Peringatan: kemungkinan akan rusak dengan versi Xcode yang berbeda karena format proyek dapat berubah, nomor unik (hardcode) mungkin tidak benar-benar unik - dan umumnya solusi oleh orang lain lebih baik - jadi kecuali Anda perlu Mendukung Appstore + Hak (dan build otomatis), jangan lakukan ini.

Ini adalah bug CMake, lihat http://cmake.org/Bug/view.php?id=14185 dan http://gitlab.kitware.com/cmake/cmake/issues/14185

kalmiya
sumber
Secara khusus - mendapatkan cmake untuk ditautkan dengan perpustakaan eksternal bukanlah masalah (ada beberapa solusi di atas). Membuat ini berfungsi secara otomatis, sehingga berfungsi dengan Apple Appstore dan hak merupakan sebuah tantangan. Dalam kasus khusus tersebut, solusi di atas tidak berfungsi karena XCode tidak akan 'melihat' pustaka yang ditautkan dengan cara itu, dan hak tidak akan berfungsi. Afaik cmake tidak dapat menambahkan pustaka seperti yang dibutuhkan xcode dengan 'cara yang kompatibel dengan appstore'- sekali lagi, silakan mencerahkan saya.
kalmiya
1
Oh, itu menyedihkan. Untuk kelengkapan tautan ke pelacak masalah baru, yang saat ini tidak mengandung commnet
usr1234567
Masalahnya telah diselesaikan 5 bulan yang lalu, jadi dengan CMake versi terbaru seharusnya tidak lagi ada. Lihat gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567