使用CMake管理C/C++项目

2,620 views

使用make工具管理C++项目的构建时,使用makefile作为输入,makefile一般包括如下内容:

  • 编译前检查
    • 检查头文件
    • 检查方法
    • 检查基本类型
    • 检查库文件
    • 检查平台特性
    • 检查编译器版本
    • 检查编译器支持的选项
    • 检查链接器版本
    • 检查链接器支持的选项
  • 定义编译目标
    • 编译
    • 清理
    • 安装
    • 卸载
    • 生成文档
  • 定义目标间依赖关系
  • 定义源文件
    • 搜索路径
    • 源文件清单
  • 定义头文件
    • 搜索路径
    • 头文件清单
  • 依赖的库文件
    • 搜索路径
    • 库文件的清单
  • 定义编译选项
  • 定义链接选项

使用CMake来管理项目,不直接编写用来构建项目的makefile,而是使用CMake定义的指令,书写CMakeList.txt,通过构建来生成指定平台的makefile,进而实现构建项目。
对于需要跨Windows和Linux平台的项目来说,通过CMake工具来管理项目,可以生成Visual Studio和gmake使用的构建文件,非常方便。如下是样例。

# 定义对CMake工具的版本要求。
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)

# 定义项目名称。
PROJECT(MYLIB)

# 定义项目的版本号。
SET(MYLIB_VERSION_MAJOR 1)
SET(MYLIB_VERSION_MINOR 0)

# 定义头文件的搜索路径。
INCLUDE_DIRECTORIES(include ${PROJECT_BINARY_DIR})

# 定义对平台的检测项目。
## 1. 检测指定的头文件是否存在。
INCLUDE(CheckIncludeFile)
check_include_file(stdio.h                  HAVE_STDIO_H)
check_include_file(stdlib.h                 HAVE_STDLIB_H)
check_include_file(malloc.h                 HAVE_MALLOC_H)
check_include_file(alloca.h                 HAVE_ALLOCA_H)

## 对于相同特性,针对不同平台,指定不同的头文件。
IF(WIN32)
    check_include_file(intrin.h             HAVE_INTRIN_H)
ELSE()
    check_include_file(x86intrin.h          HAVE_INTRIN_H)
ENDIF()


## 2. 检测指定的C++头文件是否存在
INCLUDE(CheckIncludeFileCXX)
check_include_file_cxx(cerrno               HAVE_CERRNO_H)
check_include_file_cxx(vector               HAVE_VECTOR_H)
check_include_file_cxx(queue                HAVE_QUEUE_H)
check_include_file_cxx(limits               HAVE_LIMITS_H)
check_include_file_cxx(algorithm            HAVE_ALGORITHM_H)

## 3. 检测指定的方法是否存在
INCLUDE(CheckFunctionExists)
check_function_exists(malloc                HAVE_MALLOC)

## 4. 给定头文件,检测指定的方法是否存在
INCLUDE(CheckSymbolExists)
check_symbol_exists(alloca "alloca.h"       HAVE_ALLOCA)

