【问题标题】:CMake : how to link a library WITHOUT automatic search function FIND_PACKAGE?CMake:如何在没有自动搜索功能 FIND_PACKAGE 的情况下链接库?
【发布时间】:2013-08-28 05:50:41
【问题描述】:

我想知道如何在没有任何 FIND_PACKAGE 的情况下查找/链接库。

假设我们有一个名为 testlib 的“个人”库:

/perso/testlib/include/testlib1.h
/perso/testlib/include/testlib2.h
/perso/testlib/lib/testlib1.a
/perso/testlib/lib/testlib2.a

如何将其与 CMake 链接?

1) 在CMakeLists.txt的代码中直接链接的函数有哪些?

2) 如何让用户选择文件在哪里?

3) 我很难理解 CMake 解释的内容和不解释的内容。例如,如果您定义变量 ${MYVARIABLE_INCLUDE_DIR} 或 ${MYVARIABLE_LIBRARIES} 是“INCLUDE_DIR”或“LIBRARIES”,则由 CMake 解释扩展,或者如果我将此变量称为 ${MYVARIABLE_INCDIR} 没有区别?

4) 如果您的库在 lib 目录中包含十个或更多库文件,如何执行相同的程序(包括“个人”库)?

5) 最后,当你输入TARGET_LINK_LIBRARIES(myexecutable gmp),你怎么知道库的名字是“gmp”。为什么不是“GMP”或“GMP”?放入此函数的库名称是否等于 .a 文件减去 "lib" 和 ".a" ?例如 libgmp.a -> gmp ?如果我想链接一个名为 libtestlolexample.a 的库,我必须输入 TARGET_LINK_LIBRARIES(myexecutable testlolexample) 吗?

非常感谢。

【问题讨论】:

  • 您是否也在同一个项目中使用 CMake 构建库,还是单独构建的?您希望用户分别选择 include 和 lib 目录,还是选择例如 /perso/testlib 目录并让 CMake 查看 include 和 lib 子目录?
  • 您是否有一个(或多个)默认路径来查找这些文件,或者用户是否总是需要手动选择?

标签: cmake


【解决方案1】:

您可以使用target_link_libraries(myexecutable mylib) 链接到库“mylib”。编译器将使用其默认方式来查找指定的库(例如,它将在 Linux 上查找 libmylib.a)。编译器只会查找link_directories(directory1 directory2 ...),因此您可以尝试使用该命令将所需目录添加到搜索路径中。

当“mylib”也用 CMake 编译时,这将被识别并且一切都应该自动运行。

当您希望用户指定目录时,您可以使用缓存的 CMake 变量。 set(MYPATH "NOT-DEFINED" CACHE PATH "docstring").

对于更复杂的东西,建议编写一个可与​​find_package 一起使用的 CMake 查找模块。我建议你看看FindALSA.cmake,它可以作为一个很好的起点。

有趣的部分在最后:

if(ALSA_FOUND)
  set( ALSA_LIBRARIES ${ALSA_LIBRARY} )
  set( ALSA_INCLUDE_DIRS ${ALSA_INCLUDE_DIR} )
endif()

mark_as_advanced(ALSA_INCLUDE_DIR ALSA_LIBRARY)

ALSA_LIBRARYALSA_INCLUDE_DIR 变量是用户可配置的并存储在缓存中,而 ALSA_LIBRARIESALSA_INCLUDE_DIRS 以及 ALSA_FOUND 被计算并且是查找模块的用户应该使用的变量使用。

通常人们会像这样使用 find 模块:

find_package(ALSA REQUIRED)
include_directories(${ALSA_INCLUDE_DIRS})
target_link_libraries(myexe ${ALSA_LIBRARIES})

我相信您可以将其改编为您的个人图书馆。

【讨论】:

  • FindALSA.cmake 的好建议,看起来它为一个简单的库做了所有“当前最佳实践”的事情(AFAIK)。请注意,其他一些 find_package 模块不是那么好(或使用较旧的样式/功能)。
【解决方案2】:

