【问题标题】:In cmake, can we avoid using find_package to import other packages?在cmake中,我们可以避免使用find_package导入其他包吗?
【发布时间】:2021-08-04 06:05:21
【问题描述】:

好吧,标题显然很奇怪。我希望任何能清楚地定义我的好奇心的人,都会将标题编辑成正确的标题。

在使用CMakeLists.txt时,我们通常通过命令find_package()宏导入第三方包,该宏会寻找合适的find_XXX.cmake脚本,然后输出XXX_LIBRARIESXXX_INCLUDE_DIRECTORIES等变量。

但是,最近我发现了一些 add_library() 宏的指令指南,它可以包含实际的库二进制文件作为其源(?),就像这样:

add_library(my_target STATIC IMPORTED foo.lib)

我猜,只要名称 my_target 实际上是一个目标名称,那么我们就可以向该目标添加另一个组合,就像任何其他 cmake 目标一样,如下所示。

target_inlcude_directories(my_target PUBLIC ${PKG_PREFIX}/include)
target_link_directories(my_target PUBLIC ${PKG_PREFIX}/lib)
target_compile_features(my_target PUBLIC std_cxx_17)

如果这是可能的,那么这不是更简洁的方式来描述导出的包的组成,而不是为每个手动链接和添加那些冗长的 *_LIBS *_DIRS 变量吗?像下面这样?

add_executable(foo ${MY_SOURCES})
find_package(xxx)

# BEFORE
target_link_directories(foo PRIVATE ${XXX_LINK_DIRECTORIES}) # note: I don't remember what was it exactly.
target_link_libraries(foo PRIVATE ${XXX_LIBRARIES})
target_include_directories(foo PRIVATE ${XXX_INCLUDE_DIRECTORIES})

# AFTER
target_link_libraries(foo PRIVATE xxx::my_target)

我是不是在想一些无效的东西?

【问题讨论】:

  • 这取决于包是否暴露目标。许多人都这样做。示例:openssl 定义 OpenSSL::SSLOpenSSL::Crypto。你用它代替OPENSSL_SSL_LIBRARY。但并非所有人都这样做,然后您又回到了旧方式。
  • 啊,是不是已经被广泛使用的方法了?谢谢,我不知道。我会结束这个问题......对不起,我可以在没有任何接受的答案的情况下结束这个问题吗?
  • 现代 cmake 实践的好读物:cliutils.gitlab.io/modern-cmake (我相信如果不再有用,您可以删除自己的问题,或者等待有人回答 - 我不会,得马上离开)

标签: c++ c cmake


【解决方案1】:

我们可以避免使用 find_package 导入其他包吗?

您可以,但它只是用于此目的的工具。 find_package() 基本上是带有一些特殊选项的 include()

这不是更简洁的方式来描述导出包的组成,而不是为每个手动链接和添加那些冗长的 *_LIBS *_DIRS 变量吗?像下面这样?

它会被使用。

cmake 在很短的时间内仍在进行相对较大的变化。我认为接口库不是那么流行或者前一段时间不可用。 唯一(除了一些检查等)find_package 所做的事情是它包含一个名为 FindXXX.cmake 的文件(或其他名称不同的文件)。 仅限。这完全取决于 FindXXX.cmake 文件中的内容会发生什么。

较新的 cmake FindXXX.cmake 完全符合您的建议:他们创建了一个 INTERFACE IMPORTED 库,例如在我的电脑上:

@/usr/share/cmake-3.20/Modules
$ grep add_library -wr --include='Find*' .
.... a lot of results ....
./FindBoost.cmake:    add_library(Boost::diagnostic_definitions INTERFACE IMPORTED)
./FindBoost.cmake:    add_library(Boost::disable_autolinking INTERFACE IMPORTED)
./FindBoost.cmake:    add_library(Boost::dynamic_linking INTERFACE IMPORTED)
./FindThreads.cmake:  add_library(Threads::Threads INTERFACE IMPORTED)
./FindHDF5.cmake:    add_library(HDF5::HDF5 INTERFACE IMPORTED)
./FindHDF5.cmake:        add_library("hdf5::${hdf5_target_name}" INTERFACE IMPORTED)
./FindHDF5.cmake:        add_library("hdf5::${hdf5_target_name}" UNKNOWN IMPORTED)
./FindHDF5.cmake:        add_library("hdf5::${hdf5_target_name}" INTERFACE IMPORTED)
./FindHDF5.cmake:        add_library("hdf5::${hdf5_target_name}" UNKNOWN IMPORTED)
./FindGTest.cmake:        add_library(GTest::GTest INTERFACE IMPORTED)
./FindGTest.cmake:        add_library(GTest::Main INTERFACE IMPORTED)
./FindGTest.cmake:        add_library(GTest::gtest ${GTEST_LIBRARY_TYPE} IMPORTED)
./FindGTest.cmake:        add_library(GTest::gtest_main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED)
./FindBZip2.cmake:    add_library(BZip2::BZip2 UNKNOWN IMPORTED)

较旧或“更标准”(即较旧 :) 确实会创建多个变量 - XXX_LINK_DIRECTORIES XXX_LIBRARIES 等。请注意,变量名称​​不一样无处不在(XXX_LIB? XXX_INC_DIRS? 等)并根据您调用的 FindXXX.cmake 进行更改,因为一些开发人员决定使用不同的名称。在find_package 使用变量的时候编写了很多文档,所以它在文档中仍然可见,但现在接口库明显占主导地位,并且您提出的内容已经被使用。

【讨论】:

    【解决方案2】:

    请注意,在这种情况下,导入的库没有正确设置。配置脚本 (<packageName>Config.cmake) 用作 find_package 的后备,或者如果您使用 CONFIG 版本,通常会这样做:创建一个或多个导入目标以供您在项目中使用。我强烈建议使用这些变量而不是 *_LIBS/*_DIRS 变量(如果可用)。

    这是导入库的正确版本:

    add_library(my_target STATIC IMPORTED)
    
    # INTERFACE "visibility" needed here;
    # also quote the path concatenation to avoid issues with spaces in PKG_PREFIX
    target_include_directories(my_target INTERFACE "${PKG_PREFIX}/include")
    target_link_directories(my_target INTERFACE "${PKG_PREFIX}/lib")
    
    # do you really need the linking library to use the C++ 17 standard?
    target_compile_features(my_target INTERFACE std_cxx_17)
    
    # you need specify the absolute path to the lib as IMPORTED_LOCATION target property
    # you may need to adjust the location according to the exact location of the lib file
    #
    # variables CMAKE_CURRENT_SOURCE_DIR (if used from CMakeLists.txt) or
    # CMAKE_CURRENT_LIST_DIR (if used from a script) may be helpful
    #
    # requires seperate treatment for different OS; this is not included here
    set_target_properties(my_target PROPERTIES IMPORTED_LOCATION "${PKG_PREFIX}/lib/my_target.a")
    

    请注意,在这种情况下,您需要链接的库是 my_target,而不是 xxx::my_target

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-12
      • 2011-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-23
      • 1970-01-01
      相关资源
      最近更新 更多