如何限制 CMake 组件的传播依赖项

问题描述 投票:0回答:1

我想优化我的 CMake 项目,该项目使用 Conan 作为依赖管理工具。它是一个可执行文件,依赖于几个 Conan 库。但是,出现了共享一些标头和一些依赖项的需要,因此我拆分了该项目,从而在现有的可执行目标之外产生了两个新目标。

我想根据需要将这些目标/组件链接到各种其他项目。它们都共享不同的标题和链接。问题是,我不能强迫 CMake 或 Conan 尊重这种区别,而且我开始怀疑这是否可能。

更准确地说:我的意思是,通过在另一个项目中链接

myproject::myLib
,我不想包含其他库,例如 Boost、OpenSSL 和
MyOtherLib
,它们链接到
myproject::iface 
具有 INTERFACE 范围并间接到
myExecutable
(感谢链接
iface
成分)。这可能吗?

我正在使用 GCC 14.2、CMake 3.26 和 Conan 1.65.0。

CMakeLists.txt:

project(myProject)

// ...

// looking for dependencies installed by Conan
find_package(Boost CONFIG REQUIRED)
find_package(OpenSSL CONFIG REQUIRED)
find_package(MyOtherLib CONFIG REQUIRED)

// main executable target
add_executable(myExecutable
  one.cpp
  two.cpp
)

// new static library target
add_library(myLib STATIC)
target_sources(myLib
  PRIVATE
    lib/myLib/threeLib.cpp
  PUBLIC
    FILE_SET libHeaders
    TYPE HEADERS
    BASE_DIRS lib/myLib/include
    FILES
      lib/myLib/threeLib.h
target_link_libraries(myLib PRIVATE boost::boost)

// new header only component target
add_library(iface INTERFACE)
target_sources(iface
  INTERFACE
    FILE_SET ifaceHeaders
    TYPE HEADERS
    BASE_DIRS include
    FILES
      include/fourHeader.h
      include/fiveHeader.h
target_link_libraries(iface
  INTERFACE
    boost::boost
    openssl::openssl
    myotherlib::myotherlib

// executable is using both of these libs/components
target_link_libraries(myExecutable 
  PRIVATE 
    iface
    myLib
)
// ...

conanfile.py

# some imports
class myProject(ConanFile):
    # some attributes and settings
    # version numbers might be randomized
    generators = "CMakeDeps", "CMakeToolchain"
    requires = "boost/1.80.0", "openssl/3.3.5", "myotherlib/1.0@myremote/testing"
    
    def layout(self):
        cmake_layout(self)

    def generate(self):
        toolchain = CMakeToolchain(self)
        toolchain.generate()
        deps = CMakeDeps(self)
        deps.generate()

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

我尝试过很多事情。一开始,我在包含两个组件的标头时遇到了问题,但我已经设法通过 CMake 的安装修复了它:

install(
  TARGETS iface
  EXPORT ifaceTargets
  FILE_SET ifaceHeaders
  DESTINATION include)

install(
  EXPORT ifaceTargets
  FILE ifaceTargets.cmake
  NAMESPACE myproject::
  DESTINATION lib/cmake/iface)

install(
  TARGETS myLib
  EXPORT myLibTargets
  FILE_SET myLibHeaders
  DESTINATION myLib_include
  ARCHIVE_DESTINATION lib)

install(
  EXPORT myLibTargets
  FILE myLibTargets.cmake
  NAMESPACE myproject::
  lib/cmake/mylib)

但是,问题仍然是链接

myproject::myLib
会影响链接所有其他库。

我尝试在 Conan 文件的

cpp_info
部分添加组件信息,希望在设置
requires
字段时,我能够“覆盖”一些默认生成的依赖项:

def package(self):
    cmake = CMake(self)
    cmake.install()

def package_info(self):
    self.cpp_info.components["myLib"].libs = ["myLib"]
    self.cpp_info.components["myLib"].set_property("cmake_target_name", "myproject::myLib")
    self.cpp_info.components["myLib"].includedirs = ["myLib_include"]
    self.cpp_info.components["myLib"].requires = []

    self.cpp_info.components["iface"].set_property("cmake_target_name", "myproject::iface")
    self.cpp_info.components["iface"].includedirs = ["include"]
    self.cpp_info.components["iface"].requires = ["boost::boost", "openssl::openssl", "myotherlib::myotherlib"]    

但没有效果。链接

myproject::myLib
仍然链接 Boost 和其他库,我想在不原子化项目的情况下避免这种情况。

当所有目标/组件都在一个 CMake 项目和一个 Conan 文件中定义时,我如何实现这种传播链接的划分?如果不使用自己的 CMakeLists 和 Conan 文件将目标分离到不同的项目,这是否可能?

python c++ cmake conan
1个回答
0
投票

conan 的 github 线程下进行一些研究和对话后我得出的结论是,这不是 Conan 或 CMake 的东西,而只是静态/接口库的链接方式。

我的

iface
myLib
库与其他静态库“链接”,但没有像将静态库链接到其他静态库那样的东西。在这件事上还有很多事情我需要了解,但据我了解,它们都与分层树中的第一个共享库或可执行文件链接。编译静态库不会调用链接阶段,因此
target_link_libraries
反对这样会导致仅包含公共标头。

看起来没有办法将一个项目的 CMake/Conan 组件在静态依赖关系方面完全不同。 Conan 依赖项配方中的每个要求都将在链接阶段的某个位置参与。

如果有人证实这一点,我将不胜感激。否则,如果我说得对,我会检查他们的答案。

© www.soinside.com 2019 - 2024. All rights reserved.