我们有一个存储库,其中代码的结构类似于下面的方式(最小的示例):
CMakeExample
├── Apps
│ ├── App1
│ │ ├── AppSpecificHeader.h
│ │ ├── CMakeLists.txt
│ │ └── main.c
│ ├── App2
│ │ ├── AppSpecificHeader.h
│ │ ├── CMakeLists.txt
│ │ └── main.c
│ └── CMakeLists.txt
├── CMakeLists.txt
└── Libs
├── CMakeLists.txt
├── Lib1
│ ├── CMakeLists.txt
│ ├── Lib1.c
│ └── Lib1.h
└── Lib2
├── CMakeLists.txt
├── Lib2.c
└── Lib2.h
在一个CMake项目中,我们构建了几个静态库和几个使用这些库的应用程序。
问题是一些静态库依赖于特定于应用程序的头文件。这意味着App1想要一个Lib1版本的Lib1.c在编译时包含了它的AppSpecificHeader,而App2想要一个Lib1版本的Lib1在编译时包含了AppSpecificHeader。当然,Lib2也可能依赖于Lib1,这可能会使事情进一步复杂化(?)。
到目前为止,我们所做的是根本不将Lib1构建为lib,而是包含一个文件Lib1。cmake,在每个应用程序中,以便Lib1作为各自应用程序的一部分构建。当然,如果Lib2依赖于Lib1,那么它也必须作为应用程序的一部分进行编译,即使它不直接依赖于特定于应用程序的头文件。
这个解决方法工作得相当好,但据我所知,这是一个非常糟糕的做法。然而,我们似乎找不到一个CMake机制来适应我们想要的,使用"现代"。CMake .
我们已经探索了创建一个只包含AppSpecificHeader的接口库的可能性,并使Lib1依赖于它,但是当试图在每个应用程序中创建两个具有相同名称的接口库时,这就进入了死胡同。
我们还考虑添加一个标志来指定我们想要构建的应用程序。然而,这将导致不得不多次构建,并延长编译时间。
我们是否遇到了CMake的限制?
任何关于解决方案或改进的建议都将非常感谢。
更新:应用程序/App1 AppSpecificHeader.h
#ifndef APP_SPECIFIC_HEADER_H
#define APP_SPECIFIC_HEADER_H
#define CONSTANT_CONFIG_VALUE 5U
#endif
应用程序/App2 AppSpecificHeader.h
#ifndef APP_SPECIFIC_HEADER_H
#define APP_SPECIFIC_HEADER_H
#define CONSTANT_CONFIG_VALUE 6U
#endif
/Libs/Lib1 Lib1.c
#include "Lib1.h"
#include "AppSpecificHeader.h"
void foo()
{
uint8_t val = CONSTANT_CONFIG_VALUE;
}
您所展示的库正在使用来自特定于应用程序的头文件的宏值为成员的默认初始化定义一个结构体。我会考虑以下选项。
-
你可以看看是否可以在库中声明一个默认构造函数,并且只在进行默认初始化的应用程序中实现它。在这种情况下,库永远不会
#include
特定于应用程序的头文件或使用它们的宏——应用程序将实现这些库结构的默认构造函数。或者如果这不起作用,看看你是否愿意需要一个(新的)手动初始化函数,该函数在库中声明并在应用程序中定义。
-
有一个非常非常非常小的机会,你可以将结构体的定义完全移动到应用程序本身,并且只在库中使用该结构体的前向声明。
-
就像你说的,你可以创建和你拥有的应用程序一样多的库版本。使用这种方法,将这些特定于应用程序的头分别放在它们自己的接口库目标中,然后将每个其他库也定义为接口库,然后创建实际的(静态/共享)库目标,每个库目标链接到特定于应用程序的头接口库目标和非特定于应用程序的接口库目标。这种方法的好处是,在用于创建实际库目标的两层
foreach
循环(一层用于特定于应用程序的接口目标,一层用于非特定于应用程序的接口目标)中,它将非常简单:add_library
和两个target_link_libraries
。或者你可以看看CMake的方法,在这里你不用接口目标,而是在两层
foreach
循环中完成大部分工作。