cmake学习笔记

  • Post author:
  • Post category:其他




概念

cmake 是一个跨平台的自动构建工具(除了 cmake 之外,还有一些其它的自动构建工具,常用的譬如 automake、autoconf 等),cmake 的诞生主要是为了解决直接使用 make+Makefile 这种方式无法实现跨平台的问题,所以 cmake 是可以实现跨平台的编译工具,这是它最大的特点 。

  1. 开放源代码。我们可以直接从 cmake 官网


    下载到它的源代码

  2. 跨平台。cmake 并不直接编译、构建出最终的可执行文件或库文件,它允许开发者编写一种与平台无关的 CMakeLists.txt 文件来制定整个工程的编译流程,cmake 工具会解析 CMakeLists.txt 文件语法规则,再根据当前的编译平台,生成本地化的 Makefile 和工程文件,最后通过 make 工具来编译整个工程
  3. 语法规则简单。



cmake与Makefile关系

在这里插入图片描述



cmake的使用方法

sudo apt-get install cmake

安装完成之后可以通过 cmake –version 命令查看 cmake的版本号。cmake 官方也给大家提供相应教程,链接地址如下所示:

文档总链接地址:



培训教程:

https://cmake.org/cmake/help/latest/guide/tutorial/index.html

  1. 单一源文件

    源码代码:

main.c

#include <stdio.h>
int main()
{
 printf("Hello World!\n");
 return 0;
}

CMakeList.txt

project(HELLO) #project 是一个命令,命令的使用方式有点类似于 C 语言中的函数,因为命令后面需要提供一对括号,并且通常需要我们提供参数,多个参数使用空格分隔而不是逗号“,”。project 命令用于设置工程的名称,括号中的参数 HELLO 便是我们要设置的工程名称;设置工程名称并不是强制性的,但是最好加上。
add_executable(hello ./main.c) #add_executable 同样也是一个命令,用于生成一个可执行文件,在本例中传入了两个参数,第一个参数表示生成的可执行文件对应的文件名,第二个参数表示对应的源文件

执行命令:

cmake ./   #生成Makefile
make
./hello


out-of-source方式构建

cmake 生成的文件以及最终的可执行文件 hello 与工程的源码文件 main.c 混在了一起,这使得工程看起来非常乱,当我们需要清理 cmake 产生的文件时将变得非常麻烦,这不是我们想看到的;我们需要将构建过程生成的文件与源文件分离开来,不让它们混杂在一起,也就是使用 out-of-source 方式构建

mkdir build
cd build
cmake ../
make
./hello
cd ..
rm -rf build #删除编译的结果(很关键)
  1. 多个源文件

    hello.h:
#ifndef __TEST_HELLO_
#define __TEST_HELLO_
void hello(const char *name);
#endif //__TEST_HELLO_

hello.c:

#include <stdio.h>
#include "hello.h"
void hello(const char *name)
{
 printf("Hello %s!\n", name);
}

main.c:

#include "hello.h"
int main(void)
{
 hello("World");
 return 0;
}

CMakeList.txt:

project(HELLO)
set(SRC_LIST main.c hello.c)
add_executable(hello ${SRC_LIST}) #使用到了 set 命令,set 命令用于设置变量,如果变量不存在则创建该变量并设置它
  1. 生成库文件

    CMakeList.txt:
project(HELLO)
add_library(libhello hello.c) #生成静态库.a文件
add_executable(hello main.c)
target_link_libraries(hello libhello) #target_link_libraries 命令为目标指定依赖库,在本例中,hello.c 被编译为库文件,并将其链接进 hello 程序。

如果要生成动态库文件,可以这样做:

add_library(libhello SHARED hello.c) #生成动态库文件
add_library(libhello STATIC hello.c) #生成静态库文件


修改生成的库文件名字
add_library(hello hello.c) #不能修改生成库的名称,因为不能直接修改 add_library 命令的参数
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello") #用于设置目标的属性,这里通过 set_target_properties 命令对 libhello 目标的OUTPUT_NAME 属性进行了设置,将其设置为 hello

CMakeList.txt:

cmake_minimum_required(VERSION 3.5) #要求的最低的版本
project(HELLO)
add_library(libhello SHARED hello.c) #动态库
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello") #"hello" 属性
add_executable(hello main.c)
target_link_libraries(hello libhello) #参考上文,应用程序名称
  1. 将源文件组织到不同的目录
