【Ubuntu】cmake用法的简单总结

本文全部内容都是从此篇博文中抽取的总结,感谢[爱是恒久忍耐1989]大佬。

一定要看完原博文再来看这篇,否则很乱。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

通常,一个工程的组成,需要.h文件,以及.h对应的.c文件,再加上包含主函数的main.c文件。

如果不想让别人看到某些函数内部的具体代码,可以只保留这些函数对应的.h文件,丢掉.c文件,转而用静态链接或动态链接代替。

cmake可以用来生成对应.h/.c/main.c的Makeile文档,也可以生成对应.h/(动态/静态)链接的Makefile文档,关键在于如何编写CMakeLists.txt文件。

下面就分情况递进得展示CMakeLists.txt文件如何编写。

一、CMakeLists.txt的最简单用法

在一个空文件夹test中,创建储存函数的文件testFunc.c如下:

#include <stdio.h>
#include "testFunc.h"

void func(int data)
{
	printf("data is %d\n", data);
}

创建与testFunc.c对应的.h文件如下:

#ifndef _test_FUNC_H
#define _test_FUNC_H

void func(int data);

#endif

在test文件夹中,创建main.c,并编辑如下:

#include <stdio.h>

int main(void)
{
      func(100);

	return 0;
}

然后,仍然是在test文件夹中,编写CMakeLists.txt如下:

cmake_minimum_required(VERSION 2.8)

project(demo)

add_executable(main main.c)

其中,cmake_minimum和project两条语句是必写的,一个规定了对cmake版本的最低要求,另一个规定了本项目的名字。

add_executable(main main.c)是指本项目要用到的.c文件是main.c,且将本项目最终生成的可执行文件命名为main。

然后在test文件夹中执行cmake ..   、 make即可生成可执行文件。 

这种所有.c和所有.h都在同一目录下的情况,在编写CMakeLists.txt时不需要写入include_directories(用来指出.h文件存放在哪里)等语句,只需将所有的.c文件塞入add_executable中即可。

(后面就不把各个文件的内容都明确写出来了,原博客里都有。本文只写出MakeLists文件)

二、当有多个函数时,也可以方便得用aux_source_directiory语句,将所有的.c文件存入某个自定义的变量中。如下:

在test文件夹中,有testFunc.c、testFunc.h、testFunc1.c、testFunc1.h,以及main.c。

现在仍是所有文件同属一个文件夹下的情况。

为了方便,可引入aux_source_directory语句,编写MakeLists.txt文件如下:

cmake_minimum_required(VERSION 2.8)

project(demo)

aux_source_directory(. SRC_LIST)

add_executable(main ${SRC_LIST})

这里只是为了强调一下aux_source_directory的作用,是将某目录下的所有.c文件封装到一个自定义的变量中。

三、为了方便查找,我们将不同函数的.c、.h文件分别放到不同的文件夹中,而 main.c 和 CMakeLists.txt 都放在项目的根目录(本文即为test)下,文件树如下:

这里写图片描述

这时要如何编写CMakeLists.txt呢?如下:

cmake_minimum_required(VERSION 2.8)

project(demo)

include_directories(test_func test_func1)#这条语句的参数是文件夹名称,可以有多个参数,这条语句会自动把每个参数文件夹中包含的.h文件纳入到程序中来

aux_source_directory(test_func SRC_LIST)#这条语句只能有一个文件夹、一个自定义的变量作为参数,不可有多个。这条语句会自动把每个参数文件夹中包含的.c文件纳入到程序中来

aux_source_directory(test_func1 SRC_LIST1)#同上

add_executable(main main.c ${SRC_LIST} ${SRC_LIST1})

这个例子最主要的特点是,.h文件包含在多个不同的路径中,而不像之前都只在一个路径中。这种情况下,就要用include_directories函数把所有包含.h的路径都纳入进来。

另外,不需过于害怕aux_source_directory语句,它只是为了方便得将文件夹中的所有.c文件纳入到一个变量中,从而方便add_executable的使用。

四、为了方便查找与使用,通常,项目的根目录(本文即为test)下要包含4个子目录,即bin、build、include、src,其中,src存放所有的.c文件(包含main.c及所有函数的.c文件),include存放所有的.h文件,build存放cmake产生的文件,bin存放最后生成的可执行文件。

