YouTip LogoYouTip

Cmake Exercises

This tutorial demonstrates how to use CMake to manage a moderately complex project, covering the entire process from project creation to compilation and execution, including practical applications from basic configurations to advanced features.

\n\n

The practical exercises include the following:

\n
    \n
  1. Create CMakeLists.txt files: Define projects, libraries, executables, and tests.
  2. \n
  3. Write source code and tests: Write code and test files.
  4. \n
  5. Create a build directory: Keep the source directory clean.
  6. \n
  7. Configure the project: Generate build system files.
  8. \n
  9. Compile the project: Generate target files.
  10. \n
  11. Run the executable: Execute the program.
  12. \n
  13. Run tests: Verify functional correctness.
  14. \n
  15. Use custom commands and targets: Perform additional operations.
  16. \n
  17. Cross-platform and cross-compilation: Support different platforms and architectures.
  18. \n
\n\n

Building a Simple C++ Project

\n

Suppose we have a project containing a main program and a library, with two different functional modules in the library.

\n

The project structure is as follows:

\n
MyProject/\nβ”œβ”€β”€ CMakeLists.txt\nβ”œβ”€β”€ src/\nβ”‚   β”œβ”€β”€ main.cpp\nβ”‚   β”œβ”€β”€ lib/\nβ”‚   β”‚   β”œβ”€β”€ module1.cpp\nβ”‚   β”‚   β”œβ”€β”€ module2.cpp\nβ”‚   β”œβ”€β”€ include/\nβ”‚   └── mylib.h\n└── tests/\n    β”œβ”€β”€ test_main.cpp\n    └── CMakeLists.txt
\n\n
\n\n

1. Create CMakeLists.txt Files

\n\n

1.1 Root Directory CMakeLists.txt File

\n

Create a CMakeLists.txt file in the root directory of MyProject:

\n

Example

\n
cmake_minimum_required(VERSION 3.10)# Specify the minimum CMake version\n\n project(MyProject VERSION 1.0)# Define the project name and version\n\n# Set C standard++ Standard\n\n set(CMAKE_CXX_STANDARD 11)\n\n set(CMAKE_CXX_STANDARD_REQUIRED ON)\n\n# Include header file paths\n\n include_directories(${PROJECT_SOURCE_DIR}/src/include)\n\n# Add subdirectories\n\n add_subdirectory(src)\n\n add_subdirectory(tests)
\n\n

1.2 src Directory CMakeLists.txt File

\n

Create a CMakeLists.txt file in the src directory:

\n

Example

\n
# Create a library target\n\n add_library(MyLib STATIC\n\n lib/module1.cpp\n\n lib/module2.cpp\n\n )\n\n# Specify the library's header files\n\n target_include_directories(MyLib PUBLIC ${CMAKE_SOURCE_DIR}/src/include)\n\n# Create an executable target\n\n add_executable(MyExecutable main.cpp)\n\n# Link the library to the executable\n\n target_link_libraries(MyExecutable PRIVATE MyLib)
\n\n

1.3 tests Directory CMakeLists.txt File

\n

Create a CMakeLists.txt file in the tests directory:

\n

Example

\n
# Find GTest package\n\n find_package(GTest REQUIRED)\n\n include_directories(${GTEST_INCLUDE_DIRS})\n\n# Create a test target\n\n add_executable(TestMyLib test_main.cpp)\n\n# Link library and GTest to the test target\n\n target_link_libraries(TestMyLib PRIVATE MyLib ${GTEST_LIBRARIES})
\n\n
\n\n

2. Write Source Code and Tests

\n

Below is the code for each file:

\n\n

2.1 src/main.cpp File Code

\n

Example

\n
#include \n\n#include "mylib.h"\n\nint main(){\n\n std::cout<<"Hello, CMake!"<< std::endl;\n\nreturn 0;\n\n}
\n\n

2.2 src/lib/module1.cpp File Code

\n

Example

\n
#include "mylib.h"\n\n// Implementation of module1
\n\n

2.3 src/lib/module2.cpp File Code

\n

Example

\n
#include "mylib.h"\n\n// Implementation of module2
\n\n

2.4 src/include/mylib.h File Code

\n

Example

\n
#ifndef MYLIB_H\n\n#define MYLIB_H\n\n// Declarations of module functions\n\n#endif // MYLIB_H
\n\n

2.5 tests/test_main.cpp File Code

\n

Example

\n
#include \n\n// Test cases for MyLib\n\n TEST(MyLibTest, BasicTest){\n\n EXPECT_EQ(1, 1);\n\n}
\n\n
\n\n

3. Create Build Directory

\n

Create a build directory in the project root:

\n
mkdir build cd build
\n\n
\n\n

4. Configure Project

\n

Run CMake in the build directory to configure the project:

\n
cmake ..
\n\n
\n\n

5. Compile Project

\n

Compile using the generated build system files, assuming a Makefile was generated:

\n
make
\n\n
\n\n

6. Run Executable

\n

After compilation, you can run the generated executable:

\n
./MyExecutable
\n\n
\n\n

7. Run Tests

\n

Run tests using the generated test target:

\n
./TestMyLib
\n\n
\n\n

8. Use Custom Commands and Targets

\n\n

8.1 Custom Command

\n

Add a custom command in the src/CMakeLists.txt file:

\n
add_custom_command( TARGET MyExecutable POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Build complete!")
\n\n

8.2 Custom Target

\n

Add a custom target in the src/CMakeLists.txt file:

\n
add_custom_target(run COMMAND ${CMAKE_BINARY_DIR}/MyExecutable DEPENDS MyExecutable)
\n

Run the custom target:

\n
make run
\n\n
\n\n

9. Cross-Platform and Cross-Compilation

\n\n

9.1 Specify Platform

\n

If you need to specify a platform for building, you can specify it when running CMake:

\n
cmake -DCMAKE_SYSTEM_NAME=Linux ..
\n\n

9.2 Using a Toolchain File

\n

Create a toolchain file named toolchain.cmake:

\n
set(CMAKE_SYSTEM_NAME Linux)set(CMAKE_SYSTEM_PROCESSOR arm)
\n

Build using the toolchain file:

\n
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake ..
← Cpp Data StructuresCmake Build Demo β†’