# Understanding CMakeList [Definition](#What-it-is) [Simple Examples](#Simple-Examples) - [Simple Example 1](#Simple-Example-1:-All-source-code-files-located-at-the-same-directory) - [Simple Example 2](#Simple-Example-2:-Library-and-main-were-separated) - [Simple Example 3](#Simple-Example-3:-If-the-subfolder-need-it's-own-CMake) - [Simple Example 4](#Simple-Example-4:-.c-and-.h-separated) [Advanced Examples](#More-Examples) ## What it is CMakeList is a scripting language to build and compile a complex C/C++ project. Compiling entire project code with numerous header file included are a prone error task, hence CMakeList created to reduce complexity during build and compilation. The CMakeLists.txt file typically contains instructions and commands for how to build the project, including setting up compiler flags, defining targets (executables, libraries), and specifying dependencies. It allows developers to describe the build process in a platform-independent way, making it easier to manage and build projects across different operating systems and development environments. ## Simple Examples ### Simple Example 1: All source code files located at the same directory Supposed there is 3 .c file The header file look like: ``` #ifndef FUNCTION_H #define FUNCTION_H int add(int a,int b); int sub(int a,int b); #endif ``` Code implementation for the header file look like: ``` #include "function.h" int add(int a, int b){ int result; result = a + b; return result; } int sub(int a, int b){ int result; result = a - b; return result; } ``` And the main source code look like: ``` #include <stdio.h> #include "function.h" int main(){ int a = 2; int b = 3; printf("CMakeTest\n"); printf("%d\n",add(a,b)); printf("%d\n",sub(a,b)); return 0; } ``` The CMakeList.txt will look like: ``` cmake_minimum_required(VERSION 3.0) project(projectExample) set(SOURCES function.c main.c ) add_executables(projectExample ${SOURCES}) ``` Explanation: * ```cmake_minimum_required()``` are a minimum CMake version to generate build script * ```project()``` basically this line will set the name of the project, the project name in the example is **projectExample** * ```set()``` this part will set a variable containing file/files to be compiled to an executable file. As seen in the example, the project are divided into two .c files * ```add_executables()``` this part will generate a compiling script to compile files into a single executable file. As seen in the example, the executable file will called **projectExample** After creating the CMakeList, run these command in Linux terminal: ``` mkdir build/ cmake -S ./ -B ./build/ cd ./build/ make ./projectExample ``` Explanation: * `mkdir build/` This command will create directory called **build** * `cmake -S ./ -B ./build/` This command will generate build scripts for source files located after -S option and the build scripts will be located after -B option * `cd ./build/` Change directory to build scripts location * `make` Run the build scripts * `./projectExample` Run the executable file ### Simple Example 2: Library and main were separated Project structure: ``` project_root/ |- CMakeLists.txt |- main.cpp |- src/ |- mylibrary.cpp |- mylibrary.h ``` CMakeList at project_root/: ``` cmake_minimum_required(VERSION 3.0) project(MyProject) set(SOURCES src/mylibrary.cpp ) add_library(MyLibrary ${SOURCES}) add_executable(MyExecutable main.cpp) target_link_libraries(MyExecutable MyLibrary) ``` Explanation: * `add_library()` this line is called to create a .a file consisted file pointed by SOURCES * `target_link_libraries()` this line will link the library created earlier with the executable file ### Simple Example 3: If the subfolder need it's own CMake Project Structure: ``` project_root/ |- CMakeLists.txt |- main.cpp |- mylibrary/ |- CMakeLists.txt |- mylibrary.cpp |- mylibrary.h ``` CMakeList at project_root: ``` cmake_minimum_required(VERSION 3.0) project(MyProject) add_subdirectory(mylibrary) add_executable(MyExecutable main.cpp) target_link_libraries(MyExecutable MyLibrary) ``` Explanation: * `add_subdirectory()` this line is called to add a subfolder with a CMakeList in the subfolder CMakeList at mylibrary/: ``` set(SOURCES mylibrary.cpp ) add_library(MyLibrary ${SOURCES}) ``` Explanation: * The library name specified inside `add_library()` will be linked to the executable using `target_link_libraries()` in the root CMakeList ### Simple Example 4: .c and .h separated Project structure ``` project_root/ |- CMakeLists.txt |- src/ |- main.c |- myheader.c |- include/ |- myheader.h ``` CMakeList will look like: ``` cmake_minimum_required(VERSION 3.0) project(MyProject) include_directories(include) set(SOURCES src/main.c src/myheader.c) add_executable(MyExecutable ${SOURCES}) ``` Explanation: * `include_directories()` this line will tell compiler the location of header files for entire project * As seen in the example, only .c file added to the variable SOURCES ## More Example ### Advanced Example 1 Project Structure: ``` project_root/ |- CMakeLists.txt |- src/ |- CMakeLists.txt | |- main.c | |- mylib/ | |- mylibrary.c | |- mylibrary.h |- include/ | |- myheader.h |- libs/ | |- libfoo/ | |- CMakeLists.txt | |- foo.c | |- foo.h |- tests/ |- CMakeLists.txt |- test_mylibrary.c ``` CMakeList at src/: ``` file(GLOB SOURCES "*.c") add_library(MyLibrary ${SOURCES}) add_executable(MyExecutable main.c) target_link_libraries(MyExecutable MyLibrary) ``` Exaplanation: * Similar to simple example 2 CMakeList at libs/libfoo/: ``` file(GLOB LIBFOO_SOURCES "*.c") add_library(FooLibrary ${LIBFOO_SOURCES}) ``` Exaplanation: * Similar to simple example 3 CMakeList at tests/ ``` file(GLOB TEST_SOURCES "*.c") add_executable(TestMyLibrary ${TEST_SOURCES}) target_link_libraries(TestMyLibrary MyLibrary FooLibrary) ``` Exaplanation: * Similar to simple example 3 CMakeLists at the project_root/: ``` cmake_minimum_required(VERSION 3.0) project(MyProject) # Tambahkan direktori include/ ke include path include_directories(include) # add subdirectory with CMakeList src/ add_subdirectory(src) # add subdirectory with CMakeList libs/ add_subdirectory(libs) # add subdirectory with CMakeList tests/ add_subdirectory(tests) ``` Explanation: * As seen in the project structure, Folder that has CMakeList will be added using `add_subdirectory()` and header file directories `include_directories()` ### Advanced Example 2 Project Structure: ``` project_root/ |- CMakeLists.txt |- src/ | |- main.cpp | |- math/ | |- arithmetic.cpp | |- arithmetic.h | |- utils/ | |- helper.cpp | |- helper.h |- include/ |- math/ |- arithmetic.h |- utils/ |- helper.h |- external/ |- library1/ |- library2/ ``` CMakeList at src/: ``` # Create executable main.cpp add_executable(MyExecutable main.cpp) # Add subdirectory math/ add_subdirectory(math) # Add subdirectory utils/ add_subdirectory(utils) # Link executable with the created target_link_libraries(MyExecutable MathUtils Utils) ``` CMakeList at src/math: ``` # add file from directory math/ set(MATH_SOURCES arithmetic.cpp) # Create library MathUtils add_library(MathUtils ${MATH_SOURCES}) # Add include directories to include path target_include_directories(MathUtils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../include/math) ``` CMakeList at src/utils: ``` # Add all file from utils/ set(UTILS_SOURCES helper.cpp) # Create library add_library(Utils ${UTILS_SOURCES}) # add include/utils to iclude path target_include_directories(Utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../include/utils) ``` CMakeList at external/library1/: ``` # Create library from files located at library1/ add_library(Lib1 library1.cpp) # add directory include/library1/ to include path target_include_directories(Lib1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../include/library1) ``` CMakeList at external/library2/: ``` # Create library from files library2/ add_library(Lib2 library2.cpp) # add directory include/library2/ to include path target_include_directories(Lib2 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../include/library2) ``` Explanation: * `target_include_directories()` has similar effect with `include_directories()` but only affect specific folder, not entire project CMakeList at project_root: ``` cmake_minimum_required(VERSION 3.0) project(MyProject) # add directory include/ to include path include_directories(include) # add subdirectory src/ add_subdirectory(src) # add subdirectory external/ add_subdirectory(external) ```