CMake教程(2)

步骤2:添加库(Step 2: Adding a Library)

我们已经学习了如何使用CMake创建一个基本的项目了。本步骤,我们学习如何在项目中创建和使用库,以及如何设置使用/不使用库。

练习1:创建库(Exercise 1 - Creating a Library)

在CMake中,使用命令add_library()、指定组成库的源文件来添加库。

在项目中,一般不会把所有源文件都放在一个文件夹下,而是使用多个子文件。创建一个子文件夹,用来存放库,在此文件夹下,创建一个新的CMakeLists.txt文件及源文件。在顶层的CMakeLists.txt文件中,使用命令add_subdirectory(),把子文件夹添加到生成中。

库创建后,使用命令target_include_directories()target_link_libraries()将其与可执行目标文件关联起来。

目标(Goal)

添加、使用库。

参考资料(Helpful Resources)

  • add_library()

  • add_subdirectory()

  • target_include_directories()

  • target_link_libraries()

  • PROJECT_SOURCE_DIR

需编辑的文件(Files to Edit)

  • CMakeLists.txt

  • tutorial.cxx

  • MathFunctions/CMakeLists.txt

开始(Getting Started)

本练习,添加计算数的平方根的库到项目中。可执行文件使用这个库而不是编译器提供的库来计算平方根。

将库放到MathFunctions子文件下,此文件夹下已有头文件MathFunctions.h和源文件mysqrt.cxx,不需要修改这两个文件。源文件中有一个名为mysqrt的函数,其功能与编译器的sqrt函数相似。

Help/guide/tutorial/Step2下,完成TODO 1TODO 6

首先,在子文件夹MathFunctions下的CMakeLists.txt文件中添加一行。
然后,编辑顶层CMakeLists.txt文件。
最后,在tutorial.cxx中使用新创建的MathFunctions库。

练习答案(Solution)

在文件夹MathFunctions下的CMakeLists.txt文件中,使用add_library()创建一个名为MathFunctions的库目标。库的源文件作为add_library()的参数:

  • TODO 1MathFunctions/CMakeLists.txt:
    add_library(MathFunctions mysqrt.cxx)

为了使用新的库,在顶层CMakeLists.txt文件中,使用命令add_subdirectory(),以生成库。

  • TODO 2CMakeLists.txt
    add_subdirectory(MathFunctions)

然后,使用target_link_libraries()把库目标链接到可执行目标上。

  • TODO 3CMakeLists.txt
    target_link_libraries(Tutorial PUBLIC MathFunctions)

最后,需要指定库的头文件位置。修改target_include_directories()添加MathFunctions为包含目录以找到MathFunctions.h头文件。

  • TODO 4CMakeLists.txt
    target_include_directories(Tutorial PUBLIC
                            "${PROJECT_BINARY_DIR}"
                            "${PROJECT_SOURCE_DIR}/MathFunctions"
                            )
    

现在就可以使用库了。在tutorial.cxx,包含MathFunctions.h

  • TODO 5tutorial.cxx
    #include "MathFunctions.h"

最后,使用mysqrt替换sqrt

  • TODO 6tutorial.cxx
    const double outputValue = mysqrt(inputValue);

生成运行(Build and Run)

在命令行中运行:

mkdir Step2_build
cd Step2_build
cmake ../Step2
cmake --build .

运行新生成的Tutorial,是否能求出正确的平方根。

PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source> mkdir Step2_build


    目录: D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         3/11/2023  11:16 PM                Step2_build


PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source> cd .\Step2_build\
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cmake ../Step2
-- Building for: Visual Studio 17 2022
-- The C compiler identification is MSVC 19.35.32215.0
-- The CXX compiler identification is MSVC 19.35.32215.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.35.32215/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.35.32215/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (193.0s)
-- Generating done (0.4s)
-- Build files have been written to: D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cmake --build .
MSBuild version 17.5.0+6f08c67f3 for .NET Framework

  Checking Build System
  Building Custom Rule D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2/MathFunctions/CMakeLists.txt
  mysqrt.cxx
  MathFuctions.vcxproj -> D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\MathFunctions\Debug\Math
  Fuctions.lib
  Building Custom Rule D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2/CMakeLists.txt
  tutorial.cxx
LINK : fatal error LNK1104: 无法打开文件“MathFunctions.lib” [D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_b
uild\Tutorial.vcxproj]
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cmake --build .
CMake is re-running because D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build/MathFunctions/CMakeFiles/generate.stamp is out-of-date.
  the file 'D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2/MathFunctions/CMakeLists.txt'
  is newer than 'D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build/MathFunctions/CMakeFiles/generate.stamp.depend'
  result='-1'