文件树结构如下:

这里写图片描述

这种情况下,需要在test中有一个CMakeLists.txt文件,另外在src中还有一个CMakeLists.txt文件。

test中的CMakeLists.txt文件是为了说明源文件在哪里,即src在哪里;而src中的CMakeLists.txt文件是为了说明.h等文件在哪里。

其中,test中的CMakeLists.txt文件如下:

cmake_minimum_required(VERSION 2.8)

project(demo)

add_subdirectory(src)

add_subdirectoroy就是为了告诉程序,源文件(即.c文件)在哪个文件夹里。

而对于src中的CMakeLists.txt,注意,就不必写 cmake_minimum_required 和 project 两条语句了。src中CMakeLists.txt文件如下:

aux_source_directory(. SRC_LIST)

include_directories(../include)

add_executable(main SRC_LIST)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

对比第“三”步中的CMakeLists.txt文件,不难发现,这个src中的CMakeLists.txt文件也包含

(1)指明.h文件所在的include文件夹

(2)将所有.c文件包含到某个或某些变量中

(3)add_executable

三个步骤。

但除此之外,这里还加了set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)这条语句,这是为了规定将生成的可执行文件放在bin文件夹下。

最后去build目录下执行cmake ..,然后执行make,就能在bin中找到生成的可执行文件了。

五、创建静态库和动态库

将文件树重建为如下结构:

这里写图片描述

test中存着一个CMakeLists.txt文件,以及build、lib、lib_testFunc三个文件夹,其中,build文件夹用来存放cmake生成的文件,lib用来存放最终得到的静态库和动态库文件,lib_testFunc中存放着所需的所有.c文件和.h文件。

test中的CMakeLists.txt文件内容如下,与第“四”步中的一样:

cmake_minimum_required(VERSION 2.8)

project(demo)

add_subdirectory(lib_testFunc)

而lib_testFunc中的CMakeLists.txt文件内容如下:

aux_source_directory(. SRC_LIST)

add_library(testFunc_shared SHARED ${SRC_LIST})
add_library(testFunc_static STATIC ${SRC_LIST})

set_target_properties(testFunc_shared PROPERTIES OUTPUT_NAME "test_Func")
set_target_properties(testFunc_static PROPERTIES OUTPUT_NAME "test_Func")

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

这个文件,实际上包含了三部分:

(1)用aux_source_directory语句将所有.c文件包含到一个自定义的变量SRC_LIST中

(2)用add_library配合SRC_LIST来生成 动态库(shared) 和 静态库(static)

     并用set_target_properties将生成的库文件改名为"test_Func"(由于一个是动态库,一个是静态库,两个库文件的后缀名不同,因此这里可以把他们都叫做test_Func,仍能区分的开来)

(3)用set语句指定最终生成的库存放的文件夹,类似于之前我们用set语句指定最终生成的可执行文件存放的文件夹。

六、将main.c与库文件进行链接。

如下重构文件树:

这里写图片描述

这里没有了include文件夹,是因为我们把.h放到lib_testFunc中了

test文件夹中CMakeLists.txt文件的内容如下:

cmake_minimum_required(VERSION 2.8)

project(demo)

add_subdirectory(lib_testFunc)

add_subdirectory(src)

这里除了添加函数testFunc.c源文件所在的路径外,还要添加main.c源文件所在的路径,都是用add_subdirectory添加的。

src文件夹中CMakeLists.txt文件的内容如下:

aux_source_directory(. SRC_LIST)

include_directories(../lib_testFunc)

link_directories(${PROJECT_SOURCE_DIR}/lib)

add_executable(main ${SRC_LIST})

target_link_libraries(main testFunc)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

注意了,对src中的这个CMakeLists.txt文件来说,之前不使用库文件时 与 现在使用库文件时 的区别是什么呢?

使用库文件后,我们不需再添加函数的.c文件,只需用include_directories把函数的.h文件添加进来;另外,新增的东西是,需要用link_direcctories指定搜索库的路径,并在add_executable语句之后,将可执行文件名main与库名testFunc链接起来,用到的是target_link_libraries语句。

最后再用set生成可执行文件。

猜你喜欢

转载自blog.csdn.net/qq_39642978/article/details/106306131