CMake学习笔记

时间:2022-07-22
本文章向大家介绍CMake学习笔记,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

B. Hello Headers

Directory Path

CMake语法指定了许多变量,可用于帮助您在项目或源代码树中找到有用的目录。其中一些包括:

变量

信息

CMAKE_SOURCE_DIR

root source目录

CMAKE_CURRENT_SOURCE_DIR

当前source目录(如果使用子项目和目录)

PROJECT_SOURCE_DIR

当前cmake项目的source目录

CMAKE_BINARY_DIR

root binary / build目录。这是您运行cmake命令的目录

CMAKE_CURRENT_BINARY_DIR

您当前所在的build目录

PROJECT_BINARY_DIR

当前项目的build目录

源文件变量

创建包含源文件的变量可以使您更清楚地了解这些文件,并将其轻松添加到多个命令中,例如add_executable()函数。

# Create a sources variable with a link to all cpp files to compile
set(SOURCES
    src/Hello.cpp
    src/main.cpp
)

add_executable(${PROJECT_NAME} ${SOURCES})

注意:在SOURCES变量中设置特定文件名的另一种方法是使用GLOB命令使用通配符模式匹配来查找文件。

  file(GLOB SOURCES "src/*.cpp")

Tip

对于现代CMake,不建议对源使用变量。相反,通常直接在add_xxx函数中声明源。 这对于glob命令尤其重要,如果添加新的源文件,这些命令可能不会始终为您显示正确的结果。

包含目录

当您有其他包含文件夹时,可以使用target_include_directories()函数使编译器意识到它们。编译此目标时,这将使用 -I 标志将这些目录添加到编译器,例如-I/directory/path.

使用include_directories也可以。

PRIVATE标识符指定包含的范围。这对库很重要,将在下一个示例中说明。有关此功能的更多详细信息,请参见此处。

C. Static Library

添加静态库

add_library() 函数用于从某些源文件创建一个库。

add_library(hello_library STATIC
    src/Hello.cpp
)

这将用于创建名为libhello_library.a的静态库,并在add_library调用中包含源文件。

注意

如前面的示例所述,我们将源文件直接传递给add_library调用,这是现代CMake的建议。

填充目录

在此示例中,我们使用target_include_directories()函数来包含库中的目录,scope设置为PUBLIC。

target_include_directories(hello_library
    PUBLIC
        ${PROJECT_SOURCE_DIR}/include
)

这将导致在以下情况下使用包含的目录:

  • 编译库时
  • 编译链接库的任何其他目标时

scope的参数含义是:

  • PRIVATE - 目录已添加到此目标的包含目录
  • INTERFACE - 该目录被添加到链接该库的任何目标的包含目录中。
  • PUBLIC - 如上所述,它包含在此库中以及链接到该库的所有目标

对于public headers,通常最好将include文件夹与子目录进行 “命名间隔(namespaced)”。

传递给target_include_directories的目录将是包含目录树的根,并且C++文件应包括从此处到标头的路径。

对于此示例,您可以看到我们按以下方式进行操作:

#include "static/Hello.h"

使用此方法意味着在项目中使用多个库时,头文件名冲突的可能性较小。

链接一个库 Linking a Library

创建将使用您的库的可执行文件时,必须告知编译器该库。可以使用target_link_libraries()函数来完成。

add_executable(hello_binary
    src / main.cpp
)

target_link_libraries(hello_binary
     PRIVATE
        hello_library
)

这告诉CMake在链接期间将hello_library链接到hello_binary可执行文件。它还将从链接库目标传播具有PUBLIC或INTERFACE范围的任何包含目录。

g++命令总结

以1.cpp为例

    命令:g++ 1.cpp

    功能:生成默认为a.exe的文件,包含了编译链接。 

常用命令

1.    g++   -E    1.cpp  > 1.i                  Preprocess only; do not compile, assemble or link 

   只预处理,不生成文件。这一步主要进行宏的替换、注释消除、找到库文件。1.i 中会有很多代码。

2.   g++   -S   1.cpp                           Compile only; do not assemble or link

  只编译,不汇编、不连接 ,生成1.s.,里面是汇编指令

