IDE/以glog为例实践CMake-Gui工具使用

概述

本文原旨在以glog开源库的构建为引子来简单说明CMake工具的使用奈何不那么顺利我很难将glog相关问题摘干净了来描述这次CMake工具的使用过程。如此一来本文的重点倒是有点像 ‘如何构建和编译glog库’ 了请原谅我。当前本文主要详细描述了使用cmake-gui工具构建glog开源项目的过程也描述了其编译、安装、打包过程。本文还描述了glog构建配置条目glog解决方案的组成项目等并对其中涉及的调试追踪和测试技术做了概述。

构建glog

将源码下载下来在心仪的目录下解压如下E:\GitLocal\glog-master目录。

设置源码和目标存储路径
自建目录如下 glog-build用于存放Cmake生成的工程文件和解决方案文件等。将它们设置在Cmake-gui操作界面中。
在这里插入图片描述
执行配置过程
点击Config设置按钮会弹出如下配置界面。注意完成一次配置后再点击Config按钮时不会再弹出。除非你在文件菜单中执行删除缓存操作。此处配置如下指定当前CMake工程使用的生成器类型为 VS2017选择生成器的平台为x64。
至于工具集设置
它对应着cmake指令-T参数系列用于指定构建工具集Build Toolset。构建工具集是一组编译器、库和构建工具的组合用于生成可执行文件、库和其他构建输出。例如假设您希望使用 Visual Studio 2017 的工具集进行构建可以执行以下命令

cmake -T v141

第一项配置生成器Generator是用于指定所要生成的构建系统文件的类型和格式的选项。它隐含地确定了所使用的工具集因此一般情况下并不需要再单独设置工具集。另外可以在VS项目属性-常规选项卡中设置工具集可以看到平台工具集设置为 Visual Studio 2017 (v141)而且可以对其重新进行修改。
在这里插入图片描述
这里选择使用默认的编译器平台和生成器确定后这个也可以自动确定。必要时可以手动选择它们此处暂不深究。

完成基础配置开始生成
点击上图中的Finish结束按钮。此时生成器将开始工作此时CMake将从E:\GitLocal\glog-master 源代码目录下的 CMakeLists.txt 文件开始并关联分析 E:\GitLocal\glog-master\cmake目录下的所有*.cmake文件。过程持续1min左右期间产生大量告警如下

Selecting Windows SDK version 10.0.17763.0 to target Windows 10.0.19044.
The CXX compiler identification is MSVC 19.16.27050.0
Detecting CXX compiler ABI info
Detecting CXX compiler ABI info - done
Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x64/cl.exe - skipped
Detecting CXX compile features
Detecting CXX compile features - done
Could NOT find GTest (missing: GTest_DIR)
CMake Warning at CMakeLists.txt:84 (find_package):
  By not providing "Findgflags.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "gflags", but
  CMake did not find one.

  Could not find a package configuration file provided by "gflags" (requested
  version 2.2.2) with any of the following names:

    gflagsConfig.cmake
    gflags-config.cmake

  Add the installation prefix of "gflags" to CMAKE_PREFIX_PATH or set
  "gflags_DIR" to a directory containing one of the above files.  If "gflags"
  provides a separate development package or SDK, be sure it has been
  installed.

//部分截取
Performing Test CMAKE_HAVE_LIBC_PTHREAD
Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
Looking for pthread_create in pthreads
Looking for pthread_create in pthreads - not found
Looking for pthread_create in pthread
Looking for pthread_create in pthread - not found
Found Threads: TRUE  
Could NOT find Unwind (missing: Unwind_INCLUDE_DIR Unwind_LIBRARY) 
.......
Performing Test COMPILER_HAS_DEPRECATED_ATTR - Failed
Performing Test COMPILER_HAS_DEPRECATED
Performing Test COMPILER_HAS_DEPRECATED - Success
Configuring done (116.1s)

