什么是cmake

由官网的介绍,cmake是一套开源的跨平台的工具库,这套库用来控制软件开发中的构建(build), 测试(test),封装(package)的。cmake同时简单的与平台和编译器无关的配置文件来控制编译过程,生成所在平台的Makefile或workspaces,并且你可以设置这些文件中的编译环境。

cmake提供了什么

  1. generator

    cmake通过提供多种与所在平台可用的构建工具对应的generators,来生成构建工具的input文件(eg. Makefile)。 比如在Mac平台上的generator有:

     The following generators are available on this platform (* marks default):
     * Unix Makefiles               = Generates standard UNIX makefiles.
     Ninja                        = Generates build.ninja files.
     Xcode                        = Generate Xcode project files.
     CodeBlocks - Ninja           = Generates CodeBlocks project files.
     CodeBlocks - Unix Makefiles  = Generates CodeBlocks project files.
     CodeLite - Ninja             = Generates CodeLite project files.
     CodeLite - Unix Makefiles    = Generates CodeLite project files.
     Sublime Text 2 - Ninja       = Generates Sublime Text 2 project files.
     Sublime Text 2 - Unix Makefiles
                                 = Generates Sublime Text 2 project files.
     Kate - Ninja                 = Generates Kate project files.
     Kate - Unix Makefiles        = Generates Kate project files.
     Eclipse CDT4 - Ninja         = Generates Eclipse CDT 4.0 project files.
     Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files.
    

    generator 生成构建工具使用一个叫CMakeLists.txt的脚本文件,这个文件中定义了cmake所要执行的命令。

  2. CMakeLists.txt

    编写CMakeLists.txt要使用cmake提供的

    1. 命令(command)
      • 流程控制命令(if, else等)
      • 包/库查找命令 (find_package,find_library等)
      • 添加目标命令(add_executable, add_library, add_subdirectory 等)
      • include命令 (include_directories等)
      • link命令(link_libraries, link_directoriestarget_link_libraries等)
      • 设置/获取变量(set get_property等)
    2. 模块(module)
      • FindXXX模块: 查找XXX包/库,并设置相关的变量,e.g. XXX_FOUND, XXX_VERSION
      • CheckXXX模块: e.g. CheckFunctionExists, CheckIncludeFiles, CPack, CTest
      • 等等
    3. 属性(property) 提供了一些接口可以配置目标的编译选项或其他选项 e.g.LINK_OPTIONS, COMPILE_FLAGS

    4. 变量(variables) 由cmake提供的变量,这些变量对写CMakeLists.txt很有意义 e.g. ANDROID APPLE BORLAND IOS LIBRARY_OUTPUT_PATH MINGW MSVC

例子

tutorial.cxx

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"

#ifdef USE_MYMATH
#include "mysqrt.h"
#endif

int main(int argc, char *argv[])
{
    if(argc < 2)
    {
        fprintf(stdout, "%s Version %d.%d\n",
        argv[0],
        Tutorial_VERSION_MAJOR,
        Tutorial_VERSION_MINOR);
        fprintf(stdout, "Usage: %s number\n", argv[0]);
        return 1;
    }

    double inputvalue = atof(argv[1]);
    #if defined(HAVE_LOG) && defined(HAVE_EXP)
        double outputvalue = exp(log(inputvalue)*0.5);
    #else
        #ifdef USE_MYMATH
            double outputvalue = InvSqrt(inputvalue);
        #else
            double outputvalue = sqrt(inputvalue);
        #endif
    #endif

    fprintf(stdout, "The square root of %g is %g\n",
        inputvalue,outputvalue);
    return 0;
}

MathFunctions/mysqrt.cpp

float InvSqrt(float x)
{
    float xhalf = 0.5f*x;
    int i = *(int*)&x; // get bits for floating VALUE 
    i = 0x5f375a86- (i>>1); // gives initial guess y0
    x = *(float*)&i; // convert bits BACK to float
    x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy
    x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy
    x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy

    return 1/x;
}

MathFunctions/mysqrt.h

float InvSqrt(float x);

MathFunctions/CMakeLists.txt

# add static library MathFunctions with source code mysqrt.cxx
add_library(MathFunctions SHARED mysqrt.cxx)
set_target_properties(MathFunctions PROPERTIES VERSION 1.2)

install(TARGETS MathFunctions DESTINATION bin)
install(FILES mysqrt.h DESTINATION include)

TutorialConfig.h.in

#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#cmakedefine USE_MYMATH
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
project(Tutorial)

# The version number
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)

# does this system provide the log and exp functions?
include(${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)
check_function_exists(log HAVE_LOG)
check_function_exists(exp HAVE_EXP)

# configure a header file to pass some of the CMake settings
# to the source code
configure_file(
    "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
    "${PROJECT_BINARY_DIR}/TutorialConfig.h"
)

# add the binary tree to the search path for include files
# so that we will find the TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")

# should we use our own math functions
option(USE_MYMATH "USE tutorial provided math implementation" ON)

if(USE_MYMATH)
    # add the mysqrt.h
    include_directories("${PROJECT_SOURCE_DIR}/MathFunctions")
    # the source code mysqrt.cxx
    add_subdirectory(MathFunctions)
    set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif(USE_MYMATH)


# add the add_executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial ${EXTRA_LIBS})

install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
 DESTINATION include)

 enable_testing()

#define a macro to simplify adding tests, then use it
macro(do_test arg result)
    add_test(TutorialComp${arg} Tutorial ${arg})
    set_tests_properties(TutorialComp${arg} PROPERTIES 
    PASS_REGULAR_EXPRESSION ${result})
endmacro(do_test)


do_test(25 "25 is 5")
do_test(0.01 "0.01 is 0.1")

# 构建一个 CPack 安装包
include (InstallRequiredSystemLibraries)
set (CPACK_RESOURCE_FILE_LICENSE
  "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set (CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set (CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
include (CPack)
# Build and Install
mkdir -p build && cd build
cmake -DCMAKE_INSTALL_PREFIX=$HOME/usr/local ..
make && make test && make install
# Pack
cpack -C CPackConfig.cmake # cpack -C CPackSourceConfig.cmake