Post

Mini.Project 01-03. Deploy: Integrated CMake, Docker and CI/CD

Mini.Project 01-03. Deploy: Integrated CMake, Docker and CI/CD

Mini.Project 01-03. Deploy: Integrated CMake, Docker and CI/CD


Prerequisites

1
    C++

1. CMake

C++ Project + CMake

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/Project:
  - "CMakeLists.txt"            # CMake
  - "/cmake:"
        - "CMakeGenLib.cmake"   # CMake
  - main.cpp
  - /tests:
    - test_svstring.cpp
  - /lib:
    - "CMakeLists.txt"          # CMake
    - /structlib:
      - "CMakeLists.txt"        # CMake
      - /src:
        - SVBase.cpp
        - SVString.cpp
      - /include:
        - SVBase.h
        - SVString.h
  • Each folder in the hierarchy contains a CMakeLists.txt (just one)
  • CMakeLists.txt acts like a “recipe” for building the project

2. CMakeLists.txt

Each folder in the hierarchy contains a CMakeLists.txt. CMakeLists.txt acts like a “recipe” for building the project. So CMake acts following the CMakeLists script.

The order is like this:

Following to CMakeLists, the source files are integrated and build. By means that is we should understand the flow of CMakeLists script.

Let’s see the CMakeLists of project

2-1. /Project/CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
cmake_minimum_required(VERSION 3.10)
project(deploy-project)

include(CTest)
enable_testing()

include(cmake/CMakeGenLib.cmake)

add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE structlib)

install(TARGETS ${PROJECT_NAME} 
	RUNTIME DESTINATION bin
)

install(TARGETS structlib 
	RUNTIME DESTINATION bin 
	LIBRARY DESTINATION lib
	ARCHIVE DESTINATION lib
)

add_executable(test_svstring tests/test_svstring.cpp)
target_link_libraries(test_svstring PRIVATE structlib)

add_test(NAME SVStringTest COMMAND test_svstring)

2-2. /Project/cmake/CMakeGenLib.cmake

1
add_subdirectory(lib)

cmake version and project names

1
2
cmake_minimum_required(VERSION 3.10)
project(deploy-project)

include optional test environment

1
2
include(CTest)
enable_testing()

include

1
include(cmake/CMakeGenLib.cmake)

The include script will be copy and paste from “cmake/CMakeGenLib.cmake” to “ CMakeLists.txt”. This meaning is there will be like that:

1
include(cmake/CMakeGenLib.cmake) -> add_subdirectory(lib)

explore subdirectory

1
add_subdirectory(lib)

add_subdirectory(lib) script explores subdirectory “/lib”

create executable file

1
add_executable(${PROJECT_NAME} main.cpp)

It depends on OS, on Window, extension .exe will be created. The ${PROJECT_NAME} is same XXXX of project(XXXX) script. In this case, ${PROJECT_NAME} is “deploy-project”

1
target_link_libraries(${PROJECT_NAME} PRIVATE structlib)

This script is link process on compile step “link”. At the first time, I’m little bit surprised because there’s no complie trigger. But we do not need to think compile timing.

The “structlib.lib” is linked with “project-deploy”

KeywordUsed in TargetPropagated to DependentsInclude DirectoriesCompile Options
PRIVATEYesNoNoNo
PUBLICYesYesYesYes
INTERFACENoYesYesYes

install

1
2
3
4
5
6
7
8
9
install(TARGETS ${PROJECT_NAME} 
	RUNTIME DESTINATION bin
)

install(TARGETS structlib 
	RUNTIME DESTINATION bin 
	LIBRARY DESTINATION lib
	ARCHIVE DESTINATION lib
)

The install step is following on this script. Actually the install step is not creating anythings. It will rearrange build files with Copy and Paste.

TypeRole
RUNTIMEExecutable files
LIBRARYShare library
ARCHIVEStatic library

test

1
2
3
4
add_executable(test_svstring tests/test_svstring.cpp)
target_link_libraries(test_svstring PRIVATE structlib)

add_test(NAME SVStringTest COMMAND test_svstring)

“add_executable” and “target_link_libraries” is already explained. “add_test” regists the test_svstring execuatble file as test and name will be SVStringTest. on ctest, the name is SVStringTest.

2-3. /Project/lib/CMakeLists.txt

1
add_subdirectory(structlib)

2-4. /Project/lib/structlib/CMakeLists.txt

1
2
3
4
file(GLOB SRC_FILES "src/*.cpp")

add_library(structlib STATIC ${SRC_FILES})
target_include_directories(structlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

collect to source files on var

1
file(GLOB SRC_FILES "src/*.cpp")

“file” is function related in file command “GLOB SRC_FILES “src/*.cpp”” command searches matching on source files within src directory. The files will be included in SRC_FILES var.

make library

1
add_library(structlib STATIC ${SRC_FILES})

Using SRC_FILES files, creating a library. name is structlib library

TypeLink TimeRuntime RequirementOutput Files
STATICCompile timeNone.lib / .a
SHAREDRuntimeRequired.dll / .so
MODULERuntime (manual)Required.dll / .so

include directory

1
target_include_directories(structlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

Include the .h to structlib library.

ScopeUsed by structlibUsed by dependents
PRIVATEYesNo
PUBLICYesYes
INTERFACENoYes

3. CMake command

1
Configuration → Build → Install

The commands can differ depending on the OS you are using.

3-1. Configuration

1
cmake -S . -B build 
Configuration → Generate build system (no compilation)

This step configures the project by reading the CMakeLists.txt file and generating the build system (e.g., Visual Studio solution, Makefiles, or Ninja files) inside the build directory.

  • -S . specifies the source directory (current directory)
  • -B build specifies the output directory for build files

👉 No compilation happens at this stage. It only prepares the build environment.

OR

1
make -S . -B build -G "Visual Studio 17 2022" -A x64

3-2. Build

1
cmake --build build --config Release

This step compiles the source code and links the targets defined in the project.

  • –build build tells CMake to build using the generated build system
  • –config Release specifies the build configuration (required for multi-config generators like Visual Studio)

👉 This is where actual compilation and linking occur, producing executables and libraries.

OR Linux OS

1
cmake --build build --config Release

3-3. Install

1
cmake --install build --config Release --prefix install
Install → Copy artifacts to distribution structure

This step installs the built artifacts (executables, libraries, etc.) into a structured directory for distribution.

  • –install build runs the install rules defined in CMakeLists.txt
  • –config Release ensures the correct build configuration is used
  • –prefix install sets the installation directory (e.g., ./install)

👉 Files are copied into organized folders such as bin/, lib/, etc., based on the install() rules.

3-4. Test

1
ctest --test-dir build -C Release --output-on-failure

This step runs the tests registered in the project using CTest.

  • –test-dir build specifies the directory where the build was generated
  • -C Release selects the build configuration (required for multi-config generators like Visual Studio)
  • –output-on-failure prints detailed output only when a test fails

👉 CTest executes the test commands defined by add_test() in CMakeLists.txt.

This post is licensed under CC BY 4.0 by the author.