对项目进行详细配置
上述配置过程结束后UI中将显示出此项目的所有相关的可配置条目。
在这里插入图片描述
先不去详细关注各个条目的含义因为每个条目都值得深聊一会。上述以复选框形式呈现的配置项都是glog的可选项不是必须的。先只保留 BUILLD_SHARED_LIBS 条目的复选设置如果不这么做CMake将默认构建静态库工程。完成上述条目配置后重新点击下Config按钮此时不会再弹出配置界面上图中的提示也表明了这个意思点击Config以更新红色标记的配置项。点击后执行结果显示如下不再有任何告警。

Selecting Windows SDK version 10.0.17763.0 to target Windows 10.0.19044.
Configuring done (0.1s)

截止上一步操作 glog-build文件夹下已经有所生成如要导出的头文件。但是VS工程文件并未产生。继续点击Generate生成按钮瞬间便在信息窗口提示完成此时glog-build文件夹下已经产生了 glog.slnglog.vcxprojconfig.h 等文件。

编译glog.sln解决方案

一个小插曲在上述配置下执行编译遇到如下错误。C4003 类函数宏的调用“min”参数不足。该错误定位在 glog_internal 工程 E:\GitLocal\glog-master\src\logging.cc 文件第1669行代码。

      stream() << setw(2) << 1 + logmsgtime_.month() << setw(2)
               << logmsgtime_.day() << ' ' << setw(2) << logmsgtime_.hour()
               << ':' << setw(2) << logmsgtime_.min() << ':' << setw(2)   //Line 1699
               << logmsgtime_.sec() << "." << setw(6) << logmsgtime_.usec()
               << ' ' << setfill(' ') << setw(5)
               << static_cast<unsigned int>(GetTID()) << setfill('0') << ' '
               << data_->basename_ << ':' << data_->line_ << "] ";
	  //修改后的代码行
	  << ':' << setw(2) << (logmsgtime_.min)() << ':' << setw(2)   //Line 1699 Modify

VS将错误定位在 logmsgtime_.min() 函数上我跳转min函数发现其被定位到了 minwindef.h 中的 “取最小值宏定义”这显然是不对的因为上述min()明显应该是对象logmsgtime_的成员函数只不过两者重名而已。调到类定义下该函数的定义也很奇怪

  const int&(min)() const { return time_struct_.tm_min; }  //函数名加个小括号是为啥呢?
  const int& hour() const { return time_struct_.tm_hour; }

调查了一会与想象中是一致的。这种语法利用的是宏函数不能加括号而函数名、函数指针、lambda表达式是可以加括号的。以此来区分宏函数调用和非宏函数调用。明白了这点后上述代码稍作修该即可通过编译即将成员函数加上小括号。但是我没想明白的是为啥这么牵线的错误会在我的编译环境下报告出来而在开发者的环境下没有问题呢
进一步研究
发现如果在配置项中勾选了 WITH_THREADS那么将不会有上述编译错误。文件 minwindef.h 是存在 C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\shared 下的系统头文件并不是glog的。猜测WITH_THREADS打开后可以避免系统的min(a, b)宏定义的干扰我没有继续深究验证。

编译成功
通过上述代理段中提到的方法可以解决问题但是一个没有WITH_THREAD的glog是不健全的最后还是勾选上此配置项更新配置并重新生成解决方案可以成功。编译生成的调试或发布版DLL文件分别存放于glog-build文件夹下的 Debug 和 Release 文件夹下。

安装成功
参考下一节glog的配置项-CMAKE_INSTALL_PREFIX。在解决方案INSTALL项目上右键执行生成过程即可完成安装将bin、lib、incleud 一众相关文件存放到设定的目录中。

glog的配置项

CMake工具通过对CMakeLists.txt文件和cmake文件夹下的文件的分析得出相关配置项目并以可视化的形式显示在CMake-Gui界面中。我们修改这些配置后CMake工具会修改 glog-build 根目录下的 config.h 文件中的诸多宏定义开关它会在解决方案内的多个源代码文件中被包含控制着整个编译过程。

接下来我们将逐个看看glog项目的配置项也从这个过程中进一步了解CMake工具的使用方式。这些配置项在非gui的CMake工具上可以用命令控制或配置。如

//
cmake -DWITH_GFLAGS=ON -DWITH_THREADS=ON ..
//
cmake -DCMAKE_INSTALL_PREFIX=/path/to/installation/directory /path/to/source/code

