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. linux下ffmpeg安装(转)

    1.ffmpeg下载地址: http://www.ffmpeg.org/download.html 2.解压   1 $ tar xzvf ffmpeg.tar.bz2 这里作者假设已经重命名为ffm ...

  2. HDU 6199 DP

    gems gems gems Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  3. 练习calico的网络policy

    1.安装docker,kubelet kubeadm kubectl 1 ssh-keygen 2 cat .ssh/authorized_keys 3 cat .ssh/id_rsa.pub 4 s ...

  4. zlib解压缩gzip

    zlib是个著名的开源解压缩库,gzip是一种压缩文件格式. zlib可以压缩原始数据并输出gzip文件,gzip文件中除了压缩数据外,还有描述这些数据的文件头,所以当原始数据较小时,会出现zlib的 ...

  5. centos7 samba匿名访问设置

    [global] workgroup = WORKGROUP server string = Samba Server %v netbios name = centos security = user ...

  6. 如何卸载掉eclipse中的插件

    First-->Help->About Eclipse Second--> Third-->

  7. 复制自身程序到windows目录和system32目录下

    功能:复制自身到windows目录和system32目录下. 参考代码: #include <stdio.h> #include <windows.h> void CopySe ...

  8. ⑥ 设计模式的艺术-06.建造者(Builder)模式

    场景 我们要建造一个复杂的产品.比如:神州飞船,Iphone.这个复杂的产品的创建.有这样一个问题需要处理: 装配这些子组件是不是有个步骤问题? 实际开发中,我们所需要的对象构建时,也非常复杂,有很多 ...

  9. 拦截asp.net输出流做处理

    本文标题是指对已经生成了HTML的页面做一些输出到客户端之前的处理. 方法的原理是:把Response的输出重定向到自定义的容器内,也就是我们的StringBuilder对象里,在HTML所有的向页面 ...

  10. MQTT协议及推送服务

    MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议,该协议构建 ...