Harici kitaplığa bağlantı oluşturun


126

CMake'nin bir yürütülebilir dosyayı aynı CMake projesi içinde oluşturulmayan harici bir paylaşılan kitaplığa bağlamasını nasıl sağlayabilirim?

Sadece yapmak target_link_libraries(GLBall ${CMAKE_BINARY_DIR}/res/mylib.so)hata veriyor

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)

kütüphaneyi ikili dizine kopyaladıktan sonra bin/res.

Kullanmayı denedim find_library(RESULT mylib.so PATHS ${CMAKE_BINARY_DIR}/res)

Hangi ile başarısız olur RESULT-NOTFOUND.

Yanıtlar:


101

Önce kitaplık arama yolunu ayarlayın:

LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/res)

Ve sonra sadece yap

TARGET_LINK_LIBRARIES(GLBall mylib)

44
link_directoriesKendi belgelerinde bile kullanımı tavsiye edilmez. find_libraryAsıl sorudaki başarısız aramayı çözmenin veya @ Andre'nin çözümünü kullanmanın burada daha iyi olacağını düşünüyorum .
Fraser

4
"İçe aktarılan" kitaplık hedefini, yalnızca genel bir arama yolu sağlamak yerine belirli kitaplığın konumunu hedeflediği için daha sağlam buluyorum. Andre'nin cevabına bakın.
Mark Lakata

1
find_libraryBu yolu sabit kodlamak yerine her zaman kullanmalı ve kullanmalısınız, bkz. cevabım .
usr1234567

121

arrowdodger'ın cevabı doğrudur ve birçok durumda tercih edilir. Cevabına bir alternatif eklemek isterim:

Bir bağlantı dizini yerine "içe aktarılmış" bir kitaplık hedefi ekleyebilirsiniz. Gibi bir şey:

# 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 )

Ve sonra bu kitaplık projeniz tarafından oluşturulmuş gibi bağlanın:

TARGET_LINK_LIBRARIES(GLBall mylib)

Böyle bir yaklaşım size biraz daha fazla esneklik sağlayacaktır: add_library () komutuna ve içe aktarılan kitaplıklarla ilgili birçok hedef özelliğe bir göz atın .

Bunun "güncelleştirilmiş lib sürümleri" ile ilgili sorununuzu çözüp çözmeyeceğini bilmiyorum.


2
Bu muhtemelen olur add_library( mylib SHARED IMPORTED )veya bir add_library called with IMPORTED argument but no library typehata alırsınız
Marvin

4
@Andre: IMPORTED_LOCATIONAçılış parantezinden sonra yanlış olduğunu düşünüyorum
Ela782

5
İçe aktarılan kitaplığa şu andaki dizinlerin üstündeki dizinlere erişmek istiyorsanız GLOBALsonrasına eklemeniz gerekir IMPORTED:add_library(breakpad STATIC IMPORTED GLOBAL)
Roman Kruglov

@Andre IMPORTED_LOCATION, dosyayı içeren dizin yerine dosyanın yolunu gerektiriyor gibi görünüyor
SOUser

1
@SOUser: Evet, IMPORTED_LOCATION dizini değil dosyayı göstermelidir. Bunu düzelttim, sanırım yazar şikayet etmeyecek.
Tsyvarev

65

Foo adlı bir kitaplığa bağlanmak istediğinizi varsayıyorum , dosya adı genellikle bağlantı foo.dllveya libfoo.so.

1. Kitaplığı bulun Kitaplığı
bulmanız gerekir. Kitaplığınıza giden yolu bilseniz bile bu iyi bir fikirdir. Kitaplık kaybolursa veya yeni bir ad alırsa CMake hata verecektir. Bu, hatayı erken tespit etmeye ve kullanıcıya (kendiniz de olabilir) bir soruna neyin neden olduğunu netleştirmeye yardımcı olur.
Bir kütüphane bulmak için foo ve yolu saklamak FOO_LIBkullanım

    find_library(FOO_LIB foo)

CMake, gerçek dosya adının nasıl olduğunu kendisi anlayacaktır. Bu gibi olağan yerlerde denetler /usr/lib, /usr/lib64ve yolları PATH.

Kitaplığınızın yerini zaten biliyorsunuz. CMAKE_PREFIX_PATHCMake'i aradığınızda ekleyin , ardından CMake kitaplığınızı geçirilen yollarda da arayacaktır.

Bazen ipuçları veya yol son ekleri eklemeniz gerekir, ayrıntılar için belgelere bakın: https://cmake.org/cmake/help/latest/command/find_library.html

2. Kitaplığı bağlayın 1.'den itibaren tam kitaplık adına sahipsiniz FOO_LIB. Bunu, kitaplığı olduğu GLBallgibi hedefinize bağlamak için kullanırsınız .

  target_link_libraries(GLBall PRIVATE "${FOO_LIB}")

