Cmake 实例学习 一
一. 第一个简单的例子
在一个目录下面实现一个简单的 hello world 程序
使用cmake进行构建的时候,每个目录下面都要有一个 CMakeLists.txt 的文件
如果是一个稍微大的工程,有多级目录,在上级目录中的 CMakeLists.txt 中会有定义要求编译子目录的逻辑
当前目录中定义了一个main.c 和 CMakeLists.txt 文件,两个文件的内容分别如下
main.c
#include <stdio.h>
int main()
{printf("hello world!\n");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\n");
}
hello.h
#ifndef HELLO_H
#define HELLO_H#include <stdio.h>
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 <stdio.h>
#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 <stdio.h>
#ifdef USE_MYLIB
#include "hello.h"
#endifint main()
{
#ifdef USE_MYLIBHelloFunc();
#elseprintf("AAA\n");
#endifreturn 0;
}
前面已经说过,如果在src 中的CMakeLists中的判断为真,就会加上一个宏,这个宏可以传递到代码里面的,在代码中,我们就可以通过判断这个宏是否为真的方式,来决定是否使用自己定义的库文件了
相关文章:
ORA-19502: write error on file xxxxx, block number xxxx
错误现象: 在ORACLE 10g下为表空间IGNITE_EGVSQL01增加数据文件时,报如下错误: SQL> ALTER TABLESPACE IGNITE_EGVSQL01 ADD DATAFILE /oradata/ignt/ignite_egvsql01_d02.dbf SIZE 4096M AUTOEXTEND OFF; ERROR at line 1: O…
关于Jfinal的分享代码托管GitHub
为什么80%的码农都做不了架构师?>>> Blog中所有的代码已经托管到github. https://github.com/b1412 此blog中关于Jfinal的代码分享不再维护。有兴趣的朋友可以关注我的github。 大家都贡献和分享一点,让jfinal发展的更好~ 转载于:https:…
软件发布版本的业界规则?
文章:8天学通MongoDB——第一天 基础入门 今天看到一篇文章说:业界规则,偶数为“稳定版”(如:1.6.X,1.8.X),奇数为“开发版”(如:1.7.X,1.9.X)&am…
CMake学习资料
CMake 官方 FAQ https://gitlab.kitware.com/cmake/community/wikis/FAQ CMake 官方文档 https://cmake.org/cmake/help/cmake2.4docs.html CMake 视频教程 https://www.youtube.com/watch?vCLvZTyji_Uw CMake 维基教科书 https://zh.wikibooks.org/w/index.php?titleCMake_入…
MySQL rpm包 二进制区别_Linux环境下安装mysql5.6(二进制包不是rpm格式)
一.准备:1.CentOS release 6.82.mysql-5.6.31-linux-glibc2.5-x86_64.tar.gz3.Linux下MySQL5.6与MySQL5.7安装方法略有不同二.卸载原有的mysqlfind / -name mysqlrm -rf 上边查找到的路径,多个路径用空格隔开三.在安装包存放目录下执行命令解压文件tar -zxvf mysql-…
【心情】 轻装前行
为自己做一份总结吧,从毕业到现在~ 时间过得不快不慢,从毕业到现在挣扎着已经2年多了,2年多经历的了很多事情。 毕业回国不到一个礼拜,就跑到大连工作,一个造船厂,公司在长兴岛开发区,岛上几万人…
Android 马甲包制作流程
一、马甲包的制作流程 1.配置马甲包的applicationId以及应用名称 在app的build.gradle文件中添加马甲包的配置 android {signingConfigs {config {keyAlias ****keyPassword ****storeFile file(D:/qianming/****.jks)storePassword ****}}compileSdkVersion 25buildToolsVersi…
Cmake 交叉编译
转载自 http://zhixinliu.com/2016/02/01/2016-02-01-cmake-cross-compile/ CMake交叉编译 CMake的使用,以及如何将一个项目移植到Android。 CMake的用法 先让我们简单学习回顾一下cmake的基本知识: 基本流程 以linux平台为例,使用 CMak…
利用System.Uri转URL为绝对地址
在使用ASPOSE.Word生成Word文档时可以通过InsertHtml(html)来将图文信息写入Word文档(图片内嵌),但要求html里图片的src是绝对全路径,所以需要对html进行转化。 获取html可以来自数据库数据或者通过网络抓取,得到之后使用System.Uri来进行替换…
idea上java接口自动化_Java接口自动化之IDEA创建及运行maven项目
本文2564字阅读约需7分钟第195次推送Maven作为一个项目管理工具,是一组标准集合,一个项目的生命周期、一个依赖管理系统,以下主要介绍IDEA创建及运行maven项目。01创建maven项目①打开IDEA,顶部菜单栏依次选择File-->New-->…
.NET面向上下文、AOP架构模式(实现)
.NET面向上下文、AOP架构模式(实现) 1.上下文Context、面向切面编程AOP模型分析 在本人的.NET面向上下文、AOP架构模式(概述)一文中,我们大概了解了上下文如何辅助对象在运行时的管理。在很多时候我们急需在运行时能把…
英语之弱元音Schwa
IELTS Speaking - 学会英语Schwa弱元音,你的口语也将充满英伦味 https://baijiahao.baidu.com/s?id1596905156544848616&wfrspider&forpc http://blog.sina.com.cn/s/blog_95e5f8a601017jr4.html https://www.guokr.com/blog/440820/ 打傻方进 百家号04-05…
工厂方法模式和抽象工厂模式
工厂方法模式和抽象工厂模式工厂方法模式抽象工厂模式总结:工厂方法模式 #include <string> #include <iostream>// Abstract class Splitter { private:/* data */ public:Splitter(/* args */);virtual ~Splitter(); public:virtual void split() 0; };Splitte…
关于JQuery中的ajax请求或者post请求的回调方法中的操作执行或者变量修改没反映的问题...
前段时间做一个项目,而项目中所有的请求都要用jquery 中的ajax请求或者post请求,但是开始处理一些简单操作还好,但是自己写了一些验证就出现问题了,比如表单提交的时候,要验证帐号的唯一性,所以要在submit前…
下列关于Java多线程并发控制_下列关于Java多线程并发控制机制的叙述中,错误的是...
下列叙述成都望江楼的造景手法有()。竹文化景观应体现科学性与艺术性的和谐统一,关于既要满足植物的生态习性,又能体现美学价值。在中国传统的审美趣味、多线伦理道德上,竹在造园中被拟人化为( )的代表。程并错误下列不属于竹文化旅游的发展趋…
一.vtun源码学习笔记
1.守护进程 (1)守护进程简介 守护进程,也就是我们通常所说的Daemon进程。它是一个生存期较长的进程,它通常独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。 它与普通进程相比有下面这些特殊性:守护进程最重要的…
获取data 数据
export function getData(el, name, val) {const prefix data-if (val) {return el.setAttribute(prefix name, val)}return el.getAttribute(prefix name) } 转载于:https://www.cnblogs.com/hss-blog/p/9781816.html
java jwks_Java SpringBoot 如何使用 IdentityServer4 作为验证服务器学习笔记
这边记录下如何使用IdentityServer4 作为 Java SpringBoot 的 认证服务器和令牌颁发服务器。本人也是新手,所以理解不足的地方请多多指教。另外由于真的很久没有写中文了,用词不太恰当的地方也欢迎新手大佬小伙伴指出,一起进步。另外这边令牌…
git 快速复制一个新项目
gitlab创建项目a及一个主分支master 本地整体复制已有项目b 本地克隆gitlab上新创建的项目a(git clone gitlab地址) 将本地克隆过来的a文件夹下的.git目录拷贝到b项目下(cp -r .git …/b,注意是两个点,不是三个点,写两…
微信公众平台消息接口星标功能
【微信公众平台星标功能接口被撤销】微信公众平台消息接口中的星标功能,被悄悄的去掉了。 原因应该是有的账号在程序中大量使用星标功能,造成微信服务器存储记录过于宠大。 现在要继续使用星标功能,只能在后台手工操作。 <xml> <ToU…
国庆双节长假旅游出行必装的手机软件
长假即将来临,如果打算出去溜达溜达,透透气的朋友,本文可千万别错过了。今天将介绍几款应用是旅途中绝对不能缺少的,这些应用都非常好用、功能全面,是出行必备的手机软件,希望可以伴你度过快乐的十一长假。…
Windbg双机调试环境配置(Windows7/Windows XP+VirtualBox/VMware+WDK7600)
简介:Windbg双机调试内核、驱动 下载软件: 下载Windbg(GRMWDK_EN_7600_1.ISO)下载VirtualBox 5.2/VMware 12一、安装WDK,这里要提一点的是Debugging Tools for Windows一定要打勾,因为我们后面就是要通过这个工具来进行双机调试的…
哈夫曼树的java实现_java实现哈夫曼树
哈夫曼译码,就是将输入的译码还原成对应的字符。 抽象的算法描述:将建立哈夫曼树、实现哈夫曼编码、哈夫曼译码都定义成 子函数的的形式, 然后在主函数中调用它们......数据结构课程设计设计题目: 哈夫曼树及其应用学 院:计算机科学与技术 专业:网络...用哈夫曼树实现图像压缩_…
on-my-zsh git 仓库下运行卡顿
在 oh-my-zsh 进入 包含 git 仓库目录时,执行 ls 时会比较卡顿 原因: oh-my-zsh 要获取 git 更新信息 解决办法: 设置 oh-my-zsh 不读取文件变化信息(在 git 项目目录执行下列命令) $ git config --add oh-my-zsh…
oracle, group by, having, where
选择列表中如果包含有列、表达式时,这个列、表达式必须包含在Group By子句中。另外,如果采用了表达式的话,则数据库管理员即使在选择列表中采用了别名,但是在Group By子句中仍然必须采用表达式的完整表达方式,而不能够…
[转载] CSS模块化【封装-继承-多态】
第一次听到“CSS模块化”这个词是在WebReBuild的第四届“重构人生”年会上,当时我还想,“哈,CSS也有模块化,我没听错吧?”事实上,我没听错,你也没看错,早就有CSS模块化这个概念了。之…
用jQuery写的一个翻页,并封装为插件,
用jQuery写的一个翻页,并封装为插件, 1 *{2 margin:0;3 padding: 0;4 list-style: none;5 text-decoration: none;6 }7 .page{8 width:500px;9 margin:100px auto; 10 color: #ccc; 11 } 12 .page a{ 13 display: inlin…
Ubuntu 将 /home 或 /var 目录挂载到新的分区
背景 在使用 docker 的过程中,docker 会将某些产物放到 /var/lib/docker/volumes 这会占用很大的跟目录磁盘空间,于是想办法将 /var 目录挂载到另一个一个单独的磁盘上面。 参考链接如下:Ubuntu将var目录挂载到新硬盘 步骤 1. 查看当前磁…
php 500 内部服务器错误,php 500 - 内部服务器错误的解决方法
php 500 - 内部服务器错误的解决方法发布时间:2020-11-04 09:55:31来源:亿速云阅读:71作者:小新小编给大家分享一下php 500 - 内部服务器错误的解决方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家…
网游生命周期在百度指数曲线上呈“M”形分布,各阶段搜索行为呈一定特征
(本文转载自:http://data.baidu.com/youxi3/part1.html) 产品生命周期就是一种新产品从开始进入市场到被市场淘汰的整个过程,进人和退出市场分别标志着周期的开始和结束。网络游戏的生命周期一般可以划分成测试期、成长期、成熟期…