4. CMake 系列 - 项目添加编译选项

Posted standardzero

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4. CMake 系列 - 项目添加编译选项相关的知识,希望对你有一定的参考价值。

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 系列 - 项目添加编译选项的主要内容,如果未能解决你的问题,请参考以下文章

CMake系列:问题解决点滴记录

小技巧 | 自动生成版本号及编译时间

CMake入门学习

CMake入门学习

cmake中添加-fPIC编译选项方法

CMake基础教程(17)add_compile_options添加编译选项(-g -Werror)