CMake链接到外部库

Pri*_*ime 109 cmake

如何让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)
Run Code Online (Sandbox Code Playgroud)

在我将库复制到二进制目录后bin/res.

我试过用 find_library(RESULT mylib.so PATHS ${CMAKE_BINARY_DIR}/res)

哪个失败了RESULT-NOTFOUND.

And*_*dré 111

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 )
Run Code Online (Sandbox Code Playgroud)

然后链接,好像这个库是由您的项目构建的:

TARGET_LINK_LIBRARIES(GLBall mylib)
Run Code Online (Sandbox Code Playgroud)

这种方法可以为您提供更多灵活性:查看add_library()命令以及与导入库相关许多目标属性.

我不知道这是否可以解决"更新版本的库"的问题.

  • @Andre:我认为在"IMPORTED_LOCATION"之后,开场括号错了 (4认同)
  • 如果要在当前上面的目录中访问导入的库,则需要在"IMPORTED"之后添加"GLOBAL":`add_library(breakpad STATIC IMPORTED GLOBAL) (3认同)
  • 这可能是`add_library(mylib SHARED IMPORTED)`或者你得到一个带有IMPORTED参数调用的`add_library但没有库类型`错误 (2认同)

arr*_*owd 95

首先设置库搜索路径:

LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/res)
Run Code Online (Sandbox Code Playgroud)

然后就做

TARGET_LINK_LIBRARIES(GLBall mylib)
Run Code Online (Sandbox Code Playgroud)

  • 不鼓励使用[`link_directories`](http://www.cmake.org/cmake/help/v2.8.10/cmake.html#command:link_directories),即使在自己的文档中也是如此.我认为在这里解决原始问题中失败的`find_library`调用或使用@Andre的解决方案会更好. (37认同)
  • 我发现"导入的"库目标更加健壮,因为它定位了特定库的位置,而只是简单地给出了一个全局搜索路径.见安德烈的回答. (4认同)
  • 您应该始终使用 `find_library` 并使用此路径而不是对其进行硬编码,参见。[我的回答](http://stackoverflow.com/a/41909627/2799037)。 (2认同)

usr*_*567 49

我假设你想链接到一个名为foo的库,它的文件名通常是链接foo.dlllibfoo.so.

1.找到图书馆
你必须找到图书馆.即使您知道图书馆的路径,这也是一个好主意.如果库消失或获得新名称,CMake将会出错.这有助于及早发现错误并使用户(可能是您自己)明白导致问题的原因.
要查找库foo并存储正在FOO_LIB使用的路径

    find_library(FOO_LIB foo)
Run Code Online (Sandbox Code Playgroud)

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.您可以使用它将库链接到目标,mylib如下所示

  target_link_libraries(mylib "${FOO_LIB}")
Run Code Online (Sandbox Code Playgroud)

您可能想要添加PRIVATE,PUBLICINTERFACE在库前面,参见 文档:https: //cmake.org/cmake/help/latest/command/target_link_libraries.html

3.添加包含 (此步骤可能不是必需的.)
如果您还想包含头文件,请使用find_path类似于find_library和搜索头文件.然后添加target_include_directories类似的include目录target_link_libraries.

文档:https: //cmake.org/cmake/help/latest/command/find_path.htmlhttps://cmake.org/cmake/help/latest/command/target_include_directories.html

如果可用于外部软件,则可以替换find_libraryfind_path通过find_package.

  • `find_package` 比遵循这些步骤简单得多 (3认同)
  • 恕我直言,这是最好的答案.但是,我遇到了麻烦,因为我没有在"add_executable"之后的"project"和"target_link_libraries"之后调用"find_library". (2认同)
  • 我想我听不懂步骤2。对于共享库$ {FOO_LIB}就像/full/path/to/libfoo.dylib。这有什么用?target_link_libraries不会创建“ -L / full / path / to -lfoo”,因此find_library不会返回任何有用的信息,除了验证库是否位于我已经知道的位置之外。我想念什么? (2认同)

Sor*_*ush 16

假设您有一个可执行文件,例如:

\n
add_executable(GLBall GLBall.cpp)\n
Run Code Online (Sandbox Code Playgroud)\n

如果外部库有标头,请给出其包含文件夹的路径:

\n
target_include_directories(GLBall PUBLIC "/path/to/include")\n
Run Code Online (Sandbox Code Playgroud)\n

添加库目录路径:

\n
target_link_directories(GLBall PUBLIC "/path/to/lib/directory")\n
Run Code Online (Sandbox Code Playgroud)\n

最后链接库名

\n
target_link_libraries(GLBall mylib)\n
Run Code Online (Sandbox Code Playgroud)\n

注意,库文件的前缀和扩展名被删除:

\n

libmylib.a \xe2\x9e\x9c mylib
\nmylib.so \xe2\x9e\x9c mylib

\n


kal*_*iya 5

如果您使用 Appstore,另一种选择需要“权利”,因此需要与 Apple 框架链接。

为了使权利生效(例如 GameCenter),您需要有一个“Link Binary with Libraries”-buildstep,然后与“GameKit.framework”链接。CMake 将“低级别”的库“注入”到命令行中,因此 Xcode 并不真正了解它,因此您不会在“功能”屏幕中启用 GameKit。

使用 CMake 并具有“与二进制文件链接”-buildstep 的一种方法是使用 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
Run Code Online (Sandbox Code Playgroud)

将其保存到“gamecenter.sed”,然后像这样“应用”它(它会改变你的 xcodeproj!)

sed -i.pbxprojbak -f gamecenter.sed myproject.xcodeproj/project.pbxproj
Run Code Online (Sandbox Code Playgroud)

您可能需要更改脚本命令以满足您的需要。

警告:由于项目格式可能会发生变化,因此可能会因不同的 Xcode 版本而中断,(硬编码的)唯一编号可能不是唯一的 - 通常其他人的解决方案更好 - 所以除非您需要支持 Appstore +权利(和自动构建),不要这样做。

这是一个 CMake 错误,请参阅http://cmake.org/Bug/view.php?id=14185http://gitlab.kitware.com/cmake/cmake/issues/14185