CMake

CMake

Build the Smallest Project

Create directory structure as follows:

  • Tutorial/
    • build/
    • CMakeLists.txt
    • tutorial.cpp

The files content as follows:

# CMakeLists.txt

# Specify the minimum version of CMake.
cmake_minimum_required(VERSION 3.15)
# Specify the project name.
project(Tutorial)
# It's used to generate the executables
add_executable(Tutorial tutorial.cpp)
// tutorial.cpp

#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>

int main(int argc, char* argv[])
{
    if (argc < 2) {
        std::cout << "Usage: " << argv[0] << " number" << std::endl;
        return 1;
    }

    // convert input to double
    const double inputValue = atof(argv[1]);

    // calculate square root
    const double outputValue = sqrt(inputValue);
    std::cout << "The square root of " << inputValue
              << " is " << outputValue
              << std::endl;
    return 0;
}

Enter the directory build, and execute the command cmake -G"MinGW Makefiles" ... This will generate a file called Makefile.

Execute the command cmake --build ., which calls the compiler to compile and link the project.

--build specifies the directory where the compiled files are stored, including the executable files.

The executable file Tutorial.exe are generated in the directory build, and you can execute it.

Optimize the CMakeLists.txt

Use PROJECT_NAME to replace project name in CMakeLists.txt:

cmake_minimum_required(VERSION 3.15)
project(Tutorial)
add_executable(${PROJECT_NAME} tutorial.cpp)

We can also use a variable to represent multiple source files.

set(SRC_LIST a.cpp b.cpp c.cpp)
add_executable(${PROJECT_NAME} ${SRC_LIST})

Set the Project Version

Modify the content of CMakeLists.txt

project(Tutorial VERSION 1.0.2)

Configure the header File

Create a new file named TutorialConfig.h.in in the project root directory, and the content is as follows:

#define Tutorial_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define Tutorial_VERSION_PATCH @PROJECT_VERSION_PATCH@

Add the content to CMakeList.txt as follows:

configure_file(TutorialConfig.h.in TutorialConfig.h)

TutorialConfig.h will be generated in the directory build. It depends on TutorialConfig.h.in. Therefore, it's necessary to add build to the search path list. Add the following content to the end of CMakelists.txt

target_include_directories(${PROJECT_NAME} PUBLIC
                           ${PROJECT_BINARY_DIR}
                           )

PROJECT_BINARY_DIR represents the binary path of the current project. Now it's the directory build.

Add the header TutorialConfig.h to the file tutorial.cpp, then the Macro defined in TutorialConfig.h.in can be used in tutorial.cpp, including Tutorial_VERSION_MAJOR, Tutorial_VERSION_MINOR and Tutorial_VERSION_PATCH.

Add the Compile Timestamp

Add the following content to CMakeLists.txt:

string(TIMESTAMP COMPILE_TIME %Y%m%d-%H%M%S)

Add the following content to TutorialEConfig.h.in:

#define TIMESTAMP @COMPILE_TIME@

Specify the C++ Standard

Replace atof with std::stod in the file tutorial.cpp.

Add the following content before the command add_executable to CMakeLists.txt:

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

Add the Library

Now we add a library which achieve the function of square root, and use it to replace the function provided by STL.

Create the directory named MathFunctions in the project root directory. It includes 3 files named CMakeLists.txt, MathFunctions.h and mysqrt.cpp, and the content of CMakeLists.txt is as follows:

# MathFunctions/CMakeLists.txt
add_library(MathFunctions mysqrt.cpp)

MathFunctions.h and mysqrt.cpp include a function named mysqrt, which achieves the function of square root.

To use the library MathFunctions, we need to add the following content to top level CMakeLists.txt:

add_subdirectory(MathFunctions)

What's more, in order to use MathFunctions, tutorial.cpp needs to find the library files and the corresponding header file. We can use target_link_libraries and target_include_directories to specify. Add and modify the content in the top level CMakeLists.txt as follows:

target_link_libraries(${PROJECT_NAME} PUBLIC MathFunctions)

target_include_directories(${PROJECT_NAME} PUBLIC 
                           ${PROJECT_BINARY_DIR}
                           ${PROJECT_SOURCE_DIR}/MathFunctions
                           )

Add the header MathFunctions.h, then we can use mysqrt function.

Make the Library Optional

Now we'll make the library MathFunctions optional.

At first, add an option to the top level CMakeLists.txt as follows:

option(USE_MYMATH "Use tutorial provided math implementation" ON)

option represents providing options that users can choose from, and its command format is option(<variable> "description" [initial value]).

The default value of USE_MYMATH is ON, which can be changed by the user.

The next change is to make the building and linking of the MathFunctions library conditional. Modify the content of the top level CMakeLists.txt as follows:

if(USE_MYMATH)
  add_subdirectory(MathFunctions)
  list(APPEND EXTRA_LIBS MathFunctions)
  list(APPEND EXTRA_INCLUDES ${PROJECT_SOURCE_DIR}/MathFunctions)
endif()

target_link_libraries(${PROJECT_NAME} PUBLIC ${EXTRA_LIBS})

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(${PROJECT_NAME} PUBLIC
                           ${PROJECT_BINARY_DIR}
                           ${EXTRA_INCLUDES}
                           )

Then modify the source code of tutoral.cpp as follows:

...
#ifdef USE_MYMATH
    #include "MathFunctions.h"
#endif
...
#ifdef USE_MYMATH
  const double outputValue = mysqrt(inputValue);
#else
  const double outputValue = sqrt(inputValue);
#endif
...

Because of the using of the marco USE_MYMATH in the source code, we can add the following content to TutorialConfig.h.in:

#cmakedefine USE_MYMATH

This project calls the mysqrt function by default, we can specify USE_MYMATH to use the sqrt function of STL:

# Enter the directory build.
$ cmake -G"MinGW Makefiles" ..
$ cmake -DUSE_MYMATH=OFF ..
$ cmake --build .

Add the Requirements for the Use of the Library

Now we use a more modern method to include the header file of the MathFunctions library.

Add the below content to the CMakeLists.txt file in the directory MathFunctions:

target_include_directories(MathFunctions
          INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
          )

Modify the top level CMakeLists.txt as follows:

...
if(USE_MYMATH)
  add_subdirectory(MathFunctions)
  list(APPEND EXTRA_LIBS MathFunctions)
endif()

target_include_directories(${PROJECT_NAME} PUBLIC 
                           ${PROJECT_BINARY_DIR}
                           )
...

[1]:CMake 良心教程,教你从入门到入魂
[2]:CMake Tutorial

posted @ 2023-09-24 17:00  MeYokYang  阅读(14)  评论(0编辑  收藏  举报