-- Configuring done (0.0s)
-- Generating done (0.2s)
-- Build files have been written to: D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build
MSBuild version 17.5.0+6f08c67f3 for .NET Framework

  Checking Build System
  Building Custom Rule D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2/MathFunctions/CMakeLists.txt
  mysqrt.cxx
  MathFunctions.vcxproj -> D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\MathFunctions\Debug\Mat
  hFunctions.lib
  Building Custom Rule D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2/CMakeLists.txt
  Tutorial.vcxproj -> D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Debug\Tutorial.exe
  Building Custom Rule D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2/CMakeLists.txt
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cd .\Debug\
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Debug> .\Tutorial.exe 10
Computing sqrt of 10 to be 5.5
Computing sqrt of 10 to be 3.65909
Computing sqrt of 10 to be 3.19601
Computing sqrt of 10 to be 3.16246
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
The square root of 10 is 3.16228

运行中出现错误提示,无法打开文件MathFunctions.lib,是因为在:

  • TODO 1MathFunctions/CMakeLists.txt:
    add_library(MathFunctions mysqrt.cxx)
    写错了生成的库名,写成了MathFuctions,少了个n,所以出现了上述错误。

练习2:使库可选(Exercise 2 - Making Our Library Optional)

虽然在教程中不需要选择是否使用库,但是在大型项目中,经常有这种需求。

CMake使用命令option()完成此项功能,会提供一个变量给用户,用户在配置cmake生成时可改变此变量值。此设置存在缓存中,因此,用户不需要在每次运行CMake时,都设置此值。

目标(Goal)

添加选项,以在生成时是否使用MathFunctions

参考资料(Helpful Resources)

  • if()
  • list()
  • option()
  • cmakedefine

需编辑的文件(Files to Edit)

  • CMakeLists.txt
  • tutorial.cxx
  • TutorialConfig.h.in

开始(Getting Started)

从练习1的结果开始,完成TODO 7TODO 13

首先,在顶层CMakeLists.txt文件中使用命令option()创建变量USE_MYMATH,并使用此变量决定是否在生成中使用MathFunctions库。

然后,更新文件tutorial.cxxTutorialConfig.h.in以使用USE_MYMATH

答案(Solution)

第一步,在顶层CMakeLists.txt文件中添加选项,此选项在cmake-guiccmake中默认值为ON,用户可更改。

  • TODO 7CMakeLists.txt
    option(USE_MYMATH "Use tutorial provided math implementation" ON)

然后,建立生成、链接MathFunctions的条件。

首先,在项目中创建可选库的list(),并命名为EXTRA_LIBS,目前列表中仅有MathFunctions

同样,创建包含文件的list(),命名为EXTRA_INCLUDES,在此列表中APPEND库头文件的路径。

然后,创建语句if()判断USE_MYMATH的值,在if()语句块中,添加练习1中的命令add_subdirectory(),和命令list()

USE_MYMATHON时,会生成列表并添加到项目中,当USE_MYMATHOFF时,列表为空。通过这种方式,用户可以使用USE_MYMATH控制在生成中是否使用哪些库。

顶层的CMakeLists.txt文件,添加内容:

  • TODO 8CMakeLists.txt
    if(USE_MYMATH)
      add_subdirectory(MathFunctions)
      list(APPEND EXTRA_LIBS MathFunctions)
      list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
    endif()
    

现在有了两个列表,需要更新target_link_libraries()target_include_directories()来使用这两个列表。

  • TODO 9CMakeLists.txt
    target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
    
  • TODO 10CMakeLists.txt
    target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}" ${EXTRA_INCLUDES} )
    

这是处理多个部分的经典做法。在步骤3(Step 3)中会介绍现代做法。

源代码中也需要相应的改变。在文件tutorial.cxx中,如果定义了USE_MYMATH则包含MathFunctions.h头文件。

  • TODO 11tutorial.cxx
    #ifdef USE_MYMATH
    #  include "MathFunctions.h"
    #endif
    

同样,使用USE_MYMATH开控制使用哪个平方根函数:

  • TODO 12tutorial.cxx
    #ifdef USE_MYMATH
      const double outputValue = mysqrt(inputValue);
    #else
      const double outputValue = sqrt(inputValue);
    #endif
    

