[CMake] Writing collation of CMakeList

What is CMake

If the software is to be cross-platform, it must be able to be compiled on different platforms. If you use the Make tool, you have to write a Makefile once for each standard.
CMake is a tool designed to address these issues: it first allows developers to write a platform-independent MakeList.txt file to customize the entire compilation process, and then further generates the localized Makefile s and project files needed based on the target user's platform.

The process to generate Makefile and compile it using CMake under the linux platform is as follows:

  1. Write CMake configuration file CMakeLists.txt.
  2. Execute the command cmake PATH or ccmake PATH to generate Makefile (the difference between ccmake and cmake is that they provide an interactive interface). Where PATH is the directory where CMakeLists.txt is located.
  3. Compile using the make command.

Instruction Snapshot

variable

Quote:
As mentioned earlier, ${variable_name} is used for variable reference. In statements such as IF, the variable name is used directly rather than through ${variable_name}.

Custom variable method:
There are two main types: implicit definition and explicit definition.
Explicitly define variables using the SET(variable_name value) directive.

SET(SRC_LIST main.cpp)

PROJECT directive, implicitly defined _ BINARY_DIR and _ SOURCE_DIR is two variables.

# Project Information
project(Test)

Common variables:
CMAKE_BINARY_DIR/PROJECT_BINARY_DIR /_BINARY_DIR
The directory where the cmake command is run, usually ${PROJECT_SOURCE_DIR}/build.
These three variables refer to the same content, if in-source build refers to the top level directory of the project; If it is out-of-source build, it refers to the directory where the project compilation occurs.

CMAKE_SOURCE_DIR/PROJECT_SOURCE_DIR /_SOURCE_DIR
These three variables refer to the same content and are the top-level directory of the project regardless of how they are compiled.

PROJECT_NAME: Returns the project name defined by the project command.

CMAKE_CURRENT_SOURCE_DIR
Refers to the path where CMakeLists.txt is currently being processed, such as the src source code subdirectory in the example above.

CMAKE_CURRRENT_BINARY_DIR
If compiled in-source, it follows CMAKE_CURRENT_SOURCE_DIR is consistent;
If it is an out-of-source compilation, it refers to the target compilation directory.
Use the ADD_we mentioned above SUBDIRECTORY (src bin) can change the value of this variable.
Using SET (EXECUTABLE_OUTPUT_PATH <New Path>) does not affect this variable; it only modifies the path where the final destination file is stored.
 
CMAKE_ CURRENT_ LIST_ The full path to DIR: CMakeLists.txt;
CMAKE_CURRENT_LIST_LINE: The current row.

EXECUTABLE_OUTPUT_PATH: The location where executable files are stored;
LIBRARY_OUTPUT_PATH: The location where the library files are stored.

Invoke environment variables:
Use the $ENV{variable_name} directive to invoke the system's environment variables.

set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

System information variables:
  UNIX
* true on all UNIX-like platforms, including OS X and cygwin.
  WIN32
* true on all win32 platforms, including cygwin.

# Judging platform differences and controlling for different platforms
IF(WIN32)
  MESSAGE(STATUS "Thisiswindows.")
  #Do some Windows-related operations
ELSE(WIN32)
  MESSAGE(STATUS "Thisisnotwindows")
  #Do some non-Windows related operations
ENDIF(WIN32)

Main Switch Options

set(CMAKE_CXX_STANDARD 11)
# C++11 Settings

set(CMAKE_CXX_STANDARD_REQUIRED ON)
# If not set, the previously set STANDARD 11 standard may become invalid. Therefore, it is generally used in conjunction with the latter statement.

set(CMAKE_CXX_EXTENSIONS OFF)
# This value is compiled using gnu++11 by default, and our protobuf was compiled using c++11, so it should be turned off.

instructions

cmake_minimum_required()Appoint cmake Minimum version

project()Two variables are defined: PROJECT_BINARY_DIR and PROJECT_SOURCE_DIR. 
# ${PROJECT_SOURCE_DIR}: The folder path where this CMakeLists.txt is located
# ${PROJECT_NAME}: The project name of this CMakeLists.txt

aux_source_directory(Catalog variables)Finds all source files in the specified directory and saves them to the specified variable name

add_definitions()Add compilation options

add_executable(Executable Name Source File)Generate executable files from source files;

add_library(Static Library STATIC source file)Generate static libraries from source files (when none exist) STATIC When option is selected, static libraries are generated by default;

