第 2 步:添加库
现在我们将在我们的项目中添加一个库。这个库将包含我们自己的计算平方根的实现。然后可执行文件可以使用这个库而不是编译器提供的标准平方根函数。
对于本教程,我们将把库放到一个名为MathFunctions子目录中. 这个目录已经包含了一个头文件 MathFunctions.h,和一个源文件mysqrt.cxx。源文件有一个调用函数mysqrt,它提供与编译器函数sqrt类似的功能。
将以下仅一行命令的CMakeLists.txt文件添加到MathFunctions 目录中:
*MathFunctions/CMakeLists.txt*
add_library(MathFunctions mysqrt.cxx)
为了使用新库,我们将在顶层CMakeLists.txt文件中添加一个add_subdirectory() 调用,以便构建库。我们将新库添加到可执行文件中,并添加MathFunctions为包含目录,以便mysqrt.h可以找到头文件。顶层CMakeLists.txt文件的最后几行现在应该如下所示:
*CMakeLists.txt *
# add the MathFunctions library
add_subdirectory(MathFunctions)
# add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC MathFunctions)
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/MathFunctions"
)
现在让我们将MathFunctions库设为可选。虽然对于本教程来说确实没有必要这样做,但对于较大的项目来说,这很常见。第一步是向顶层 CMakeLists.txt文件添加一个选项。
*CMakeLists.txt*
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# configure a header file to pass some of the CMake settings
# to the source code
configure_file(TutorialConfig.h.in TutorialConfig.h)
该选项将显示在cmake-gui和具有默认值ON的ccmake中,以方便用户更改。此设置将存储在缓存中,因此用户无需在每次在构建目录上运行 CMake 时设置该值。
下一个更改是使构建和链接MathFunctions库成为有条件的。为此,我们将创建一个if语句来检查选项的值。在if块内,将前面add_subdirectory()命令和一些用来存储链接到库所需的信息、在Tutorial Target里将子目录添加为包含目录的列表命令附加进来。顶层CMakeLists.txt文件的结尾现在如下所示:
*CMakeLists.txt*
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()
# add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
${EXTRA_INCLUDES}
)
请注意使用该变量EXTRALIBS来收集任何可选库,以便稍后链接到可执行文件中。该变量 EXTRAINCLUDES类似地用于可选头文件。这是处理许多可选组件时的经典方法,我们将在下一步中介绍现代方法。
对源代码的相应更改相当简单。首先,如果需要,请在tutorial.cxx中包含标题:MathFunctions.h
*tutorial.cxx*
#ifdef USE_MYMATH
# include "MathFunctions.h"
#endif
然后,在同一个文件中,USE_MYMATH控制使用哪个平方根函数:
*tutorial.cxx*
#ifdef USE_MYMATH
const double outputValue = mysqrt(inputValue);
#else
const double outputValue = sqrt(inputValue);
#endif
由于源代码现在需要USE_MYMATH我们可以 TutorialConfig.h.in使用以下行添加它:
*TutorialConfig.h.in*
#cmakedefine USE_MYMATH
练习:TutorialConfig.h.in:为什么我们 在选项之后进行配置很重要USE_MYMATH?如果我们颠倒两者会发生什么?
运行cmake可执行文件或 cmake-gui配置项目,然后使用您选择的构建工具构建它。然后运行构建的 Tutorial 可执行文件。
现在让我们更新的值USE_MYMATH。如果你在终端里,最简单的方法是使用 cmake-gui或者 ccmake。或者,如果您想从命令行更改选项,请尝试:
cmake ../Step2 -DUSE_MYMATH=OFF
重新构建并再次运行教程。
哪个函数提供更好的结果,sqrt或者mysqrt?
附完整代码:
1. tutorial.cpp
#include<iostream>
#include<string>
#include<math.h>
#include"TutorialConfig.h"
#ifdef USE_MYMATH
#include "MathFunctions/MathFunctions.h"
#endif
int main(int argc, char * argv[])
{
//std::cout << argc << std::endl;
if (argc < 2) {
// report version
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "." << Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
system("pause");
return 1;
}
else
{
const double d = std::stod(argv[1]);
//double d;
std::cout << "请输入一个实数:";
//std::cin >> d;
std::cout << std::endl;
#ifdef USE_MYMATH
std::cout << "这是自定义库" << std::endl;
std::cout << d << "的平方根是:" << mysqrt(d) << std::endl;
#else
std::cout << "这是系统库" << std::endl;
std::cout << d << "的平方根是:" << sqrt(d) << std::endl;
#endif
std::cout << std::endl;
return 0;
}
}
2. TutorialConfig.h.in
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#cmakedefine USE_MYMATH
3. CmakeLists.txt
#step1
cmake_minimum_required(VERSION 3.20)
#step1
project(Tutorial VERSION 1.0)
#step1-1
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
#step2-1
option(USE_MYMATH "Use tutorial provided math implementation" ON)
#step1-1
configure_file(${PROJECT_SOURCE_DIR}/TutorialConfig.h.in ${PROJECT_SOURCE_DIR}/TutorialConfig.h)
#step2
# add the MathFunctions library
#add_subdirectory(MathFunctions)
#step2-1
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()
#step1
# add the executable
add_executable( Tutorial tutorial.cpp)
#step2-1
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
#step1-1
#target_include_directories(Tutorial PUBLIC
# "${PROJECT_SOURCE_DIR}"
# )
#step2
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
#target_include_directories(Tutorial PUBLIC
# "${PROJECT_SOURCE_DIR}"
# "${PROJECT_SOURCE_DIR}/MathFunctions"
# )
#step2-1
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_SOURCE_DIR}"
${EXTRA_INCLUDES}
)
4. MathFunctions/mysqrt.cpp
#include "MathFunctions.h"
double mysqrt(double d)
{
return sqrt(d);
}
5. MathFunctions/MathFunctions.h
#include <iostream>
#include <string>
#include <math.h>
double mysqrt(double a);
6. MathFunctions/CmakeLists.txt
add_library(MathFunctions mysqrt.cpp)