๐ Official Tutorial: https://cmake.org/cmake/help/latest/guide/tutorial/index.html
Why do we need CMake?
Although we already have Make, why should we use CMake?
1. Cross-platform support: It works not only on Linux but also on Windows, macOS, and other platforms.
2. Easy configuration: Describe the build process with simple scripts, avoiding the need to repeatedly write complex Makefiles.
3. Automated dependency management: Automatically updates build rules based on changes to source and header files.
4. Strong extensibility: Supports modular builds and management of large projects.
5. Good IDE integration: CMake can generate project files for various IDEs such as Visual Studio, Xcode, Ninja, etc.
6. Support for multiple compilers: Such as GCC, Clang, MSVC.
Alright, let’s first take a look at Make
Makefile syntax
target: dependencies commands
Where:
ยท ($@ is the target)
ยท ($<): is the name of the first dependency file for the current rule (e.g., hello.cpp)
ยท %.o: %.cpp โ Automatic generation rule
Code example
.PHONY: clean allCFLAGS = -std=c++14 -Wall -g -O2targets = mainsources = hello.cpp main.cppobjects = hello.o main.o
all: $(targets) @echo Successful # @ indicates that the command will not print itself, only the output result$(targets): $(objects) gcc $(objects) -o $@%.o: %.cpp gcc $(CFLAGS) -c $<clean: rm *.o $(targets)
<span>.PHONY</span> indicates phony targets, telling <span>make</span>:
-
<span>clean</span>and<span>all</span>are not file names, but command targets. -
Thus, even if there are files with the same name in the directory, it will not mistakenly think that the target already exists.
# Define clean target: clean up generated .o files and executable files.clean: rm *.o $(targets)
Execute the command make to generate the main executable file<code><span>Executing `</span>make clean` will execute๏ผrm *.o ($targets)
Common compilation options:
-
-std=c++14 โ Use C++14 standard
-
-Wall โ Enable common warnings to help write safer code
-
-g โ Enable debug symbols for easier gdb debugging
-
-O2 โ Enable medium-level optimization to improve execution efficiency
Now let’s take a look at CMake
CMakeLists.txt file
cmake_minimum_required(VERSION 3.10) # Set the minimum required version of CMakeproject(MyProject C CXX) # Define project name and supported languageset(CMAKE_C_STANDARD 99) # Specify C language standardset(CMAKE_CXX_STANDARD 17) # Specify C++ language standard
add_executable(myapp main.cpp hello.cpp) # Define executable file and dependent source files# add_library(mylib STATIC lib.cpp) # Define static library# add_library(mylib SHARED lib.cpp) # Use SHARED to generate a dynamic library
# target_link_libraries(myapp PUBLIC mylib) # Link library to executable# target_include_directories(myapp PUBLIC include) # Specify header file search path include support
Run the command cmake -B build to generate a /build folder in the current directory
cmake -B build # Create build folder and generate build files in the current directory
We can see the Makefile generated by cmake in the build folder, and we can build it using make
Other common options for targets
In addition to <span>target_include_directories</span>, CMake also provides many common options.<span>PUBLIC</span> and <span>PRIVATE</span> have the same meaning:
-
PUBLIC: Effective for the current target and any target that depends on it
-
PRIVATE: Effective only for the current target
Example:
target_include_directories(myapp PUBLIC /usr/include/eigen3) # Add header file search directorytarget_link_libraries(myapp PUBLIC hellolib) # Add libraries to linktarget_compile_definitions(yapp PUBLIC MY_MACRO=1) # Add a macro definitiontarget_compile_definitions(myapp PUBLIC -DMY_MACRO=1) # Equivalent writingtarget_compile_options(myapp PUBLIC -fopenmp) # Add compiler command line optionstarget_sources(myapp PUBLIC hello.cpp other.cpp) # Add source files to compile