add_library(Dynamic Library SHARED source file) Generate dynamic or shared libraries from source files.

add_subdirectory(Subdirectories)Specify the calling subdirectory CMakeLists.txt,Usually used to compile source files in subdirectories into libraries to give the files in the parent directory CMakeLists.txt Use. (For parent directories at this time CMakeLists.txt For example, you already know that compiled libraries exist in subdirectories, so you don't need to use them link_directories()Include the library in a separate file directory.)
# In add_ Variables set before subdirectory can be called in subfolders!

include_directories(Catalog)Specify the header file directory;

link_directories(Catalog)Specify the library file directory.

target_link_libraries()Specify Link Library

option(macro "Remarks" ON)Add an option and set the default value to On

configure_file(Profile Configuration Header File)Generate configuration header file from configuration file

message()Print message

include()Specify other to include CMake File or Directory

find_package()Introducing external dependency packages, find_program()

FetchContent_Declare(),FetchContent_MakeAvailable()

Common combinations:

# Search all.cpp files in the current directory, store them in a variable, and specify a build target.
aux_source_directory(. SRC_LIST) 
add_library(Test ${SRC_LIST})
# Subfile:
# Search the current directory and all.cpp files in the protocol directory and generate a link library
file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp")
add_library(MathFunctions ${SRC_LIST})
# perhaps
file(GLOB SRC_LIST "*.cpp")
file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp")
add_library(MathFunctions ${SRC_LIST} ${SRC_PROTOCOL_LIST})
# perhaps
aux_source_directory(. SRC_LIST)
aux_source_directory(protocol SRC_PROTOCOL_LIST)
add_library(MathFunctions ${SRC_LIST} ${SRC_PROTOCOL_LIST})
# Root file:
# Add Link Library
target_link_libraries(Test4 MathFunctions)

Normal process:

project(xxx)                                          #Must

add_subdirectory(Subfolder Name)                         #Parent directory must, subdirectory does not have to

add_library(Library File Name STATIC file)                    #Normal subdirectories (2-choice)
add_executable(Executable Name File)                     #Normally parent directory (2-choice)

include_directories(Route)                              #Must
link_directories(Route)                                 #Must

target_link_libraries(Library File Name/Executable Name Linked Library File Name)       #Must

Technological process

if statement

if(...)
  ...
else()
  ...
endif

the while statement

while(condition)
    ...
endwhile()

foreach statement

foreach(_target
  ... ...
  )
  ...
  endforeach

For example:

foreach(i RANGE 1 9 2) #1 is the start number, 9 is the end number, and 2 is the step size.
    message(${i})
endforeach(i)

Start simple

CMakeList case insensitive.

Write CMakeLists.txt

First write the CMakeLists.txt file and save it in the same directory as the main.cc source file:

# CMake Minimum Version Number Requirements
cmake_minimum_required (VERSION 3.10.0)
# Project Information
project(Test)
# Specify a build target
add_executable(Test main.cpp)
  1. cmake_minimum_required: Specify the minimum version of CMake required to run this profile;
  2. Project: The parameter value is Test, which means the name of the project is Test.
  3. add_executable: Compile the source file named main.cpp into an executable file named Test.

It can also be written as:

# CMake Minimum Version Number Requirements
cmake_minimum_required (VERSION 3.10.0)
# Project Information
project(Test)
# Setting CMakeList variable
SET(SRC_LIST main.cpp)
# Specify a build target
# add_executable(ClionProject main.cpp)
ADD_EXECUTABLE(Test1 ${SRC_LIST})

SET is used to set the CMake variable and to reference it in the form of ${VAR_NAME}

Compile Project

Then, execute cmake., get Makefile, and compile Demo1 executable using make command.

(base) liana@liana-930MBE:~/Learning/CMakeListTest$ cmake .
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/liana/Learning/CMakeListTest

(base) liana@liana-930MBE:~/Learning/CMakeListTest$ make
Scanning dependencies of target Test1
[ 50%] Building CXX object CMakeFiles/Test1.dir/main.cpp.o
[100%] Linking CXX executable Test1
[100%] Built target Test1

(base) liana@liana-930MBE:~/Learning/CMakeListTest$ ./Test1 5 4
5 ^ 4 is 625

Cmake.:'. 'denotes the current directory and will automatically generate the CMakeFiles folder, CMakeCache.txt, cmake_after running Install.cmake, and so on, and generated Makefile.

make is the Makefile to execute to generate our target file, CLionProject.

Use make clean to delete the generated executable.

Or do an external build, create a new build folder and enter:

(base) liana@liana-930MBE:~/Learning/CMakeListTest$ mkdir build
(base) liana@liana-930MBE:~/Learning/CMakeListTest$ cd build

(base) liana@liana-930MBE:~/Learning/CMakeListTest/build$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/liana/Learning/CMakeListTest/build

(base) liana@liana-930MBE:~/Learning/CMakeListTest/build$ make
Scanning dependencies of target MathFunctions

The..in cmake..represents the parent directory of the build directory, which is our source code project directory, because the parent directory has the MakeLists.txt we need. It is generally recommended that you create a new build directory under the source code project directory.
The catalog of project source files completed by external build is as follows. The intermediate products and target files during the build process are stored in the build catalog, and the source files are not affected by them. By deleting this folder, you can quickly delete intermediate files. That is, out-of-source (i.e., generated intermediate and source code separation)

One directory, multiple cpp files

If there are multiple cpp files,

./Test2
    |
    +--- main.cpp
    |
    +--- MathFunctions.cpp
    |
    +--- MathFunctions.h

Just write as:

add_executable(Test2 main.cpp MathFunctions.cpp)

Or use aux_source_directory command, which finds all source files in the specified directory and stores the results in the specified variable name. Its syntax is as follows:

aux_source_directory(<dir> <variable>)
# Find all source files in the current directory
# And save the name to DIR_SRCS variable
aux_source_directory(. DIR_SRCS)
# Specify a build target
add_executable(Test3 ${DIR_SRCS})

In this way, CMake assigns the file names of all source files in the current directory ('. 'denotes the current directory) to the variable DIR_SRCS, then the variable DIR_ The source files in SRCS need to be compiled into an executable named Test3.

Multiple directories, multiple source files

./Test4
    |
    +--- main.cpp
    |
    +--- math/
          |
          +--- MathFunctions.cpp
          |
          +--- MathFunctions.h

In this case, you need to write a CMakeLists.txt file in the project root directory Demo3 and math directories, respectively. For convenience, we can compile the files in the math directory into a static library and call it by the main function.

Remember the main function header file path:

CMakeLists.txt in the root directory:

# CMake Minimum Version Number Requirements
cmake_minimum_required (VERSION 3.10.0)
# Project Information
project(Test)
# Find all source files in the current directory
# And save the name to DIR_SRCS variable
aux_source_directory(. DIR_SRCS)
# Add math subdirectory
add_subdirectory(math)
# Specify a build target 
add_executable(Test4 ${DIR_SRCS})
# Add Link Library
target_link_libraries(Test4 MathFunctions)

Use the command add_ The subdirectory indicates that this project contains a subdirectory math so that the CMakeLists.txt file and source code under the math directory will also be processed.
Use the command target_link_libraries indicate that the executable main needs to connect to a link library called MathFunctions.

CMakeLists.txt in the subdirectory:

# Find all source files in the current directory
# And save the name to DIR_LIB_SRCS variable
aux_source_directory(. DIR_LIB_SRCS)
# Generate Link Library
add_library (MathFunctions ${DIR_LIB_SRCS})

Use the command add_in this file Library compiles the source files in the src directory into the static link library MathFunctions.

Custom Compile Options

CMake allows you to add compilation options to your project so that you can choose the most appropriate compilation scenario based on your environment and needs.

For example, you can set the MathFunctions library as an optional library, and if the option is ON, use the mathematical functions defined by the library to perform operations. Otherwise, the math function library in the standard library is called.

Modify the CMakeLists.txt file in the root directory:

# CMake Minimum Version Number Requirements
cmake_minimum_required (VERSION 3.10.0)
# Project Information
project(Test)

# Add a configuration header file to handle CMake source settings
configure_file (
  "${PROJECT_SOURCE_DIR}/config.h.in"
  "${PROJECT_BINARY_DIR}/config.h"
  )
# Whether to use your own MathFunctions Library
option (USE_MYMATH
       "Use provided math implementation" ON)
# Whether to join the MathFunctions Library
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/math")
  add_subdirectory (math)  
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)