Sen eklemek gerekir PRIVATE, PUBLICya da INTERFACEhedef, krş sonra belgeler: https://cmake.org/cmake/help/latest/command/target_link_libraries.html

Eğer bu görünürlük belirticilerinin tane ekleyin yoksa, o da böyle davranacağı PRIVATEveya PUBLICCKağıt sürümü ve politikaları sette bağlı.

3. İçerir ekleyin (Bu adım zorunlu olmayabilir.)
Ayrıca başlık dosyalarını da dahil etmek istiyorsanız, find_pathbenzeri kullanın find_libraryve bir başlık dosyası arayın. Daha sonra, ile target_include_directoriesbenzer içeren içerme dizinini ekleyin target_link_libraries.

Belgeler: https://cmake.org/cmake/help/latest/command/find_path.html ve https://cmake.org/cmake/help/latest/command/target_include_directories.html

Harici yazılımlar için mevcut ise, yerini alabilir find_libraryve find_pathtarafından find_package.


5
IMHO bu en iyi cevaptır. Ancak sorun yaşadım çünkü "proje" den sonra "find_library" ve "add_executable" dan sonra "target_link_libraries" çağırmıyordum.
smoothware

1
find_packagebu adımları takip etmekten çok daha kolay
aktifedecay

2
Sanırım 2. adımı anlamıyorum. Paylaşılan bir kitaplık için $ {FOO_LIB}, /full/path/to/libfoo.dylib gibi olacaktır. Bu nasıl işe yarar? target_link_libraries "-L / full / path / to -lfoo" oluşturmuyor, bu nedenle find_library, kütüphanenin zaten bildiğim konumda olduğunu doğrulamaktan başka yararlı bir şey döndürmüyor. Neyi kaçırıyorum?
guymac

target_link_libraries(mylib "${FOO_LIB}")? Hedef, mylibgerçek hedefi yerine GLBallmi? bana pek mantıklı gelmiyor
Bersan

5

Bir alternatif daha, Appstore ile çalışıyorsanız, "Yetkilere" ihtiyacınız var ve bu nedenle bir Apple-Framework ile bağlantı kurmanız gerekiyor.

İşe Görevlendirmeler için (örneğin Gamecenter) Eğer ihtiyaç bir "Kütüphaneler ile bağlantı Binary" -buildstep olması ve ardından "GameKit.framework" ile bağlayın. CKağıt "enjekte eder" komut içine "düşük düzeyde" konulu kütüphaneler, dolayısıyla Xcode değil gerçekten bunu bilmek ve bu gibi olacak değil GameKit Yetenekleri ekranında etkin olsun.

CMake'i kullanmanın ve bir "İkililerle Bağlantı Kurma" yapmanın bir yolu, xcodeproj'u CMake ile oluşturmak ve ardından 'sed' kullanarak 'ara ve değiştir' ve GameKit'i XCode'un beğeneceği şekilde eklemektir ...

Komut dosyası şöyle görünür (Xcode 6.3.1 için).

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

bunu "gamecenter.sed" e kaydedin ve ardından bu şekilde "uygulayın" (xcodeproj'unuzu değiştirir!)

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

İhtiyaçlarınıza uyması için komut dosyası komutlarını değiştirmeniz gerekebilir.

Uyarı: Proje formatı değişebileceğinden, (kodlanmış) benzersiz numara gerçekten benzersiz olmayabilir - ve genellikle diğer kişilerin sunduğu çözümler daha iyidir - bu nedenle Appstore + 'yı Desteklemeniz gerekmedikçe, farklı Xcode sürümlerinden ayrılma olasılığı yüksektir. Yetkilendirmeler (ve otomatik derlemeler) bunu yapmayın.

Bu bir CMake hatasıdır, bkz. Http://cmake.org/Bug/view.php?id=14185 ve http://gitlab.kitware.com/cmake/cmake/issues/14185


Spesifik olarak - cmake'ı harici bir kitaplığa bağlamak sorun değil (yukarıda birkaç çözüm var). Bunun otomatik bir şekilde çalışmasını sağlamak, böylece Apple Appstore ve yetkilendirmelerle çalışması bir zorluktur. Bu özel durumda, yukarıdaki çözümler işe yaramaz çünkü XCode bu şekilde bağlanmış kitaplıkları 'görmez' ve yetkilendirmeler çalışmaz. Afaik cmake, libarileri xcode'un ihtiyaç duyduğu şekilde 'appstore uyumlu bir şekilde' ekleyemez - yine beni aydınlatmaktan çekinmeyin.
kalmiya

1
Oh, bu üzücü. Eksiksizlik için şu anda hiçbir iletişim ağı içermeyen yeni sorun izleyicinin bağlantısı: gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567

Sorun 5 ay önce çözüldü, bu nedenle CMake'nin son sürümünde artık mevcut olmamalı. Bkz gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.