添加库

添加库

我们可以将平方根函数重写并编译成库,用来代替数学库中的函数

添加并使用MathFunctions库

首先创建一个名为MathFunctions的文件夹,先写好函数:

1
2
/* MathFunctions.h */
double mysqrt(double x);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* mysqrt.c */
#include <stdio.h>

// a hack square root calculation using simple operations
double mysqrt(double x)
{
if (x <= 0) {
return 0;
}

double result = x;

// do ten iterations
for (int i = 0; i < 10; ++i) {
if (result <= 0) {
result = 0.1;
}
double delta = x - (result * result);
result = result + 0.5 * delta / result;
}
return result;
}

接着写CMakeLists,因为这个编译生成库属于子项目,相关语言参数都会从上一层的CMakeLists传过来,所以我们只用写一行,这行的作用就是通过mysqrt.c生成一个名为MathFunctions的库:

1
add_library(MathFunctions mysqrt.c)

编写主CMakeLists,添加子项目目录,以及使用MathFunctions库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# set the cmake version
cmake_minimum_required(VERSION 3.5)

# set the project name
project(tutorial VERSION 0.0.1 LANGUAGES C)

# The set is used to set the value of a parameter
set (MAJOR_VERSION 0)
set (MINOR_VERSION 1)

# set the configure file
configure_file(
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)

# add subdirectory
add_subdirectory(MathFunctions)

# add the executable
add_executable(Tutorial tutorial.c)

# set link libraries
target_link_libraries(Tutorial PUBLIC MathFunctions m)

# set include directories
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/MathFunctions"
)

指定了子项目的目录以后,会自动寻找子目录的CMakeLists,可以看到除了之前的math库,多加了一个MathFunctions库,最后指定了头文件夹的目录

再修改下程序代码,添加头文件并将函数sqrt()改为mysqrt():

1
double outputValue = mysqrt(inputValue);

到此就完成了库的添加工作

添加编译条件

既然有两个库都可以提供相同的功能,那么把选择使用哪个交给用户选择。这个功能在多平台的代码中比较常见,因为平台的不同,一些函数的使用方式或是参数类型也可能不同。CMakeLists如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# set the cmake version
cmake_minimum_required(VERSION 3.5)

# set the project name
project(tutorial VERSION 0.0.1 LANGUAGES C)

# The set is used to set the value of a parameter
set (MAJOR_VERSION 0)
set (MINOR_VERSION 1)

# add option USE_MYMATH ,default value is ON
option(USE_MYMATH "Use tutorial provided math implementation" ON)

# set the configure file
configure_file(
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)

if(USE_MYMATH)
# add subdirectory
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
else()
list(APPEND EXTRA_LIBS m)
endif()


# add the executable
add_executable(Tutorial tutorial.c)

# set link libraries
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})

# set include directories
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
${EXTRA_INCLUDES}
)

option参数即为选项,可以设置默认为,当前设置为ON,同时使用变量EXTRA_LIBS来存所有需要链接的库,使用EXTRA_INCLUDES来存用到的头文件的目录,最后使用变量替代之前的绝对路径

更新配置文件,以及代码,添加宏和宏判断:

1
2
3
4
/* config.h.in */
#define MAJOR_VERSION @MAJOR_VERSION@
#define MINOR_VERSION @MINOR_VERSION@
#cmakedefine USE_MYMATH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* tutorial.c */
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#ifndef USE_MYMATH
#include <math.h>
#else
#include "MathFunctions.h"
#endif


int main (int argc, char *argv[])
{
if (argc < 2)
{
fprintf (stdout, "Usage: %s number\nversion is %d.%d\n", argv[0], MAJOR_VERSION, MINOR_VERSION);
return 1;
}

double inputValue = atof (argv[1]);
#ifndef USE_MYMATH
double outputValue = sqrt(inputValue);
fprintf (stdout, "The square root of %g is %g\n", inputValue, outputValue);
#else
double outputValue = mysqrt(inputValue);
fprintf (stdout, "The mysqrt root of %g is %g\n", inputValue, outputValue);
#endif
return 0;
}

构建项目

使用USE_MYMATH选项的默认值,在build目录中输入以下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/carl/test/cmake/build

$ make
-- Configuring done
-- Generating done
-- Build files have been written to: /home/carl/test/cmake/build
Scanning dependencies of target Tutorial
[ 50%] Building C object CMakeFiles/Tutorial.dir/tutorial.c.o
[100%] Linking C executable Tutorial
[100%] Built target Tutorial

$ ./Tutorial 100
The square root of 100 is 10

设置USE_MYMATH选项为ON,在build目录中输入以下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cmake .. -DUSE_MYMATH=ON
-- Configuring done
-- Generating done
-- Build files have been written to: /home/carl/test/cmake/build

$ make
Scanning dependencies of target MathFunctions
[ 25%] Building C object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.c.o
[ 50%] Linking C static library libMathFunctions.a
[ 50%] Built target MathFunctions
Scanning dependencies of target Tutorial
[ 75%] Building C object CMakeFiles/Tutorial.dir/tutorial.c.o
[100%] Linking C executable Tutorial
[100%] Built target Tutorial

$ ./Tutorial 100
The mysqrt root of 100 is 10

可以明显的看出在make时多编译了一个我们自己写的库

添加库的使用要求

为了更好的控制库的链接和头文件之间的关系,我们将头文件与库进行关联,规定使用库的时候也要使用它的头文件,即在MathFunctions文件夹的CMakelists末尾添加:

1
2
3
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)

INTERFACE意味着使用者需要但制造者可能不需要的东西

这样只要使用这个库就会默认包含它的头文件,如果不使用则不包含。

接着删除顶层CMakelists对库MathFunctions的头文件的引用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if(USE_MYMATH)
# add subdirectory
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
# list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
else()
list(APPEND EXTRA_LIBS m)
endif()


# add the executable
add_executable(Tutorial tutorial.c)

# set link libraries
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})

# set include directories
target_include_directories(Tutorial PUBLIC
# "${PROJECT_BINARY_DIR}"
${EXTRA_INCLUDES}
)

添加库
https://carl-5535.github.io/2021/08/11/CMake/添加库/
作者
Carl Chen
发布于
2021年8月11日
许可协议