如何让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
。
答案 0 :(得分:107)
arrowdodger的答案在许多场合都是正确和首选的。我只想添加一个替代答案:
您可以添加“导入的”库目标,而不是链接目录。类似的东西:
# 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( )命令和many target-properties related to imported libraries。
我不知道这是否能解决“更新版本的lib”的问题。
答案 1 :(得分:86)
首先设置库搜索路径:
LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/res)
然后就这样做
TARGET_LINK_LIBRARIES(GLBall mylib)
答案 2 :(得分:40)
我假设您要链接到名为 foo 的库,其文件名通常是链接/users/2/posts?num=78
或foo.dll
。
<强> 1。找到图书馆
你必须找到图书馆。即使您知道图书馆的路径,这也是一个好主意。如果库消失或获得新名称,CMake将会出错。这有助于及早发现错误,并使用户(可能是您自己)明白导致问题的原因
要查找库 foo 并将路径存储在libfoo.so
使用
FOO_LIB
CMake将自己弄清楚实际文件名是怎样的。它会检查 find_library(FOO_LIB foo)
,/usr/lib
等常用地点以及/usr/lib64
中的路径。
您已经知道图书馆的位置。当你调用CMake时将它添加到PATH
,然后CMake也会在传递的路径中查找你的库。
有时您需要添加提示或路径后缀,有关详细信息,请参阅文档: https://cmake.org/cmake/help/latest/command/find_library.html
<强> 2。链接库
从1.您在CMAKE_PREFIX_PATH
中拥有完整的库名称。您可以使用它将库链接到目标FOO_LIB
,如
mylib
您可能希望在库前面添加 target_link_libraries(mylib "${FOO_LIB}")
,PRIVATE
或PUBLIC
,参见文件:
https://cmake.org/cmake/help/latest/command/target_link_libraries.html
第3。添加包含 (此步骤可能不是强制性的。)
如果您还想要包含头文件,请使用与INTERFACE
类似的find_path
并搜索头文件。然后添加包含find_library
的include目录,类似于target_include_directories
。
文档: https://cmake.org/cmake/help/latest/command/find_path.html 和 https://cmake.org/cmake/help/latest/command/target_include_directories.html
如果可用于外部软件,则可以target_link_libraries
替换find_library
和find_path
。
答案 3 :(得分:3)
在您使用Appstore的情况下,还有一个替代方案需要“Entitlements”,因此需要与Apple-Framework链接。
要使权利工作(例如GameCenter),您需要拥有“与图书馆链接二进制文件”-buildstep,然后与“GameKit.framework”链接。 CMake将“低级别”的库“注入”到命令行中,因此Xcode不会真正知道它,因此你将不启用GameKit功能界面。
使用CMake和“使用二进制链接”-buildstep的一种方法是使用CMake生成xcodeproj,然后使用'sed'来'搜索&amp;替换'并以XCode喜欢的方式添加GameKit ......
脚本如下所示(对于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 + Entitlements(和自动构建)不要这样做。
这是一个CMake错误,请参阅http://cmake.org/Bug/view.php?id=14185和http://gitlab.kitware.com/cmake/cmake/issues/14185
答案 4 :(得分:1)
假设您有一个可执行文件,例如:
add_executable(GLBall GLBall.cpp)
如果外部库有标题,请给出其包含文件夹的路径:
target_include_directories(GLBall PUBLIC "/path/to/include")
添加库目录路径:
target_link_directories(GLBall PUBLIC "/path/to/lib/directory")
最后链接库名
target_link_libraries(GLBall mylib)
注意去掉了库文件的前缀和扩展名:
libmylib.a ➜ mylib
mylib.so ➜ mylib