cmake wiki

1.cmake教程

1.基本起点:

1.基本点

最基本的项目是从源代码文件构建的可执行文件。 对于简单的项目,只需要两行CMakeLists.txt文件。

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
add_executable(Tutorial tutorial.cxx)

请注意,此示例在CMakeLists.txt文件中使用小写命令。 CMake支持上,下和混合大小写命令。

2.添加版本号和配置的头文件

我们将添加的第一个功能是为我们的可执行文件和项目提供版本号。 虽然您可以在源代码中专门执行此操作,但在CMakeLists.txt文件中执行此操作可提供更大的灵活性。

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
# The version number.
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
 
# 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 TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")
 
# add the executable
add_executable(Tutorial tutorial.cxx)

由于配置的文件将写入二叉树,我们必须将该目录添加到路径列表中以搜索包含文件。 然后,我们在源代码树中创建一个TutorialConfig.h.in文件,其中包含以下内容:

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

当CMake配置此头文件时,@ Tutorial_VERSION_MAJOR @和@Tutorial_VERSION_MINOR @的值将替换为CMakeLists.txt文件中的值。 接下来,我们修改tutorial.cxx以包含配置的头文件并使用版本号。

#include "TutorialConfig.h"

2.添加库

现在我们将为我们的项目添加一个库。 该库将包含我们自己的实现,用于计算数字的平方根。 然后,可执行文件可以使用此库而不是编译器提供的标准平方根函数。 在本教程中,我们将把库放入一个名为MathFunctions的子目录中。

add_library(MathFunctions mysqrt.cxx)

源文件mysqrt.cxx有一个名为mysqrt的函数,它提供与编译器的sqrt函数类似的功能。 为了使用新库,我们在顶级CMakeLists.txt文件中添加了一个add_subdirectory调用,以便构建库。 我们还添加了另一个include目录,以便可以为函数原型找到MathFunctions / MathFunctions.h头文件。 最后一个更改是将新库添加到可执行文件中。 顶级CMakeLists.txt文件的最后几行现在看起来像:

include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
add_subdirectory (MathFunctions) 
 
# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial MathFunctions)

现在让我们考虑使MathFunctions库可选。 在本教程中,没有任何理由这样做,但是有更大的库或库依赖于您可能想要的第三方代码。 第一步是向顶级CMakeLists.txt文件添加一个选项。

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

这将显示在CMake GUI中,默认值为ON,用户可以根据需要更改。 此设置将存储在缓存中,这样用户每次在此项目上运行CMake时都不需要继续设置它。 下一个更改是使MathFunctions库的构建和链接成为条件。 为此,我们将顶级CMakeLists.txt文件的末尾更改为如下所示:

# add the MathFunctions library?
#
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
  add_subdirectory (MathFunctions)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
 
# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial  ${EXTRA_LIBS})

这使用USE_MYMATH的设置来确定是否应编译和使用MathFunction。 请注意,使用变量(在本例中为EXTRA_LIBS)来收集任何可选的库,以便以后链接到可执行文件中。 这是用于保持具有许多可选组件的较大项目清洁的常用方法。 源代码的相应更改非常简单,让我们:

// A simple program that computes the square root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"
#ifdef USE_MYMATH
#include "MathFunctions.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]);
 
#ifdef USE_MYMATH
  double outputValue = mysqrt(inputValue);
#else
  double outputValue = sqrt(inputValue);
#endif
 
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}

在源代码中我们也使用了USE_MYMATH。 这是通过TutorialConfig.h.in配置文件从CMake提供给源代码,方法是添加以下行:

#cmakedefine USE_MYMATH

3.安装和测试

对于下一步,我们将为项目添加安装规则和测试支持。 安装规则非常简单。 对于MathFunctions库,我们通过将以下两行添加到MathFunctions的CMakeLists.txt文件来设置库和要安装的头文件:

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

对于应用程序,将以下行添加到顶级CMakeLists.txt文件以安装可执行文件和配置的头文件:

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

