admin 发布的文章

CMake从入门到精通

0. 了解

cmake是cross platform make的缩写,用于跨平台的工程构建和编译。它在make基础上,使用比make更加简单的语法来构建软件工程。cmake能感知系统和平台,生成不同的工程文件,比如unix的Makefile,Windows的sln或者苹果系统的XCode工程。

在Linux系统,比起手写Makefile来,cmake也是简单一些,目前很多开源软件都提供了cmake脚本来构建项目。在Linux下,cmake的功能是根据脚本,生成Makefile文件,用于构建。

1. 熟悉

1.1 环境搭建

Ubuntu系统,通过以下命令安装cmake

sudo apt-get install cmake

1.2 HelloWorld

先来一个最简单的例子,打开终端,输入以下命令:

mkdir HelloWorld
cd HelloWorld
touch CMakeLists.txt
touch main.c

编辑main.c和CMakeLists.txt

main.c内容如下:

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

CMakeLists.txt内容如下

project(HelloWorld)
add_executable(HelloWorld.bin main.c)

在HelloWorld目录下,执行以下命令:

mkdir build
cd build
cmake ..
make

编译后会产生一个HelloWorld.bin,执行它会输出HelloWorld

1.3 HelloWorld的解释

HelloWorld工程的CMakeLists.txt非常简单,简要介绍以下

# 指定工程名称为HelloWorld
project(HelloWorld)
# 用main.c编译HelloWorld.bin
add_executable(HelloWorld.bin main.c)

命令的解释:

mkdir build

由于cmake在编译时产生很多中间文件,为了隔离中间文件和源代码,一般会创建一个目录来存放中间文件,一般目录名字为build,这个是可选的,但是大家都这么做。

cd build
cmake ..

进入到中间目录,执行cmake命令,cmake命令的参数..表示CMakeLists.txt在上层目录,cmake命令会生成Makefile,同时做一些必要的环境检查。

make

编译

2 掌握

恭喜你,到这里时,你已经学会如何使用cmake来构建应用程序了。但是还不够的是,还是有许多的问题没有解决。

2.1 使用变量

使用变量能够使代码变得有可读性和可维护性,通过set指令,来定义变量,通过${}来引用变量。以上的CMakeLists.txt,也可以改成这样子:

project(HelloWorld)
set(src main.c)
add_executable(HelloWorld.bin ${src})

set(src main.c)表示定义一个变量src,让它等于main.c。如果一个工程有多个文件,那么可以写成这样子:

project(HelloWorld)
set(src main.c func.c foo.c)
add_executable(HelloWorld.bin ${src})

2.2 搜索目录

如果目录下有100个文件,10000个文件,这么写超级累,还是用大招吧。aux_source_directory可以将目录中的所有源码,加入到工程。

cmake_minimum_required(VERSION 3.7)
project(HelloWorld)
# set(src main.c foo.c func.c)
aux_source_directory(. src)
add_executable(HelloWorld.bin ${src})

注意上面的代码,set指令已经被注释了,取而代之的是aux_source_directory指令。

要注意的是,aux_source_directory这个指令,不会递归的搜索子目录,如果有子目录的代码也要加入,比如该目录下有一个sub目录,那么应该这样写:

cmake_minimum_required(VERSION 3.7)
project(HelloWorld)
# set(src main.c foo.c func.c)
aux_source_directory(. src)
aux_source_directory(./sub src)
add_executable(HelloWorld.bin ${src})

注意,从这里开始多了一行cmake_minimum_required(VERSION 3.7),这个表示要求用户的cmake版本是3.7以上

以后把代码写到一个目录,然后xxx就完事儿了,貌似是比make方便一些。

2.3 链接动态库

如果代码用了pthread_create,要链接一个动态库怎么办?不用着急,对cmake来说,是小意思。使用target_link_libraries,让最终目标链上动态库即可。不过要注意的是,target_link_libraries指令要放在add_executable指令之后。例子如下:

cmake_minimum_required(VERSION 3.7)
project(HelloWorld)
#set(src main.c foo.c func.c)
aux_source_directory(. src)
aux_source_directory(./sub src)
add_executable(HelloWorld.bin ${src})
target_link_libraries(HelloWorld.bin pthread)

上面的例子,HelloWorld.bin用了两次,这意味着将来如果要修改,那么可能会修改多次,可以使用变量优化一下。

cmake_minimum_required(VERSION 3.7)
project(HelloWorld)
set(target HelloWorld.bin)
aux_source_directory(. src)
aux_source_directory(./sub src)
add_executable(${target} ${src})
target_link_libraries(${target} pthread)

2.4 设置头文件目录和库目录

2.4.1 设置头文件目录

有时候需要链接第三方库,以及要包含第三方的头文件,cmake那么强大,这个自然也是小意思的,用include_directories就可以了,它可以同时指定多个目录。下面的代码没测试过,我就那么一写,读者可以去测试一下效果。

cmake_minimum_required(VERSION 3.7)
project(HelloWorld)
set(target HelloWorld.bin)
set(opencv_include /home/xueguoliang/opencv/include)
set(libevent_include /home/xueguoliang/libevent/include)
include_directories(${opencv_include} ${libevent_include})
aux_source_directory(. src)
aux_source_directory(./sub src)
add_executable(${target} ${src})
target_link_libraries(${target} pthread)

2.4.2 设置库目录

使用link_directories来设置库目录。比如

link_directories(/home/xueguoliang/opencv/lib /home/xueguoliang/libevent/lib)

2.5 编译目标是一个动态库或者静态库

add_library
set_target_properties

2.6 定义宏

可以通过指令add_definitions(-DFOO -DBAR ...),也可以在命令时通过cmake -DFOO来增加,也可以让cmake内置变量,是什么来着,忘记了,以上两种也够用了啊。

所有内置变量:https://cmake.org/cmake/help/v3.0/manual/cmake-variables.7.html

2.7 设置编译选项

使用add_compile_options(-std=c++11)来添加-std=c++11选项,其他选项也类似。

ubuntu下安装ffmpeg

在$HOME目录下编译安装ffmpeg

sudo apt-get install vim git qt-sdk ctags qtmultimedia5-dev
mkdir open
cd open
git clone https://github.com/FFmpeg/FFmpeg.git
sudo apt-get install libsdl2-dev
sudo apt-get install libx264-dev
sudo apt-get install libfaac-dev libfdk-aac-dev
./configure --prefix=/usr --enable-libx264 --enable-libfdk-aac --enable-gpl --enable-nonfree --disable-asm --enable-shared
make
sudo make install

在ubuntu14.04上安装obs

然后执行以下命令:

sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next
sudo apt-get update && sudo apt-get install ffmpeg
sudo add-apt-repository ppa:obsproject/obs-studio
sudo apt-get update && sudo apt-get install obs-studio

pip安装软件失败

由于运行了抓包软件fiddler,而fidder设置了SSL相关的东西,导致pip安装软件失败,报[SSL: CERTIFICATE_VERIFY_FAILED]错误,所以如果pip安装软件出现这种错误的话,请特别关注下是否启动了fiddler或者其他web抓包工具。

fflush和sync

问题由来

IO写操作为了提高效率,会将数据先写入缓冲区,然后在合适的时间再写入硬盘。但是缓冲区有系统级和应用级两层缓冲。

描述

fflush只是将应用层的数据写入系统级的缓冲区,而sync是将系统级的缓冲区,写入硬盘。所以如果只使用fflush,其实数据还是没有写入硬盘。