CMake Build project template

Posted by Boozi on Fri, 04 Mar 2022 10:08:17 +0100

summary:

CMake is a more advanced compilation and configuration tool than make. It can generate corresponding Makefile or vcproj projects according to different platforms and compilers. By writing cmakelists Txt, you can control the generated Makefile to control the compilation process.

We often use the Makefile automatically generated by CMake to build projects, generate target files and install files. This paper mainly introduces several common engineering structures and the writing method of the corresponding CMakeList file.

case1:

In the introductory example, all files are in the same folder.

Source code from: https://github.com/yanxicheung/CMakeNote/tree/main/CMakeDemo/case1

Directory structure:

.
├── CMakeLists.txt
├── main.cpp
├── MathFunctions.cpp
└── MathFunctions.h

CMakeLists:

# CMake minimum version number requirements
cmake_minimum_required (VERSION 2.8)

# Project information
project (Demo2)

# Find all source files in the directory
# And save the name to DIR_SRCS variable
aux_source_directory(. DIR_SRCS)

# Specify build target
add_executable(Demo ${DIR_SRCS})

case2:

Multiple directories and multiple files, using an example of CMakeLists.

Source code from: https://github.com/yanxicheung/CMakeNote/tree/main/CMakeDemo/case2/quantity

Directory structure:

.
├── CMakeLists.txt
├── include
│   ├── Amount.h
│   └── Length.h
├── source
│   └── Length.cpp
└── test
    ├── LengthTest.cpp
    └── main.cpp

CMakeLists:

# Set project name
project(quantity) 
cmake_minimum_required(VERSION 2.8)

# Used to set environment variables
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")

# Set header file include path
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)

# Traversal file
file(GLOB_RECURSE all_files
source/*.cpp
source/*.cc
source/*.c
test/*.cpp
test/*.cc
test/*.c)

# Generate target executable
add_executable(quantity-test ${all_files})

# Since the gtest framework is used, this library needs to be linked
target_link_libraries(quantity-test gtest)

case3:

case3 is a multi-level directory using cmakelists Txt.

Source code from: https://github.com/yanxicheung/CMakeLists

Directory structure:

.
├── CMakeLists.txt               // Top CMakeList
├── hello
│   ├── CMakeLists.txt           // Static libraries will be generated for top-level calls
│   ├── include
│   │   └── hello.h
│   └── source
│       └── hello.cpp
├── main.cpp
└── world
    ├── CMakeLists.txt           // Static libraries will be generated for top-level calls
    ├── include
    │   └── world.h
    └── source
        └── world.cpp

CMakeLists:

top floor:

cmake_minimum_required(VERSION 2.8)

set(curr_dir ${CMAKE_CURRENT_SOURCE_DIR})
set(hello_dir ${curr_dir}/hello)
set(world_dir ${curr_dir}/world)

project(helloworld)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

# Add header file include directories
include_directories(
    ${hello_dir}/include
    ${world_dir}/include
)

# Add block directories
add_subdirectory(hello)
add_subdirectory(world)
# Target
add_executable(helloworld main.cpp)
target_link_libraries(helloworld hello world)

Subdirectory hello:

set(curr_dir ${CMAKE_CURRENT_SOURCE_DIR})

include_directories(
    include
)

aux_source_directory(${curr_dir}/source DIR_HELLO_SRCS)

add_library(hello ${DIR_HELLO_SRCS})    // The default is STATIC library

Subdirectory world:

set(curr_dir ${CMAKE_CURRENT_SOURCE_DIR})

include_directories(
    include
)

aux_source_directory(${curr_dir}/source DIR_WORLD_SRCS)

add_library(world ${DIR_WORLD_SRCS})   // The default is STATIC library

case4:

In this example, we need to:

  1. Add compilation options for the project, so that the most appropriate compilation scheme can be selected according to the user's environment and needs: when enable_ When test is opened, a static library file libcub.exe is generated A and compile unit tests to generate executable files. Otherwise, only the static library file libcub a
  2. The static library file libcub A and header files are installed in the system directory.

Source code from: https://github.com/yanxicheung/cub

Directory structure:

.
├── build.sh
├── CMakeLists.txt            // Top layer CMakeList
├── doc
├── include
│   └── cub
│       ├── algo
│       ├── base
│       ├── cub.h
│       ├── dci
│       ├── ...
├── README.md
├── src
│   ├── CMakeLists.txt        // Static libraries will be generated for top-level calls
│   ├── log
│   ├── mem
│   └── sched
└── test
    ├── CMakeLists.txt       // The executable file of the unit test is generated
    ├── main.cpp
    ├── ...

CMakeLists:

top floor

cmake_minimum_required(VERSION 2.8)

project("cub")

if(UNIX)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof  -g -std=c++14")
endif()

include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")

add_subdirectory("src")

if(ENABLE_TEST)
  add_subdirectory(test)
endif()

install(DIRECTORY include/cub DESTINATION include)  #Install the header file into / usr/local/include

Static library libcub a

FILE(GLOB_RECURSE all_files
*.cpp
*.cc
*.c++
*.c
*.C)

add_library(cub STATIC ${all_files} ../include/cub/network/ByteOrder.h ../test/TestByteOrder.cpp)

install(TARGETS cub ARCHIVE DESTINATION lib)  #Set libcub A install in / usr/local/lib
# The installation part of the header file can also be written here: install (directory.. / include / cub destination include)

Unit test:

project(cub-test)

include_directories(${MAGELLAN_INCLUDE_DIR}) #You can not write it. The top-level cmakelists have been included

if(UNIX)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()

FILE(GLOB_RECURSE all_files
*.cpp
*.cc
*.c++
*.c
*.C)

add_executable(cub-test ${all_files})
target_link_libraries(cub-test cut cub)

Compile library files only:

cd cub
mkdir build
cd build
cmake ..
make

Install library files:

sudo make install

Generate unit test executable:

cd build
cmake -DENABLE_TEST=1 ..   #cmake -DENABLE_TEST=ON ..  it's fine too
make
./test/cub-test

case5:

This example is mainly used to demonstrate conditional compilation of source code.

Source code from: https://github.com/yanxicheung/CMakeNote/tree/main/CMakeDemo/case5

Directory structure:

.
├── CMakeLists.txt
├── main.cpp
├── MathFunctions.cpp
└── MathFunctions.h

CMakeLists:

cmake_minimum_required (VERSION 2.8)
project (Demo2)

if(DEFINED USE_MYMATH)
    message("USE_MYMATH is defined")
    add_definitions(-DUSE_MYMATH) 
else()
    message("USE_MYMATH is not defined")
endif()

aux_source_directory(. DIR_SRCS)
add_executable(Demo ${DIR_SRCS})

If you need to use your own implementation:

cmake -DUSE_MYMATH=ON ..
make

reference:

  1. CMake introduction practice: https://www.hahack.com/codes/cmake/
  2. https://github.com/wzpan/cmake-demo
  3. CMake conditional compilation: https://www.cnblogs.com/binbinjx/p/5648957.html
  4. Conditional compilation of CMake and Cpp (I): https://www.dennisthink.com/2020/10/18/877/
  5. Conditional compilation of CMake and Cpp (II): https://www.dennisthink.com/2020/10/18/893/

Topics: C++ Single-Chip Microcomputer stm32