2401cmake,学习cmake3

步7:构建安装器.

下一步,假定想要发布项目,以便其他人可用.想在多种平台上发布二进制和源码.这和第四步有所不同.

第四步安装的是从源码构建的二进制.本例中,会构建支持二进制安装和包管理特性安装包.为此,使用CPack来生成对应平台的安装器.

即,需要在顶级CMakeLists.txt底添加几行:

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)

就这样就可以了.通过包含InstallRequiredSystemLibraries来开始.这一模块会包含项目所需当前平台的运行库.下一步在存储项目许可和版本信息的位置,设置一些CPack变量.

先前已设置好了版本信息.这一步在顶级源目录中包含license.txt.

最后,包含CPackmodule.CPack模块会用这些变量和当前系统的其他变量来配置安装器.

下一步,与正常一样,构建项目然后运行cpack可执行文件.

binary目录下运行以下命令以构建二进制发布:

cpack

-G选项来指定生成器,对多配置构建,用-C来指定配置,如:

cpack -G ZIP -C Debug

为了构建源码发布,可:

cpack --config CPackSourceConfig.cmake

或运行makepackage,或在IDE中右键Package目录然后BuildProject.
运行二进制目录中的安装器,然后运行安装可执行文件并验证可运行.

步8:增加支持Dashboard

添加把测试提交到仪表盘的支持是很简单的.在支持测试一步中,已给项目定义了一系列测试.现在只需要运行这些测试,并提交他们到仪表盘上即可.

为了支持仪表盘,在顶级CMakeLists.txt里包含CTest模块.

//启用测试
enable_testing()

替换为

//启用仪表板脚本
include(CTest)

CTest模块会自动调用enable_testing(),所以可从CMake文件里移除这一语句.

还要在顶级目录下(指定项目名并提交到面板目录),创建CTestConfig.cmake文件.

set(CTEST_PROJECT_NAME "CMakeTutorial")
set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
set(CTEST_DROP_SITE_CDASH TRUE)

ctest可执行文件,会在运行时读取该文件.可运行cmakecmake-gui配置项目,但是不构建项目,来创建简单面板.切换到二进制树目录下然后运行:

ctest [-VV] -C Debug -D Experimental

或在IDE中构建Experimental目标.

ctest可执行文件会构建和测试项目,并提交结果Kitware的公共面板:https://my.cdash.org/index.php?project=CMakeTutorial.

步9:混合静态和共享

展示BUILD_SHARED_LIBS变量是如何控制add_library().且允许控制构建无显式类型(STATIC,SHAREDMODULEOBJECT)的库.

要在顶级CMakeLists.txt里增加BUILD_SHARED_LIBS.用option()命令来让用户可选的开或关.

下一步要重构MathFunctions,让它变成封装调用mysqrtsqrt真实的库,而非调用代码来实现逻辑的库.

也表明USE_MYMATH不再控制构建MathFunctions,而是控制的行为.

第一步是更新顶级CMakeLists.txt的第一节如下:

cmake_minimum_required(VERSION 3.10)
//设置项目名和版本
project(Tutorial VERSION 1.0)
//指定`C++`标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
 //控制`静态库和共享库`的`构建位置`,这样在`Windows`上就不需要修改运行`可执行文件`的路径

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)

//配置头文件为仅传递版本号
configure_file(TutorialConfig.h.in TutorialConfig.h)
//添加`MathFunctions`库
add_subdirectory(MathFunctions)
//添加可执行文件
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC MathFunctions)

既然总是使用MathFunctions.需要更新库的逻辑.因此在MathFunctions/CMakeLists.txt里需要创建一个SqrtLibrary.

该库会在启用USE_MYMATH构建并安装.现在,显式要求按静态库构建SqrtLibrary就可以了.

结果是MathFunctions/CMakeLists.txt应该如下:

//添加运行的库
add_library(MathFunctions MathFunctions.cxx)
//说明外部`链接`都要包含当前的`源目录`才能找到`MathFunctions.h`,而我们不必.
target_include_directories(MathFunctions
    INTERFACE${CMAKE_CURRENT_SOURCE_DIR}
)
//应该用自己的数学函数吗
option(USE_MYMATH "用自己的" ON)
if(USE_MYMATH)
  target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
  # 先加造表的exe
  add_executable(MakeTable MakeTable.cxx)
  # 加命令来生成源码
  add_custom_command(
    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
    COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
    DEPENDS MakeTable
    )
  # 干活的库
  add_library(SqrtLibrary STATIC
    mysqrt.cxx
    ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  )
  # 依赖`dir`来找Table.h
  target_include_directories(SqrtLibraryPRIVATE
      ${CMAKE_CURRENT_BINARY_DIR}
  )
  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()

//定义符号,说明在`窗口`上,构建时要用`declspec(dllexport)`
target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
//安装规则
set(installable_libs MathFunctions)
if(TARGET SqrtLibrary)
  list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs} DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include)

下一步更新MathFunctions/mysqrt.cxx以使用mathfunctionsdetail名字空间:

#include 
#include "MathFunctions.h"
//包括生成的表
#include "Table.h"
namespace mathfunctions {
namespace detail {
//使用简单操作的`hack`平方根计算
double mysqrt(double x)
{
  if (x <= 0) {
    return 0;
  }
  //用该表帮助查找初值
  double result = x;
  if (x >= 1 && x < 10) {
    std::cout << "用表" << std::endl;
    result = sqrtTable[static_cast(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;
}
}
}

还要调整tutorial.cxx,不再使用USE_MYMATH:
1.总是包含MathFunctions.h
2.总是使用mathfunctions::sqrt
3.不包含cmath

最后更新MathFunctions/MathFunctions.h来用dll导出定义:

#if defined(_WIN32)
#  if defined(EXPORTING_MYMATH)
#    define DECLSPEC __declspec(dllexport)
#  else
#    define DECLSPEC __declspec(dllimport)
#  endif
#else // non windows
#  define DECLSPEC
#endif

namespace mathfunctions {
    double DECLSPEC sqrt(double x);
}

这时,如果再构建,会注意到链接失败,因为试图把包含非位置无关代码(PIC)静态库(指SqrtLibrary)和另一个包含(PIC)的库(指MathFunctions)组合在一起.

不管什么构建类型,要显式设置SqrtLibraryPOSITION_INDEPENDENT_CODE(PIC)目标属性为True.

  # 默认共享库时,SqrtLibrary需要PIC
  set_target_properties(SqrtLibrary PROPERTIES
    POSITION_INDEPENDENT_CODE${BUILD_SHARED_LIBS}
  )
  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)

练习:修改MathFunctions.h来使用dll导出定义.使用CMake文档,能否用辅助模块来简化?

你可能感兴趣的:(cmake,c++,cmake)