想象以下设置:
您有许多个人库和应用程序:
libA
、libB
、libC
、appA
、appB
,它们具有如下依赖树:
appA -> {libA}
libC -> {libA}
appB -> {libB, libC}
其中
appA
取决于 libA
,并且 appB
也从 libA
传递地依赖于 libC
。
所有库都在积极开发中,因此共享最新版本对于所有人来说都是有用的。
一种方法是将所有项目存储在同一级别,并使用
add_subdirectory()
:
.
├── appA
├── appB
├── libA
├── libB
└── libC
appA
CMakeLists.txt
例如:
add_executable(appA main.cpp)
add_subdirectory(../libA libA)
target_link_library(appA PRIVATE libA)
libC
CMakeLists.txt
例如:
add_library(libC ${libc_SRC})
add_subdirectory(../libA libA)
target_link_library(libC PUBLIC libA)
appB
CMakeLists.txt
例如:
add_executable(appB main.cpp)
add_subdirectory(../libB libB)
add_subdirectory(../libC libC)
target_link_library(appA PRIVATE libB libC)
这种方法效果很好,因为它将源代码直接添加到构建中,因此您可以直接从任何地方对其进行编辑,并且其他人都可以看到编辑内容(与使用包不同,因为这是基于最新安装的)。
但是,如果您想使用此环境之外的库(克隆
libA
并将其放置在 libC
的同一级别以便在其他地方使用 libC
?恶心,这种方法显然不起作用)
是否有某种方法可以设置
find_package()
,使其在设置了特定环境变量后与add_subdirectory()
完全一样?这样add_subdirectory()
的所有用途都可以被替换吗?我想提交更改,以便通过安装使用时它可以按预期工作,但随后我可以配置我的环境,以便它以上述开发方式工作
根据我所读到的内容,我想我可以回答我自己的问题:
使用以下内容更新每个库:
add_library(libA::libA ALIAS libA)
libA::libA
被添加为别名,即使通过调用 add_subdirectory(../libA libA)
包含库也是如此
现在,通过
libA
包含 add_subdirectory()
的应用程序可以链接到 libA::libA
,因为它仅指向 libA
target_link_libraries(appA PRIVATE libA::libA)
但是,由于
libC
依赖于 libA
,在构建 appA
的背景下,libC
知道 libA
,这很好,但是,如果将 libC
添加到另一个项目中,则可以构建它现在依赖于该项目添加 libA
来 target_link_libraries(libC INTERFACE libA::libA)
才能成功,这不好。
因此,我们仍然需要在
find_package(libA REQUIRED)
中调用 libC
来使该依赖项不透明,但如果我们不想将 libA
作为外部包使用,因此还没有安装它,则会失败。
所以解决办法就是检查
libA::libA
是否可用,如果不可用,则尝试使用find_package(libA REQUIRED)
例如
if (NOT TARGET libA::libA)
find_package(libA CONFIG REQUIRED)
endif()
现在,如果
libA
之前已通过 libC
可供 add_subdirectory(../libA libA)
使用,那么 libC
就可以找到它,因为它只是构建树中的另一个项目,并且它定义了符号 libA::libA
。但是,如果 libC
以其他方式使用,则 libA::libA
将不会被定义,因此它会尝试在安装位置找到它。如果成功,它会定义 libA::libA
(如果遵循通常的约定)。
所以无论哪种情况,
libC
都能找到它需要的东西。