当写的程序由多个模块组成,如何组织这些代码,以及如何利用模块代码生成的库呢?
以求一个数的平方根为例。
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如下
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