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\nThe practical exercises include the following:
\n- \n
- Create
CMakeLists.txtfiles: Define projects, libraries, executables, and tests. \n - Write source code and tests: Write code and test files. \n
- Create a build directory: Keep the source directory clean. \n
- Configure the project: Generate build system files. \n
- Compile the project: Generate target files. \n
- Run the executable: Execute the program. \n
- Run tests: Verify functional correctness. \n
- Use custom commands and targets: Perform additional operations. \n
- Cross-platform and cross-compilation: Support different platforms and architectures. \n
Building a Simple C++ Project
\nSuppose we have a project containing a main program and a library, with two different functional modules in the library.
\nThe project structure is as follows:
\nMyProject/\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\n1.1 Root Directory CMakeLists.txt File
\nCreate a CMakeLists.txt file in the root directory of MyProject:
\nExample
\ncmake_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\n1.2 src Directory CMakeLists.txt File
\nCreate a CMakeLists.txt file in the src directory:
\nExample
\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\n1.3 tests Directory CMakeLists.txt File
\nCreate a CMakeLists.txt file in the tests directory:
\nExample
\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
\nBelow is the code for each file:
\n\n2.1 src/main.cpp File Code
\nExample
\n#include\n\n\n\n#include "mylib.h"\n\nint main(){\n\n std::cout<<"Hello, CMake!"<< std::endl;\n\nreturn 0;\n\n}
2.2 src/lib/module1.cpp File Code
\nExample
\n#include "mylib.h"\n\n// Implementation of module1\n\n
2.3 src/lib/module2.cpp File Code
\nExample
\n#include "mylib.h"\n\n// Implementation of module2\n\n
2.4 src/include/mylib.h File Code
\nExample
\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
\nExample
\n#include\n\n\n\n// Test cases for MyLib\n\n TEST(MyLibTest, BasicTest){\n\n EXPECT_EQ(1, 1);\n\n}
\n\n
3. Create Build Directory
\nCreate a build directory in the project root:
\nmkdir build cd build\n\n
\n\n
4. Configure Project
\nRun CMake in the build directory to configure the project:
\ncmake ..\n\n
\n\n
5. Compile Project
\nCompile using the generated build system files, assuming a Makefile was generated:
\nmake\n\n
\n\n
6. Run Executable
\nAfter compilation, you can run the generated executable:
\n./MyExecutable\n\n
\n\n
7. Run Tests
\nRun tests using the generated test target:
\n./TestMyLib\n\n
\n\n
8. Use Custom Commands and Targets
\n\n8.1 Custom Command
\nAdd a custom command in the src/CMakeLists.txt file:
\nadd_custom_command( TARGET MyExecutable POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "Build complete!")\n\n8.2 Custom Target
\nAdd a custom target in the src/CMakeLists.txt file:
\nadd_custom_target(run COMMAND ${CMAKE_BINARY_DIR}/MyExecutable DEPENDS MyExecutable)\nRun the custom target:
\nmake run\n\n
\n\n
9. Cross-Platform and Cross-Compilation
\n\n9.1 Specify Platform
\nIf you need to specify a platform for building, you can specify it when running CMake:
\ncmake -DCMAKE_SYSTEM_NAME=Linux ..\n\n
9.2 Using a Toolchain File
\nCreate a toolchain file named toolchain.cmake:
\nset(CMAKE_SYSTEM_NAME Linux)set(CMAKE_SYSTEM_PROCESSOR arm)\n
Build using the toolchain file:
\ncmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake ..
YouTip