cmake 学习笔记(一)

  • 最大的Qt4程序群(KDE4)采用cmake作为构建系统
  • Qt4的python绑定(pyside)采用了cmake作为构建系统
  • 开源的图像处理库 opencv 采用cmake 作为构建系统
  • ...

看来不学习一下cmake是不行了,一点一点来吧,找个最简单的C程序,慢慢复杂化,试试看:

例子一

单个源文件 main.c

例子二

==>分解成多个 main.c hello.h hello.c

例子三

==>先生成一个静态库,链接该库

例子四

==>将源文件放置到不同的目录

例子五

==>控制生成的程序和库所在的目录

例子六

==>使用动态库而不是静态库

例子一

一个经典的C程序,如何用cmake来进行构建程序呢?

//main.c
#include <stdio.h>
int main()
{printf("Hello World!/n");return 0;
}

编写一个 CMakeList.txt 文件(可看做cmake的工程文件):

project(HELLO)
set(SRC_LIST main.c)
add_executable(hello ${SRC_LIST})

然后,建立一个任意目录(比如本目录下创建一个build子目录),在该build目录下调用cmake

  • 注意:为了简单起见,我们从一开始就采用cmake的 out-of-source 方式来构建(即生成中间产物与源代码分离),并始终坚持这种方法,这也就是此处为什么单独创建一个目录,然后在该目录下执行 cmake 的原因
cmake .. -G"NMake Makefiles"
nmake

或者

cmake .. -G"MinGW Makefiles"
make

即可生成可执行程序 hello(.exe)

目录结构

+
| 
+--- main.c
+--- CMakeList.txt
|
/--+ build/|+--- hello.exe

cmake 真的不太好用哈,使用cmake的过程,本身也就是一个编程的过程,只有多练才行。

我们先看看:前面提到的这些都是什么呢?

CMakeList.txt

第一行 project 不是强制性的,但最好始终都加上。这一行会引入两个变量

  • HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR

同时,cmake自动定义了两个等价的变量

  • PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR

因为是out-of-source方式构建,所以我们要时刻区分这两个变量对应的目录

可以通过message来输出变量的值

message(${PROJECT_SOURCE_DIR})

set 命令用来设置变量

add_exectuable 告诉工程生成一个可执行文件。

add_library 则告诉生成一个库文件。

  • 注意:CMakeList.txt 文件中,命令名字是不区分大小写的,而参数和变量是大小写相关的。

cmake命令

cmake 命令后跟一个路径(..),用来指出 CMakeList.txt 所在的位置。

由于系统中可能有多套构建环境,我们可以通过-G来制定生成哪种工程文件,通过 cmake -h 可得到详细信息。

要显示执行构建过程中详细的信息(比如为了得到更详细的出错信息),可以在CMakeList.txt内加入:

  • SET( CMAKE_VERBOSE_MAKEFILE on )

或者执行make时

  • $ make VERBOSE=1

或者

  • $ export VERBOSE=1
  • $ make

例子二

一个源文件的例子一似乎没什么意思,拆成3个文件再试试看:

  • hello.h 头文件
#ifndef DBZHANG_HELLO_
#define DBZHANG_HELLO_
void hello(const char* name);
#endif //DBZHANG_HELLO_
  • hello.c
#include <stdio.h>
#include "hello.h"void hello(const char * name)
{printf ("Hello %s!/n", name);
}
  • main.c
#include "hello.h"
int main()
{hello("World");return 0;
}
  • 然后准备好CMakeList.txt 文件

 

project(HELLO)
set(SRC_LIST main.c hello.c)
add_executable(hello ${SRC_LIST})

执行cmake的过程同上,目录结构

 

+
| 
+--- main.c
+--- hello.h
+--- hello.c
+--- CMakeList.txt
|
/--+ build/|+--- hello.exe

例子很简单,没什么可说的。

例子三

接前面的例子,我们将 hello.c 生成一个库,然后再使用会怎么样?

改写一下前面的CMakeList.txt文件试试:

project(HELLO)
set(LIB_SRC hello.c)
set(APP_SRC main.c)
add_library(libhello ${LIB_SRC})
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)