# tree
.
├── build
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── 3.16.3
│   │   │   ├── CMakeCCompiler.cmake
│   │   │   ├── CMakeCXXCompiler.cmake
│   │   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   │   ├── CMakeSystem.cmake
│   │   │   ├── CompilerIdC
│   │   │   │   ├── a.out
│   │   │   │   ├── CMakeCCompilerId.c
│   │   │   │   └── tmp
│   │   │   └── CompilerIdCXX
│   │   │       ├── a.out
│   │   │       ├── CMakeCXXCompilerId.cpp
│   │   │       └── tmp
│   │   ├── cmake.check_cache
│   │   ├── CMakeDirectoryInformation.cmake
│   │   ├── CMakeOutput.log
│   │   ├── CMakeTmp
│   │   ├── Makefile2
│   │   ├── Makefile.cmake
│   │   ├── progress.marks
│   │   └── TargetDirectories.txt
│   ├── cmake_install.cmake
│   ├── libhello
│   │   ├── CMakeFiles
│   │   │   ├── CMakeDirectoryInformation.cmake
│   │   │   ├── libhello.dir
│   │   │   │   ├── build.make
│   │   │   │   ├── C.includecache
│   │   │   │   ├── cmake_clean.cmake
│   │   │   │   ├── cmake_clean_target.cmake
│   │   │   │   ├── DependInfo.cmake
│   │   │   │   ├── depend.internal
│   │   │   │   ├── depend.make
│   │   │   │   ├── flags.make
│   │   │   │   ├── hello.c.o
│   │   │   │   ├── link.txt
│   │   │   │   └── progress.make
│   │   │   └── progress.marks
│   │   ├── cmake_install.cmake
│   │   ├── libhello.a
│   │   └── Makefile
│   ├── Makefile
│   └── src
│       ├── CMakeFiles
│       │   ├── CMakeDirectoryInformation.cmake
│       │   ├── hello.dir
│       │   │   ├── build.make
│       │   │   ├── C.includecache
│       │   │   ├── cmake_clean.cmake
│       │   │   ├── DependInfo.cmake
│       │   │   ├── depend.internal
│       │   │   ├── depend.make
│       │   │   ├── flags.make
│       │   │   ├── link.txt
│       │   │   ├── main.c.o
│       │   │   └── progress.make
│       │   └── progress.marks
│       ├── cmake_install.cmake
│       ├── hello
│       └── Makefile
├── CMakeLists.txt #顶层CMakeLists.txt
├── libhello
│   ├── CMakeLists.txt #CMakeLists.txt,在src文件夹中
│   ├── hello.c
│   └── hello.h
└── src
    ├── CMakeLists.txt #CMakeList.txt,在libhello文件夹中
    └── main.c
16 directories, 56 files


顶层 CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(HELLO)
add_subdirectory(libhello) #子目录
add_subdirectory(src)  #子目录


src 目录下的 CMakeLists.txt
include_directories(${PROJECT_SOURCE_DIR}/libhello) #新增加了 include_directories 命令用来指明头文件所在的路径,并且使用到了 PROJECT_SOURCE_DIR 变量,该变量指向了一个路径,从命名上可知,该变量表示工程源码的目录。
add_executable(hello main.c)
target_link_libraries(hello libhello)


libhello 目录下的 CMakeLists.txt
add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
  1. 将生成的可执行文件和库文件放置到单独的目录下

    在默认情况下,make 编译生成的可执行文件和库文件会与 cmake 命令产生的中间文件(CMakeCache.txt、CmakeFiles、cmake_install.cmake 以及 Makefile 等)混在一起,也就是它们在同一个目录下;如果我想让可执行文件单独放置在 bin 目录下,而库文件单独放置在 lib 目录下,就像下面这样:

    (1)将 src 目录下的 CMakeList.txt 文件进行修改:
include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) #设置bin文件夹
add_executable(hello main.c)
target_link_libraries(hello libhello)

(2)对 libhello 目录下的 CMakeList.txt 文件进行修改:

set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

文件结构:

#tree
.
├── build
│   ├── bin
│   │   └── hello
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── 3.16.3
│   │   │   ├── CMakeCCompiler.cmake
│   │   │   ├── CMakeCXXCompiler.cmake
│   │   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   │   ├── CMakeSystem.cmake
│   │   │   ├── CompilerIdC
│   │   │   │   ├── a.out
│   │   │   │   ├── CMakeCCompilerId.c
│   │   │   │   └── tmp
│   │   │   └── CompilerIdCXX
│   │   │       ├── a.out
│   │   │       ├── CMakeCXXCompilerId.cpp
│   │   │       └── tmp
│   │   ├── cmake.check_cache
│   │   ├── CMakeDirectoryInformation.cmake
│   │   ├── CMakeOutput.log
│   │   ├── CMakeTmp
│   │   ├── Makefile2
│   │   ├── Makefile.cmake
│   │   ├── progress.marks
│   │   └── TargetDirectories.txt
│   ├── cmake_install.cmake
│   ├── lib
│   │   └── libhello.a
│   ├── libhello
│   │   ├── CMakeFiles
│   │   │   ├── CMakeDirectoryInformation.cmake
│   │   │   ├── libhello.dir
│   │   │   │   ├── build.make
│   │   │   │   ├── C.includecache
│   │   │   │   ├── cmake_clean.cmake
│   │   │   │   ├── cmake_clean_target.cmake
│   │   │   │   ├── DependInfo.cmake
│   │   │   │   ├── depend.internal
│   │   │   │   ├── depend.make
│   │   │   │   ├── flags.make
│   │   │   │   ├── hello.c.o
│   │   │   │   ├── link.txt
│   │   │   │   └── progress.make
│   │   │   └── progress.marks
│   │   ├── cmake_install.cmake
│   │   └── Makefile
│   ├── Makefile
│   └── src
│       ├── CMakeFiles
│       │   ├── CMakeDirectoryInformation.cmake
│       │   ├── hello.dir
│       │   │   ├── build.make
│       │   │   ├── C.includecache
│       │   │   ├── cmake_clean.cmake
│       │   │   ├── DependInfo.cmake
│       │   │   ├── depend.internal
│       │   │   ├── depend.make
│       │   │   ├── flags.make
│       │   │   ├── link.txt
│       │   │   ├── main.c.o
│       │   │   └── progress.make
│       │   └── progress.marks
│       ├── cmake_install.cmake
│       └── Makefile
├── CMakeLists.txt
├── libhello
│   ├── CMakeLists.txt
│   ├── hello.c
│   └── hello.h
└── src
    ├── CMakeLists.txt
    └── main.c

18 directories, 56 files



版权声明:本文为wangwenzhou0624原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。