Review: Why do we use Make and CMake tools? The main reasons are to automate the build process, manage dependencies, and simplify cross-platform development for complex project compilation requirements: Large C++ projects often consist of multiple source files, header files, and library dependencies, making manual compilation commands (like <span>g++</span>) error-prone and inefficient.
- Dependency Management: Build tools can automatically detect file modifications and only recompile necessary parts, avoiding redundant work.
- Cross-Platform Support: Different operating systems (like Linux, Windows, macOS) have different compilation commands and library paths, which build tools can manage uniformly.
- CMake is responsible for abstracting project configuration (like include paths and compiler flags).
- Make is responsible for executing specific compilation commands (like invoking
<span>g++</span>). - Typical Workflow of CMake + Make:
- Division of Labor:
- Steep learning curve; one must master CMake syntax.
- May seem redundant for extremely simple projects.
- Simplifies cross-platform development; one configuration can compile across multiple systems.
- Automatically handles complex dependencies (like finding system libraries and generating link commands).
- Supports modular builds (like subdirectory management and conditional compilation).
- Declares project structure, dependencies, and compilation options through
<span>CMakeLists.txt</span>. - Generates platform-independent build files (like
<span>Makefile</span>, Visual Studio projects). - Function:
- Advantages:
- Disadvantages:
- Manually writing
<span>Makefile</span>is labor-intensive, especially for large projects. - Poor cross-platform compatibility (requires maintaining different rules for different systems).
- Lightweight and flexible, suitable for small to medium-sized projects.
- Direct control over compilation details (like compiler options, link parameters).
- Defines compilation rules, target files, and dependencies through
<span>Makefile</span>. - When executing commands (like
<span>make</span>), automatically compiles code based on rules. - Function:
- Advantages:
- Disadvantages:
Make (Traditional Build Tool)
CMake (Modern Build Tool)
Why Use Both?
- Write
<span>CMakeLists.txt</span>to describe project structure. - Run
<span>cmake</span>to generate the corresponding platform’s<span>Makefile</span>. - Execute
<span>make</span>to complete the compilation.
CMakeLists will be one level above build and devel; in build, CMake .. and Make add_library is divided into two types: one is a static library ending with .a, and the other is a dynamic library ending with .o. All libraries are collections of functions packaged together, with the difference being that static libraries generate a copy each time they are called, while shared libraries have only one copy.If you want to compress into a shared library, the format isadd_library( yourLibName SHARED YourFileName.cpp)target_link_libraries is used to specify the target (like executable files, static libraries, shared libraries, etc.) that needs to link libraries during the linking phase.—-What commands does g++ have:`g++` is the tool used to compile C++ code in the GNU Compiler Collection, with numerous parameters. Basic compilation parameters like `-o` specify the output file name, `-c` compiles without linking, `-S` generates assembly code, `-E` only preprocesses; for include paths and library paths, `-I` specifies the header file search path, `-L` specifies the library file search path, `-l` specifies the library name to link; optimization parameters range from `-O0` to `-O3` for different optimization levels and `-Os` for optimizing file size; debugging parameter `-g` generates debugging information for easier debugging; standard parameter `-std` can specify the C++ standard; warning parameter `-Wall` enables common compilation warnings, and `-Werror` treats warnings as errors. More parameters can be viewed with `g++ –help`.—Simple Introduction to Compilation and Linking
The compilation phase is the process of converting source code written in a high-level language into assembly code, which is further converted into object files. It can be subdivided into preprocessing, compiling, and assembling.
1. Preprocessing
- Function: Processes preprocessing directives in the source code, such as
<span>#include</span>,<span>#define</span>,<span>#ifdef</span>, etc., generating a preprocessed intermediate file. - Specific Operations
- Header File Inclusion: Inserts the content of the header file specified by the
<span>#include</span>directive into the source code. For example,<span>#include <iostream></span>will copy the content of the<span>iostream</span>header file into the current file. - Macro Replacement: Replaces macros defined by
<span>#define</span>with text. For example,<span>#define PI 3.14159</span>, when encountering<span>PI</span>in the code, it will be replaced with<span>3.14159</span>. - Conditional Compilation: Decides which code blocks to keep and which to delete based on directives like
<span>#ifdef</span>,<span>#ifndef</span>,<span>#endif</span>. - Example Command:
<span>g++ -E main.cpp -o main.i</span>, using the<span>-E</span>parameter of<span>g++</span>for preprocessing, outputting the result to<span>main.i</span>file.
2. Compiling
- Function: Converts the preprocessed source code into assembly code. The compiler performs syntax analysis, semantic analysis, code optimization, and generates assembly language code that conforms to the target machine architecture.
- Specific Operations
- Syntax Checking: Checks whether the code conforms to C++ language syntax rules, such as matching parentheses and complete statements.
- Semantic Analysis: Analyzes the semantics of the code, such as whether variables are declared and whether function calls are correct.
- Code Optimization: Optimizes the code, such as constant folding and loop unrolling, to improve execution efficiency.
- Example Command:
<span>g++ -S main.i -o main.s</span>, using the<span>-S</span>parameter of<span>g++</span>to compile the preprocessed<span>main.i</span>file into assembly code<span>main.s</span>.
3. Assembling
- Function: Converts assembly code into machine language code, generating object files (usually with a
<span>.o</span>extension). Object files are binary files that contain machine instructions and data but cannot be executed directly. - Specific Operations: The assembler converts mnemonics in the assembly code (like
<span>mov</span>,<span>add</span>, etc.) into corresponding machine instructions while handling the symbol table and relocation information. - Example Command:
<span>g++ -c main.s -o main.o</span>, using the<span>-c</span>parameter of<span>g++</span>to assemble the assembly code<span>main.s</span>into the object file<span>main.o</span>.
Linking Phase
The linking phase is the process of combining multiple object files and library files into a single executable file, primarily addressing symbol reference issues to ensure the program runs correctly. The linking phase can be divided into static linking and dynamic linking.
1. Static Linking
- Function: Merges all required object files and static library files into a single executable file. During the linking process, the linker copies the code from the static library into the executable file, so the executable contains all necessary code and does not depend on external library files.
- Specific Operations
- Symbol Resolution: The linker scans all object files and library files, matching symbol references (like function calls, variable references, etc.) with symbol definitions. If a symbol definition cannot be found, the linking process fails.
- Relocation: Since the addresses in object files are relative to themselves, the linker needs to convert these relative addresses into absolute addresses in the final executable file.
- Example Command:
<span>g++ main.o -static -o my_program</span>, using the<span>-static</span>parameter of<span>g++</span>for static linking, linking the<span>main.o</span>object file and static library into the executable file<span>my_program</span>.
2. Dynamic Linking
- Function: The executable file loads the required dynamic libraries (usually with a
<span>.so</span>or<span>.dll</span>extension) at runtime. Dynamic libraries are not copied into the executable file but are dynamically loaded into memory by the operating system during execution. - Specific Operations
- Symbol Resolution: Similar to static linking, the linker resolves symbol references, but for symbols in dynamic libraries, resolution occurs at runtime.
- Runtime Loading: During program execution, the operating system loads the required dynamic libraries into memory based on the dynamic linking information in the executable file and binds symbol references to the definitions in the dynamic libraries.
- Example Command:
<span>g++ main.o -o my_program</span>, by default,<span>g++</span>uses dynamic linking to link the<span>main.o</span>object file and dynamic libraries into the executable file<span>my_program</span>.
Summary
The compilation phase converts source code into object files, including preprocessing, compiling, and assembling; the linking phase combines object files and library files into executable files, with static and dynamic linking methods. The entire process ensures that programs can be converted from high-level language code into binary code that can run on target machines.
Make is a rule-based build tool that determines which files need to be recompiled and linked by reading the rules in the <span>Makefile</span> file. The <span>Makefile</span> defines the relationships between targets (like executable files, object files), dependencies (files that targets depend on), and commands (commands used to generate targets). Make uses file modification times to determine which dependency files have changed, thus only recompiling and linking those affected targets.
If you forget to link a library to the executable program, will the compilation throw an error? What kind of error?
It will throw an Undefined error, indicating that the required library function cannot be found.
How to install a package locally:Use install in CMake (TARGETS xxx DESTINATION xxx) and then use sudo make install to install it to the system’s shared library.To allow <span>find_package</span> to locate our library, we need to create a <span>HelloSlamConfig.cmake</span> file. This file helps CMake locate our library and header files.
# Set library pathset(HelloSlam_INCLUDE_DIRS /usr/local/include)set(HelloSlam_LIBRARIES /usr/local/lib/libhello_slam.so)# Create an import targetadd_library(HelloSlam::hello_slam SHARED IMPORTED)set_target_properties(HelloSlam::hello_slam PROPERTIES IMPORTED_LOCATION ${HelloSlam_LIBRARIES} INTERFACE_INCLUDE_DIRECTORIES ${HelloSlam_INCLUDE_DIRS})# Provide version information for find_package set(HelloSlam_VERSION 1.0)
Place this file in the <span>/usr/local/lib/cmake/HelloSlam</span> directory (you need to create this directory manually).
sudo mkdir -p /usr/local/lib/cmake/HelloSlamsudo cp HelloSlamConfig.cmake /usr/local/lib/cmake/HelloSlam/
At this point, in the new task’s CMakeLists, write
find_package(HelloSlam REQUIRED)
# Link HelloSlam librarytarget_link_libraries(new_project PRIVATE HelloSlam::hello_slam)
<span>find_package</span> is an important command in CMake used to find and configure external dependency packages, and its working mechanism involves various search modes and paths. Below is a detailed introduction to how it finds related packages.
Search Modes
<span>find_package</span> supports two main search modes: Module Mode and Config Mode, and CMake will choose the appropriate mode based on the specific situation.
Module Mode
- Principle: CMake itself contains a series of module files (usually named
<span>Find<PackageName>.cmake</span>), which define the rules for finding specific packages. When using<span>find_package</span>, if the specified package does not have a corresponding configuration file, CMake will attempt to use Module Mode, searching for the corresponding<span>Find<PackageName>.cmake</span>file in its built-in module files and executing the search logic within. - Search Process
- Search Module Files: CMake will look for
<span>Find<PackageName>.cmake</span>files in a series of predefined search paths. These search paths include the<span>Modules</span>directory under the CMake installation directory and any custom module paths specified by the user through the<span>CMAKE_MODULE_PATH</span>variable. - Execute Search Logic: After finding the corresponding module file, CMake will execute the code within, which typically attempts to find the package’s header files, library files, etc., in standard system paths (like
<span>/usr/include</span>,<span>/usr/lib</span>, etc.) and user-specified paths. - Set Variables: If the package is found, the module file will set some variables, such as
<span><PackageName>_FOUND</span>indicating whether the package was found,<span><PackageName>_INCLUDE_DIRS</span>indicating the package’s header file directory, and<span><PackageName>_LIBRARIES</span>indicating the package’s library file path, for later use.
Config Mode
- Principle: Some modern libraries provide their own configuration files (usually named
<span><PackageName>Config.cmake</span>or<span><PackageName>-config.cmake</span>), which contain detailed information about the library, such as header file paths, library file paths, version information, etc. When using<span>find_package</span>, if the specified package has a corresponding configuration file, CMake will use Config Mode to directly load and execute that configuration file. - Search Process
- Search Configuration Files: CMake will look for
<span><PackageName>Config.cmake</span>or<span><PackageName>-config.cmake</span>files in a series of predefined search paths. These search paths include standard CMake package paths (like<span>/usr/local/lib/cmake/<PackageName></span>) and paths specified by the user through the<span>CMAKE_PREFIX_PATH</span>variable. - Load Configuration Files: After finding the corresponding configuration file, CMake will load and execute the code within, which will set some variables and import targets for later use.
- Use Configuration Information: Configuration files will define some import targets (like
<span><PackageName>::<TargetName></span>), which can be directly used in commands like<span>target_link_libraries</span>, making it convenient for the project to use that package.
—



if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)" ) include(ProcessorCount) ProcessorCount(N) message("Processor number: ${N}") if(N GREATER 4) add_definitions(-DMP_EN) add_definitions(-DMP_PROC_NUM=3) message("core for MP: 3") elseif(N GREATER 3) add_definitions(-DMP_EN) add_definitions(-DMP_PROC_NUM=2) message("core for MP: 2") else() add_definitions(-DMP_PROC_NUM=1) endif()else() add_definitions(-DMP_PROC_NUM=1)endif()







Function: Specifies private header file include directories for the <span>fastlio_mapping</span> executable, meaning only this executable can use these header file directories.—