和前面相比,我们添加了一个新的目标 libhello,并将其链接进hello程序

然后想前面一样,运行cmake,得到

+
| 
+--- main.c
+--- hello.h
+--- hello.c
+--- CMakeList.txt
|
/--+ build/|+--- hello.exe+--- libhello.lib

里面有一点不爽,对不?

  • 因为我的可执行程序(add_executable)占据了 hello 这个名字,所以 add_library 就不能使用这个名字了
  • 然后,我们去了个libhello 的名字,这将导致生成的库为 libhello.lib(或 liblibhello.a),很不爽
  • 想生成 hello.lib(或libhello.a) 怎么办?

添加一行

set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

就可以了

例子四

在前面,我们成功地使用了库,可是源代码放在同一个路径下,还是不太正规,怎么办呢?分开放呗

我们期待是这样一种结构

+
|
+--- CMakeList.txt
+--+ src/
|  |
|  +--- main.c
|  /--- CMakeList.txt
|
+--+ libhello/
|  |
|  +--- hello.h
|  +--- hello.c
|  /--- CMakeList.txt
|
/--+ build/

哇,现在需要3个CMakeList.txt 文件了,每个源文件目录都需要一个,还好,每一个都不是太复杂

  • 顶层的CMakeList.txt 文件
project(HELLO)
add_subdirectory(src)
add_subdirectory(libhello)
  • src 中的 CMakeList.txt 文件
include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(APP_SRC main.c)
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)
  • libhello 中的 CMakeList.txt 文件
set(LIB_SRC hello.c)
add_library(libhello ${LIB_SRC})
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

恩,和前面一样,建立一个build目录,在其内运行cmake,然后可以得到

  • build/src/hello.exe
  • build/libhello/hello.lib

回头看看,这次多了点什么,顶层的 CMakeList.txt 文件中使用 add_subdirectory 告诉cmake去子目录寻找新的CMakeList.txt 子文件

在 src 的 CMakeList.txt 文件中,新增加了include_directories,用来指明头文件所在的路径。

例子五

前面还是有一点不爽:如果想让可执行文件在 bin 目录,库文件在 lib 目录怎么办?

就像下面显示的一样:

   + build/|+--+ bin/|  ||  /--- hello.exe|/--+ lib/|/--- hello.lib
  • 一种办法:修改顶级的 CMakeList.txt 文件
project(HELLO)
add_subdirectory(src bin)
add_subdirectory(libhello lib)

不是build中的目录默认和源代码中结构一样么,我们可以指定其对应的目录在build中的名字。

这样一来:build/src 就成了 build/bin 了,可是除了 hello.exe,中间产物也进来了。还不是我们最想要的。

  • 另一种方法:不修改顶级的文件,修改其他两个文件

src/CMakeList.txt 文件

include_directories(${PROJECT_SOURCE_DIR}/libhello)
#link_directories(${PROJECT_BINARY_DIR}/lib)
set(APP_SRC main.c)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)

libhello/CMakeList.txt 文件