通常当你想链接一个没有 find_package 模块的库时(例如,它是一个不常见的库,或者它是你自己的库),那么你可以使用基本命令(find_X 命令)来设置变量您需要的路径。然后将这些变量与 find_package 一起使用(include_directories, target_link_libraries)。

如果你打算从多个包中使用这个库,你可能需要创建一个 find_package 模块;基本上它使用具有某些约定的相同命令。

其中任何一个都允许您指定要查看的路径(在 CMake 模块中),并且它们允许用户覆盖路径(变量在ccmake/cmake-gui 中显示为选项)。

我很乐意添加其中一种或两种方法的示例,请告诉我您在寻找什么。

如果你只是想要一个快速而肮脏的解决方案,你可以这样做,但我不建议这样做:

include_directories(/perso/testlib/include)
add_executable(myexecutable myexecutable.cpp)
target_link_libraries(myexecutable
    /perso/testlib/lib/testlib1.a
    /perso/testlib/lib/testlib2.a)

关于您关于target_link_libraries (#5) 的问题,您可以通过多种方式进行。如果您愿意,您可以提供全名(例如target_link_libraries(myexe libfoo.a)),但我认为使用短名称(例如target_link_libraries(myexe foo)更好(我想更便携)。您还可以包含链接器标志;我不确定我在哪里读到它,但我认为它可能会为不同的链接器翻译 -L 和 -l 标志。

例如,如果我在同一个目录中有一堆库,并且我知道名称,我可能会找到目录,将其存储在变量中,然后执行以下操作:

# First, find and set TESTLIB_LIBRARY_DIR, e.g. with find_path
# ...

# This assumes the libraries are e.g. 'libtestlib1.a' and 'libtestlib2.a'
set(TESTLIB_LIBRARIES
    -L${TESTLIB_LIBRARY_DIR)
    -l testlib1
    -l testlib2)

add_executable(myexecutable myexecutable.cpp)
target_link_libraries(myexecutable ${TESTLIB_LIBRARIES})

如果你想制作自己的 find_package 模块(就像trenki 提到的,FindALSA.cmake 似乎是一个很好的起点),你可以通过将目录添加到CMAKE_MODULE_PATH 来使用它;例如,如果您将模块放在 cmake/modules/ 子目录中:

# Look for extra CMake modules in a subdirectory of this project
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/" ${CMAKE_MODULE_PATH})

FindALSA.cmake 的一个可能问题是:我不确定CMAKE_CURRENT_LIST_DIR 是否有效。所以我认为你应该做出这个改变(我写的模块中的第二个工作):

# Change this line
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)

# To this (with no path/extension it will search the CMake modules path):
include(FindPackageHandleStandardArgs)

要了解FIND_PACKAGE_HANDLE_STANDARD_ARGS 的用法,请查看CMake Modules 目录中的FindPackageHandleStandardArgs.cmake

【讨论】:

    【解决方案3】:

    CMake 有一个很好的documentation

    1. 通过将 STATIC 关键字传递给 add_library 来存档静态链接(如果我理解你的正确)
    2. 我建议不要这样做(我不是 CMake 专家),但听起来费用会很大。
    3. 没有区别,${MYVARIABLE_INCLUDE_DIR} 只是一个变量名,随便你。但我建议您遵循命名约定。
    4. 一个库始终是一个 .lib/.a 文件,因此使用 add_library& target_link_libraries& add_dependencies 函数应该没有问题。
    5. 库名称始终是您传递给add_library 的名称。但是 Gmp 或 gMP 将与 CMake 一样是区分大小写的

    【讨论】:

    • 注意:如果您使用 CMake 构建库,则使用 add_library 函数。如果它已经构建,您将使用其他功能。
    • @Wolf:看我的答案或trenki的。
    • 谢谢,有帮助。它还有助于理解 CMake 根本不关心其他 CMakeLists.txt 文件中的内容。即使我的可执行文件已定义(在子目录的文件中),它也未被视为在我的项目文件中定义。这个“包含”的概念是违反直觉的。现在我为子目录使用库,为项目使用一个可执行文件。这样就简单多了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-29
    • 1970-01-01
    • 2012-10-05
    • 2015-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多