Update and rename sources/tech/20220112 Set up a build system with CMake and VSCodium.md to translated/tech/20220112 Set up a build system with CMake and VSCodium.md

This commit is contained in:
2022-02-02 22:16:02 +08:00 committed by GitHub
parent 6b8d75d7ea
commit 7af13191e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 296 additions and 297 deletions

View File

@ -1,297 +0,0 @@
[#]: subject: "Set up a build system with CMake and VSCodium"
[#]: via: "https://opensource.com/article/22/1/devops-cmake"
[#]: author: "Stephan Avenwedde https://opensource.com/users/hansic99"
[#]: collector: "lujun9972"
[#]: translator: "robsesan"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
Set up a build system with CMake and VSCodium
======
Providing a proper CMake configuration makes it much easier for others
to build, use and contribute to your project.
![woman on laptop sitting at the window][1]
This article is part of a series about open source DevOps tools for C/C++ development. If you build up your project from the beginning on a powerful toolchain, you will benefit from a faster and safer development. Aside from that, it will be easier for you to get others involved in your project. In this article, I will prepare a C/C++ build system based on [CMake][2] and [VSCodium][3]. As usual, the related example code is available on [GitHub][4].
I've tested the steps described in this article. This is a solution for all platforms.
### Why CMake?
[CMake][5] is a build system generator that creates the Makefile for your project. What sounds simple at first glance can be pretty complex at second glance. At a high altitude, you define the individual parts of your project (executables, libraries), compiling options (C/C++ standard, optimizations, architecture), the dependencies (header, libraries), and the project structure on file level. This information gets made available to CMake in the file `CMakeLists.txt` using a special description language. When CMake processes this file, it automatically detects the installed compilers on your systems and creates a working Makefile.
In addition, the configuration described in the `CMakeLists.txt` can be read by many editors like QtCreator, VSCodium/VSCode, or Visual Studio.
### Sample program
Our sample program is a simple command-line tool: It takes an integer as an argument and outputs numbers randomly shuffled in the range from one to the provided input value.
```
$ ./Producer 10
3 8 2 7 9 1 5 10 6 4 
```
In the `main() `function of our executable, we just process the input parameter and exit the program if no one value (or a value that can't be processed) is provided.
**producer.cpp**
```
int main(int argc, char** argv){
    if (argc != 2) {
        std::cerr << "Enter the number of elements as argument" << std::endl;
        return -1;
    }
    int range = 0;
    
    try{
        range = std::stoi(argv[1]);
    }catch (const std::invalid_argument&){
        std::cerr << "Error: Cannot parse \"" << argv[1] << "\" ";
        return -1;
    }
    catch (const std::out_of_range&) {
        std::cerr << "Error: " << argv[1] << " is out of range";
        return -1;
    }
    if (range <= 0) {
        std::cerr << "Error: Zero or negative number provided: " << argv[1];
        return -1;
    }
    std::stringstream data;
    std::cout << Generator::generate(data, range).rdbuf();
}
```
The actual work gets done in the [Generator][6], which is compiled and linked as a static library to our `Producer` executable. 
**Generator.cpp**
```
std::stringstream &Generator::generate(std::stringstream &stream, const int range) {
    std::vector<int> data(range);
    std::iota(data.begin(), data.end(), 1);
    std::random_device rd;
    std::mt19937 g(rd());
    std::shuffle(data.begin(), data.end(), g);
    for (const auto n : data) {
        stream << std::to_string(n) << " ";
    }
    return stream;
}
```
The function `generate` takes a reference to a [std::stringstream][7] and an integer as an argument. Based on the value _n_ of the integer `range`, a vector of integers in the range of 1 to _n_ is made and afterward shuffled. The values in the shuffled vector are then converted into a string and pushed into the `stringstream`. The function returns the same `stringstream` reference as passed as argument.
### Top-level CMakeLists.txt
The top-level [CMakeLists.txt][8] is the entry point of our project. There can be several `CMakeLists.txt `files in subdirectories (for example, libraries or other executables associated with the project). We start by going step by step over the top-level `CMakeLists.txt`.
The first lines tell us about the version of CMake, which is required to process the file, the project name, and its versions, as well as the intended C++ standard.
```
cmake_minimum_required(VERSION 3.14)
project(CPP_Testing_Sample VERSION 1.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
```
We tell CMake to look into the subdirectory `Generator` with the following line. This subdirectory includes all information to build the `Generator` library and contains a `CMakeLists.txt` for its own. We'll get to that shortly.
```
`add_subdirectory(Generator)`
```
Now we come to an absolute special feature: [CMake Modules][9]. Loading modules can extend CMake functionality. In our project, we load the module [FetchContent][10], which enables us to download external resources, in our case [GoogleTest][11] when CMake is run.
```
include(FetchContent)
FetchContent_Declare(
  googletest
  URL <https://github.com/google/googletest/archive/bb9216085fbbf193408653ced9e73c61e7766e80.zip>
)
FetchContent_MakeAvailable(googletest)
```
In the next part, we do what we would usually do in an ordinary Makefile: Specify which binary to build, their related source files, libraries which should be linked to, and the directories in which the compiler can find the header files.
```
add_executable(Producer Producer.cpp)
target_link_libraries(Producer PUBLIC Generator)
target_include_directories(Producer PUBLIC "${PROJECT_BINARY_DIR}")
```
With the following statement, we get CMake to create a file in the build folder called `compile_commands.json`. This file exposes the compile options for every single file of the project. Loaded in VSCodium, this file tells the IntelliSense feature where to find the header files (see [documentation][12]).
```
`set(CMAKE_EXPORT_COMPILE_COMMANDS ON)`
```
The last part defines the tests for our project. The project uses the previously loaded  GoogleTest framework. The whole topic of unit tests will be part of a separate article.
```
enable_testing()
add_executable(unit_test unit_test.cpp)
target_link_libraries(unit_test gtest_main)
include(GoogleTest)
gtest_discover_tests(unit_test)
```
### Library level CMakeLists.txt
Now we look at the [CMakeLists.txt][13] file in the subdirectory `Generator` containing the eponymous library. This `CMakeLists.txt` is much shorter, and besides the unit test-related commands, it contains only two statements.
```
add_library(Generator STATIC Generator.cpp Generator.h)
target_include_directories(Generator INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
```
With `add_library(...)` we define a new build target: The static `Generator` library. With the statement `target_include_directories(...)`, we add the current subdirectory to the search path for header files for other build targets. We also specify the scope of this property to be of type `INTERFACE`: This means that the property will only affect build targets that link against this library, not the library itself.
### Get started with VSCodium
With the information available in the `CMakeLists.txt`, IDEs like VSCodium can configure the build system accordingly. If you haven't already experience with VSCodium or VS Code, this example project is a good starting point. First, go to their [website][3] and download the latest installation package for your system. Open VSCodium and navigate to the **Extensions** tab.
To properly build, debug and test the project, search for the following extensions and install them.
![Searching extensions][14]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
If not already done, clone the repository by clicking on **Clone Git Repository** on the start page.
![Clone Git repository][16]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
Or manually by typing:
```
`git clone https://github.com/hANSIc99/cpp_testing_sample.git`
```
Afterward, check out the tag _devops_1_ either by typing:
```
`git checkout tags/devops_1`
```
Or by clicking on the **main** branch button (red box) and selecting the tag from the drop-down menu (yellow box).
![Select devops_1 tag][17]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
Once you open the repository's root folder inside VSCodium, the `CMake Tools` extensions detect the `CMakeLists.txt` file and immediately scan your system for suitable compilers. You can now click on the **Build** button at the bottom of the screen (red box) to start the build process. You can also change the compiler by clicking on the area at the bottom (yellow box) mark, which shows the currently active compiler.
![Build compiler][18]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
To start debugging the `Producer` executable, click on the debugger symbol (yellow box) and choose **Debug Producer** (green box) from the drop-down menu.
![Starting the debugger][19]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
As previously mentioned, the `Producer` executable expects the number of elements as a command-line argument. The command-line argument can be specified in the file `.vscode/launch.json.`
![Command-line arguments][20]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
Alright, you are now able to build and debug the project.
### Conclusion
Thanks to CMake, the above steps should work no matter what OS you're running. Especially with the CMake-related extensions, VSCodium becomes a powerful IDE. I didn't mention the Git integration of VSCodium because you can already find many resources on the web. I hope you see that providing a proper CMake configuration makes it much easier for others to build, use and contribute to your project. In a future article, I will look at unit tests and CMake's testing utility `ctest`.
--------------------------------------------------------------------------------
via: https://opensource.com/article/22/1/devops-cmake
作者:[Stephan Avenwedde][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/hansic99
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/lenovo-thinkpad-laptop-window-focus.png?itok=g0xPm2kD (young woman working on a laptop)
[2]: https://cmake.org/
[3]: https://vscodium.com/
[4]: https://github.com/hANSIc99/cpp_testing_sample
[5]: https://opensource.com/article/21/5/cmake
[6]: https://github.com/hANSIc99/cpp_testing_sample/blob/main/Generator/Generator.cpp
[7]: https://en.cppreference.com/w/cpp/io/basic_stringstream
[8]: https://github.com/hANSIc99/cpp_testing_sample/blob/main/CMakeLists.txt
[9]: https://cmake.org/cmake/help/latest/manual/cmake-modules.7.html
[10]: https://cmake.org/cmake/help/latest/module/FetchContent.html
[11]: https://github.com/google/googletest
[12]: https://code.visualstudio.com/docs/cpp/c-cpp-properties-schema-reference
[13]: https://github.com/hANSIc99/cpp_testing_sample/blob/main/Generator/CMakeLists.txt
[14]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_extensions.png (Searching extensions)
[15]: https://creativecommons.org/licenses/by-sa/4.0/
[16]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_git_clone.png (Clone Git repository)
[17]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_select_tag.png (Select devops_1 tag)
[18]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_compiler_2.png (Build compiler)
[19]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_start_debugging.png (Starting the debugger)
[20]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_arguments.png (Command-line arguments)

View File

@ -0,0 +1,296 @@
[#]: subject: "Set up a build system with CMake and VSCodium"
[#]: via: "https://opensource.com/article/22/1/devops-cmake"
[#]: author: "Stephan Avenwedde https://opensource.com/users/hansic99"
[#]: collector: "lujun9972"
[#]: translator: "robsean"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
使用 CMake 和 VSCodium 设置一个构建系统
======
提供一个适当的 CMake 配置文件来使其他人可以更容易地构建、使用和贡献你的工程。
![woman on laptop sitting at the window][1]
这篇文章是关于 C/C++ 开发系列的开发工具的一部分。如果你从一个功能强大的工具链开始构建你的工程,你将从一个更快和更安全的开发环境中受益。除此之外,它会使别人更容易地参与你的工程。在这篇文章中,我将准备一个基于 [CMake][2] 和 [VSCodium][3] 的 C/C++ 构建系统。像往常一样,相关的示例代码可以在 [GitHub][4] 上找到。
我已经测试了在本文中描述的步骤。这是一种适用于所有平台的解决方案。
### 为什么是 CMake
[CMake][5] 是一个构建系统生成器,为你的工程创建 Makefile 。乍一看简单的东西可能乍一看相当地复杂。在较高的层次上,你可以定义你的工程 (可执行文件,库) 的各个部分,编译选项 (C/C++ 标准,优化,架构),依赖关系项 (头文件,库)和文件级的工程结构。CMake 使用的这些信息可以在文件 `CMakeLists.txt` 中获取,它使用一种特殊的描述性语言编写。当 CMake 处理这个文件时,它将自动地侦测在你的系统上已安装的编译器,并创建一个用于启动它的 Makefile 文件。
此外,在 `CMakeLists.txt` 中描述的配置,能够被很多编辑器读取,像 QtCreator, VSCodium/VSCode, 或 Visual Studio 。
### 示例程序
我们的示例程序是一个简单的命令行工具:它获取一个整数来作为一个参数,输出一个从 1 到所提供输入值的范围内的随机排列的数字。
```
$ ./Producer 10
3 8 2 7 9 1 5 10 6 4 
```
在我们的可执行文件中的 `main()` 函数,如果没有提供一个值 (或者一个不能被处理的值) 的话,我们只处理输入的参数,并退出程序。
**producer.cpp**
```
int main(int argc, char** argv){
if (argc != 2) {
std::cerr << "Enter the number of elements as argument" << std::endl;
return -1;
}
int range = 0;
try{
range = std::stoi(argv[1]);
}catch (const std::invalid_argument&){
std::cerr << "Error: Cannot parse \"" << argv[1] << "\" ";
return -1;
}
catch (const std::out_of_range&) {
std::cerr << "Error: " << argv[1] << " is out of range";
return -1;
}
if (range <= 0) {
std::cerr << "Error: Zero or negative number provided: " << argv[1];
return -1;
}
std::stringstream data;
std::cout << Generator::generate(data, range).rdbuf();
}
```
实际的工作是在 [Generator][6] 中完成的,它将被编译,并将作为一个静态库来链接到我们的`Producer` 可执行文件。 
**Generator.cpp**
```
std::stringstream &Generator::generate(std::stringstream &astream, const int range) {
std::vector<int> data(range);
std::iota(data.begin(), data.end(), 1);
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(data.begin(), data.end(), g);
for (const auto n : data) {
stream << std::to_string(n) << " ";
}
return stream;
}
```
函数 `generate` 引用一个 [std::stringstream][7] 和一个整数来作为一个参数。 以整数 `range` 的值 _n_ 为基础, 制作一个在 1 到 _n_ 的范围之中的整数向量,并随后排列。接下来排序的向量值转换成一个字符串,并推送到 `stringstream` 之中。该函数返回与作为参数传递的 `stringstream` 引用相同。
### CMakeLists.txt 的顶部层次
[CMakeLists.txt][8] 的顶部层次是我们工程的入口点。在子目录中有几个 `CMakeLists.txt` 文件 (例如,与工程所相关联的库或其它可执行文件)。我们先一步一步地读破 `CMakeLists.txt` 的顶部层次。
第一行告诉我们 CMake 的版本, CMake 需要处理的文件,工程名称,和其版本,以及意欲使用的 C++ 标准。
```
cmake_minimum_required(VERSION 3.14)
project(CPP_Testing_Sample VERSION 1.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
```
我们告诉 CMake 使用下面的代码行来查看子目录 `Generator` 。这个子目录包括构建 `Generator` 库的所有信息,并包含它自身的一个 `CMakeLists.txt` 。我们很快就会谈到这个问题。
```
`add_subdirectory(Generator)`
```
现在,我们将涉及一个绝对特别的功能: [CMake 模块][9] 。加载模块可以扩展 CMake 功能。在我们的工程中,我们将加载模块 [FetchContent][10] ,这能使我们能够在 CMake 运行时下载外部的资源,在我们的示例中是 [GoogleTest][11] 。
```
include(FetchContent)
FetchContent_Declare(
googletest
URL <https://github.com/google/googletest/archive/bb9216085fbbf193408653ced9e73c61e7766e80.zip>
)
FetchContent_MakeAvailable(googletest)
```
在接下来的部分中,我们将会做一些我们通常在一个普通的 Makefile 中会做的事: 具体指定哪个库来构建,它们相关的源文件文件,应该链接到的库,和编译器能够在哪些目录中查找头文件。
```
add_executable(Producer Producer.cpp)
target_link_libraries(Producer PUBLIC Generator)
target_include_directories(Producer PUBLIC "${PROJECT_BINARY_DIR}")
```
通过下面的语句,我们使 CMake 来在 build 文件夹中创建一个名称为 `compile_commands.json` 的文件。这个文件为工程的每个文件揭示编译器选项。在 VSCodium 中加载,这个文件告知 IntelliSense 功能在哪里查找头文件 (查看 [文档][12]) 。
```
`set(CMAKE_EXPORT_COMPILE_COMMANDS ON)`
```
最后的部分为我们的工程定义一些测试。工程使用先前加载的 GoogleTest 框架。单元测试的整个话题将会划归到另外一篇文章。
```
enable_testing()
add_executable(unit_test unit_test.cpp)
target_link_libraries(unit_test gtest_main)
include(GoogleTest)
gtest_discover_tests(unit_test)
```
### CMakeLists.txt 的库层次
现在,我们来看看包含同名库的子目录 `Generator` 中的 [CMakeLists.txt][13] 文件。这个 `CMakeLists.txt` 文件的内容更简短一些,除了单元测试相关的命令外,它仅包含 2 条语句。
```
add_library(Generator STATIC Generator.cpp Generator.h)
target_include_directories(Generator INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
```
我们使用 `add_library(...)` 来定义一个新的构建目标:静态的 `Generator` 库。我们使用语句 `target_include_directories(...)` 来把当前子目录添加到其它构建目标的头文件的搜索路径之中。我们也可以具体指定这个属性的范围为类型 `INTERFACE`:这意味着该属性仅影响链接到这个库的构建目标,而不是库本身。
### 开始使用 VSCodium
使用 `CMakeLists.txt` 文件中的可用信息,, IDEs like像 VSCodium 一样的 IDE 可用相应地配置构建系统。如果你还没有体验过 VSCodium 或 VS Code ,这个示例工程会是一个很好的起点。首先,转到它们的 [网站][3] ,然后针对你的系统下载最新的安装软件包。打开 VSCodium 并导航到 **Extensions** 标签页。
为了正确地构建,调试和测试工程,搜索下面的扩展并安装它们。
![Searching extensions][14]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
如果尚未完成,通过单击起始页的 **Clone Git Repository** 来复刻存储库。
![Clone Git repository][16]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
或者手动输入:
```
`git clone https://github.com/hANSIc99/cpp_testing_sample.git`
```
之后,通过输入 tag _devops_1_ 来签出每一个:
```
`git checkout tags/devops_1`
```
或者,通过单击 **main** 分支按钮 (红色框) ,并从下拉菜单 (黄色框) 中选择标签。
![Select devops_1 tag][17]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
在你打开 VSCodium 内部中的存储库的根文件夹后,`CMake Tools` 扩展会侦测 `CMakeLists.txt` 文件并立即扫描适合你的系统的编译器。你现在可以单击屏幕的底部的 **Build** 按钮 (红色框) 来开始构建过程。你也可以通过单击底部区域的按钮 (黄色框) 标记来更改编译器,它显示当前活动的编译器。
![Build compiler][18]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
为开始调试 `Producer` 可执行文件,单击调试器符号 (黄色框) 并从下拉菜单中选择 **Debug Producer** (绿色框)。
![Starting the debugger][19]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
如上所述,`Producer` 可执行文件要求元素的数字作为一个命令行的参数。命令行参数可以在 `.vscode/launch.json.` 中具体指定。
![Command-line arguments][20]
(Stephan Avenwedde, [CC BY-SA 4.0][15])
明白了吗,你现在能够构建和调试工程了。
### 结束语
归功于 CMake ,不管你正在运行哪种操作系统,上述步骤应该都能工作。特别是使用与 CMake 相关的扩展VSCodium 变成看一个强大的 IDE 。我没有提及 VSCodium 的 Git 集成,是因为你已经能够在网络上查找很多的资源。我希望你可以看到:提供一个适当的 CMake 配置文件可以使其他人更容易地构建,使用和贡献于你的工程。在未来的一篇文字中,我将看看单元测试和 CMake 的测试实用程序 `ctest`
--------------------------------------------------------------------------------
via: https://opensource.com/article/22/1/devops-cmake
作者:[Stephan Avenwedde][a]
选题:[lujun9972][b]
译者:[robsean](https://github.com/robsean)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/hansic99
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/lenovo-thinkpad-laptop-window-focus.png?itok=g0xPm2kD (young woman working on a laptop)
[2]: https://cmake.org/
[3]: https://vscodium.com/
[4]: https://github.com/hANSIc99/cpp_testing_sample
[5]: https://opensource.com/article/21/5/cmake
[6]: https://github.com/hANSIc99/cpp_testing_sample/blob/main/Generator/Generator.cpp
[7]: https://en.cppreference.com/w/cpp/io/basic_stringstream
[8]: https://github.com/hANSIc99/cpp_testing_sample/blob/main/CMakeLists.txt
[9]: https://cmake.org/cmake/help/latest/manual/cmake-modules.7.html
[10]: https://cmake.org/cmake/help/latest/module/FetchContent.html
[11]: https://github.com/google/googletest
[12]: https://code.visualstudio.com/docs/cpp/c-cpp-properties-schema-reference
[13]: https://github.com/hANSIc99/cpp_testing_sample/blob/main/Generator/CMakeLists.txt
[14]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_extensions.png (Searching extensions)
[15]: https://creativecommons.org/licenses/by-sa/4.0/
[16]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_git_clone.png (Clone Git repository)
[17]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_select_tag.png (Select devops_1 tag)
[18]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_compiler_2.png (Build compiler)
[19]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_start_debugging.png (Starting the debugger)
[20]: https://opensource.com/sites/default/files/uploads/cpp_unit_test_vscodium_arguments.png (Command-line arguments)