# Find all source files in the current directory
# And save the name to DIR_SRCS variable
aux_source_directory(. DIR_SRCS)
# Specify a build target 
add_executable(Test5 ${DIR_SRCS})
# Add Link Library
target_link_libraries(Test5 ${EXTRA_LIBS})
  • Configure_ The file command is used to add a configuration header file, config.h, generated by CMake from config.h.in, through which code generation can be controlled by predefining some parameters and variables.
  • The option command adds a USE_MYMATH option, and the default value is ON.
  • According to USE_ The value of the MYMATH variable determines whether to use our own MathFunctions library.

Modify main.cpp file
Then modify the main.cpp file so that it follows the USE_MYMATH's predefined values determine whether to call the Standard or MathFunctions libraries:

#include "config.h"

#ifdef USE_MYMATH
  #include "math/MathFunctions.h"
#else
  #include <math.h>
#endif

int main(int argc, char *argv[])
{

#ifdef USE_MYMATH
    printf("Now we use our own Math library. \n");
    //
#else
    printf("Now we use the standard library. \n");
    //
#endif
    //
    return 0;
}

Write config.h.in file
Notable in the above program is line 2, which references a config.h file that predefines USE_ Value of MYMATH.

./Test5
    |
    +--- main.cpp
    |
    +--- CMakeLists.txt
    |
    +--- config.h.in
    |
    +--- math/
          |
          +--- MathFunctions.cpp
          |
          +--- MathFunctions.h
          |
          +--- CMakeLists.txt

