首页 > Cmake 实例学习 一

Cmake 实例学习 一

一. 第一个简单的例子

在一个目录下面实现一个简单的 hello world 程序

使用cmake进行构建的时候,每个目录下面都要有一个 CMakeLists.txt 的文件

如果是一个稍微大的工程,有多级目录,在上级目录中的 CMakeLists.txt 中会有定义要求编译子目录的逻辑

当前目录中定义了一个main.c 和 CMakeLists.txt 文件,两个文件的内容分别如下

main.c

#include 
int main()
{printf("hello world!
");return 0;
}

CMakeLists.txt

project (hello)
set(SRC_LIST main.c)
message(STATUS "this is binary dir" ${HELLO_BINARY_DIR})
message(STATUS "this is source dir" ${HELLO_SOURCE_DIR})
add_executable(hello ${SRC_LIST})

重点解释 CMakeLists.txt 中的内容

project 定义工程名成set 定义一个变量,把后面的 mian.c 赋值给了 SRC_LIST ,这样做的好处是,
如果需要编译多个文件构成同一个可执行程序的时候,
在后面用到的时候,不需要每次都写多个文件,只需要使用这个变量名就可以了message 打印一些信息,这里可以打印多种信息,上文中需要打印出来的信息就是一个状态信息
后面可能会用到的打印信息包括,
SEND_ERROR,产生错误,生成过程被跳过。FATAL_ERROR,立即终止所有 cmake 过程.等add_executable 添加可执行程序,hello 是生成的可执行程序名
后面的符号表示生成这个可执行程序需要依赖的源文件注意其中的变量,使用set定义了变量之后,后面在使用的时候一般是需要加上 ${} 符号的
但是在 IF 判断语句中,如果使用 ${} 判断指令的话,就是不正确的,
因为那个样子的话,IF 判断的就是变量本身的内容另外注意的是,工程名project中的hello和可执行程序名中 add_executable 
中的 hello 是没有直接关系的,即两处的名称可以不同
二. 第二个例子,使hello更像一个工程

本小结将完成如下工作

1,为工程添加一个子目录 src,用来放置工程源代码;
2,添加一个子目录 doc,用来放置这个工程的文档 hello.txt
3,在工程目录添加文本文件 COPYRIGHT, README;
4,在工程目录添加一个 runhello.sh 脚本,用来调用 hello 二进制
4,将构建后的目标文件放入构建目录的 bin 子目录;
5,最终安装这些文件:将 hello 二进制与 runhello.sh 安装至/usr/bin,将 doc 目录
的内容以及 COPYRIGHT/README 安装到/usr/share/doc/cmake/t2,将

我们需要在上一节的基础之上,将文件改一下

首先新建一个目录t2,将上一个工程中的所有文件添加到这个文件中

在当前目录下面新建目录src。这个src专门用于存放文件程序的源代码

把 main.c 移动到 src 目录下面

上文提到每个目录下面需要增加CMakeLists.txt文件

所以需要在src目录下面新建一个CMakeLists.txt 文件,文件中写入如下内容

add_executable(hello main.c)

因为在工程中增加了子目录,我们需要在相应的父目录中的CMakeLists.txt 中增加相关的配置

在父目录下面的CMakeLists.txt 中修改最后的add,改成

add_subdirectory(src bin)

父目录中 CMakeLists 全文如下

project (hello)
set(SRC_LIST main.c)
message(STATUS "this is binary dir" ${HELLO_BINARY_DIR})
message(STATUS "this is source dir" ${HELLO_SOURCE_DIR})
#add_executable(hello ${SRC_LIST})
add_subdirectory(src bin)

这里解释一下最后一句

因为增加了子目录,这里需要将子目录增加进来,并且将子目录编译的结果放到了 bin目录下面

这里的重点是,将整个子目录将入到工程中,从而这个父目录和这个子目录整体构成了一个工程

另外我们也可以通过修改内置的隐式变量来指定程序输出的位置,简要如下

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
三 . 添加共享库

有了上面的基础,添加动态库也是如此的简单

创建一个新的目录,用于存放新的工程t3

将之前t2的内容拷贝到t3中

新建一个lib目录,在lib目录下面创建三个文件,分别是 hello.c 和 hello.h 和 CMakeLists.txt

hello.c

#include "hello.h"
void HelloFunc()
{printf("hello world
");
}

hello.h

#ifndef HELLO_H
#define HELLO_H#include 
void HelloFunc();#endif

CMakeLists

set(LIBHELLO_SRC hello.c)
add_library(hello SHARED ${LIBHELLO_SRC})

这里解释一下子目录中的定义,其实很简单,就是生成一个库文件,这里hello是库文件的名称 ,SHARED 表示生成的是动态库,如果要生成静态库,使用的是STATIC,后面表示生成库文件需要的源文件是什么

在父目录中,修改 CMakeLists如下

cmake_minimum_required(VERSION 2.6)
project (hellolib)
#add_executable(hello ${SRC_LIST})
#add_subdirectory(src bin)
add_subdirectory(lib)

父目录中的CMakeLists就是添加一个子目录,子目录执行的任务在子目录中会定义

四. 生成一个库文件,并链接他

在同一个一个工程中,我们既需要生成一个库文件,又需要链接这个库文件

在上面 二 和 三 的基础之上,即既保留了 src 目录,又保留了 lib 目录的基础之上,

保持 lib 中的CMakeLists不变,需要修改父目录中的 CMakeLists如下

cmake_minimum_required(VERSION 2.6)
project (hellolib)
#add_executable(hello ${SRC_LIST})
#add_subdirectory(src bin)
add_subdirectory(lib)
add_subdirectory(src bin)

父目录中实际只是在 生成 lib 的基础之上,增加了而一个新的子目录 src

进入到 src 目录中,修改源代码,我们需要在 main.c 中增加头文件和修改函数,如下所示

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

重点在 src 中的 CMakeLists 的编写,这里因为需要链接到库文件,所以需要注意两个内容,

一个是头文件,一个是库文件

src 中 CMakeLists 的书写如下所示

include_directories("${PROJECT_SOURCE_DIR}/lib")
add_executable(main main.c)
target_link_libraries(main hello)

第一行,增加头文件的查找目录,这里使用了 变量 , PROJECT_SOURCE_DIR 是 cmake 的内置变量,表示工程的目录所在位置,加上这个头文件目录的选项之后,程序在编译的时候,就会到这个目录下面去寻找头文件

第二行 不在赘述

第三行 表示,编译源文件 main 的时候,需要链接的库文件,这个库文件就是之前在 lib 中生成的库文件 hello

综上,在一个程序编译的时候,需要使用库文件的时候,需要注意两个内容,一个是头文件,一个就是库文件

五. 使用 cmake 和 程序代码,决定是否调用自制库文件

在 四 的基础之上,我们需要改变一些CMakeLists的配置,通过判断是否需要一些条件来执行一些函数

在顶层的CMakeLists中,修改如下

cmake_minimu_required(VERSION 2.6)
project (hellolib)
#add_executable(hello ${SRC_LIST})
#add_subdirectory(src bin)
option(USE_MYLIB "Use my lib" ON)
add_subdirectory(lib)
add_subdirectory(src bin)

此处在中间加了一个options的选项,定义了一个选项USE_MYLIB 并默认为打开的

如果需要不想要一些逻辑的话,我们直接可以通过修改这个 ON 为OFF就可以关掉一些功能了

在 src 的CMakeLists中需要修改如下

if (USE_MYLIB)add_definitions(-DUSE_MYLIB)include_directories("${PROJECT_SOURCE_DIR}/lib")set(EXTRA_LIBS ${EXTRA_LIBS} hello)
endif (USE_MYLIB)message(STATUS "extra libs: " ${EXTRA_LIBS})
add_executable(main main.c)
target_link_libraries(main ${EXTRA_LIBS})

这里开始就是一个判断,就是判断这个 USE_MYLIB 是否为真,注意这里的 USE_MYLIB 不需要加 ${} 如果加上的,就表示取 他的值了

如果这个判断为真,就执行如下的操作 ,这个值在顶层的 CMakeLists 中,已经定义为 ON了,所以此处会判断为真

在这个 if 为真的判断中,需要加上一个宏定义,定义了 一个东西,这个宏是可以传递到代码中的

此外,如果这个判断为真,还是加上需要链接的头文件,和需要链接的库文件,这里没有直接链接上库文件,而是通过将库文件赋值给了一个变量,这个变量是cmake内置的变量

最后,编译这个程序,如果上面的判断为真,就会链接到了这个库文件,如果为假,则这个内置变量就是空的,具体是不是cmake内置的变量还有待考证

修改了 CMakeLists之后,还需要在代码中进行修改 ,src 中修改之后的代码如下

#include 
#ifdef USE_MYLIB
#include "hello.h"
#endifint main()
{
#ifdef USE_MYLIBHelloFunc();
#elseprintf("AAA
");
#endifreturn 0;
}

前面已经说过,如果在src 中的CMakeLists中的判断为真,就会加上一个宏,这个宏可以传递到代码里面的,在代码中,我们就可以通过判断这个宏是否为真的方式,来决定是否使用自己定义的库文件了

更多相关:

  • 本文来自 运维人生 ,作者:fly是个稻草人链接:http://www.ywadmin.com/?id=76误删除linux系统文件了?不用急,本文将给你一个恢复linux文件的方法,让你轻松应对运维中的各风险问题。方法总比问题多~说在前面的话针对日常维护操作,难免会出现文件误删除的操作。大家熟知linux文件系统不同win有回收...

  • 原文来自SecIN社区—作者:WiHat0x00 什么是WebShell渗透测试工作的一个阶段性目标就是获取目标服务器的操作控制权限,于是WebShell便应运而生。Webshell中的WEB就是web服务,shell就是管理攻击者与操作系统之间的交互。Webshell被称为攻击者通过Web服务器端口对Web服务器有一定的操作权限,而...

  • 断电时文件系统发生了什么?硬盘又发生了什么?下一次开机时写到一半的文件在系统层面还在吗?在底层还在吗?更进一步的, 文件系统如何保证事务性, 会不会存在某种极端情况导致例如最后几个bit还没写完, 文件系统却认为它成功了的情况?回答不限任何文件系统,谢谢!下面是「北极」的回复分享断电的一瞬间,很多事情是无法确定的:1. 你无法确定...

  • 接到项目需求。需要搭建一个页面进行交互,慢慢来b (2).jpg使用python django框架进行页面的搭建在项目文件下打开窗口,输入命令;django-admin startproject helloword#在文件helloword/helloword/创建view.py在view.py文件中输入以代码from django....

  • 常见的错误集合解决方案(一)No.1提示错误'Microsoft.VC90.CRT,version="9.0.21022.8"把Microsoft.NET Framework 3.5.1下面的全部勾选上。No.2解决Qt Designer设计的图标但是VS生成不显示问题描述:在Qt designer中为菜单栏和工具栏设计的图标,但是...

  • 这里用散装版本的AutoScssStruct4Vue为例 先去https://github.com/accforgit/AutoScssStruct4Vue下载 然后把解压后的包放入C:UsersAdministrator.vscodeextensions(地址根据你自己的安装目录而定)    点开目录在资源管理器...

  • 网上搜到的结果大都不令人满意,这里综合了网上的结构,做了小许改动.希望对大家有帮助. 在Linux下的目录结构操作基本上使用opendir,readdir,closedir就够了. #include #include #include #include

  • 文章目录git 最小配置作用域git 创建本地仓库git log 查看版本演进.git 目录refs目录objectsgit 三种对象类型详解 (commit ,tree,blob)...

  • 一 . 进入目录权限 如果我在普通用户下创建了一个目录f1,然后使用chomd u-rwx,g-rwx,o-rwx之后,我在普通用户下想进入f1目录,权限不允许。 然后我切换到超级用户下,再次尝试进入到f1目录,这个时候允许进入。 然后回到普通用户下,只给f1的所有者读的权限,然后在普通用户下尝试进入,此时权限还是...

  • windows下rpc框架thrift的环境配置 引用链接: https://www.cnblogs.com/49er/p/7193829.html 最近在弄windows下 的Facebook的rpc 框架 thrift , 网上东西看了很多, 但是大都不能一篇到位, 这里总结了一下, 也记一下自己遇到的问题和解决的方法 这里...

  • 原文出处: 韩昊    1 2 3 4 5 6 7 8 9 10 作 者:韩 昊 知 乎:Heinrich 微 博:@花生油工人 知乎专栏:与时间无关的故事   谨以此文献给大连海事大学的吴楠老师,柳晓鸣老师,王新年老师以及张晶泊老师。   转载的同学请保留上面这句话,谢谢。如果还能保留文章来源就更感激不尽了。 我保证这篇文章...

  • 原文出处: 韩昊   我保证这篇文章和你以前看过的所有文章都不同,这是 2012 年还在果壳的时候写的,但是当时没有来得及写完就出国了……于是拖了两年,嗯,我是拖延症患者…… 这篇文章的核心思想就是: 要让读者在不看任何数学公式的情况下理解傅里叶分析。 傅里叶分析不仅仅是一个数学工具,更是一种可以彻底颠覆一个人以前世界观的思维...

  • 很多Linux高手都喜欢使用screen命令,screen命令可以使你轻松地使用一个终端控制其他终端。尽管screen本身是一个非常有用的工具,byobu作为screen的增强版本,比screen更加好用而且美观,并且提供有用的信息和快捷的热键。 想象一下这样一个场景:你通过Secure Shell(ssh)链接到一个服务器,并...

  • NarrowbandPrimary Synchronization Signal时域位置每1个SFN存在一个NPSSSFNSubframeSymbol长度每个SFN5最后11个symbol11个symbols频域位置NB-IOT下行带宽固定180kHz,一个PRB,12个子载波。...

  •  [h1]反斜杠只能够阻止一个字符  [h2]位于键盘的左上角,和~公用一个键。...