【CMake】教程:第2步 添加库

【CMake】教程:第2步 添加库

【问题】

当写的程序由多个模块组成,如何组织这些代码,以及如何利用模块代码生成的库呢?

【解答思路】

  1. 编写模块代码
  2. 将模块代码生成库
  3. 编写调用程序
  4. 编译链接模块库

以求一个数的平方根为例。

编写模块代码

MathFunctions.h
#ifndef __MATHFUNCTIONS_H__
#define __MATHFUNCTIONS_H__

// 求一个数的平方根
double mysqrt(double x);

#endif /* __MATHFUNCTIONS_H__ */

每个头文件需要加上 #ifndef ,以免重复添加头文件,造成重复声明。

mysqrt.cpp
#include 
#include "MathFunctions.h"

double mysqrt(double x)
{
    if (x <= 0)
    {
        return 0;
    }

    double result = x;

    for (int i = 0; i < 10; ++i)
    {
        if (result <= 0)
        {
            result = 0.1;
        }
        double delta = x - (result * result);
        result = result + 0.5 * delta / result;
        std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
    }

    return result;
}

生成库

一个模块生成库,用 add_library 即可。

CMakeLists.txt
# 如果模块引用其他模块,应链接相应库
add_library(MathFunctions mysqrt.cpp)

调用程序

调用程序可能用c++自带的函数库也可以用模块库,可以用选择编译的方式进行调用;

tutorial.cpp
// 一个简单的计算平方根的程序
#include 
//#include  // when use c++11
#include 
#include 
#include "MathFunctions.h"
#include "TutorialConfig.h"

int main(int argc, char* argv[])
{
    // 打印版本号
    std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
                << Tutorial_VERSION_MINOR << std::endl;

    if (argc < 2) {
        std::cout << "Usage: " << argv[0] << " number" << std::endl;
        return 1;
    }

    // 数据转换为 double
    // const double inputValue = atof(argv[1]);
    const double inputValue = std::stod(argv[1]);  // c++11

#ifdef USE_MYMATH
    const double outputValue = mysqrt(inputValue);
#else
    // 计算平方根
    const double outputValue = sqrt(inputValue);
#endif

    std::cout << "The square root of " << inputValue << " is " << outputValue
                << std::endl;
    return 0;

}

#ifdef USE_MYMATH 中的 USE_MYMATH 是在 CMakeLists.txt里定义的,然后通过 config 的方法将其配置到头文件 TutorialConfig.h中。

链接库

CMakeLists.txt

主CMakeLists.txt如下

cmake_minimum_required(VERSION 3.10)

# 设置项目名称
# project(Tutorial)
# 设置项目名称及版本号
project(Tutorial VERSION 1.1)

# 设置C++
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

option(USE_MYMATH "Use tutorial provided math implementation" ON)

# 通过配置文件将版本号配置到程序中,当然也可以通过git的编号或版本号自动配置进去
# 当然也可以通过配置文件将其他的CMake参数配置到程序中,
# 例如一些不常改变的参数可以通过宏配置进去
configure_file(TutorialConfig.h.in TutorialConfig.h)

if (USE_MYMATH)
    add_subdirectory(MathFunctions)
    list(APPEND EXTRA_LIBS MathFunctions)
    list(APPEND EXTRA_INCS "${PROJECT_SOURCE_DIR}/MathFunctions")
endif(USE_MYMATH)


# 添加执行程序
add_executable(Tutorial tutorial.cpp)

# 添加链接库
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})


# 添加头文件
target_include_directories(Tutorial PUBLIC 
                        "${PROJECT_BINARY_DIR}" 
                        ${EXTRA_INCS}
                        )

option 指令可以将某些变量设置成开关量,可以根据开关量进行编译。
如果 option 里设置为 ON,在例子中实际就是将 USE_MYMATH 设置为 True

add_subdirectory: 将包含子目录,进入子目录后会查找内部的 CMakeLists.txt 继续执行。

target_link_libraries: 添加链接库,除了自己编译的模块,也可以链接其他开源库等。

target_include_directories: 添加目标的链接目录。

TutorialConfig.h.in
// the configured options and settings for Tutorial

#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@

#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

#cmakedefine USE_MYMATH

如果 USE_MYMATH 在编译的时候指定为 ON,则 #cmakedefine USE_MYMATH配置后变成 #define USE_MYMATH

#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@@...@部分替换成 CMakeLists.txt里定义的值,如本例中为 1

【汇总】

## 目录结构如下
.
├── build
├── CMakeLists.txt
├── MathFunctions
│   ├── CMakeLists.txt
│   ├── MathFunctions.h
│   └── mysqrt.cpp
├── TutorialConfig.h.in
└── tutorial.cpp
mkdir build && cd build
cmake ..
make 
./Tutorial 100

你可能感兴趣的:(项目及产品管理,c++,c语言,开发语言)