## 5. 检测指定的C++特性是否可用
INCLUDE(CheckCXXSymbolExists)
INCLUDE(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
IF(COMPILER_SUPPORTS_CXX11)
    SET(CMAKE_CXX_FLAGS           "-std=c++11 ${CMAKE_CXX_FLAGS}")
ELSE()
    MESSAGE(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
ENDIF()
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD_REQUIRED True)

## 6. 针对给定的编译器,如GCC,开启指定的选项
IF(CMAKE_COMPILER_IS_GNUCXX)
    SET(CMAKE_CXX_FLAGS           "-Wall     ${CMAKE_CXX_FLAGS}")
    SET(CMAKE_CXX_FLAGS           "-g        ${CMAKE_CXX_FLAGS}")
    SET(CMAKE_CXX_FLAGS           "-fPIC     ${CMAKE_CXX_FLAGS}")
    # CMAKE_BUILD_TYPE
    SET(CMAKE_CXX_FLAGS_RELEASE   "-O3       ${CMAKE_CXX_FLAGS_RELEASE}")
    SET(CMAKE_CXX_FLAGS_RELEASE   "-s        ${CMAKE_CXX_FLAGS_RELEASE}")
    SET(CMAKE_CXX_FLAGS_DEBUG     "-ggdb     ${CMAKE_CXX_FLAGS_DEBUG}")
    SET(CMAKE_CXX_FLAGS_DEBUG     "-O0       ${CMAKE_CXX_FLAGS_DEBUG}")
ENDIF(CMAKE_COMPILER_IS_GNUCXX)

SET(CMAKE_MODULE_PATH ${CMAKE_ROOT}/Modules ${CMAKE_SOURCE_DIR}/cmake/Modules)
## 导入其它自定义的组件
INCLUDE(./cmake/avx.cmake)
# platform checks.

# 定义项目配置的头文件,文件内容见下。
CONFIGURE_FILE(
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)

# 定义源文件
SET(SRC_MYLIB a.cpp)
# 定义头文件
SET(INC_MYLIB a.h)

# 定义输出目标,指定为动态库
ADD_LIBRARY(MYLIB SHARED ${SRC_MYLIB} )

# 定义编译选项
target_compile_features(MYLIB PUBLIC cxx_std_11)

# 对于动态库,定义
SET_TARGET_PROPERTIES(MYLIB PROPERTIES 
    VERSION 1.2 
    SOVERSION 1
    )

INCLUDE(GenerateExportHeader)
generate_export_header(MYLIB
             BASE_NAME MYLIB
             EXPORT_MACRO_NAME MYLIB_EXPORT
             EXPORT_FILE_NAME MYLIB_Export.h

# 定义源文件
SET(SRC_MYEXE b.cpp)
# 定义输出目标,指定为可执行文件
add_executable(MYEXE ${SRC_MYEXE});
)

引入的自定义的文件avx.cmake


# 检测编译选项是否可用。
IF(CMAKE_COMPILER_IS_GNUCXX)
  INCLUDE(CheckCXXSourceRuns)
  INCLUDE(CheckCXXCompilerFlag)

## 1. 检测编译选项是否可用。
  check_cxx_compiler_flag(-msse CXX_HAS_SSE)

# 2. 检测编译选项是否可用。
  SET(CMAKE_REQUIRED_FLAGS -msse)
  CHECK_CXX_SOURCE_RUNS(
  "#include 
  int main()
  {
    __m128 x;
    x = _mm_set_ps(1.0f,1.0f,1.0f,1.0f);
      
    return 0;
  }" SSE_RUN)

  IF(${SSE_RUN})
      SET(HAVE_SSE 1)
  ENDIF(${SSE_RUN})

  IF(${HAVE_SSE})
    MESSAGE(STATUS "\tSSE support... yes")
  ELSE()
    MESSAGE(STATUS "\tSSE support... no")
  ENDIF()

  IF(CXX_HAS_SSE)
    SET(CMAKE_CXX_FLAGS "-msse ${CMAKE_CXX_FLAGS}")
  ENDIF()
ENDIF()

项目配置的头文件,文件内容见下。

#pragma once
#ifndef __MYLIB_CONFIG_H__
#define __MYLIB_CONFIG_H__

#include "MYLIB_Export.h"

#define MYLIB_VERSION_MAJOR @MYLIB_VERSION_MAJOR@
#define MYLIB_VERSION_MINOR @MYLIB_VERSION_MINOR@

#if defined (_WIN32)
  #if defined(MYLIB_EXPORTS)
    #define  MYLIB_DLL_EXPORT __declspec(dllexport)
  #else
    #define  MYLIB_DLL_EXPORT __declspec(dllimport)
  #endif /* MYLIB_EXPORTS */
#else /* defined (_WIN32) */
 #define MYLIB_DLL_EXPORT
#endif

#cmakedefine HAVE_STDIO_H        @HAVE_STDIO_H@
#cmakedefine HAVE_STDLIB_H       @HAVE_STDLIB_H@
#cmakedefine HAVE_MALLOC_H       @HAVE_MALLOC_H@
#cmakedefine HAVE_ALLOCA_H       @HAVE_ALLOCA_H@
#cmakedefine HAVE_INTRIN_H       @HAVE_INTRIN_H@
#cmakedefine HAVE_MALLOC         @HAVE_MALLOC@

#endif

参考资料



若非注明,均为原创,欢迎转载,转载请注明来源:使用CMake管理C/C++项目

关于 JackieAtHome

基层程序员,八年之后重新启航

此条目发表在 Linux 分类目录,贴了 标签。将固定链接加入收藏夹。