1. 项目目录结构

test3
├── add
│   ├── add.c
│   ├── add.h
│   └── CMakeLists.txt
├── build
├── CMakeLists.txt
├── config.h.in
├── example
│   ├── CMakeLists.txt
│   └── test.c
└── sub
├── CMakeLists.txt
├── sub.c
└── sub.h

很多开源项目都支持编译选项控制编译,用户可以根据编译选项定制需要的功能,典型例子如linux内核,用户可根据自身裁剪内核。

CMake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。

编译选项控制编译的核心思想:通过CMake生成config.h, config.h文件定义一些宏,项目代码包含config.h文件,通过这些宏控制代码模块。

2. 相关代码

2.1 add 模块

add.h

#ifndef _ADD_H
#define _ADD_H int add(const int a, const int b); #endif

add.c

#include "add.h"

int add(const int a, const int b)
{
return a+b;
}

CMakeLists.txt

# 递归获取目录下所有的C文件
file(GLOB_RECURSE c_files ./*.c) # 递归获取目录下所有的h文件
file(GLOB_RECURSE h_files ./*.h) #生成动态库和静态库
add_library(add_lib_shared SHARED ${c_files})
add_library(add_lib_static STATIC ${c_files}) #将动态库和静态库的名字设置为 add
set_target_properties(add_lib_shared PROPERTIES OUTPUT_NAME "add")
set_target_properties(add_lib_static PROPERTIES OUTPUT_NAME "add") #设置动态库版本
set_target_properties(add_lib_shared PROPERTIES VERSION 1.0 SOVERSION 1) #安装动态库和静态库
INSTALL(TARGETS add_lib_shared add_lib_static
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib) #安装头文件
INSTALL(FILES ${h_files} DESTINATION include)

2.2 sub 模块

sub.h

#ifndef _SUB_H
#define _SUB_H int sub(const int a, const int b); #endif

sub.c

#include "sub.h"

int sub(const int a, const int b)
{
return a - b;
}

CMakeLists.txt

#递归获取目录下所有的C文件
file(GLOB_RECURSE c_files ./*.c) # 递归获取目录下所有的h文件
file(GLOB_RECURSE h_files ./*.h) #生成动态库和静态库
add_library(sub_lib_shared SHARED ${c_files})
add_library(sub_lib_static STATIC ${c_files}) #将动态库和静态库的名字设置为 sub
set_target_properties(sub_lib_shared PROPERTIES OUTPUT_NAME "sub")
set_target_properties(sub_lib_static PROPERTIES OUTPUT_NAME "sub") #设置动态库版本
set_target_properties(sub_lib_shared PROPERTIES VERSION 1.0 SOVERSION 1) #设置动态库版本
set_target_properties(sub_lib_shared PROPERTIES VERSION 1.0 SOVERSION 1) #安装动态库和静态库
INSTALL(TARGETS sub_lib_shared sub_lib_static
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib) #安装头文件
INSTALL(FILES ${h_files} DESTINATION include)

2.3 example 模块

test.c

#include "config.h"

#ifdef ENABLE_ADD
#include "add.h"
#endif #ifdef ENABLE_SUB
#include "sub.h"
#endif #include <stdio.h> int main(int argc, char **argv)
{
int a = 10;
int b = 8;
#ifdef ENABLE_ADD
printf("%d + %d = %d\n", a, b, add(a, b));
#endif #ifdef ENABLE_SUB
printf("%d - %d = %d\n", a, b, sub(a, b));
#endif return 0;
}

CMakeLists.txt

# 添加头文件路径
include_directories(${PROJECT_SOURCE_DIR}/add)
include_directories(${PROJECT_SOURCE_DIR}/sub)
include_directories(${PROJECT_SOURCE_DIR}) # 添加第三方库(add)头文件路径
link_directories(${PROJECT_SOURCE_DIR}/lib) # 生成执行文件
add_executable(test_add_sub test.c) # 链接库文件
if(ENABLE_ADD)
target_link_libraries(test_add_sub add)
endif(ENABLE_ADD) if(ENABLE_SUB)
target_link_libraries(test_add_sub sub)
endif(ENABLE_SUB) INSTALL(TARGETS test_add_sub
RUNTIME DESTINATION bin)

2.4 顶层 CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

# 设置库文件输出目录
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) # 设置执行文件输出目录
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) # 添加编译选项
option(ENABLE_ADD "enable add" ON)
option(ENABLE_SUB "enable sub" ON) if(ENABLE_ADD)
add_subdirectory(add)
endif(ENABLE_ADD) if(ENABLE_SUB)
add_subdirectory(sub)
endif(ENABLE_SUB) # 加入一个头文件配置,让cmake对源码进行操作
configure_file(
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_SOURCE_DIR}/config.h"
) add_subdirectory(example)

说明

configure_file命令用于加入一个配置头文件config.h ,这个文件由CMake从config.h.in生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。

option命令添加了ENABLE_ADD 选项

ENABLE_SUB选项,并且默认值为ON

cmake 可以根据ENABLE_ADD 选项

ENABLE_SUB选项的值来控制是否编译add模块和sub模块。

要想在config.h生成对应的宏,需要对config.h.in进行如下配置

config.h.in

#cmakedefine ENABLE_ADD
#cmakedefine ENABLE_SUB

3. 配置&编译

默认配置&编译

$ cd build
$ cmake ..
$ make
$ cd ..
$ tree bin lib

效果如下:

bin
└── test_add_sub
lib
├── libadd.a
├── libadd.so -> libadd.so.1
├── libadd.so.1 -> libadd.so.1.0
├── libadd.so.1.0
├── libsub.a
├── libsub.so -> libsub.so.1
├── libsub.so.1 -> libsub.so.1.0
└── libsub.so.1.0

从生成的lib库,可以看出,add模块和sub模块都生成了。

查看config.h

#define ENABLE_ADD
#define ENABLE_SUB

自定义配置&编译

$ cd build
$ cmake -DENABLE_ADD=OFF ..
$ make
$ cd ..
$ tree bin lib

效果如下:

bin
└── test_add_sub
lib
├── libsub.a
├── libsub.so -> libsub.so.1
├── libsub.so.1 -> libsub.so.1.0
└── libsub.so.1.0

从生成的lib库,可以看出,add模块并未生成了。

查看config.h

/* #undef ENABLE_ADD */
#define ENABLE_SUB

使用ccmake工具进行配置

当我们的项目很大且配置选项很多的时候,可以选择ccmake工具进行配置编译选项,这个是交互式配置工具,有点类似内核的menuconfigure的功能。

说明

enter: 编辑选项

c: 配置

g:生成makefile

q:退出

h: 帮助

4. CMake 系列 - 项目添加编译选项的更多相关文章

  1. VisualGDB系列8:使用VS创建CMake Linux项目

    根据VisualGDB官网(https://visualgdb.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指正. 本文介绍如何使用VS来创建.构建.调试一 ...

  2. CMAKE为项目输出名添加后缀

    概述 本文将介绍cmake配置动态库和可执行程序两种,使用cmake为其添加Debug和Release配置下的后缀 动态库 下面将介绍使用CMAKE_DEBUG_POSTFIX和CMAKE_RELEA ...

  3. CMake入门-04-自定义编译选项

    工作环境 系统:macOS Mojave 10.14.6 CMake: Version 3.15.0-rc4 Hello,World! - 自定义编译选项 CMake 允许为项目增加编译选项,从而可以 ...

  4. 【tornado】系列项目(二)基于领域驱动模型的区域后台管理+前端easyui实现

    本项目是一个系列项目,最终的目的是开发出一个类似京东商城的网站.本文主要介绍后台管理中的区域管理,以及前端基于easyui插件的使用.本次增删改查因数据量少,因此采用模态对话框方式进行,关于数据量大采 ...

  5. 学习ASP.NET Core Razor 编程系列二——添加一个实体

    在Razor页面应用程序中添加一个实体 在本篇文章中,学习添加用于管理数据库中的书籍的实体类.通过实体框架(EF Core)使用这些类来处理数据库.EF Core是一个对象关系映射(ORM)框架,它简 ...

  6. 学习ASP.NET Core Razor 编程系列十——添加新字段

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  7. CMake 构建项目教程-简介

    CMake 构建项目教程-简介 Linux 平台构建项目,选择了CLion作为C++的IDE,而CLion默认就是使用CMake构建项目,所以这里记录了CMake在构建项目过程的一些小知识. 1. 项 ...

  8. Android Studio向项目添加C/C++原生代码教程

    说明:本文相当于官方文档的个人重新实现,官方文档链接:https://developer.android.com/studio/projects/add-native-code 向项目添加C/C++代 ...

  9. VisualGDB:使用VS创建CMake Linux项目

    转载地址:点击打开链接 根据VisualGDB官网(https://visualgdb.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指正. 本文介绍如何使用 ...

随机推荐

  1. VMware 与Ubuntu通过samba服务器共享文件

    Linux和windows在虚拟机下文件共享有很多种方式,常用的有使用VMware Tools共享和Samba服务器进行共享,使用VMware Tools这里就不说了,我使用的是Samba服务器. 其 ...

  2. jquery validate 二选一,错误提示在一处

    转载自:http://blog.51yip.com/jsjquery/1483.html 有一同事对jquery validate这个插件不熟,实现多处报错信息在一处,并且还有二选一的情况,二个输入框 ...

  3. angularjs结合plupload实现文件上传

    转载注明:(罗志强的博客) angularjs的指令directive非常好使,可以很方便的结合各种插件,实现很强大的功能. 今天用到了plupload,就拿它举例吧. 正常的plupload用法应该 ...

  4. 使用git拉取github上的项目

    一. 安装Git 去Git官网,下载安装包,一路点next,默认安装. 安装之后,在空白处右键,菜单显示有 Git GUI Here 和 Git Bash Here ,表示Git安装成功. 二. 配置 ...

  5. Linux下如何卸载软件(Debian系)

    说明:此方法适用于Debian.Ubuntu等带apt工具的操作系统. 步骤: 1.首先我们需要知道将要卸载的软件名称,比如我现在打算卸载tightvncserver,但是如果你不确定名称,没关系,可 ...

  6. hdu 2121 Ice_cream’s world II

    Ice_cream’s world II http://acm.hdu.edu.cn/showproblem.php?pid=2121 Time Limit: 3000/1000 MS (Java/O ...

  7. How to Evaluate Machine Learning Models, Part 4: Hyperparameter Tuning

    How to Evaluate Machine Learning Models, Part 4: Hyperparameter Tuning In the realm of machine learn ...

  8. (4.1)LingPipe在Eclipse中的运行

    酒店评论情感分析系统(四)——LingPipe在Eclipse中的运行 本来打算在做这个项目的时候,使用基于语义的文本倾向性分析方法,即先通过对评论文本进行中文分析,去停用词,然后在倾向性语义模式库的 ...

  9. ③ 设计模式的艺术-03.工厂方法(Factory Method)模式

    public interface Car { void run(); } public class Audi implements Car { @Override public void run() ...

  10. 正则表达式:Python 模块 re 简介

    为了使文章更具可读性,本文将正则表达式冗长的 语法介绍 放在了文章的末尾. 一.正则表达式简介 正则表达式(RegExp)是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(元字符 ...