由于源代码需要使用USE_MYMATH,需要把它添加到TutorialConfig.h.in文件中:

  • TODO 13TutorialConfig.h.in
    #cmakedefine USE_MYMATH
    

如此,就可以在生成或使用过程中来决定是否选用库文件了。

疑问

为啥需要在option USE_MYMATH后,再配置TutorialConfig.h.in,颠倒顺序会怎么样?

解答

因为配置TutorialConfig.h.in时,使用了USE_MYMATH的值,如果先于option()进行配置,则无法使用USE_MYMATH正确的值。

生成运行(Build and Run)

cd ../Step2_build
cmake --build .

然后,运行可执行文件Tutorial,以验证程序的正确性。

改变USE_MYMATH值为OFF。最简单的方法是使用cmke-gui或在终端(terminal)中使用ccmake。另外,也可在命令行中运行:
cmake ../Step2 -D USE_MYMATH=OFF

然后,重新生成代码:
cmake --build .

再次运行可执行文件,确保其在USE_MYMATH值为OFF时仍可正确工作。哪个函数的结果更好,sqrt还是mysqrt

PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Debug> cd ..
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cmake --build .
CMake is re-running because D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build/CMakeFiles/generate.stamp is out-of-date.
  the file 'D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2/CMakeLists.txt'
  is newer than 'D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build/CMakeFiles/generate.stamp.depend'
  result='-1'
CMake Error at CMakeLists.txt:31 (add_subdirectory):
  The binary directory

    D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build/MathFunctions

  is already used to build a source directory.  It cannot be used to build
  source directory

    D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2/MathFunctions

  Specify a unique binary directory name.


-- Configuring incomplete, errors occurred!
CMake Configure step failed.  Build files cannot be regenerated correctly.
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cmake --build .
CMake is re-running because D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build/CMakeFiles/generate.stamp is out-of-date.
  the file 'D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2/CMakeLists.txt'
  is newer than 'D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build/CMakeFiles/generate.stamp.depend'
  result='-1'
-- Configuring done (0.0s)
-- Generating done (0.1s)
-- Build files have been written to: D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build
MSBuild version 17.5.0+6f08c67f3 for .NET Framework

  MathFunctions.vcxproj -> D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\MathFunctions\Debug\Mat
  hFunctions.lib
  tutorial.cxx
D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2\tutorial.cxx(20,44): error C2065: “Tutorial_VERSION_MAJO
R”: 未声明的标识符 [D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Tutorial.vcxproj]
D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2\tutorial.cxx(21,18): error C2065: “Tutorial_VERSION_MINO
R”: 未声明的标识符 [D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Tutorial.vcxproj]
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cmake --build .
MSBuild version 17.5.0+6f08c67f3 for .NET Framework

  MathFunctions.vcxproj -> D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\MathFunctions\Debug\Mat
  hFunctions.lib
  tutorial.cxx
  Tutorial.vcxproj -> D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Debug\Tutorial.exe
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cd .\Debug\
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Debug> .\Tutorial.exe 10
Computing sqrt of 10 to be 5.5
Computing sqrt of 10 to be 3.65909
Computing sqrt of 10 to be 3.19601
Computing sqrt of 10 to be 3.16246
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
The square root of 10 is 3.16228

PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Debug> cd ..
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cmake ../Step2 -D USE_MYMATH=OFF
-- Configuring done (0.1s)
-- Generating done (0.2s)
-- Build files have been written to: D:/VisualStudioProjects/cmake-3.26.0-rc6-tutorial-source/Step2_build
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cmake --build .
MSBuild version 17.5.0+6f08c67f3 for .NET Framework

  Checking Build System
  tutorial.cxx
  Tutorial.vcxproj -> D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Debug\Tutorial.exe
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build> cd .\Debug\
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Debug> .\Tutorial.exe 10
The square root of 10 is 3.16228
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Debug> .\Tutorial.exe 100
The square root of 100 is 10
PS D:\VisualStudioProjects\cmake-3.26.0-rc6-tutorial-source\Step2_build\Debug> .\Tutorial.exe 1000
The square root of 1000 is 31.6228

第一个CMakeLists.txt文件错误是,忘了注释掉:

# TODO 2: Use add_subdirectory() to add MathFunctions to this project
  add_subdirectory(MathFunctions)

第二个错误未声明的标识符....原因是,错误的注释掉了//#include "TutorialConfig.h",而是应该注释掉:

// TODO 5: Include MathFunctions.h
//#include "MathFunctions.h"
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容