CMake有非常丰富的指令-D参数只是其中一种而已前边我们还提到了 -T参数。
-D [:]= = Create or update a cmake cache entry.

BUILD_SHARED_LIBS

设置为 ON 以构建共享库DLL设置为 OFF 以构建静态库。

BUILD_TESTING

用于控制是否构建测试相关的代码和可执行文件。
要注意此处测试相关的代码旨在测试 glog 本身的功能和正确性以确保库在各种情况下都能正常工作。这些测试用例覆盖了 glog 库的不同特性和功能通过执行这些测试可以验证 glog 在各种场景下的行为是否符合预期。虽然此类代码可以展示如何使用 glog 来记录日志、处理错误和管理日志配置等然而测试用例的主要目的仍然是验证 glog 的内部逻辑和行为而不是作为教学材料。用户最好参考 glog 的文档和官方示例来了解更详细的使用方法和最佳实践。

CMAKE_CONFIGURATION_TYPES

在 CMake 中一个项目可以有多个构建配置例如 Debug、Release、RelWithDebInfo 等。CMAKE_CONFIGURATION_TYPES 变量用于定义这些配置类型的集合。配置类型 RelWithDebInfo 是一种常见的构建配置通常在发布Release版本中使用。它在生成的可执行文件中包含了调试信息Debug Information以便在需要进行调试时能够提供有用的调试信息。

CMAKE_INSTALL_PREFIX

用于指定项目构建完成后安装或部署的目标路径。在构建过程中CMake 将使用 CMAKE_INSTALL_PREFIX 变量的值来确定生成的可执行文件、库文件、头文件和其他资源应该被复制到哪个目录中。
对于 Makefile 构建系统打开命令行终端运行 make install 命令来执行安装过程。对于 Visual Studio 构建系统在glog.sln解决方案下找到 INSTALL 项目然后右键选择“生成”以执行安装过程。
CMake给出的默认路径是 C:\Program Files\glog可能是由于访问权限的问题因此我的INSTALL过程总不成功提示MSB307 命令setlocal执行错误或被跳过。后来我将其修改为 E:/GitLocal/glog-build/mydll安装过程显示成功。
其中mydll文件夹若不存在CMake会自动创建它。安装过程成功后在mydll文件夹下可得bin/glogd.dll 和 lib/glogd.lib 和 include。在E:\GitLocal\glog-build\Debug目录下的dll 和lib文件也还在看来它们不是移动而是复制到了CMAKE_INSTALL_PREFIX相关目录下。
插曲有那么1个小时我不知道dll被生成后扔到哪里去了使用EveryThing全盘没有搜到。哈哈原来是不小心将BUILD_SHARED_LIBS动态库标记在手哆嗦的时候勾掉啦

WITH_GTEST

该配置选项用于控制是否构建和使用 Google TestGTest库进行 glog 的单元测试。在此配置ON下CMake 会尝试查找并使用 GTest 库进行 glog 的单元测试。

GTest_DIR

用于指定 Google TestGTest库的安装路径的配置项。Google Test 是一个用于 C++ 的功能强大的单元测试框架用于编写和运行单元测试。它提供了丰富的断言和测试组织机制能够帮助开发者编写可靠的单元测试代码。CMake 将使用该路径来查找 GTest 的头文件和库文件并将其包含到 glog 的构建中。

WITH_GFLAGS

设置为 ON 启用与 gflags 库的集成支持用于处理命令行参数。
gflags 是一个开源的 C++ 库也是google的哦。它被设计为易于使用、可扩展和可定制的工具用于处理应用程序的命令行参数。它允许开发者定义和解析命令行参数以及提供了一些方便的功能如帮助信息生成、默认值设置、类型检查等。需要注意的是启用WITH_GFLAGS 选项需要您在编译环境中正确配置和安装 gflags 库。因为我没有安装它所以一开始的配置过程中大量报错。
他的强大之处在于它允许您在运行程序时通过命令行传递参数并在程序中访问和使用这些参数

gflag_DIR

用于指定 gflagsGoogle Commandline Flags库的安装路径。

PRINT_UNSYMBOLIZED_STACK_TRACES

