CMake降低耦合

前言

这节课中的依赖是狭义的认为不需要提供的库不链接,换一句话说只有当前库中有调用另一个库的函数那么构成依赖。

预览

做法是将源代码文件(在这个案例中是 .cpp 文件,对于 C 项目将是 .c 文件)编译并打包成库文件。然后添加访问权级,让库可以被其他部分的项目代码链接和使用。
Cmake 权级如下:

范围 目标构建时 链接目标时 描述
PRIVATE 目标私有,库或路径仅用于构建当前目标,在当前目标的外部不可见。
INTERFACE 目标接口,用于目标接口的库或路径不直接用于构建目标,但会传递给链接此目标的其他目标。
PUBLIC 两者兼而有之,库或路径用于构建当前目标,且会传递给任何链接了该目标的其他目标。

[Pasted image 20231227225906.png]

课程文件

以下是(比飞鸟贵重的多_HKL)up 教程里的各个文件代码
add.hh

1
2
#pragma once
int add(int a, int b);

add.cpp

1
2
3
4
5
6
7
8
9
10
#include "common.h"
int add(int x, int y)

{

    printResult(x + y);

    return x + y;

}

calculator.h

1
2
3
4
5
6
7
8
9
10
11
class Calculator

{

public:

    int calcAdd(int x, int y);

    int calcSub(int x, int y);

};

calculator.cpp

1
2
3
4
5
6
7
8
9
10
11
#include "calculator.h"
#include "add.h"
#include "sub.h"
int Calculator::calcAdd(int x, int y)
{
    return add(x, y);
}
int Calculator::calcSub(int x, int y)
{
    return sub(x, y);
}

common.h

1
2
#pragma once
void printResult(int a);

common.cpp

1
2
3
4
5
6
#include <iostream>
void printResult(int a)

{
    std::cout << "result is: " << a << std::endl;
}

sub.h

1
2
#pragma once
int sub(int a, int b);

sub.cpp

1
2
3
4
5
6
#include "common.h"
int sub(int a, int b)
{
    printResult(a - b);
    return a - b;
}

文件关系处理

[Pasted image 20231227231456.png]
我们希望的是每一个库只取自己需要的部分来减轻依赖,而不是
[Pasted image 20231227231627.png]
这就要求我们对 cmakelists 进行配置

这是 add 的 CMakelists.txt 配置+解释

1
2
3
4
5
6
7
8
9
10
11
# add_library(add STATIC add.cpp)

#[[这行代码创建了一个名为 add 的静态库。静态库与动态库(共享库)不同,是将代码直接嵌入到最终可执行文件中。由于这个静态库在链接时会全部复制到最终的可执行文件,它不会在运行时引入额外的依赖性。]]

# target_link_libraries(add PRIVATE common)

#[[这行代码指定了库 add 链接了另一个库,这里假设为 common。使用 PRIVATE 关键字表示 common 库的链接仅仅对 add 库内部实现是必需的,而不会影响那些链接了 add 库的上层目标(比如可执行文件或其他库)。也就是说,对于链接了 add 的上层目标来说,common 这个依赖是看不见的,降低了这个依赖的传播。]]

# target_include_directories(add PUBLIC ./)

#[[这行代码设置了 add 库的公开头文件路径。使用 PUBLIC 关键字意味着如果一个目标链接了 add 库,那么这个目标也会自动具有对 add 公开头文件的访问权。这里 ./ 指的可能是库源代码的根目录。这样使得任何链接了 add 的上层目标都会正确地找到这个库的头文件,而不需要这些上层目标自己再去指定包含路径。这减少了使用 add 库的上层目标的配置负担,因为它们不需要知道 add 库头文件的具体位置。]]

一共三句话,构建库,指出依赖对象和权级,提供头文件路径。
[Pasted image 20231227232305.png]

依次配置四个文件的 CMakelists.txt 即可减小依赖。

后续

main.cpp 的同级下配置以下,以提供 cmake 路径

1
2
3
4
# add_subdirectory(common)
# add_subdirectory(add)
# add_subdirectory(sub)
# add_subdirectory(calculator)

构建可执行文件

1
2
3
# add_executable(lesson3_1 main.cpp)

# target_link_libraries(lesson3_1 calculator)

Q 1:
为什么 main 函数不需要构建静态库
A 1:
由于 main 函数是程序的起始点,它不是用于被其他函数或程序调用的,并不需要作为库中的一部分。库(无论是静态的还是动态的)是一组代码,其目的在于提供给其他程序调用,以实现代码复用或分离等目的。一个静态库或动态库包含了可以被各种不同程序重用的函数和数据。

最后顶级 CMakelists.txt 加上即可

1
add_subdirectory(lesson3_1)#去寻找cmake文件