这就是它的全部。 此时,您应该能够构建教程,然后键入make install(或从IDE构建INSTALL目标),它将安装相应的头文件,库和可执行文件。 CMake变量CMAKE_INSTALL_PREFIX用于确定文件的安装位置。 添加测试也是一个相当简单的过程。 在顶级CMakeLists.txt文件的末尾,我们可以添加许多基本测试来验证应用程序是否正常工作。

include(CTest)

# does the application run
add_test (TutorialRuns Tutorial 25)
# does it sqrt of 25
add_test (TutorialComp25 Tutorial 25)
set_tests_properties (TutorialComp25 PROPERTIES PASS_REGULAR_EXPRESSION "25 is 5")
# does it handle negative numbers
add_test (TutorialNegative Tutorial -25)
set_tests_properties (TutorialNegative PROPERTIES PASS_REGULAR_EXPRESSION "-25 is 0")
# does it handle small numbers
add_test (TutorialSmall Tutorial 0.0001)
set_tests_properties (TutorialSmall PROPERTIES PASS_REGULAR_EXPRESSION "0.0001 is 0.01")
# does the usage message work?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number")

构建之后可以运行“ctest”命令行工具来运行测试。 第一个测试只是验证应用程序运行,不会发生段错误或以其他方式崩溃,并且返回值为零。 这是CTest测试的基本形式。 接下来的几个测试都使用PASS_REGULAR_EXPRESSION测试属性来验证测试的输出是否包含某些字符串。 在这种情况下,验证计算出的平方根是它应该是什么,并在提供不正确数量的参数时打印使用消息。 如果您想添加大量测试来测试不同的输入值,您可以考虑创建一个如下所示的宏:

#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 a bunch of result based tests
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")

4.添加系统检测

接下来让我们考虑在项目中添加一些代码,这些代码取决于目标平台可能没有的功能。对于此示例,我们将添加一些代码,这些代码取决于目标平台是否具有log和exp函数。当然,几乎每个平台都有这些功能,但本教程假设它们不太常见。如果平台有日志,那么我们将使用它来计算mysqrt函数中的平方根。我们首先使用顶级CMakeLists.txt文件中的CheckFunctionExists.cmake宏测试这些函数的可用性,如下所示:

include(CheckFunctionExists)
check_function_exists(log HAVE_LOG)
check_function_exists(exp HAVE_EXP)

接下来我们修改TutorialConfig.h.in以定义这些值,如果CMake在平台上找到它们,如下所示:

#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP

在TutorialConfig.h的configure_file命令之前完成log和exp的测试非常重要。configure_file命令使用CMake中的当前设置立即配置文件。最后在mysqrt函数中,如果使用以下代码在系统上可用,我们可以提供基于log和exp的备用实现:

//如果我们同时有log和exp,那么就使用它们
#if defined(HAVE_LOG)&& defined(HAVE_EXP)
  result = exp(log(x)* 0.5);
#else //否则使用迭代方法

5.添加生成的文件和生成器

在本节中,我们将展示如何将生成的源文件添加到应用程序的构建过程中。对于此示例,我们将创建一个预先计算的平方根表,作为构建过程的一部分,然后将该表编译到我们的应用程序中。为此,我们首先需要一个生成表的程序。在MathFunctions子目录中,一个名为MakeTable.cxx的新源文件就是这样做的。

// A simple program that builds a sqrt table 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
int main (int argc, char *argv[])
{
  int i;
  double result;
 
  // make sure we have enough arguments
  if (argc < 2)
    {
    return 1;
    }
  
  // open the output file
  FILE *fout = fopen(argv[1],"w");
  if (!fout)
    {
    return 1;
    }
  
  // create a source file with a table of square roots
  fprintf(fout,"double sqrtTable[] = {\n");
  for (i = 0; i < 10; ++i)
    {
    result = sqrt(static_cast<double>(i));
    fprintf(fout,"%g,\n",result);
    }
 
  // close the table with a zero
  fprintf(fout,"0};\n");
  fclose(fout);
  return 0;
}