3.   g++    -c 1.cpp                            Compile and assemble, but do not link

  从汇编生成目标代码(机器码).   生成1.o文件。

4.   g++ 1.o    -L  <PATH>           

  链接目标代码,生成可执行程序

5.  g++    xxx.x    -o   yyy.x

  输出自己想要的名字。

GTEST总结

LCOV

1. Lcov是什么?

是GCOV图形化的前端工具, 是Linux Test Project维护的开放源代码工具,最初被设计用来支持Linux内核覆盖率的度量。 基于Html输出,并生成一棵完整的HTML树,输出包括概述、覆盖率百分比、图表,能快速浏览覆盖率数据。 支持大项目,提供三个级别的视图:目录视图、文件视图、源码视图。

2. 如何在Linux平台安装Lcov?

# wget http://downloads.sourceforge.net/ltp/lcov-1.9.tar.gz

# tar -zxvf lcov-1.9.tar.gz

# cd lcov-1.9

# ls

bin      contrib  descriptions.tests  lcovrc    man     rpm

CHANGES  COPYING  example             Makefile  README

# make install

不需要编译,直接安装即可,lcov, gendesc, genhtml, geninfo, genpng将被安装到/usr/bin目录。

Gtest 基本概念

当使用google test,通过编写启动assertions,这是检查条件是否为真的statement。断言的结果可能是successnonfatal failure fatal failure。如果发生fatal failure,它将中止当前功能。否则程序将继续正常运行。

Tests 使用assertions来验证被测试代码的行为。如果测试崩溃或断言失败,则它fails;否则success

一个测试套件test suite包含一个或多个测试。您应该将测试分为反映被测代码结构的测试套件。当一个测试套件中的多个测试需要共享通用对象common objects和子例程subroutines时,可以将它们放入一个 test fixture 类。

一个测试程序 test program 可以包含多个测试套件。

现在,我们将说明如何编写测试程序,该程序从各个assertion level开始,直至构建测试和测试套件。

Assertions

ASSERT_*版本失败时会产生致命故障,并中止当前函数EXPECT_*版本会产生非致命故障,不会中止当前函数。通常EXPECT_*是首选,因为它们允许在测试中报告多个故障。但是,如果在断言失败时继续执行没有意义,则应使用ASSERT_*

由于一个失败的ASSERT_*会立即从当前函数返回,可能会跳过其后的清理代码,因此可能会导致空间泄漏。根据泄漏的性质,它可能值得或不值得修复 —— 因此请牢记这一点,如果您除了断言错误之外还遇到堆检查程序错误。

要提供自定义失败消息,只需使用<<运算符或此类运算符的序列将其流式传输到宏中macro 即可 。一个例子:

ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";

for (int i = 0; i < x.size(); ++i) {
  EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}

可以流到ostream的任何内容都可以流到一个断言宏assertion macro —— 特别是C字符串和string对象。如果一个宽字符串(wchar_t*TCHAR*在Windows的UNICODE模式上,或std::wstring)流式传输到一个断言assertion,在打印时将被转换为UTF-8。

Basic Assertions

These assertions do basic true/false condition testing.

Fatal assertion

Nonfatal assertion

Verifies

ASSERT_TRUE(condition);

EXPECT_TRUE(condition);

condition is true

ASSERT_FALSE(condition);

EXPECT_FALSE(condition);

condition is false

Binary Comparison

This section describes assertions that compare two values.

Fatal assertion

Nonfatal assertion

Verifies

ASSERT_EQ(val1, val2);

EXPECT_EQ(val1, val2);

val1 == val2

ASSERT_NE(val1, val2);

EXPECT_NE(val1, val2);

val1 != val2

ASSERT_LT(val1, val2);

EXPECT_LT(val1, val2);

val1 < val2

ASSERT_LE(val1, val2);

EXPECT_LE(val1, val2);

val1 <= val2

ASSERT_GT(val1, val2);

EXPECT_GT(val1, val2);

val1 > val2

ASSERT_GE(val1, val2);

EXPECT_GE(val1, val2);

val1 >= val2