用于控制是否在日志中打印未经符号化的堆栈跟踪信息。当其设置为 ON 时意味着在日志中显示的堆栈跟踪信息将不包含函数名称和源代码行号等符号化的信息。

WITH_SYMBOLIZE

用于控制是否启用符号化支持。符号化是将程序中的地址转换为对应的函数名称、源代码文件和行号等符号信息的过程。启用符号化支持可以在日志输出中提供更详细和可读性更好的堆栈跟踪信息包括函数调用链和源代码位置。

WITH_FUZZING

用于控制是否启用模糊测试Fuzzing支持。模糊测试是一种软件测试技术通过自动生成输入数据并将其输入到被测试的程序中以发现潜在的安全漏洞和程序错误。通过模糊测试可以检测程序对于不合法、异常或非预期输入的处理能力提高程序的稳定性和安全性。

WITH_THREADS

用于指定是否启用多线程支持。
设置为 ON 时glog 将会在日志记录过程中使用线程安全的机制以确保在多线程环境下的并发访问不会导致数据竞争或其他并发问题。这意味着在多线程应用程序中可以同时调用 glog 的日志记录函数而不会出现冲突。在单线程环境下禁用多线程支持可以减少一些同步开销但在多线程环境下使用非线程安全的 glog 函数可能会导致数据错乱或崩溃。

WITH_TLS

用于控制是否启用线程本地存储Thread-Local StorageTLS支持。
线程本地存储是一种机制允许每个线程拥有其自己的独立存储空间可以在不同线程之间保存各自的数据。在多线程程序中使用线程本地存储可以确保数据的独立性和线程安全性。
当 WITH_TLS 属性设置为 ON 意味着 glog 在日志记录过程中会使用线程本地存储来管理日志数据的存储和访问。否则glog 将使用全局存储空间来管理日志数据可能会导致多线程环境下的竞争和不确定行为。
WinAPI提供了相关操作接口。要启用TLS您可以使用 TlsAlloc 函数分配一个新的TLS索引并使用 TlsSetValue 函数将需要存储的值与该索引关联起来。可以在需要访问线程本地存储的位置使用 TlsGetValue 函数来获取该值使用完成后使用TlsFree 函数释放先前分配的TLS索引。

WITH_GMOCK

Google Mock 是 Google 提供的一个 C++ 的模拟测试框架用于编写单元测试中的模拟对象。GMock 提供了丰富的工具和语法用于创建模拟对象、设置模拟行为和断言模拟对象的方法调用。它可以与 Google TestGTest一起使用提供更全面的单元测试框架。
注意这里的测试指的是对 glog 库本身的单元测试验证 glog 库的不同组件和功能是否按预期工作以确保其正确性和稳定性。使用 GMock 进行单元测试需要正确安装和配置 GMock 库如设置相关的路径和库链接。

在软件系统中组件之间常常存在依赖关系一个组件可能依赖于其他组件或外部服务的功能。在进行单元测试时为了隔离被测试组件的行为并专注于特定功能的测试需要模拟这些依赖项的行为。Mock 技术通过创建虚拟对象称为 Mock 对象来模拟依赖项的行为。 Mock 对象具有与实际依赖项相同的接口但其实现是被控制和配置的。通过在测试中使用 Mock 对象替代实际的依赖项我们可以精确地控制依赖项的行为模拟各种情况和错误条件并验证被测试组件对依赖项的正确使用。Mock 技术的优势在于它可以提供可控、可复制和可预测的测试环境使开发人员能够专注于被测试组件的特定行为。它可以帮助发现和修复潜在的问题提高测试覆盖率并促进测试驱动开发TDD和单元测试实践的采用。

Qt框架下也有类似的功能其提供了一个名为 QTest 的模块其中包含了用于单元测试的工具和功能。使用 QTest 的 Mock 功能您可以创建虚拟对象来替代实际依赖项并控制这些虚拟对象的行为。通过配置虚拟对象的返回值、信号和槽等您可以模拟各种测试情景和测试条件以验证被测试组件的正确性。

WITH_PKGCONFIG

