C/C++ cross-platform build tool CMake-----Read the contents of the CMakeLists.txt configuration file in the C++ source code

1.Description of requirements

When we develop software projects, we usually use version control. Each version will have different modifications, because once the software is released to users, when we upgrade the version, some users' versions will inevitably be old versions, so Every time a version is released, there will be a version number to identify the user's version. This version number is usually placed in the build configuration file. For example, Android is placed in the build.gradle file in the App directory, and we use the CMake tool. In the built C/C++ project, it is naturally placed in the CMakeLists.txt configuration file. In CMakeLists.txt, the following statement is used to declare the version number:

project(Tutorial VERSION 2.11)

Suppose we want to read this version number in our C/C++ source code and upload it to the server for identification. Direct reading is definitely not possible because CMakeLists.txt and C/C++ source files belong to different systems. So what needs to be done. This article introduces how to read the values ​​we set (not just the version number) from CMakeLists.txt, and access them in C/C++ source files.

2. Requirement preparation

2.1 Create project

Creating a C/C++ demo project is very simple. Find a directory, create a new folder in the directory, and create the file corresponding to the number as shown below: The directory contains a build directory to store the built product, a
Insert image description herebuild The script CmakeLists.txt is a C++ source code file used to read the values ​​in the build script: readConfigValue.cpp. Then we use the IDE to open this directory, or we can write it directly. Anyway, do whatever is convenient for you. I use VScode to open it.

2.2 Edit the CMakeLists.txt file

Write the following statement code in the CMakeLists.txt file:

#1.设置最小要求的Cmake版本号
cmake_minimum_required(VERSION 3.10)

#2.设置项目名称
project(ReadConfigValue)

#3.设置项目的版本号,在C++源文件中会读取这个版本号
project(ReadConfigValue VERSION 1.0)

#4.设置C++ 的版本,这里选择的是C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

#5.将项目编译成一个可执行文件,Windows上的 .exe文件
add_executable(ReadConfigValue readConfigValue.cpp)

Only basic configuration is done here, mainly to verify whether the project runs smoothly. We will edit this file later to complete our final requirements.

2.3 Writing C++ files

Write the following code in the ReadConfigValue.cpp file:

#include<iostream>
#include<string>

int main(int argc,char* argv[]){
    
    
    std::cout<<"Hello CMake"<<std::endl;
    return 0;
}

2.4 Compile and build the project

Enter the project directory we created, enter the build directory, open the command line tool CMD, enter the command:
cmake ..compile project, and then enter the command: cmake --build .build project.
Insert image description here
After executing the above command, some compiled files and executables will be generated in the build directory. File:
Insert image description hereAfter we execute the exe file on the command line, the information we output in the C++ source code proves that our environment is ready. The output of the sample project is: Hello CMake.

3. Requirement realization

After the project environment is ready, we can start to implement our needs. In fact, those of us who are familiar with Android Gradle build scripts may notice that when writing Android programs, we can use a class called BuildConfig, which is compiled During this period, it is generated by the Gradle plug-in provided by Android. The CMakeLists.txt implementation here is similar to Gradle's method. The general idea here is to put the values ​​we want to give to the C++ source code into a generated header file during compilation, and reference this header file in the C++ program. That's it. Next let’s look at the specific implementation:

3.1 Output log information in CMakeLists.txt

When writing the CMakeLists.txt file, we often need to print some information. Here we use a function: message(STATUS 内容), as shown below:

#1.设置最小要求的Cmake版本号
cmake_minimum_required(VERSION 3.10)

#2.设置项目名称
project(ReadConfigValue)

#3.设置项目的版本号,在C++源文件中会读取这个版本号
project(ReadConfigValue VERSION 1.0)

#4.设置C++ 的版本,这里选择的是C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

#5.将项目编译成一个可执行文件,Windows上的 .exe文件
add_executable(ReadConfigValue readConfigValue.cpp)

#6.打印调试信息
message(STATUS "Hello from CMakeLists.txt")
message(STATUS "${PROJECT_BINARY_DIR}")
message(STATUS "${ReadConfigValue_VERSION_MAJOR}")
message(STATUS "${ReadConfigValue_VERSION_MINOR}")

