[TOC]
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
: 幫助