But we don't write this file directly. To import the configuration from CMakeLists.txt, we write a config.h.in file, which reads as follows:

#cmakedefine USE_MYMATH

Compile Project
Now compile this project so that you can interactively select the value of this variable using the ccmake command (or the cmake -i command, which provides a session-based interactive configuration interface)
Here you can find the USE_just defined MYMATH option, keyboard arrow keys can jump between different options windows, press enter to modify the option. After the modification is complete, you can press the c option to complete the configuration, and then press the g key to confirm that the Makefile was generated. Other operations of ccmake can refer to the instructions given below the window.

This allows you to connect CMakeLists.txt to the cpp file using the config.h file

Installation and testing

CMake can also specify installation rules and add tests. These two functions can be performed by using make install and make test after making a file. In previous GNU Makefile s, you might have written two pseudo targets and corresponding rules for install and test, but in CMake, this would also require a few simple command calls.

Custom Installation Rules
First add the following two lines to the math/CMakeLists.txt file:

# Specify the installation path for the MathFunctions Library
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

Indicates the installation path for the MathFunctions library. Then also modify the MakeLists file in the root directory, adding the following lines at the end:

# Specify Installation Path
install (TARGETS Test6 DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
         DESTINATION include)

With the customization above, the generated Test6 file and the MathFunctions library libMathFunctions.o file will be copied to / usr/local/bin, while MathFunctions.h and the generated config.h file will be copied to / usr/local/include.

We can verify (incidentally, /usr/local/is the root directory installed by default, and you can specify which root directory these files should be copied to by modifying the value of the CMAKE_INSTALL_PREFIX variable):

Formatting Project

In addition to the cmake.. above, more formatting projects are needed to make the whole better.

./Test4
├── build
| └── bin
| | └── <project_name>
├── doc
| └── <project_name>.txt
├── src
| ├── xxx.c
| └── CMakeLists.txt
├── CMakeLists.txt

├── COPYRIGHT
├── README

└── run<project_name>.sh
  • src, which places the project source code, including the source file, header file, and Make file in that directory;
  • doc, the documentation used to place the project;
  • Text files COPYRIGHT and README are instructions on license s and how to use them; The target file will be placed in the bin subdirectory of the build directory.
  • Add a run<project_to the project directory Name>.sh script, which can be used to call binary files, such as multiple target files that need to be configured and ordered to complete the entire project.

First, write the project source code in the src directory, including main.c and the Make file CMakeLists.txt in that directory (this is mainly CMakeLists.txt)

# ./src/CMakeLists.txt
ADD_EXECUTABLE(hello main.c)
 
INSTALL(TARGETS hello RUNTIME DESTINATION bin)
# The INSTALL directive defines the installation rules, which can include target binaries, dynamic libraries, static libraries, files, directories, scripts, and so on.
# TARGETS in the parameter is followed by ADD_EXECUTABLE or ADD_ Target file defined by LIBRARY (executable binary, dynamic library, static library)
# There are three corresponding target types, ARCHIVE refers to static library, LIBRARY refers to dynamic library, and RUNTIME refers to executable target binary.
# DESTINATION defines the path to the installation, which, if started with/refers to an absolute path; Otherwise it is the relative path ${CMAKE_INSTALL_PREFIX}/<dir>

