CMake 链接到外部库
Posted
技术标签:
【中文标题】CMake 链接到外部库【英文标题】:CMake link to external library 【发布时间】:2012-01-08 01:16:04 【问题描述】:如何让 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
失败。
【问题讨论】:
【参考方案1】: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。
我不知道这是否会解决您关于“更新版本的库”的问题。
【讨论】:
那可能是add_library( mylib SHARED IMPORTED )
或者你得到一个add_library called with IMPORTED argument but no library type
错误
@Andre:我认为IMPORTED_LOCATION
之后的左括号是错误的
如果要访问当前目录上方的导入库,则需要在IMPORTED
之后添加GLOBAL
:add_library(breakpad STATIC IMPORTED GLOBAL)
@SOUser:是的,IMPORTED_LOCATION 应该指向文件,而不是目录。我已经解决了,估计作者不会抱怨。
我真的不知道为什么那些基本的用法官方没有明确支持!谢谢【参考方案2】:
先设置库搜索路径:
link_directories($CMAKE_BINARY_DIR/res)
然后就做
target_link_libraries(GLBall mylib)
【讨论】:
不鼓励使用link_directories
,即使在它自己的文档中也是如此。我认为在这里解决原始问题中失败的find_library
调用会更好,或者使用@Andre 的解决方案。
我发现“导入的”库目标更加健壮,因为它针对特定库的位置,而不是简单地提供全局搜索路径。见安德烈的回答。
您应该始终使用find_library
并使用此路径而不是对其进行硬编码,参见。 my answer.【参考方案3】:
我假设你想链接到一个名为 foo 的库,它的文件名通常是链接 foo.dll
或 libfoo.so
。
1.查找图书馆
你必须找到图书馆。这是一个好主意,即使您知道库的路径。如果库消失或获得新名称,CMake 将出错。这有助于及早发现错误并让用户(可能是您自己)清楚导致问题的原因。
要查找库 foo 并将路径存储在 FOO_LIB
中,请使用
find_library(FOO_LIB foo)
CMake 会自己弄清楚实际的文件名是怎样的。它会检查/usr/lib
、/usr/lib64
等常用位置以及PATH
中的路径。
您已经知道图书馆的位置。调用 CMake 时将其添加到 CMAKE_PREFIX_PATH
,然后 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_library
的find_path
并搜索头文件。然后添加与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
。
【讨论】:
恕我直言,这是最好的答案。但是,我遇到了麻烦,因为我没有在“project”之后调用“find_library”,在“add_executable”之后没有调用“target_link_libraries”。find_package
比按照这些步骤简单得多
我想我不明白第 2 步。对于共享库 $FOO_LIB 将类似于 /full/path/to/libfoo.dylib。这有什么用? target_link_libraries 没有创建“-L/full/path/to -lfoo”,所以 find_library 没有返回任何有用的东西,除了验证库是否在我已经知道的位置。我错过了什么?
target_link_libraries(mylib "$FOO_LIB")
?目标是mylib
而不是他的实际目标GLBall
?对我来说没有多大意义【参考方案4】:
另一种选择,如果您正在使用 Appstore,则需要“权利”,因此需要与 Apple 框架链接。
要使授权正常工作(例如 GameCenter),您需要具有“将二进制文件与库链接”-构建步骤,然后与“GameKit.framework”链接。 CMake 将“低级别”的库“注入”到命令行中,因此 Xcode 并不真正了解它,因此您将不启用 GameKit功能屏幕。
使用 CMake 并拥有“与二进制文件链接”的一种方法是使用 CMake 生成 xcodeproj,然后使用“sed”来“搜索和替换”并以 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
【讨论】:
特别 - 让 cmake 与外部库链接不是问题(上面有几种解决方案)。让它以自动化的方式工作,以便它与 Apple Appstore 和权利一起工作是一个挑战。在这种特定情况下,上述解决方案不起作用,因为 XCode 不会“看到”以这种方式链接的库,并且权利将不起作用。 Afaik cmake 无法以“与应用商店兼容的方式”以 xcode 需要的方式添加库 - 再次,请随时启发我。 哦,这很可悲。为了完整起见,新问题跟踪器的链接目前不包含任何通信:gitlab.kitware.com/cmake/cmake/issues/14185 问题已在 5 个月前解决,因此对于最新版本的 CMake,它应该不再存在。见gitlab.kitware.com/cmake/cmake/issues/14185 在 CMake 3.19 中修复,具体来说。【参考方案5】:假设您有一个可执行文件,例如:
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
【讨论】:
您的回答对我有用!这是一个不同的用例,但在我尝试你的方式之前我真的很卡住:) 假设 mylib.a -> mylib 是否安全?以上是关于CMake 链接到外部库的主要内容,如果未能解决你的问题,请参考以下文章