After modifying CMakeLists.txt, enter the project's build directory and enter the command. You cmake .will get the information in the figure below:
Insert image description here

3.2 Add configuration to generate C++ header files

If we want to read the value in CMakeLists.txt in C++, we need to generate a header file first. To generate the header file, we need to first create a config.h.in file in the root directory to configure the generated header file information: The created file is as shown below: Then add
Insert image description herecode in the CMakeLists.txt file to reference our newly created configuration file, the code is as follows:

configure_file(config.h.in config.h)

And configure the values ​​we want to give C++ access to in the config.h.in we created, as follows:

#define ReadConfigValue_VERSION_MAJOR ${
      
      ReadConfigValue_VERSION_MAJOR}
// 可以使用@ 或者${}去获取对应的值
#define ReadConfigValue_VERSION_MINOR @ReadConfigValue_VERSION_MINOR@

3.3 Access configured values ​​in C++ source code

After writing the above configuration, we reference the config.h header file in the readConfigValue.cpp file

#include<iostream>
#include<string>
#include "config.h"

int main(int argc,char* argv[]){
    
    
    std::cout<<"Hello CMake"<<std::endl;
    std::cout<<"Major version=>"<<ReadConfigValue_VERSION_MAJOR<<std::endl;
    std::cout<<"Major version=>"<<ReadConfigValue_VERSION_MINOR<<std::endl;
    return 0;
}

Then we will get a config.h header file after compilation:
Insert image description herethe content in the header file is the value we configured in the CMakeLists.txt file:
Insert image description here

But when we build, an error will be reported:
Insert image description here
the reason is that our config.h file was successfully generated, but it was not correctly referenced into the C++ source file. That is to say, include "config.h" cannot find the path to config.h, so We need to configure this path in the CMakeLists.txt file. The code is as follows:

target_include_directories(ReadConfigValue PUBLIC "${PROJECT_BINARY_DIR}")

这里的第一个参数是我们的项目名称,第二个参数可以是PUBLIC、PRIVATE、INTERFACE 目前暂时使用PUBLIC就行,最后一个是我们生成的config.h所在目录的路径,我们的config.h实际上是在build目录下的,我们在前面输出的调试信息中也发现${PROJECT_BINARY_DIR}输出的是build目录的路径,所以配置好它就行了

After the configuration is completed, we compile and build again and find that it can run and successfully read the value of the CMakeLists.txt file.
Insert image description here

3.4 Read the string in CMakeLists.txt from the C++ file

If we want to read the string in the CMakeLists.txt file, it is also possible. It is relatively simple. First, set the string we want to read in the C++ source code file in CMakeLists.txt:

#.设置字符串给C++文件读取
set(STR_VALUE "I am String from CMakeLists.txt")

Insert image description here如上图所示,需要注意set()语句的位置,不能放在最后否则这个值无法生成
Then add the configuration in config.h.in:

//必须使用双引号,否则在C++源码读取的时候这里没有双引号包裹,会导致读取错误
#define STR_VALUE "@STR_VALUE@"

注意:配置字符串时必须使用双引号包裹我们的取值语句,否则在C++源码读取的时候这里没有双引号包裹,会导致读取错误
Then access it in the C++ file:

#include<iostream>
#include<string>
#include "config.h"

int main(int argc,char* argv[]){
    
    
    std::cout<<"Hello CMake"<<std::endl;
    std::cout<<"Major version=>"<<ReadConfigValue_VERSION_MAJOR<<std::endl;
    std::cout<<"Major version=>"<<ReadConfigValue_VERSION_MINOR<<std::endl;
    std::cout<<"String value from CMakeLists.txt==>"<<STR_VALUE<<std::endl;
    return 0;
}

Finally compile and run:
Insert image description here

Summarize

Although this article is simple, it is indeed useful in development. For example, when we want to distinguish the debug environment and the release environment in our program, we can add configurations in CMakeList, just like the BuildCongfig class generated by Android's gradle plug-in, we can conveniently Use DEBUG and RELEASE of this class to distinguish the development environment from the formal environment, so as to isolate some development environment logs. Therefore, it is recommended that friends become familiar with this method of use. It will be very useful for development.

Guess you like

Origin blog.csdn.net/zxj2589/article/details/133436375