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

Answers:


100

首先设置库搜索路径:

LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/res)

然后做

TARGET_LINK_LIBRARIES(GLBall mylib)

43
link_directories不鼓励使用,即使在其自己的文档中也是如此。我认为最好解决find_library原始问题中的失败呼叫,或者使用@Andre的解决方案。
Fraser

4
我发现“导入的”库目标更可靠,因为它以特定库的位置为目标,而不是简单地给出全局搜索路径。参见安德烈的答案。
Mark Lakata '16

1
您应始终使用find_library并使用此路径,而不是对其进行硬编码,请参见。我的回答
usr1234567

121

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()命令和许多与导入库有关的target-properties

我不知道这是否可以解决“ libs的更新版本”的问题。


2
那可能是add_library( mylib SHARED IMPORTED )或者您得到一个add_library called with IMPORTED argument but no library type错误
Marvin

4
@Andre:我认为在IMPORTED_LOCATION开括号之后错了
Ela782 2014年

5
您需要添加GLOBAL后,IMPORTED如果要访问导入库目录中的电流以上:add_library(breakpad STATIC IMPORTED GLOBAL)
罗马克鲁格洛夫

@Andre IMPORTED_LOCATION似乎需要文件的路径,而不是包含文件的目录
SOUser 2015年

1
@SOUser:是的,IMPORTED_LOCATION应该指向文件,而不是目录。我已经解决了这个问题,猜想作者不会抱怨。
Tsyvarev

64

我假设您要链接到名为foo的库,其文件名通常是link foo.dlllibfoo.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}")

您应该在目标之后添加PRIVATEPUBLICINTERFACEcf。文档:https : //cmake.org/cmake/help/latest/command/target_link_libraries.html

如果不添加这些可见性说明符之一,则其行为将类似于PRIVATEPUBLIC,具体取决于CMake版本和设置的策略。

3.添加包含 (此步骤可能不是强制性的。)
如果您还想要包含头文件,请使用find_path类似于头文件find_library并搜索头文件。然后添加包含目录,target_include_directories类似于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


4
恕我直言,这是最好的答案。但是,我遇到了麻烦,因为我没有在“项目”之后调用“ find_library”,而在“ add_executable”之后没有调用“ target_link_libraries”。
平板电脑

1
find_package比执行以下步骤简单得多
activedecay

2
我想我不理解第2步。对于共享库$ {FOO_LIB}就像/full/path/to/libfoo.dylib。这有什么用?target_link_libraries不会创建“ -L / full / path / to -lfoo”,因此find_library不会返回任何有用的信息,除了验证库是否位于我已经知道的位置。我想念什么?
guymac

target_link_libraries(mylib "${FOO_LIB}")?目标是mylib他的实际目标,而不是GLBall?没有多大意义,我
Bersan

5

在使用Appstore的情况下,还有另一种方法需要“权利”,因此需要与Apple框架链接。

为了使权利起作用(例如GameCenter),您需要具有“将二进制文件与库链接” -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

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

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

您可能需要更改脚本命令以适合您的需求。

警告:随着项目格式的更改,它可能会因不同的Xcode版本而中断,(硬编码的)唯一编号可能不是真正唯一的-通常其他人的解决方案更好-因此,除非您需要支持Appstore +授权(和自动构建),请勿执行此操作。

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


具体来说-使cmake与外部库链接不是问题(上面有几种解决方案)。使它以自动化的方式工作,使其与Apple Appstore 权利一起使用是一个挑战。在这种特定情况下,上述解决方案将不起作用,因为XCode不会“看到”以这种方式链接的库,而权利将不起作用。Afaik cmake不能以xcode以“与应用商店兼容的方式”添加xlib所需的库,再次给我启发。
kalmiya

1
哦,真可悲。为了完整起见,指向新问题跟踪器的链接(当前不包含任何通讯):gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567 '17

该问题已在5个月前解决,因此在最新版本的CMake中应该不再存在。见gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567 '19
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.