CMake使用记录

发布时间 2023-11-26 20:29:15作者: -ssdq-

使用CMake写工程管理真的很方便,配合make或者ninja工具,用起来确实爽。

这里记录一个简单的使用示例,实现代码的分层管理。

cmake文件的标准步骤就是下面几个步骤:

  1. 确定cmake的最低版本要求;
  2. 确定project的名字;
  3. 确定需要加入编译的源文件列表;
  4. 确定需要加入编译的头文件路径清单;
  5. 确定最终输出的可执行文件/库文件;
  6. 确定project/target需要加入链接的库。

我这里实现一个主cmake文件以及3个子模块。

先确定目录分层

  • main目录,存放可执行文件的输出;
  • sub1目录,编译成sub1库,供main链接使用;
  • sub2目录,编译成sub2库,供sub1和main链接使用。
# tree -a
.
├── CMakeLists.txt
├── build-target.txt
├── main
│   ├── CMakeLists.txt
│   └── main.c
├── sub1
│   ├── CMakeLists.txt
│   ├── sub1.c
│   └── sub1.h
└── sub2
    ├── CMakeLists.txt
    ├── sub2.c
    └── sub2.h

 

根CMakeLists.txt文件

 1 cmake_minimum_required(VERSION 3.22 FATAL_ERROR)
 2 
 3 set(CMAKE_C_STANDARD 99)
 4 set(CMAKE_CXX_STANDARD 17)
 5 
 6 project(hello
 7     VERSION 1.0
 8     LANGUAGES C CXX ASM)
 9 
10 set(CMAKE_EXPORT_COMPILE_COMMANDS OFF)
11 set(CMAKE_VERBOSE_MAKEFILE OFF)
12 
13 
14 add_subdirectory(main)
15 add_subdirectory(sub1)
16 add_subdirectory(sub2)
根CMakeLists.txt

 

主目录下的文件详情

 1 #include <stdio.h>
 2 #include "sub1.h"
 3 #include "sub2.h"
 4 
 5 
 6 void function_defined_in_main(void) {
 7     printf("function_defined_in_main() invoked.\n");
 8 }
 9 
10 int main(void) {
11     printf("enter main function.\n");
12 
13     printf("invoke sub1() in main.\n");
14     sub1();
15 
16     printf("invoke sub2() in main.\n");
17     sub2();
18     
19     printf("exit main function.\n");
20     
21     printf("press Enter key to exit.\n");
22     getchar();
23     return 0;
24 }
main.c
 1 cmake_minimum_required(VERSION 3.22)
 2 
 3 set(TARGET "main")
 4 project(${TARGET} C CXX ASM)
 5 
 6 
 7 # 可执行输出
 8 add_executable(${TARGET} ${CMAKE_CURRENT_LIST_DIR}/main.c)
 9 
10 # 目标依赖的头文件路径
11 target_include_directories(${TARGET} PUBLIC
12     ${CMAKE_CURRENT_LIST_DIR}/../sub1
13     ${CMAKE_CURRENT_LIST_DIR}/../sub2
14     ${CMAKE_CURRENT_LIST_DIR})
15 
16 # 目标链接需要的库
17 target_link_libraries(${TARGET} PRIVATE sub1 sub2)
18 
19 # 指明优先在当前路径下查找库
20 target_link_directories(${TARGET} PRIVATE ${CMAKE_CURRENT_LIST_DIR})
main/CMakeLists.txt

 

目录sub1下的文件详情

 1 cmake_minimum_required(VERSION 3.22)
 2 
 3 set(TARGET "sub1")
 4 project(${TARGET} C CXX ASM)
 5 
 6 
 7 add_library(${TARGET} STATIC ${CMAKE_CURRENT_LIST_DIR}/sub1.c)
 8 
 9 # 目标依赖的头文件路径
10 target_include_directories(${TARGET} PUBLIC
11     ${CMAKE_CURRENT_LIST_DIR}
12     ${CMAKE_CURRENT_LIST_DIR}/../sub2)
sub1/CMakeLists.txt
 1 #include <stdio.h>
 2 #include "sub2.h"
 3 
 4 void function_defined_in_sub1(void) {
 5     printf("function_defined_in_sub1() invoked.\n");
 6 }
 7 
 8 void sub1(void) {
 9     printf("enter sub1 function.\n");
10     printf("invoke sub2() in library \"sub1\"\n");
11     sub2();
12     printf("exit sub1 function.\n");
13 }
sub1.c
1 #ifndef __SUB1_H__
2 #define __SUB1_H__
3 
4 
5 void sub1(void);
6 
7 #endif/*__SUB2_H__*/
sub1.h

 

