Посилання CMake на зовнішню бібліотеку


126

Як змусити CMake зв’язати виконуваний файл із зовнішньою спільною бібліотекою, яка не побудована в рамках одного проекту CMake?

Просто дію target_link_libraries(GLBall ${CMAKE_BINARY_DIR}/res/mylib.so)дає помилку

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)

після того як я скопіював бібліотеку у бінарний реж bin/res.

Я спробував використовувати find_library(RESULT mylib.so PATHS ${CMAKE_BINARY_DIR}/res)

Яка не вдається RESULT-NOTFOUND.

Відповіді:


101

Спочатку встановіть шлях пошуку бібліотек:

LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/res)

А потім просто робити

TARGET_LINK_LIBRARIES(GLBall mylib)

44
Використання link_directoriesвідмовляє навіть у власній документації. Я думаю, що тут було б краще вирішити невдалий find_libraryдзвінок в оригінальному запитанні або скористатися рішенням @ Andre.
Фрейзер

4
Я вважаю, що "імпортна" ціль бібліотеки є більш надійною, оскільки вона орієнтована на розташування конкретної бібліотеки, а не просто дає глобальний шлях пошуку. Дивіться відповідь Андре.
Марк Лаката

1
Ви завжди повинні використовувати find_libraryта використовувати цей шлях замість жорсткого кодування, пор. моя відповідь .
usr1234567

121

Відповідь стрілецького доктора правильна і багато разів бажана. Я просто хотів би додати альтернативу до своєї відповіді:

Ви можете додати "імпортну" ціль бібліотеки замість посилання-каталогу. Щось на зразок:

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

А потім зв’яжіть так, ніби ця бібліотека була побудована за вашим проектом:

TARGET_LINK_LIBRARIES(GLBall mylib)

Такий підхід надасть вам трохи більше гнучкості: подивіться на команду add_library () та безліч цільових властивостей, пов’язаних із імпортованими бібліотеками .

Я не знаю, чи це вирішить вашу проблему з "оновленими версіями libs".


2
Мабуть, це буде add_library( mylib SHARED IMPORTED )або ви отримаєте add_library called with IMPORTED argument but no library typeпомилку
Marvin

4
@Andre: Я думаю, що після IMPORTED_LOCATIONвідкриття дужка помиляється
Ela782

5
вам потрібно додати GLOBALпісля того, IMPORTEDяк ви хочете отримати доступ до імпортованої бібліотеки в каталогах вище поточного:add_library(breakpad STATIC IMPORTED GLOBAL)
Роман Круглов

@Andre IMPORTED_LOCATION, здається, вимагає шлях до файлу, а не до каталогу, що містить файл
SOUser

1
@SOUser: Так, IMPORTED_LOCATION має вказувати на файл, а не на каталог. Я це виправив, думаю, автор не скаржиться.
Циварев

64

Я припускаю, що ви хочете зв’язатись з бібліотекою під назвою foo , її ім'я файлу зазвичай є чимось посиланням foo.dllабо libfoo.so.

1. Знайдіть бібліотеку
Ви повинні знайти бібліотеку. Це гарна ідея, навіть якщо ви знаєте шлях до вашої бібліотеки. CMake помилиться, якщо бібліотека зникла або отримала нову назву. Це допомагає виявити помилку рано і дати зрозуміти користувачеві (може самостійно), що викликає проблему.
Щоб знайти бібліотеку Foo і зберегти шлях в FOO_LIBвикористанні

    find_library(FOO_LIB foo)

CMake сам розбереться, як власне ім'я файлу. Він перевіряє звичайні місця, як /usr/lib, /usr/lib64і шляхи в PATH.

Ви вже знаєте місце розташування вашої бібліотеки. Додайте його до CMAKE_PREFIX_PATHвиклику CMake, тоді CMake також шукатиме вашу бібліотеку в пройдених шляхах.

Іноді вам потрібно додати підказки або суфікси шляху, детальну інформацію див. У документації: https://cmake.org/cmake/help/latest/command/find_library.html

2. Зв’яжіть бібліотеку З 1. у вас є повна назва бібліотеки FOO_LIB. Ви використовуєте це для прив'язки бібліотеки до цілі, GLBallяк і раніше

  target_link_libraries(GLBall PRIVATE "${FOO_LIB}")