set(LIB_SRC hello.c)
add_library(libhello ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

例子六

在例子三至五中,我们始终用的静态库,那么用动态库应该更酷一点吧。 试着写一下

如果不考虑windows下,这个例子应该是很简单的,只需要在上个例子的 libhello/CMakeList.txt 文件中的add_library命令中加入一个SHARED参数:

add_library(libhello SHARED ${LIB_SRC})

可是,我们既然用cmake了,还是兼顾不同的平台吧,于是,事情有点复杂:

  • 修改 hello.h 文件
#ifndef DBZHANG_HELLO_
#define DBZHANG_HELLO_
#if defined _WIN32#if LIBHELLO_BUILD#define LIBHELLO_API __declspec(dllexport)#else#define LIBHELLO_API __declspec(dllimport)#endif
#else#define LIBHELLO_API
#endif
LIBHELLO_API void hello(const char* name);
#endif //DBZHANG_HELLO_
  • 修改 libhello/CMakeList.txt 文件
set(LIB_SRC hello.c)
add_definitions("-DLIBHELLO_BUILD")
add_library(libhello SHARED ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

恩,剩下来的工作就和原来一样了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/433567.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++邮递员投递经过特定点_厉害了斑马鱼,动物实验体天团C位

明明是一条鱼&#xff0c;为什么在保健食品以及药品领域即将成为实验动物C位&#xff1f;越来越多的药品及保健食品企业&#xff0c;都想邀请它们成为座上宾&#xff0c;是时候展示真正的技术了&#xff01;透明就是很厉害斑马鱼从胚胎阶段至未来的成熟阶段&#xff0c;身体中有…

选了combobox里的选项后没激发change事件_备胎测试:来测测你被备胎了没?

很多人在感情里被备胎而不自知&#xff0c;今天就来教大家如何辨别备胎。你知道备胎的最大特征是什么吗&#xff1f;是在面对关系定位时&#xff0c;态度上的模棱两可。想想你身边养备胎的人&#xff0c;如果没有的话&#xff0c;想想电视剧或小说里养备胎的人&#xff0c;想想…

第七章:清楚简洁的英文 --《英语科技写作(文法与修辞原则)》by 方克涛

1. 在英文写作中&#xff0c;最好的方法是效仿英文为母语的写作者。 2. 资深的英文写作者&#xff0c;都喜欢直接而间接的写作方式。在中文写作中&#xff0c;作者有时候会假定读者已经知道主语是谁而将其省略&#xff0c;而英文中主语是必须有的&#xff0c;不能省略。 7.1 句…

warning no newline at the end of file

main.c :10:2 warning: no newline at the end of file 修复这个警告&#xff0c;在文件结尾回车一下就行了。可以很少会有人去仔细探究&#xff0c;为什么gcc会给出这么一个警告&#xff1f; 原因其实也很简单&#xff0c;因为标准规定如此。C99第5.1.1.2节这样写道&#xff1…

halcon旋转后坐标_FPGA大赛【八】具体模块设计图像旋转方案

【注】该项目是我们团队参加2019届全国大学生FPGA大赛的作品&#xff0c;系统主要实现视频任意角度旋转。该项目最终晋级决赛&#xff0c;并获得紫光同创企业特别奖。该系列文章介绍我们团队的作品。关注公众号“数字积木”对话框回复 FPGA2019 &#xff0c;即可获得该项目的工…

python获取pid并杀死_用python记录运行pid,并在需要时kill掉它们的实例

我在跑爬虫程序的时候&#xff0c;由于爬虫程序的等待目标服务器返回数据的时间很长&#xff0c;而cpu占用很低&#xff0c;所以经常挂着代理一跑就跑好几百个。但是爬虫程序通常是写了死循环&#xff0c;或直到分配给该进程的任务都跑完才退出的。如果我们想中途结束掉这些任务…

ASP.NET 错误

用Visual Studio2008 启动调试时出现以下错误&#xff1a; configuring web site for asp.net failed you must manually configure this site..... 在IE中浏览网页时&#xff1a; 访问IIS元数据库失败 异常详细信息: System.Web.Hosting.HostingEnvironmentException: 访问 …

hashmap value占用空间大小_HashMap的put和get实现原理及源码分析

水平有限&#xff0c;难免会有疏漏之处&#xff0c;如有错误&#xff0c;还请指出&#xff0c;感谢&#xff01;前言HashMa是Java中最常用的集合类框架&#xff0c;也是Java语言中非常典型的数据结构&#xff0c;同时也是我们需要掌握的数据结构&#xff0c;更重要的是进大厂面…

pthread_cond_wait的spurious wakeup问题

最近在温习pthread的时候&#xff0c;忽然发现以前对pthread_cond_wait的了解太肤浅了。昨晚在看《Programming With POSIX Threads》的时候&#xff0c;看到了pthread_cond_wait的通常使用方法&#xff1a; pthread_mutex_lock(); while(condition_is_false) pthread_con…

CABasicAnimation

CABasicAnimation 自己只有三个property fromValue toValue ByValue 当你创建一个 CABasicAnimation 时,你需要通过-setFromValue 和-setToValue 来指定一个开始值和结束值。 当你增加基础动画到层中的时候,它开始运行。当用属性做动画完成时,例如用位置属性做动画,层就会立…

python中func函数用法_python之4类回调函数的使用方法

原标题&#xff1a;python之4类回调函数的使用方法 将函数作为参数传递给另一个函数&#xff0c;一共分为4种情况&#xff1a; 将普通函数传递给普通函数 将普通函数传递给类成员函数 将类成员函数传递给普通函数 将类成员函数传递给类成员函数 这4种情况&#xff0c;在python中…

c#sql防注入模糊查询_SQL中利用LIKE实现模糊查询的功能

大家好&#xff0c;今日继续讲解《VBA数据库解决方案》&#xff0c;今日讲解的内容是&#xff1a;利用ADO,实现模糊查询。在上一讲中&#xff0c;我们实现了利用ADO快速查找的功能&#xff0c;今日我们实现工作表中模糊查找的功能。我们仍是利用上一讲的数据实现, 在"两表…

C++的一般引用及其数组引用

引用就是某一变量&#xff08;目标&#xff09;的一个别名&#xff0c;对引用的操作与对变量直接操作完全一样。 引用的声明方法&#xff1a;类型标识符 &引用名目标变量名&#xff1b; 【例1】&#xff1a;int a; int &raa; //定义引用ra,它是变量a的引用&#xff0…

马云卸任CEO演讲全文:明天起生活将是我的工作

马云&#xff1a;大家晚上好&#xff01;谢谢各位&#xff0c;谢谢大家从全国各地&#xff0c;我知道也有从美国、英国和印度来的同事&#xff0c;感谢大家来到杭州&#xff0c;感谢大家参加淘宝的十周年&#xff01; 今天是一个非常特别的日子&#xff0c;当然对我来讲&#x…

idea断点_IDEA Debug 无法进入断点的解决方法

前言某个多模块项目中使用多个版本的 Spring&#xff0c;如 Spring 4&#xff0c;Spring 5&#xff0c;在使用 IDEA Debug 过程中发现&#xff0c;Spring 部分 jar 如 spring-core 中的上面断点&#xff0c;IDEA 可以成功进入。但是有部分如 spring-context IDEA 始终无法进入断…

win10taskkill无法终止进程_Win10无法终止进程拒绝访问

用任务管理器强制结束一些已经不使用程序的进程&#xff0c;是很多用户会用的功能之一&#xff0c;但是最近有使用win10系统的用户&#xff0c;遇到结束进程的时候&#xff0c;被拒绝访问。遇到这样的问题&#xff0c;给大家带来了这篇文章的方法&#xff0c;希望能帮助到大家。…

c++对数组的引用

所谓数组引用&#xff0c;即指向数组的引用&#xff1b;如 int a[10] ; int (&b)[10] a ;如果写成 int a[10] ;int* &b a ;将会报错&#xff1a; cannot convert from int [10] to int *&。或许你会说在数组名不就是指向这个数组的一个指针吗&#…

python 线程池_老程序员的经验分享:Python 从业十年是种什么体验?

出于某些原因&#xff0c;想记录一下我过去数年使用 Python 的经验和一些感悟。毕竟算是一门把我带入互联网行业的语言&#xff0c;而我近期已经几乎不再写 Py 代码&#xff0c; 做一个记录&#xff0c;也许会对他人起到些微的帮助&#xff0c;也算是纪念与感恩了。作者&#x…

【转】C#中Invoke的用法

在多线程编程中&#xff0c;我们经常要在工作线程中去更新界面显示&#xff0c;而在多线程中直接调用界面控件的方法是错误的做法&#xff0c;Invoke 和 BeginInvoke 就是为了解决这个问题而出现的&#xff0c;使你在多线程中安全的更新界面显示。正确的做法是将工作线程中涉及…

练字格子纸模板pdf_高考英语作文模板(总结八种常考题型,配合例文,纯手打的)...

又是一年高考结束&#xff0c;又有不少新高三的学弟学妹问我一些学习上的方法。额&#xff0c;今天我们就单说这个英语作文。英语作文第一件事练字&#xff0c;其次背模板。高考无非就几种信件变着花考察。几种基本信件模板稍加变通就可以很简单完成作文。本人2019年河南考生&a…