The default installation path prefix ${CMAKE_INSTALL_PREFIX} is/usr/local, so when you make install with the default installation path, you will get an error due to permission issues.

The parameter CMAKE_can be specified when executing the cmake command INSTALL_ PREFIX, as follows:

ADD_EXECUTABLE is used to generate the target file. The INSTALL command is related to make install installation. Here is the install target file.

Next is CMakeLists.txt in the project root directory, which is the CMake file for the entire project, requiring the CMake file in the src directory.

# ./CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.10.0)
 
PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)
# This directive adds a subdirectory to the current project where source files are stored and specifies where intermediate and target binaries are stored.
# The example above defines adding an src subdirectory to a project and specifies that the compile output (including the intermediate results of compilation) path is the bin directory.
# If you do not specify a bin directory, the compilation results (including intermediate results) will be stored in the build/src directory (which corresponds to the original SRC directory)
# When you specify the bin directory, you rename the src to bin at compile time, and all intermediate results and target binaries are stored in the bin directory.
 
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
# Executable program installations (such as scripts) for non-target files, similar to FILES instructions
INSTALL(FILES COPYRIGHT README DESTINATION doc/cmake/ex_02)
# Used to install generic files and specify access permissions. The file name is the relative path to the path where the instruction is located (relative to CMakeLists.txt where the instruction is located)
INSTALL(DIRECTORY doc/ DESTINATION doc/cmake/ex_02)
# DIRECTORY is followed by a relative path to the Source directory, but it is important to note that ABC and abc/are very different.
# If the directory name does not end/end, the directory will be installed as abc in the target path;
# If the directory name ends with / it means installing the contents of the directory to the destination path, but not including the directory itself
 
ADD_TEST(mytest ${PROJECT_BINARY_DIR}/bin/hello)
ENABLE_TESTING()

ADD_SUBDIRECTORY associates the CMake file of the entire project with the source code of the src project;
INSTALL is used for installation, where are the installation script files, normal files, and doc directories.
ADD_TEST and ENABLE_TESTING is related to "make test"

Build:
The build process is basically the same as the previous example, after make, the generated target file will be saved in the. /build/bin/directory, make test, make install execute the above ADD_TEST and INSTALL directives.

> cd ~/Workspace/cmake_ws/ex_02/
> mkdir build
> cd build/
> cmake ..
> make
> ./hello
> make test
> make install
> cd ..
> rm -rf build/

install
Mainly because the stored paths are special, such as / usr / local mentioned above, which exist in the shell's default path. For example, if an executable is installed in/usr/local, it can run in any terminal, just like if you double-click a desktop icon on Windows to start a program and install that program on your system.

Migrate projects from other platforms to CMake

CMake makes it easy to build a project environment that works on a variety of platforms. If the current engineering environment is not CMake but based on a specific platform, can you migrate to CMake? The answer is possible. The migration scenarios for several common platforms are listed below.

autotools

  • am2cmake A project from the autotools system can be converted to CMake, and one success case for this tool is KDE.
  • Alternative Automake2CMake can convert a KDevelop project using automake.
  • Converting autoconf tests

qmake
qmake converter Projects using qmake with QT can be converted.

Visual Studio

  • vcproj2cmake.rb It can be generated from a Visual Studio project file (suffix name is.vcproj or.vcxproj)
    The CMakeLists.txt file.

  • PowerShell version of vcproj2cmake.ps1 vcproj2cmake.

  • folders4cmake generates the corresponding "source_group" from the Visual Studio project file
    Information, which can be easily used in CMake scripts. Supports Visual Studio 9/10 project files.

Automatic Derivation of CMakeLists.txt

  • gencmake derives the CMakeLists.txt file from the existing file.

  • CMakeListGenerator creates a complete CMakeLists.txt file using a set of file and directory analyses. Only Win32 platform is supported.

Reference Web Site

https://cmake.org/cmake/help/v3.15/
https://www.hahack.com/codes/cmake/
https://durant35.github.io/2016/04/21/tool_CMake_%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/
https://blog.csdn.net/mindizhike/article/details/113749198?spm=1001.2014.3001.5506

Keywords: C++

Added by miro on Sat, 04 Dec 2021 19:23:37 +0200