Ви повинні додати PRIVATE, PUBLICабо INTERFACEпісля цілі, пор. документація: https://cmake.org/cmake/help/latest/command/target_link_libraries.html

Якщо ви не додасте один із цих специфікаторів видимості, він буде вести себе як, PRIVATEабо PUBLICзалежно від версії CMake та встановленої політики.

3. Додати включення (Цей крок може бути не обов'язковим.)
Якщо ви також хочете включити файли заголовків, використовуйте find_pathподібні find_libraryта шукайте файл заголовка. Потім додайте каталог включення з target_include_directoriesподібним до target_link_libraries.

Документація: https://cmake.org/cmake/help/latest/command/find_path.html та https://cmake.org/cmake/help/latest/command/target_include_directories.html

Якщо для зовнішнього програмного забезпечення, ви можете замінити find_libraryі find_pathна find_package.


4
ІМХО це найкраща відповідь. Однак у мене виникли проблеми, тому що я не викликав "find_library" після "project" та "target_link_libraries" після "add_executable".
smoothware

1
find_packageнабагато простіше, ніж виконувати ці кроки
activedecay

2
Я думаю, що я не розумію крок 2. Для спільної бібліотеки $ {FOO_LIB} буде подібний /full/path/to/libfoo.dylib. Чим це корисно? target_link_libraries не створює "-L / full / шлях / до -lfoo", тому find_library не повертає нічого корисного, крім перевірки того, що бібліотека знаходиться в тому місці, де я вже знаю, що це. Що я пропускаю?
guymac

target_link_libraries(mylib "${FOO_LIB}")? Ціль mylibзамість фактичної мети GLBall,? не має для мене особливого сенсу
Берсан

5

Ще одна альтернатива: у випадку, коли ви працюєте з Appstore, потрібні «Права» і як такі потрібно зв’язуватися з Apple-Framework.

Щоб правомочності працювали (наприклад, GameCenter), вам потрібно мати "Build Binary з бібліотеками" -buildstep, а потім посилання на "GameKit.framework". CMake "вводить" бібліотеки на "низькому рівні" в командний рядок, отже, Xcode насправді про це не знає, і як такий ви не отримаєте GameKit включеним на екрані "Capability".

Один із способів використання CMake та побудови "Посилання з бінарними файлами" - це генерувати xcodeproj з CMake, а потім використовувати "sed" для "пошуку та заміни" та додавання GameKit так, як XCode подобається ...

Сценарій виглядає приблизно так (для 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

збережіть це в "gamecenter.sed", а потім "застосуйте" це так (це змінює ваш xcodeproj!)

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

Можливо, вам доведеться змінити команди-скрипти відповідно до ваших потреб.

Попередження: ймовірно, що вийде з різною версією Xcode, оскільки формат проекту міняється, унікальний номер (твердо кодований) може бути насправді не унікальним - і зазвичай рішення інших людей краще - тому, якщо вам не потрібно підтримувати Appstore + Права (і автоматизовані побудови) не роблять цього.

Це помилка CMake, див. Http://cmake.org/Bug/view.php?id=14185 та http://gitlab.kitware.com/cmake/cmake/isissue/14185


Зокрема, зв’язок cmake для зв’язку із зовнішньою бібліотекою не є проблемою (вище є кілька рішень). Робота з цим автоматизованим способом, щоб він працював із Apple Appstore та правами - це складне завдання. У цьому конкретному випадку вищезазначені рішення не працюють, оскільки XCode не буде "бачити" пов'язані таким чином бібліотеки, і права просто не працюватимуть. Cfake Afaik не може додати бібліотекам те, як потрібен xcode в "сумісному з додатком способі". Знову ж, не соромтеся просвітити мене.
калмія

1
О, це сумно. Для повноти посилання на новий трекер випуску, який наразі не містить кометей: gitlab.kitware.com/cmake/cmake/isissue/14185
usr1234567

Проблема була вирішена 5 місяців тому, тому з останньою версією CMake її більше не має бути. Дивіться gitlab.kitware.com/cmake/cmake/isissue/14185
usr1234567
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.