做第一个linux项目时,Makefile是一行行敲入的,第二个项目后,开始使用cmake。至于为何选择cmake,倒不是觉得它有什么好,仅仅是因为当时项目组中的一个linux前辈向我们推荐了这个。经过一番研究之后,并在项目中使用,现将使用经验总结一下,供大家参考。
学习一项新知识的时候,最好是从sample开始。cmake官方网站就给出了一个简单的例子。在开始之前,还是先安装cmake程序,在ubuntu下非常简单,输入以下命令即可:
$
sudo apt-get install cmake
下面来看看sample中的内容。sample包含一个主目录,下面两个子目录: Demo和Hello。其中Hello包含程序库代码,Demo中为可执行程序,需要连接Hello中的程序库。总共有三个CMakeLists.txt文件,每个目录下一个。主目录下的CMakeLists.txt文件内容为:
Hello目录下的CMakeLists.txt文件为:
最后,Demo包含如下CMakeLists.txt文件:
CMake在主目录执行时,会处理该目录下CMakeLists.txt文件,然后进入到子目录,处理子目录下的CMakeLists.txt.
从字面上看,我们差不多可以理解这三个文件的涵义。第一个CMakeLists.txt文件指定包含Hello和Demo两个子目录。第二个文件则指定生成Hello库文件,第三个文件则是生成一个可执行文件helloDemo,另外两个附加语句则用来指明头文件路径以及所要链接的库。
乍一看,为了编译一个程序,需要写三个CMakeLists.txt文件,相对于原来只需写一个Makefile文件,不是更复杂了吗?事实上不尽然,虽然要写三个CMakeLists文件,但每个文件都非常简单,总共算起来,并不比一个Makefile文件多多少。更重要的是,这其中隐含着linux哲学:分而治之。每个模块自行编写配置文件,只负责自己份内的事务,所以可扩展性好。在进行大型项目开发,就可以体现出优势了。
CMakeLists.txt相当于定义了一套生成Makefile文件的规则,下面就可以生成Makefile文件了,命令如下:
$
cmake .
注:.表示当前目录,如果CMakeLists.txt不在当前目录,请在cmake后面指定。在主目录下和Demo、Hello子目录下均会生成一个Makefile文件,有了这个文件,我们就可以敲入make编译目标程序了。
总结起来,使用CMake编译应用程序的流程为:
CMake语法非常简单,包含注释、命令和空格。以#开头的行为注释行,命令则由命令名、括号及以空格进行分隔的参数组成。命令可以是诸如add_library这样的内置命令,也可以是子定义的宏或者函数。CMake的输入是主目录下的CMakeLists.txt文件,该文件可以使用include或者add_directory命令添加其它的输入文件。
命令的形式如下:
command (args ...)
其中<I>command</I>为命令名,<B>args</B>为空格分隔的参数列表,如果参数中包含空格,使用双引号引起来。命令不区分大小写。
lists and strings. CMake的基本数据类型为字符串,字符串又可以组成list类型,有两种方式:一种通过分号分隔,一种通过空格分隔。比如以下例子给VAR赋了同样的值:
set(VAR a;b;c) set(VAR a b c)
字符串列表主要用于foreach进行迭代,有些命令也用于对list进行处理。
CMake支持字符串和list类型的简单变量,变量以${VAR}形式引用。多个参数可以用set命令组成一个list,命令将展开list,例如:
set(Foo a b c)
command(${Foo})
等价于
command(a b c)
如果你希望将list当作一个参数传递给命令,就应该用双引号把list引起来,如command("${Foo}")等价于command("a b c")
写CMakeLists.txt文件就象写一个简单的程序,CMake提供了三种流程控制结构:
- 条件语句if
# some_command will be called if the variable's value is not:
# empty, 0, N, NO, OFF, FALSE, NOTFOUND, or -NOTFOUND.
if(var)
some_command(...)
endif(var)
- 循环结构
set(VAR a b c)
# loop over a, b,c with the variable f
foreach(f ${VAR})
some_command(${f})
endforeach(f)
- 宏和函数,函数在2.6及以上版本才支持,函数和宏的区别在于函数中可定义局部变量,而宏定义的变量都是全局变量。
# define a macro hello
macro(hello MESSAGE)
message(${MESSAGE})
endmacro(hello)
# call the macro with the string "hello world"
hello("hello world")
# define a function hello
function(hello MESSAGE)
message(${MESSAGE})
endfunction(hello)
本文通过一个简单的工程示例,我们了解到要让CMake工作起来,需要编写CMakeLists.txt文件,CMake据此生成Makefile。然后简单的过了以下CMake的语法,有了这个基础,我们就可以自行编写CMakeLists.txt文件了。当然,对于一个大型的工程,仅仅掌握这些还不够,需要进一步掌握一些CMakeLists.txt文件的编写技巧,将在后续的文件中继续这个话题。
Jan Engels. CMake Tutorial.
. CMake官方网站:www.cmake.org.
cmake使用总结(2)
Abstract
本文总结了CMake在linux嵌入式系统项目开发中的应用
在前面一篇文章中,我们从一个sample入手,了解了CMake的基本用法和语法。但这个例子与实际开发还有一段距离,主要存在以下几点问题:
- 生成的二进制程序和源程序混在一起
- 使用gcc进程程序编译,而不是使用交叉编译工具
- 为指定编译选项,通常会生成debug版本供调试用,release版本用于发布
在本章,我们将sample程序逐步改造,解决上述问题。
一个项目,通常包含若干子模块。比如上一篇的sample,我们可以认为它包含两个子模块,Hello为程序库,Demo为主程序。很少有项目会把目标二进制文件和源程序放在一起的,通常会建立一个bin目录,存放生成的二进制文件,发布程序则放在release。根据我在项目开发中的习惯,将目录结构修改如下:
CMakeSample
|--- release
|--- doc
|--- lib
|--- source
|--- include
|--- bin
|--- Hello
|--- Demo
其中,release存放程序发布相关文件,包括程序文件、脚本、参数等。doc包含项目开发中的相关文档,如设计说明以及通过doxgen等工具从代码中生成的文档。lib存放项目中使用的第三方库,项目中自己编写的库不放在此目录,应该作为项目的一个模块放在source目录下。include包含整个项目中使用的公共头文件,如果子模块中的头文件仅在该子模块类使用,不需放到include目录。bin目录存放编译后的调试版本代码。其它的子目录则为各模块的代码及头文件。
按照以上目录结构,将Hello下的hello.h移到include目录,因为这个头文件被Demo模块包含。这个sample中未使用第三方库,所以暂时为空。
从上文中我们知道,通过set语句可以自定义变量,然而,CMake还包含大量的内置变量,这些变量和自定义变量的用法没有区别,下面就列出一些常用的变量:
- CMAKE_C_COMPILER
指定C编译器,通常,CMake运行时能够自动检测C语言编译器。进行嵌入式系统开发时,通常需要设置此变量,指定交叉编译器。
- CMAKE_CXX_COMPILER
指定C++编译器
- CMAKE_C_FLAGS
指定编译C文件时编译选项,比如-g指定产生调试信息。也可以通过add_definitions命令添加编译选项。
- EXECUTABLE_OUTPUT_PATH
指定可执行文件存放的路径。
- LIBRARY_OUTPUT_PATH
指定库文件放置的路径
除了内置变量,我们还可以通过命令来修改编译选项,现将一些常用的命令列出来:
- include_directories
指定头文件的搜索路径,相当于指定gcc编译器的-I参数
- link_directories
动态链接库或静态链接库的搜索路径,相当于指>定gcc的-L参数
- add_subdirectory
包含子目录,当工程包含多个子目录时,此命令有用
- add_definitions
添加编译参数,比如add_definitions(-DDEBUG)将在gcc命令行添加DEBUG宏定义
- add_executable
编译可执行程序
- target_link_libraries
指定链接库,相同于指定-l参数
本文经过修改目录结构,指定编译工具链,生成动态链接库等动作,将前文的sample修改成一个比较接近实际工程的嵌入式环境。当然这个sample仍然只是一个自娱自乐的小玩意,但对于说明CMake用法已经足够了,有了这些基本的CMake知识,在项目中使用CMake就成为可能了。当然不同的环境会遇到一些新问题,借助于互联网,没有什么解决不了的问题。赶快动手吧,抛弃手工编写Makefile的痛苦,加入CMake使用者行列吧。
分享到:
相关推荐
1. 使用`cmake_minimum_required(VERSION 2.8)`声明CMake的最低版本需求。 2. `project(helloworld)`定义项目名称。 3. 设置`CMAKE_VERBOSE_MAKEFILE`为`on`,使得构建过程更加透明。 4. 指定C++编译器为`g++`,并...
当使用`ADD_SUBDIRECTORY(src bin)`时,`CMAKE_CURRENT_BINARY_DIR`会更新为指定的`bin`目录。 `EXECUTABLE_OUTPUT_PATH`和`LIBRARY_OUTPUT_PATH`用于设定最终生成的可执行文件和库文件的存放路径。需要注意的是,`...
"CMake学习总结" CMake是一种流行的构建自动化工具,它可以跨平台生成编译文件,从而简化了工程的构建过程。在CMake中,我们可以使用CMakeLists.txt文件来指定构建规则和依赖关系。下面是CMake学习总结的知识点: ...
总结一下,使用CMake编译iOS框架涉及的关键步骤包括: 1. 创建并配置工具链文件(iOS.cmake)。 2. 编写CMakeLists.txt,定义源文件、构建目标和框架属性。 3. 处理Info.plist以提供框架元数据。 4. 可选:编写Shell...
下面是cmake大全的知识点总结: cmake安装 cmake的安装非常简单,只需要下载并安装相应的安装包即可。cmake支持多种平台,包括Windows、Linux、Mac OS等。 cmake基本概念 cmake的基本概念包括项目(project)、...
### CMake使用教程知识点概述 #### 一、CMake简介与背景 - **起源与发展**:CMake由Kitware公司及开源社区共同开发,最初作为VTK(Visualization Toolkit)等工具套件的一部分出现,后来发展成一个独立的开源项目...
总结一下,"cmake使用实例"主要涵盖了以下知识点: 1. CMake的基本概念和作用。 2. `CMakeLists.txt`文件的编写,包括设置项目属性、添加源文件和库依赖。 3. CMake命令的使用,如`cmake_minimum_required`、`...
CMake是一种跨平台的构建工具,它...总结来说,CMake是构建多平台软件项目的强大工具,通过CMakeLists.txt文件,你可以控制项目结构、编译选项、依赖关系等。熟练掌握CMake的使用,将使你的开发工作更加高效和灵活。
在本文中,我们将深入探讨如何使用CMake来生成动态库,这对于那些希望将代码库作为库文件供其他程序使用的开发者来说非常重要。 ### CMake简介 CMake不是直接构建工具,而是生成构建文件的工具,如Unix下的...
文档《modern-cmake.pdf》提供了一个对现代CMake的介绍,强调了使用更新版本的CMake(3.1以上版本,特别是3.18+)的优越性,相较于早期版本或是包含糟糕示例的CMake,它更加清晰、强大和优雅。文档内容详尽,从基础...
总结以上内容,这份文档为读者提供了一份详尽的CMake入门到精通的学习路径。它从CMake的历史和背景讲起,详细介绍了CMake的特点和优势,并且结合了作者个人在学习和使用CMake过程中的心得和实践案例。文档不仅注重...
理解并熟练使用CMake,不仅可以提升开发效率,还能更好地管理和维护复杂的工程结构。通过阅读《cmake实践.pdf》文档,你将能够深入掌握CMake的高级特性和实践技巧,从而在服务器领域构建C/C++工程时游刃有余。
总结来说,CMake是一个强大的构建工具,尤其适合处理复杂的跨平台项目。CMake 3.25.0 window 64位版本为Windows用户提供了一个高效且易用的构建环境,特别是对于C++开发者来说,CMake能够简化他们的项目管理,提高...
总结来说,使用CMake与Qt6结合,可以简化Windows环境下项目的构建和部署流程。通过合理配置CMakeLists.txt,我们可以确保Qt库和所有依赖文件在目标机器上正确可用,从而提高项目的移植性和可维护性。
CMake使用简单的语句(称为CMakeLists.txt文件)来定义项目结构、依赖关系和构建选项。这些语句是平台无关的,由CMake解析后生成特定平台的构建脚本,如Unix Makefiles、Visual Studio解决方案或Xcode项目。CMake的...
总结来说,这个离线CMake依赖包是针对Linux开发环境的重要资源,它提供了CMake和GCC编译器的离线版本,便于在无网络条件下的软件构建。同时,包含的mysql编译依赖包则方便了对MySQL项目的源码编译,这对于Linux系统...
总结来看,这份CMake中文手册.pdf详细介绍了CMake的基础概念、项目构建方法以及项目配置文件的编写,通过一个具体案例,逐步深入,让读者能够逐步掌握CMake的强大功能,从而在实际开发中提高开发效率和代码质量。
"cmake-cmake使用示例之Imported-Targets.zip"这个压缩包文件显然是一个关于CMake中Imported Targets特性的示例。Imported Targets是CMake处理外部库或已编译组件的一种方式,这对于依赖第三方库或者链接系统库的...
总结来说,"cmake_test cmake_test cmake_test" 项目是一个关于 CMake 配置和测试的实践案例,旨在帮助开发者掌握如何有效地管理和构建 CMake 项目,同时利用 CTest 实现自动化测试。通过这个项目,你可以提升在跨...