请注意,该表是作为有效的C ++代码生成的,并且要将输出写入的文件的名称作为参数传入。下一步是将相应的命令添加到MathFunctions的CMakeLists.txt文件以构建MakeTable可执行文件,然后在构建过程中运行它。完成此操作需要一些命令,如下所示。

# first we add the executable that generates the table
add_executable(MakeTable MakeTable.cxx)
 
# add the command to generate the source code
add_custom_command (
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  DEPENDS MakeTable
  )
 
# add the binary tree directory to the search path for 
# include files
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
 
# add the main library
add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h  )

首先添加MakeTable的可执行文件,因为将添加任何其他可执行文件。然后我们添加一个自定义命令,指定如何通过运行MakeTable来生成Table.h。接下来我们必须让CMake知道mysqrt.cxx依赖于生成的文件Table.h。这是通过将生成的Table.h添加到库MathFunctions的源列表中来完成的。我们还必须将当前二进制目录添加到包含目录列表中,以便可以在mysqrt.cxx中找到并包含Table.h。构建此项目时,它将首先构建MakeTable可执行文件。然后它将运行MakeTable来生成Table.h。最后,它将编译包含Table.h的mysqrt.cxx以生成MathFunctions库。此时,我们添加了所有功能的顶级CMakeLists.txt文件如下所示:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
include(CTest)
 
# 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)
 
# should we use our own math functions
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 (
  "${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 TutorialConfig.h
include_directories ("${PROJECT_BINARY_DIR}")
 
# add the MathFunctions library?
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
  add_subdirectory (MathFunctions)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
 
# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial  ${EXTRA_LIBS})
 
# add the install targets
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"        
         DESTINATION include)
 
# does the application run
add_test (TutorialRuns Tutorial 25)
 
# does the usage message work?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage
  PROPERTIES 
  PASS_REGULAR_EXPRESSION "Usage:.*number"
  )
 
 
#define a macro to simplify adding tests
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 a bunch of result based tests
do_test (4 "4 is 2")
do_test (9 "9 is 3")
do_test (5 "5 is 2.236")
do_test (7 "7 is 2.645")
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")
do_test (0.0001 "0.0001 is 0.01")

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
 
// does the platform provide exp and log functions?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP

MathFunctions的CMakeLists.txt文件如下所示:

# first we add the executable that generates the table
add_executable(MakeTable MakeTable.cxx)
# add the command to generate the source code
add_custom_command (
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  DEPENDS MakeTable
  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  )
# add the binary tree directory to the search path 
# for include files
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
 
# add the main library
add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h)
 
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

6.构建安装程序

接下来假设我们想将项目分发给其他人,以便他们可以使用它。我们希望在各种平台上提供二进制和源代码分发。这与我们之前在安装和测试(步骤3)一节中所做的安装略有不同,我们正在安装从源代码构建的二进制文件。在此示例中,我们将构建支持二进制安装和软件包管理功能的安装包,如cygwin,debian,RPM等中所示。为实现此目的,我们将使用CPack创建特定于平台的安装程序,如使用CPack打包一章中所述。具体来说,我们需要在我们的顶级CMakeLists.txt文件的底部添加几行。

# build a CPack driven installer package
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变量设置为我们存储此项目的许可证和版本信息的位置。版本信息使用我们在本教程前面设置的变量。最后,我们将包含CPack模块,该模块将使用这些变量以及您所使用的系统的其他一些属性来设置安装程序。

下一步是以通常的方式构建项目,然后在其上运行CPack。要构建二进制分发,您将运行:

cpack --config CPackConfig.cmake

要创建源分发,请键

cpack --config CPackSourceConfig.cmake

猜你喜欢

转载自blog.csdn.net/xiaoma_bk/article/details/85305091