pkg-config 是一个常用的软件包配置工具用于帮助构建系统自动定位和配置安装的库。通过在 CMake 构建过程中配置 WITH_PKGCONFIG您可以决定是否生成和安装 pkg-config 配置文件以方便其他项目在构建时使用 glog。这些配置文件将提供有关 glog 库的信息例如库路径、头文件路径和链接选项等。

WITH_UNWIND

该配置选项用于控制是否启用异常栈回溯支持。这确实很有用但同样需要第三库的支持。
异常栈回溯是一种用于在程序发生异常时获取函数调用堆栈信息的机制。通过启用 WITH_UNWINDglog 将使用操作系统提供的异常处理机制如 POSIX signals 或 Windows SEH来捕获和解析异常的调用堆栈信息。
属性设置为 ON 时意味着当程序发生异常时glog 将尝试获取异常的调用堆栈信息并将其记录在日志中。这可以帮助定位异常发生的位置提供更详细的错误信息和上下文对于调试和故障排查非常有用。但请注意启用异常栈回溯可能会对程序的性能产生一定的影响因为它涉及额外的系统调用和堆栈解析操作。
具体的当程序发生异常时可以使用 glog 提供的宏 LOG(FATAL) 或 LOG(ERROR) 来记录日志并触发异常栈回溯。

LOG(FATAL) << "An error occurred!";

在异常发生时glog 将自动获取当前线程的函数调用堆栈信息并将其记录在日志中glog 将输出类似以下内容的日志信息
F0528 12:34:56.789012 12345 example.cpp:42] An error occurred!
Stack trace:
/path/to/example.cpp:42 (main)

其中example.cpp:42 表示异常发生在 example.cpp 文件的第 42 行后续的堆栈跟踪信息会显示调用栈中的其他函数和位置。

Unwind_INCLUDE_DIR 和 Unwind_LIBRARY

如果只是勾选了 WITH_UNWIND 配置则会提示Could NOT find Unwind (missing: Unwind_INCLUDE_DIR Unwind_LIBRARY) 。在CMake-gui界面中勾选 Advanced 高级可以显示上述两个配置。
Unwind是一个提供堆栈展开stack unwinding支持的库用于获取程序的调用堆栈信息。它通常在调试和错误报告工具中使用用于生成堆栈跟踪stack trace并获取程序的执行流程信息。
在Windows系统上原生的Unwind库不可用。不过有一个针对Windows的Unwind库的移植版本称为libunwind-win。这个库提供类似于原始Unwind库的功能并且可以与glog在Windows系统上一起使用。

异常栈回溯技术在 release 版本中一般是可以使用的但需要注意以下几点
确保在编译 release 版本时启用了符号信息的生成。在大多数情况下使用编译器的 -g 选项可以生成符号信息。这些符号信息允许 glog 在异常发生时正确解析函数调用堆栈信息。另外请注意LOG(FATAL) 宏将触发异常栈回溯并终止程序的执行因此在 release 版本中使用时需谨慎。由于异常栈回溯会涉及额外的系统调用和堆栈解析操作可能会对程序的性能产生一定的影响。在 release 版本中您可能需要权衡性能和功能之间的平衡根据实际需求决定是否启用异常栈回溯。

OTHER

勾选主页面上的ADVANCED复选框会显示更多的高级配置此处不再说明。争取以后有机会了把glog涉及到到其他第三方库都搞上去在test工程里好好体验一番它们的强大功能。这必定会为以后的软件开发和调试工作带来更多欢乐

glog解决方案

在这里插入图片描述
在这里插入图片描述
如上可以看到glog解决方案以供包含了6个项目配置项只勾选了WITH_THREAD该库的源码都存在于glog_internal项目下。生成顺序配置如上图依赖关系如下描述
glog_internal 项目依赖于 ZERO_CHECK 项目
glog 项目依赖于 ZERO_CHECK 和 glog_internal 项目
ALL_BUILD 项目依赖于 ZERO_CHECK 和 glog_internal 和 glog 项目
INSTALL 项目依赖于 ZERO_CHECK 和 ALL_BUILD 项目
PACKAGE 项目依赖于 ZERO_CHECK 和 ALL_BUILD 项目

