抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Cmake的使用

CMake是什么

Cmake是一种跨平台的项目构建工具,它使用符合CMake要求的项目生成平台原生的项目,从而利用平台原生的工具来构建你的项目。

例如:

平台类型 生成的项目类型
UNIX/LINUX Makefile构建的项目
Windows Visual Studio项目
Mac OS XCode项目

CMake的用法

cmake [路径] 

即可生成对应的项目,以Linux平台为例,cmake可以为我们制作出Makefile项目,再执行

make

即可得到我们想要的可执行文件

CMake构建的项目

何为CMake构建的项目?CMake构建的项目使用CMakeLists.txt文件来描述项目的组织情况,一个CMakeLists.txt应该具有如下要素

cmake_minimum_required(VERSION 构建此项目所需的最低cmake版本)
project(项目名)

# 添加一个可执行文件
add_executable(可执行文件名 组成该可执行文件的所有源代码文件名的列表)

# 添加一个静态库
add_library(库名 STATIC 组成该库的所有源代码文件名的列表)

# 将两个或多个target[s]链接起来
target_link_libraries(生成的target[可执行文件名/库名] 它所需链接的target[s]列表)

第一句,制定了此项目所需的最低cmake版本,一般地,此版本应设置为3.0.0

第二句,设定了该项目的名称;

第三句,设定了一个可执行文件作为target(目标),即此句话的目的是生成该目标,而为了生成该目标,需要对它进行一些描述,一般是指构建它所需的所有源文件名;

第四句,设定了一个库作为target(目标),即此句话的目的是生成该目标;

第五句,用于在需要链接外部库或自己定义的库的时候,用于将它们链接起来。

一些实例

HelloWorld

俗话说得好,不知道写什么的时候就写Hello,World!其实是我说的

项目中文件如下

  • main.c
  • CMakeLists.txt
# CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(helloworld)

add_executable(hello main.c)
// main.c
#include <stdio.h>

int main()
{
printf("Hello,World!\n");
}

再执行

# .代表当前目录,..代表上级目录
cmake .
make

即可得到可执行文件hello了

多文件项目

项目中文件如下

  • main.c
  • add.h
  • add.c
  • CMakeLists.txt
# CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(add_test)

add_executable(add_test_exec main.c add.c)
// add.h
#ifndef __FUNC_H__
#define __FUNC_H__

int add(int, int);

#endif // __FUNC_H__
// add.c
#include "add.h"

int add(int a, int b)
{
return a + b;
}
// main.c
#include "add.h"
#include <stdio.h>

int main()
{
printf("%d\n", add(1, 2));
}

库项目

库是什么?库是程序的一部分,但它不可以直接执行,通常库中包含了库所编写的函数的实现,但并没有main函数,即它不能自己执行,需要别的程序来调用它才能执行。从链接方式上来看,库分为静态库(static)和动态库(dynamic)。

静态库类似多文件项目中,某源文件编译过程中生成的二进制文件,它保留了函数入口及实现。将在链接后被包含到可执行文件中;

动态库在链接时仅告诉可执行文件一些函数的信息,而不告诉它具体的实现,而在运行时,可执行文件会在某些规则下寻找动态库文件并将其载入内存中进行函数调用。

不难看出,动态库的优点在于节省了可执行文件的体积,而且多个不同的可执行文件可以共享一份动态库文件,从而有效节约硬盘资源。但其也有弊端,比如程序在别的计算机上运行时,可能那台计算机并没有所需的动态库,则需要将动态库也拷贝一份,否则程序将无法执行,而使用静态库的程序只要拷贝一个可执行文件就可以运行了。

此处我们使用一个静态库项目来举例

项目中文件如下

  • add.h
  • add.c
  • CMakeLists.txt
# CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(add)

# static是指生成静态库
add_library(add STATIC add.c)
// add.h
#ifndef __FUNC_H__
#define __FUNC_H__

int add(int, int);

#endif // __FUNC_H__
// add.c
#include "add.h"

int add(int a, int b)
{
return a + b;
}

Linux平台下构建得到libadd.a文件,a是指archive,译为档案,就是静态库的意思,add是我们生成的库名,通过执行

ar -t ./libadd.a 

可以得到这个档案中所包含的内容,此处为add.c.o,正是我们add.c在编译时产生的二进制文件!也就是称库与源文件编译过程中生成的二进制文件类似的原因。

同理Windows下会得到后缀名为lib的库文件,lib是library的意思。

使用库的项目

我们写好了一个库,那就要给别人/自己用啊。如何利用cmake来将库加入自己的项目中呢?

项目中文件如下

  • add.h
  • main.c
  • libadd.a
  • CMakeLists.txt
# CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(test_lib_add)

# 此处指定了库所在的目录,如果不指定的话,系统会在系统设置的环境变量中遍历寻找
link_directories(.)

add_executable(test_lib_add main.c)

# 将add库与测试add的项目链接起来
target_link_libraries(test_lib_add add)
// add.h
#ifndef __FUNC_H__
#define __FUNC_H__

int add(int, int);

#endif // __FUNC_H__
// main.c
#include "add.h"
#include <stdio.h>

int main()
{
printf("%d\n", add(1, 2));
}

想要使用库文件,必须知道我们需要使用的函数的定义,即拥有上例add库的头文件add.h

而在链接时需要函数实现,故还需add库生成的libadd.a文件

我们与多文件项目相比可谓是多此一举,但使用库有什么意义呢?

答案是隐藏了你的源码。在使用库的项目测试中,无需add.c来告诉编译器add函数如何实现,只是借add.h告诉了编译器:“我有个函数叫add,使用两个int做参数,使用int做返回值,你看着办!” 而编译器会在链接时,尝试找到所有未实现的函数并把它们的定义和其实现(在库文件中)进行关联,从而生成可执行程序。

而且用户无需考虑你的具体实现,只要调用它即可。现在很多项目都是使用这种方法来提供自己的API(Application Programming Interface,类似于此处的函数定义)的。

其他实例

更多实例请看这个开源项目

评论