我想优化我的 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 文件将目标分离到不同的项目,这是否可能?
在 conan 的 github 线程下进行一些研究和对话后我得出的结论是,这不是 Conan 或 CMake 的东西,而只是静态/接口库的链接方式。
我的
iface
和 myLib
库与其他静态库“链接”,但没有像将静态库链接到其他静态库那样的东西。在这件事上还有很多事情我需要了解,但据我了解,它们都与分层树中的第一个共享库或可执行文件链接。编译静态库不会调用链接阶段,因此 target_link_libraries
反对这样会导致仅包含公共标头。
看起来没有办法将一个项目的 CMake/Conan 组件在静态依赖关系方面完全不同。 Conan 依赖项配方中的每个要求都将在链接阶段的某个位置参与。
如果有人证实这一点,我将不胜感激。否则,如果我说得对,我会检查他们的答案。