`
gaofen100
  • 浏览: 1218332 次
文章分类
社区版块
存档分类
最新评论

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_DIRPROJECT_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")

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

分享到:
评论

相关推荐

    cmake学习笔记 密码 123456

    cmake学习笔记 密码 123456

    个人cmake学习笔记

    cmake学习笔记 CMake 是一个跨平台的构建工具,用于管理软件的编译和安装过程。下面是 cmake 的一些基本知识点和使用技巧。 1. 生成器错误解决方案 在使用 cmake 时,可能会遇到生成器错误的问题。解决方案是使用...

    cMake 学习笔记,快速入门

    **cMake 学习笔记,快速入门** cMake 是一种跨平台的构建系统,用于管理软件项目的构建过程。它能够生成各种编译器所需的构建文件,如Visual Studio的解决方案文件或Unix Makefiles,使得开发者无需关心底层构建...

    cmake 学习笔记(一) - 1+1=10 - 博客频道 - CSDN1

    【CMake学习笔记(一)】介绍 CMake是一个跨平台的构建系统,它用于管理项目的构建过程,支持多种编译器和构建工具。在C++领域,许多大型项目如KDE4、Qt4的Python绑定(PySide)以及开源图像处理库OpenCV都采用CMake...

    cmake 学习笔记(三) - Mingz技术博客 - 博客频道 - CSDN1

    本篇学习笔记主要探讨了如何使用CMake来寻找和管理第三方库,特别是通过`find_package`命令来自动化这一过程。 `find_package`是CMake的一个关键功能,它允许在构建项目时自动定位并链接所需的外部库。例如,当你...

    cmake 学习笔记(二) - Mingz技术博客 - 博客频道 - CSDN1

    在`CMake学习笔记(二)`中,作者深入介绍了`CMake`的基本语法和常用命令。以下是对这些知识点的详细说明: 1. **基本语法与注释**: 在`CMakeLists.txt`文件中,注释使用`#`符号开始。命令通常由`COMMAND(参数1 ...

    CMake入门笔记-王逸凡_488011331

    CMake 是一种构建工具,它旨在管理项目中的源文件和其他非源文件,使得构建过程更加简单和高效。CMake 的核心是 CMakeLists.txt 文件,这个文件定义了...通过学习和熟练掌握 CMake,可以提升项目的可维护性和开发效率。

    CMake学习资料.rar

    《一起学习CMake.doc》可能是一份综合性的学习笔记或者社区贡献的学习材料,包含了作者在学习CMake过程中遇到的问题、解决方案和经验总结,可能包含了一些实战案例和技巧,帮助读者避免常见陷阱,提高CMake的使用...

    CMake——入门到精通.pdf

    这表明,该文件不仅提供了基础概念的讲解,还包含了作者的个人实践经验和学习笔记,为初学者提供了宝贵的参考。 标签“cmake”简单直接,但表明了文件的主要内容是围绕CMake这一主题展开的。 在文档的具体内容中,...

    CMake_Practice(带书签版本).pdf

    本文档《CMake 实践》(Cmake Practice)是边学习边编写的成果,更像是一个学习笔记和 Tutorial,旨在帮助读者快速掌握 CMake 的使用和实践。同时,本文档也欢迎读者对其进行修改和补充,以共同提高 CMake 的使用和...

    CMake实践 中文翻译版

    文档包含了作者在学习过程中的一些学习笔记和心得体会,以及在实际应用中遇到的问题和解决方案。作者也明确表示了,希望文档能够开放给所有人阅读、修改和补充,以共同提升对cmake的掌握和运用。

    cmake 学习笔记

    CMake 是一个跨平台的构建系统,用于管理项目的构建过程,尤其适合多语言和多配置的项目。在本文中,我们将深入探讨...学习 CMake 不仅能够提高项目构建的效率,还能使开发者更好地控制编译选项,适应不同的开发需求。

    cmake实践.pdf

    该书是作者在学习CMake的过程中编写的学习笔记和教程,旨在为其他用户提供实用的参考。尽管官方文档不多且存在错误,但是通过实际经验的积累和CMake社区的帮助,作者逐渐深入理解了CMake的使用方法,并在文档中分享...

    【二合一】CMake 实践+开发手册详解.pdf

    本文档是边学习边编写的成果,更像是一个学习笔记和 Tutorial,因此难免有失误或者理解不够透彻的地方。 在 CMake 中,变量的使用是非常重要的。例如,在介绍 Find&lt;Name&gt; 模块编写的文档中,模块名称为 FOO,但是...

    CMake Practice.pdf

    因此,本教程《cmake实践》是由一位KDE开发者撰写,通过边学习边编写的成果,既是一个学习笔记也是一个教程(Tutorial)。该文档面向实际应用,旨在帮助用户掌握CMake的使用,并鼓励所有读者对文档进行修改和补充,...

    CMake官网教程中的工程

    在"CMake入门笔记--CMake官网教程中的工程"中,我们可以学习到如何使用CMake来管理和构建项目。这份笔记可能包含了对CMake基础概念的解释,如`CMakeLists.txt`文件的编写,这是每个CMake项目的核心,它包含了项目的...

    超详细的cmake教程(去糟粕-重实践-学以致用).pdf

    CMake实践是一个学习文档,它的编写初衷是面向使用和实用,更像一个学习笔记和教程。文档的作者在学习过程中发现官方文档较少且错误较多,例如在介绍Find模块编写时出现的错误。因此,作者在学习的同时编写这份文档...

    cmake实战 ------学习cmake的绝佳查询手册

    cmake实战,学习cmake的绝佳查询手册,意在为读者提供一本实用的cmake学习参考书籍。cmake是一个开源的跨平台构建系统,最初用于管理VTK工具套件的构建过程,后发展成为一个独立的项目。由于其在KDE4项目中的成功...

    vscode+gtest+cmake

    6. **学习资源**:压缩包中的“cmake学习笔记”、“vscode学习笔记”和“gtest学习笔记”应包含详细的步骤和示例,帮助初学者理解这些工具的使用方法。它们可能会涵盖CMake的基本语法、VSCode的配置选项、gtest测试...

Global site tag (gtag.js) - Google Analytics