目录sub2下的文件详情

 1 cmake_minimum_required(VERSION 3.22)
 2 
 3 set(TARGET "sub2")
 4 project(${TARGET} C CXX ASM)
 5 
 6 
 7 add_library(${TARGET} STATIC ${CMAKE_CURRENT_LIST_DIR}/sub2.c)
 8 
 9 
10 # 目标依赖的头文件路径
11 target_include_directories(${TARGET} PUBLIC
12     ${CMAKE_CURRENT_LIST_DIR})
sub2/CMakeLists.txt
 1 #include <stdio.h>
 2 
 3 extern void function_defined_in_main(void);
 4 extern void function_defined_in_sub1(void);
 5 
 6 void sub2(void) {
 7     printf("enter sub2 function.\n");
 8     printf("invoke function_defined_in_main in library \"sub2\".\n");
 9     function_defined_in_main();
10     printf("invoke function_defined_in_sub1 in library \"sub2\".\n");
11     function_defined_in_sub1();
12     
13     printf("exit sub2 function.\n");
14 }
sub2.c
1 #ifndef __SUB2_H__
2 #define __SUB2_H__
3 
4 
5 void sub2(void);
6 
7 #endif/*__SUB2_H__*/
sub2.h

 

编译命令

在根目录下执行cmake编译,将输出全部指定在 build 目录下。

  • “cmake -B build”表示将所有输出放到 build 目录下。
  • “./build/main/mian”是启动可执行文件。
# cmake -B build . && cd ./build && make && cd .. && ./build/main/main

 

输出结果

 1 root@lxxx:/mnt/d/workspace/hello# ls
 2 CMakeLists.txt  build-target.txt  main  sub1  sub2
 3 root@lxxx:/mnt/d/workspace/hello# cmake -B build . && cd ./build && make && cd .. && ./build/main/main
 4 -- The C compiler identification is GNU 11.4.0
 5 -- The CXX compiler identification is GNU 11.4.0
 6 -- The ASM compiler identification is GNU
 7 -- Found assembler: /usr/bin/cc
 8 -- Detecting C compiler ABI info
 9 -- Detecting C compiler ABI info - done
10 -- Check for working C compiler: /usr/bin/cc - skipped
11 -- Detecting C compile features
12 -- Detecting C compile features - done
13 -- Detecting CXX compiler ABI info
14 -- Detecting CXX compiler ABI info - done
15 -- Check for working CXX compiler: /usr/bin/c++ - skipped
16 -- Detecting CXX compile features
17 -- Detecting CXX compile features - done
18 -- Configuring done
19 -- Generating done
20 -- Build files have been written to: /mnt/d/workspace/hello/build
21 [ 16%] Building C object sub2/CMakeFiles/sub2.dir/sub2.c.o
22 [ 33%] Linking C static library libsub2.a
23 [ 33%] Built target sub2
24 [ 50%] Building C object sub1/CMakeFiles/sub1.dir/sub1.c.o
25 [ 66%] Linking C static library libsub1.a
26 [ 66%] Built target sub1
27 [ 83%] Building C object main/CMakeFiles/main.dir/main.c.o
28 [100%] Linking C executable main
29 [100%] Built target main
30 enter main function.
31 invoke sub1() in main.
32 enter sub1 function.
33 invoke sub2() in library "sub1"
34 enter sub2 function.
35 invoke function_defined_in_main in library "sub2".
36 function_defined_in_main() invoked.
37 invoke function_defined_in_sub1 in library "sub2".
38 function_defined_in_sub1() invoked.
39 exit sub2 function.
40 exit sub1 function.
41 invoke sub2() in main.
42 enter sub2 function.
43 invoke function_defined_in_main in library "sub2".
44 function_defined_in_main() invoked.
45 invoke function_defined_in_sub1 in library "sub2".
46 function_defined_in_sub1() invoked.
47 exit sub2 function.
48 exit main function.
49 press Enter key to exit.
50 
51 root@lxxx:/mnt/d/workspace/hello#
输出结果

 

 

特此记录。