cmake practice笔记
创始人
2024-06-03 11:07:40
0

本文为Cmake Practice--Cjacker这本电子书的实践笔记,作者之前将这个cmake过过一次手,现在再来写一个笔记,对之前不是很理解知识的有了新的的认知

安装

Download | CMake

t1:cmake 的 helloworld

t1文件夹中创建文件:

分别写入:

PROJECT (HELLO)  #文件名
SET(SRC_LIST main.c)   #设置变量
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})   #在cmake的时候输出一个消息
MESSAGE(STATUS "This is SOURCE dir "${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})   #作者这里代码错了,引用变量需要使用${}
//main.c
#include 
int main()
{
printf("Hello World from t1 Main!\n");
return 0;
}

在t1中构建:

cmake .
make

即可产生可执行文件hello,然后执行:

./hello

即可输出

语句解释:

PROJECT(projectname [CXX] [C] [Java])
这个指令隐式的定义了两个 cmake 变量:

_BINARY_DIR 以及_SOURCE_DIR

这里就是
HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR

所以 CMakeLists.txt 中两个 MESSAGE指令可以直接使用了这两个变量。

因为采用的是内部编译,两个变量目前指的都是工程所在路径/cmake/t1,后面我们会讲到外部编译,两者所指代的内容会有所不同。
同时 cmake 系统也帮助我们预定义了 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR变量,他们的值分别跟 HELLO_BINARY_DIR 与HELLO_SOURCE_DIR 一致。为了统一起见,建议以后直接使用PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,即使修改了工程名称,也不会影响这两个变量。如果使用了_SOURCE_DIR ,修改工程名称后,需要同时修改这些变量。

ADD_EXECUTABLE(hello ${SRC_LIST})
定义了这个工程会生成一个文件名为 hello 的可执行文件,相关的源文件是 SRC_LIST 中
定义的源文件列表, 本例中你也可以直接写成 ADD_EXECUTABLE(hello main.c)。

cmake:是为了生成编译所需的Makefile以及其他中间文件

make:构建工程

make clean:即可对构建结果进行清理,这里清理的就是可执行文件hello

t2:更好一点的 Hello World

外部构建和安装(make install),安装部分还不是特别理解

从上到下CMakeLists、runhello.sh、CMakeLists、main依次为:

PROJECT (HELLO)
ADD_SUBDIRECTORY(src bin)
ADD_EXECUTABLE(hello main.c)
//main.c
#include 
int main()
{
printf("Hello World from t1 Main!\n");
return 0;
}

解释

ADD_SUBDIRECTORY(source_dir    [binary_dir]    [EXCLUDE_FROM_ALL])

这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存
放的位置。EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除,比如工程
的 example,可能就需要工程构建完成后,再进入 example 目录单独进行构建(当然,你
也可以通过定义依赖来解决此类问题)。

如果不进行 bin 目录也就是[binary_dir]的指定,那么编译结果(包括中间结果)都将存放在
build/src 目录,指定 bin 目录后,相当于在编译时将 src 重命名 为 bin,所有的中间结果和目标二进制都将存放在 bin 目录。

我们可以通过 SET 指令重新定义 EXECUTABLE_OUTPUT_PATH 和LIBRARY_OUTPUT_PATH 变量来指定最终的目标二进制的位置(指最终生成的 hello 或者最终的共享库,不包含编译生成的中间文件)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

t3:静态库与动态库构建

任务:建立一个静态库和动态库,提供 HelloFunc 函数供其他程序编程使用,HelloFunc
向终端输出 Hello World 字符串。

 

从上到下:

PROJECT(HELLOLIB)
ADD_SUBDIRECTORY(lib)
cmake_minimum_required(VERSION 3.10)
SET(LIBHELLO_SRC hello.c)
#这个最终版的CMakeLists在后面的静态库和共享库共存部分给出
#include “hello.h”
void HelloFunc()
{
printf(“Hello World\n”);
}
#ifndef HELLO_H
#define HELLO_H
#include 
void HelloFunc();
#endif

编译:

cmake ..
make

可以看到生成libhello.so共享库

如果你要指定 libhello.so 生成的位置,可以通过在主工程文件 CMakeLists.txt 中修改 ADD_SUBDIRECTORY(lib)指令来指定一个编译输出位置或者在 lib/CMakeLists.txt 中添加SET(LIBRARY_OUTPUT_PATH <路径>)来指定一个新的位置。

ADD_LIBRARY(libname   [SHARED|STATIC|MODULE]    [EXCLUDE_FROM_ALL]
source1 source2 ... sourceN):

你不需要写全 libhello.so,只需要填写 hello 即可,cmake 系统会自动为你生成
libhello.X

类型有三种:
SHARED,动态库
STATIC,静态库
MODULE,在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。


EXCLUDE_FROM_ALL 参数的意思是这个库不会被默认构建,除非有其他的组件依赖或者手
工构建。

同名的共享和静态库共存:

上面的步骤(lib中的CMakeLists.txt)添加的是共享库,如果我们要添加静态库就需要把关键字改为STATIC:ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})

但是如果直接加上这句话

 

就会报错:

 

因为hello作为一个target不能重名,虽然我们可以通过改名字的方式如:

将两者区分开 ,但是这种结果显示不是我们想要的,我们需要的是名字相同的静态库和动态库,因为 target 名称是唯一的,所以,我们肯定不能通过 ADD_LIBRARY 指令来实现了。这时候我们需要用到
另外一个指令:

SET_TARGET_PROPERTIES(target1 target2 ...
PROPERTIES prop1 value1
prop2 value2 ...):

这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API 版本。

在本例中,我们需要作的是向 lib/CMakeLists.txt 中添加一条:
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
这样,我们就可以同时得到 libhello.so/libhello.a 两个库了。

但是由于cmake 在构建一个新的 target 时,会尝试清理掉其他使用这个名字的库,因为,在构建libhello.a 时,就会清理掉 libhello.so.为了回避这个问题,比如再次使用SET_TARGET_PROPERTIES 定义CLEAN_DIRECT_OUTPUT 属性。

即加入SET_TARGET_PROPERTIES (hello_static PROPERTIES OUTPUT_NAME "hello")

所以最终的CMakeLists.txt这样:

cmake_minimum_required(VERSION 3.10)
SET(LIBHELLO_SRC hello.c)ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})  #共享库
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})  #静态库SET_TARGET_PROPERTIES (hello_static PROPERTIES OUTPUT_NAME "hello")
#下面两行为作者说要进一步进行修改的,不然就不会出现同名的.so和.a文件,但是我并不需要加上下面两步就可以出现。
# SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
# SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

即可同时构建,如下图:

 有libhello.so和libhello.a

为了实现动态库版本号,我们仍然需要使用 SET_TARGET_PROPERTIES 指令。
具体使用方法如下:
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
VERSION 指代动态库版本,SOVERSION 指代 API 版本。
将上述指令加入 lib/CMakeLists.txt 中,重新构建看看结果。
在 build/lib 目录会生成:
libhello.so.1.2
libhello.so.1->libhello.so.1.2
libhello.so ->libhello.so.1
 

最后安装库:

库的安装是为了让别的工程项目也调用自己写好的函数,这里我们的函数就是一个简单的输出hello的效果。

我们向 lib/CMakeLists.txt 中添加如下指令:

INSTALL(TARGETS hello hello_staticLIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
INSTALL(FILES hello.h DESTINATION include/hello)

注意,静态库要使用 ARCHIVE 关键字

cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make
make install

我们就可以将头文件和共享库分别安装到系统目录/usr/include/hello和/usr/lib 中了。

 

 

t4:如何使用外部共享库和头文件

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...