glog项目
主要包含了glog库的公共接口和头文件以及与日志记录相关的配置和初始化逻辑。它负责定义日志记录的API接口以及提供了对外可见的功能和结构。我们可以看到本项目下并没有任何源码只包含了 CMakeLists.txt 文件 和 一堆 obj 文件。

glog_internal项目
包含了glog库的源代码实现和内部功能。它包含了日志记录的具体实现、内部辅助函数、日志输出的格式化和管理等细节。该项目通常不需要直接引用它主要是为glog项目提供支持和实现细节。
在这里插入图片描述
该项目的配置类型是静态库而且在其输出目录下也确实生成了该静态库但是在glog项目中却没有发现对它的引用痕迹。
Why
在 glog 项目中并没有直接使用 glog_internal 项目生成的静态库文件而是使用了 glog_internal 项目生成的 OBJECT 类型的中间文件在glog项目下确实能看到一个名为Object Librries的筛选器其下包含许多 .obj 类型的中间文件。当 glog 项目构建时这些中间文件会与其他源文件一起进行编译和链接最终生成 glog 库的目标文件静态库文件或动态库文件。这种方式允许 glog 项目在编译过程中共享和重用 glog_internal 项目中的源文件而不需要单独生成和维护 glog_internal 的静态库文件。通过使用 OBJECT 类型的中间文件可以更好地管理项目之间的依赖关系减少构建时间和构建产物的数量。这在大型项目中特别有用可以提高构建效率和代码复用性。

INSTALL项目
在这里插入图片描述
INSTALL项目的生成是通过CMake中的install指令来完成的。在 CMakeLists.txt 文件中通过配置install指令的参数指定了安装的目标文件、目录、权限等信息。然后在生成解决方案时CMake会自动将这些配置转化为对应的安装操作并将其作为一个虚拟项目添加到glog.sln中。
如上INSTALL项目的属性信息其配置类型是 “实用工具”而不是我们常见的动态库、静态库、应用程序ZERO_CHECK和 PACKAGE 项目配置类型也是如此。他是一个虚拟项目当构建该项目时它将执行一系列的安装操作将glog库的构建结果安装到指定的目标路径。具体来说INSTALL项目会执行以下操作
拷贝生成的可执行文件包括库文件和可执行文件到指定的安装目录。
拷贝头文件到指定的安装目录。
拷贝其他必要的资源文件如配置文件、示例文件等到指定的安装目录。

ZERO_CHECK 项目
ZERO_CHECK项目的生成是由CMake自动生成的它是一个虚拟项目不包含实际的源代码或构建规则。它的作用是定期检查项目文件包括CMakeLists.txt和其他源文件是否有变化如果有变化则重新生成整个解决方案。当您在编辑项目文件或添加、删除源文件时CMake会自动检测到这些变化并生成或更新ZERO_CHECK项目。这样每次构建解决方案时都会先检查项目文件的一致性确保构建的是最新版本的代码。

PACKAGE 项目
PACKAGE项目是由CMake自动生成的它是一个虚拟项目不包含实际的源代码或构建规则。它的作用是在构建完成后生成软件的安装包以方便用户进行安装和使用。需要注意的是PACKAGE项目的生成需要依赖于CMakeLists.txt文件中的相关配置如安装目录、文件列表、版本号等。如果没进行过相关配置对该项目执行生成时会出现编译错误。如
Cannot find NSIS compiler makensis: likely it is not installed, or not in your PATH
NSIS (Nullsoft Scriptable Install System) 是一个用于创建 Windows 安装程序的开源工具它被 CMake 用于生成软件的安装包。CMake-gui配置项中并没有涉及太多你可能要去CMakeLists.txt文件中找到与PACKAGE 相关的配置并正确修改。

CMake指令工具

需要注意的是虽然这是个exe可执行程序但是它不能直接在操作系统上直接运行而是要在控制台中运行否则它会闪退。Qt的qmake工具也是这也样子的必须要依赖系统控制台窗口或者是Unix/Linux的终端窗口。如果你没有在系统环境变量中配置其路径你可以直接将其拖拽进cmd中或cd到其所在目录后再执行它。一部分指令如下图。
在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6