Introduction to CMake - know almost 0 Sequential CMake is a cross platform open source construction tool. Using CMake can easily manage the directory hierarchy that depends on multiple libraries, generate makefile s, and use GNU make to compile and connect programs. 1. Build a single file 1.1 compile using GCC suppose now we want to write a functionhttps://zhuanlan.zhihu.com/p/149828002CMake practical application topic - Zhihu introduces the practical experience of CMake engineering application.https://www.zhihu.com/column/c_1369781372333240320gcc links static libraries and dynamic libraries to generate executable files_ CSDN blog - this article compiles executable files by linking static libraries and dynamic libraries, understands the difference and relationship between linked static libraries and dynamic libraries in the process of gcc compilation, and deeply understands how to compile and assemble source programs into executable files step by step on Linux system. Directory (I) library file (II) link static library file at compile time 1 Source 2 Compile the static library file libx2 A (I) library files (II) linking static library files at compile time 1 Source program main C (main function) #include "sub1. H" #include "sub2. H" #include < stdio h>int main(){int x.https://blog.csdn.net/qq_45237293/article/details/109115445After C language is compiled successfully, the suffix is generated o what is a file_ Source code killer blog - CSDN blog o file Baidu answer 1: it is a file compiled into bai work, with Hello C as an example: first compile and du translate the source file into the target zhi file: GCC - C hello c. Generate hello o file, dao then compiles the target file into an executable file: GCC - o hello o this generates an executable file in/ Hello, you can run hello. Baidu answer 2: suffix o is object, which is equivalent to the obj file compiled under windows, commonly known as the object file. This file refers to the binary code generated by the source code through the compiler and can be directly recognized by the cpu. Generated by the compiler, the specific generation methods are developed in different wayshttps://blog.csdn.net/weixin_41194129/article/details/107935356The story behind Hello World: how to compile C language programs on Linux - welcome to my website to view the original text: https://lulaoshi.info/blog/2020/05/31/compile-c-hello-world-on-linux.htmlC The classic language program "Hello world" is not difficult to write. Many friends can write it with their eyes closed. So compile a "Hello worldhttps://zhuanlan.zhihu.com/p/225749331What is the so file of Linux? Analysis of Linux dynamic link library - know WeChat official account: ilulaoshi, the original is published on my personal website: what is the so file of Linux exactly? In the last article, we analyzed how Hello World compiles. Even a very simple program needs to rely on C standard library and system library. The link is actuallyhttps://zhuanlan.zhihu.com/p/235551437 1.gcc, make and cmake
gcc compiles source files into executable files or library files. When there are many things to compile, you need to explain what to compile first and then what to compile. This process becomes construction. The common tool is make. The corresponding file defining the construction process is makefile. Writing makefile is complex for large projects. cmke can define the construction process through a more concise syntax, cmake the file that defines the build process is cmakelists txt.
2. The core concepts of cmake grammar
Variables: use the set and unset commands in cmake to set or unset variables
# Set variable set(AUTHOR_NAME Farmer) set(AUTHOR "Farmer Li") set(AUTHOR Farmer\ Li) # Set list set(SLOGAN_ARR To be) # Saved as "To;be" set(SLOGAN_ARR To;be) set(SLOGAN_ARR "To;be") set(NUM 30) # Saved as string, but can compare with other number string set(FLAG ON) # Bool value # set(<variable> <value>... CACHE <type> <docstring> [FORCE]) set(CACHE_VAR "Default cache value" CACHE STRING "A sample for cache variable") # set(ENV{<variable>} [<value>]) set(ENV{ENV_VAR} "$ENV{PATH}") message("Value of ENV_VAR: $ENV{ENV_VAR}")
Common script commands:
1. Message printing, i.e. message command, is actually printing log, which is used to print different messages,
message([<mode>] "message text" ...)
2. Conditional branch
set(EMPTY_STR "") if (NOT EMPTY_STR AND FLAG AND NUM LESS 50 AND NOT NOT_DEFINE_VAR) message("The first if branch...") elseif (EMPTY_STR) message("EMPTY_STR is not empty") else () message("All other case") endif()
3. List operation
List is also a command of cmake. There are many useful subcommands. The more common ones are append: add elements to the list, length: get the number of list elements, and join: connect the list elements with the specified separator.
set(SLOGAN_ARR To be) # Saved as "To;be" set(SLOGAN_ARR To;be) set(SLOGAN_ARR "To;be") set(WECHAT_ID_ARR Real Cool Eengineer) list(APPEND SLOGAN_ARR a) # APPEND sub command list(APPEND SLOGAN_ARR ${WECHAT_ID_ARR}) # Can append another list list(LENGTH SLOGAN_ARR SLOGAN_ARR_LEN) # LENGTH sub command # Convert list "To;be;a;Real;Cool;Engineer" # To string "To be a Real Cool Engineer" list(JOIN SLOGAN_ARR " " SLOGEN_STR) message("Slogen list length: ${SLOGAN_ARR_LEN}") message("Slogen list: ${SLOGAN_ARR}") message("Slogen list to string: ${SLOGEN_STR}\n")
4. File operation
CMake's file command supports many operations, such as reading and writing, creating or copying files and directories, calculating file hash, downloading files, compressing files, etc. The syntax used is similar. Taking the recursive traversal of files commonly used by the author as an example, the following is an example of obtaining the list of all c files in the two subdirectories under the src Directory:
file(GLOB_RECURSE ALL_SRC src/module1/*.c src/module2/*.c ) GLOB_RECURSE Means to perform recursive search to find all files in the directory that match the specified regular expression.
5. Configuration file generation
Using configure_ The file command can replace the specific content in the configuration file template to generate a target file.
set(VERSION 1.0.0) configure_file(version.h.in "${PROJECT_SOURCE_DIR}/version.h")
6. Execute system commands
Using execute_ The process command can execute one or more system commands in sequence.
7. Find library files
Through find_library finds the library with the specified name under the specified path and the related default path.
find_library (<VAR> name1 [path1 path2 ...])
8.include other modules
include(CPack) # Turn on the packaging function include(CTest) # Enable test related functions
3.CMakeLists.txt
cmake_minimum_required(VERSION 3.12) project(CMakeTemplate VERSION 1.0.0 LANGUAGES C CXX DESCRIPTION "A cmake template project") ##--------------------- Version file ---------------------------------------## configure_file(src/c/cmake_template_version.h.in "${PROJECT_SOURCE_DIR}/src/c/cmake_template_version.h") # Specified the language standard set(CMAKE_C_STANDARD 99) set(CMAKE_CXX_STANDARD 11) ##--------------------- Compile Options ------------------------------------## # Configure compile options add_compile_options(-Wall -Wextra -pedantic -Werror) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -std=c99") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe -std=c++11") # Set build type # set(CMAKE_BUILD_TYPE Debug) # Use `cmake -DCMAKE_BUILD_TYPE=Debug` more better message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") # Compile options for Debug variant set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -O0") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0") # Compile options for Release variant set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2") message(STATUS "Compile options for c: ${CMAKE_C_FLAGS}") message(STATUS "Compile options for c++: ${CMAKE_CXX_FLAGS}") ##--------------------- Global Macros --------------------------------------## add_definitions(-DDEBUG -DREAL_COOL_ENGINEER) ##--------------------- Include directories --------------------------------## include_directories(src/c) ##--------------------- Source files ---------------------------------------## file(GLOB_RECURSE MATH_LIB_SRC src/c/*.c ) ##--------------------- Build target ---------------------------------------## option(USE_IMPORTED_LIB "Use pre compiled lib" OFF) if (USE_IMPORTED_LIB) # add_library(math STATIC IMPORTED) # set_property(TARGET math PROPERTY IMPORTED_LOCATION "./lib/libmath.a") find_library(LIB_MATH_DEBUG mathd HINTS "./lib") find_library(LIB_MATH_RELEASE math HINTS "./lib") add_library(math STATIC IMPORTED GLOBAL) set_target_properties(math PROPERTIES IMPORTED_LOCATION "${LIB_MATH_RELEASE}" IMPORTED_LOCATION_DEBUG "${LIB_MATH_DEBUG}" IMPORTED_CONFIGURATIONS "RELEASE;DEBUG" ) add_subdirectory(src/c/nn) else() # Build math lib add_subdirectory(src/c/math) add_subdirectory(src/c/nn) endif() # Merge library if (APPLE) set(MERGE_CMD libtool -static -o) add_custom_command(OUTPUT libmerge.a COMMAND libtool -static -o libmerge.a $<TARGET_FILE:math> $<TARGET_FILE:nn> DEPENDS math nn) else() add_custom_command(OUTPUT libmerge.a COMMAND ar crsT libmerge.a $<TARGET_FILE:math> $<TARGET_FILE:nn> DEPENDS math nn) endif() add_custom_target(_merge ALL DEPENDS libmerge.a) add_library(merge STATIC IMPORTED GLOBAL) set_target_properties(merge PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/libmerge.a ) # Build demo executable add_executable(demo src/c/main.c) target_link_libraries(demo PRIVATE merge) ##--------------------- Build unit tests -----------------------------------## option(CMAKE_TEMPLATE_ENABLE_TEST "Whether to enable unit tests" ON) if (CMAKE_TEMPLATE_ENABLE_TEST) message(STATUS "Unit tests enabled") enable_testing() add_subdirectory(third_party/googletest-release-1.10.0 EXCLUDE_FROM_ALL) include_directories(third_party/googletest-release-1.10.0/googletest/include) add_executable(test_add test/c/test_add.cc) add_executable(test_minus test/c/test_minus.cc) add_executable(test_gtest_demo test/c/test_gtest_demo.cc) target_link_libraries(test_add math gtest gtest_main) target_link_libraries(test_minus math gtest gtest_main) target_link_libraries(test_gtest_demo math gtest gtest_main) add_test(NAME test_add COMMAND test_add) add_test(NAME test_minus COMMAND test_minus) add_test(NAME test_gtest_demo COMMAND test_gtest_demo) endif() ##--------------------- Install and Package target -------------------------## # Install if (NOT USE_IMPORTED_LIB) install(TARGETS math nn demo RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib PUBLIC_HEADER DESTINATION include) file(GLOB_RECURSE MATH_LIB_HEADERS src/c/math/*.h) install(FILES ${MATH_LIB_HEADERS} DESTINATION include/math) endif() # Package, These variables should set before including CPack module set(CPACK_GENERATOR "ZIP") set(CPACK_SET_DESTDIR ON) # The specified installation directory is supported set(CPACK_INSTALL_PREFIX "RealCoolEngineer") include(CPack)
1. Set version item
2. Specify the programming language version
In order to be more uniform on different machines, it is best to specify the language version, such as declaring that c uses the c99 standard and c + + uses the c++11 standard. The variables set here are CMAKE_ At the beginning (including the variables automatically set by the project command), these variables are built-in variables of CMAKE, and the behavior of CMAKE construction is configured by modifying the values of these variables.
set(CMAKE_C_STANDARD 99) set(CMAKE_CXX_STANDARD 11)
3. Configure compilation options
Via add_ compile_ The options command can configure compilation options for all compilers; Set CMAKE_C_FLAGS can configure the compilation options of c compiler; Set variable CMAKE_CXX_FLAGS configures compilation options for the c + + compiler.
add_compile_options(-Wall -Wextra -pedantic -Werror) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -std=c99") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe -std=c++11")
4. Configure compilation type
By setting CMAKE_BUILD_TYPE to configure the compilation type, which can be set to Debug, Release, etc.
set(CMAKE_BUILD_TYPE Debug)
If the type is set to debug, for the c compiler, CMake checks whether there is a compilation option CMake for this variant type_ c_ FLAGS_ Debug, if any, add its configuration content to CMake_ c_ In flags. Different compilation options can be set for different compilation types. For the debug version, turn on the debugging information without code optimization
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -O0") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0")
For the Release version, debugging information is not included, and the optimization level is set to 2
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
5. Add global macro definition
Via add_definitions you can add global macro definitions
add_definitions(-DDEBUG -DREAL_COOL_ENGINEER)
6. Add the include directory
By include_directoories to set the search directory for header files
include_directories(src/c)
4. Static library, dynamic library and executable file
Library file: in essence, a library is an executable binary form that can be loaded into memory by the operating system for execution. Some public functions are made into function libraries for use by other programs. Function libraries are divided into static libraries and dynamic libraries. The static library will be linked to the object code when the program is compiled. It is no longer necessary to change the static library when the program is running. The name of the static library is generally libxxx a. xxx is the name of the lib. The dynamic library will not be linked to the object code when the program is compiled, but will be loaded when the program is running. Therefore, the dynamic library is also required when the program is running. The name of the dynamic library is usually libxxx so. major. Minor, xxx is the name of the lib, major is the major version number, minor is the minor version number.
ldd executable can view a dynamic library of executable dependencies
Suffix o is object, which is equivalent to the obj file compiled under windows, commonly known as the object file. This file refers to the binary code generated by the source code through the compiler and can be directly recognized by the cpu. Generated by compiler, the specific generation methods are different in different development environments
On linux, cpp can be compiled into o file, yes o after that, you can compile the static library a. You can also compile dynamic libraries So, after compilation, connect to an executable file A linked executable can be deleted So links the executable file and saves it. The trouble with dynamic library linking is that it is loaded only at runtime, so the loading path needs to be paid attention to. It is generally generated The so file is in the generation directory. When the program runs, it will find the required dynamic library file in / usr/lib or / usr/lib64. If it is found, it will load the dynamic library, otherwise an error will be reported. However, the address of the file to be compiled into so can be specified during cmake compilation.
5.c/cpp compilation
c and cpp files cannot be run directly, and need to be compiled with a compiler c and other source files into executable files, such as exe is run by computer on windows. Many software used in reality are composed of hundreds of source code files. The process of converting these source code files into executable files is called build. The construction process of complex software will include a series of activities. It is really troublesome to build large software. Generally, there are some tools to assist in completing the above work. The compilation stage is generally divided into four steps: preprocessing, compilation, assembly and link.
gcc is a collection of compilers that support cpp, go and other languages. gcc is not the only compiler. gcc wraps a lot of content and hides complex steps.
1. Preprocessing: precompiling mainly processes precompiled instructions starting with # in the source code. As long as the rules are as follows: process #include precompiled instructions and insert the included files into the location of the precompiled instructions. This is a recursive process. If the included files also contain other files, this process will be completed recursively. Pre compilation specification of processing conditions, such as #if,#ifdef,#else. Delete #define and expand all macro definitions. Add line number and file name identification.
2. Compilation: the compilation process is mainly for lexical analysis, syntax analysis and semantic analysis. Only compilation, not assembly, can generate assembly language related to hardware platform. A corner cc1 tool is used in gcc.
3. Assembly: it becomes binary machine code, but it cannot be executed because it lacks the library necessary for system operation, such as the assembly language put function corresponding to printf in C. The system does not know the specific location of the put function in memory. If external functions or variables are used, it also needs to be linked.
4. Linking: there are two ways, one is static linking and the other is dynamic linking. Static linking packages all the dependent third-party library functions together, resulting in a very large executable file. Dynamic linking does not directly take out those library files, but uses them at runtime and then reads them, resulting in assembly o after the file is linked, a real executable file is generated. The dynamic link library will prefix the namespec with lib and will eventually be named libnamespec so.
The Dynamic link library files of different operating systems are slightly different. linux calls it the shared object file, and the file suffix is so, the suffix of Dynamic link library file of windows is dll.
No matter what operating system, all function calls involving third-party libraries in the target file generated by dynamic link are address independent, and the address here is the virtual address of the process in memory.
6. so
Multiple executables can share and use the shared library in the system. Each executable is smaller and occupies relatively small disk space. The isolation between shared libraries determines that shared libraries can be upgraded with small versions of code, recompiled and deployed to the operating system without affecting its calling by executable files. Any function of the static link library has been changed. Except that the static link library itself needs to be recompiled and built, the left and right executables that depend on this function need to be recompiled and built again. Now we usually use so.
But shared libraries also have disadvantages: 1 It is troublesome to directly migrate the target file. To ensure that all the so required by the file are present, the interface of the shared library cannot be moved.
If the linux program reports an error indicating that a library is missing, you can use ldd to detect which so to rely on, and copy the corresponding so to / usr/lib / or / usr/lib64. If not, use the environment variable LD_LIBRARY_PATH to adjust.
As mentioned just now, the vast majority of Linux dynamic link libraries are under / lib and / usr/lib, and the operating system will search for dynamic link libraries under these two paths by default. In addition, / etc / LD so. The path can be configured in the conf file, / etc / LD so. The conf file will tell the operating system which paths to search for dynamic link libraries. There are many dynamic link libraries in these locations. If the linker traverses these paths every time, it is very time-consuming. Linux provides the ldconfig tool, which will create a soft connection to the dynamic link libraries of these paths according to the SONAME rule, and also generate a Cache to / etc / LD so. In the Cache file, the linker can find each item faster according to the Cache So file. Each time a new library is installed in / lib and / usr/lib, or / etc / ld so. Conf files need to be updated by calling the ldconfig command to regenerate the soft connection and Cache. But / etc / LD so. The conf file and the ldconfig command are preferably operated using the root account. Non root users can install library files in a path and add this path to / etc / LD so. Conf file, and then the root user calls ldconfig.
For non root users, another approach is to use LD_LIBRARY_PATH environment variable. LD_LIBRARY_PATH stores several paths. The linker will go to these paths to find the library. Non root can install a library in a path with non root permissions, and then add it to the environment variable.
7.examples
./cmake-template ├── CMakeLists.txt ├── src │ └── c │ ├── cmake_template_version.h │ ├── cmake_template_version.h.in │ ├── main.c │ └── math │ ├── add.c │ ├── add.h │ ├── minus.c │ └── minus.h └── test └── c ├── test_add.c └── test_minus.
Math becomes a static library and compiles main C is an executable file and depends on math static library
1. Compile static library
file(GLOB_RECURSE MATH_LIB_SRC src/c/math/*.c ) add_library(math STATIC ${MATH_LIB_SRC})
Compile the source file under src/c/math into a static library, and use the file command to get all the files under math c file, through add_ The library is compiled into a static library of math. The type of the library is specified by static. For a dynamic library, it is shared.
2. Compile executable
add_executable(demo src/c/main.c) target_link_libraries(demo math)
Via add_executable builds executable programs, but for executable files, sometimes they depend on other libraries, so target needs to be used_ link_ Libraries to declare the libraries that need to be linked to build this executable. main.c uses some function structures implemented under src/c/math, so it depends on the previous math library.
Note that until add_library can generate so file, and then call so file, add_exectable generates executable files, which can be quickly measured through external args executable files.
8. Modular construction
CMakeLists.txt defines a directory construction system, so for modular construction, it is actually to write a cmakelista for each sub module directory Txt, the build system that imports a subdirectory into its parent directory generates the corresponding target for use in the parent directory.
The math directory is regarded as a sub module, and the build system is defined separately for it. The whole project depends on the compilation results of the math module.
1. Define the construction system of subdirectories
As long as the build system of the directory is defined, a cmakelists is created under this directory Txt file.
cmake_minimum_required(VERSION 3.12) project(CMakeTemplateMath VERSION 0.0.1 LANGUAGES C CXX) aux_source_directory(. MATH_SRC) message("MATH_SRC: ${MATH_SRC}") add_library(math STATIC ${MATH_SRC})
Subdirectories generally have their own project s. If necessary, they can also specify their own version number, aux_source_directory, you can search all source files in the specified directory (the first parameter) and save the list of source files to the specified variable (the second parameter).
2. Include subdirectories
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
Where source_dir is the target directory to include, and there must be a cmakelists Txt file, generally relative to the current cmakelists Txt directory path, of course, can also be an absolute path.
add_subdirectory(src/c/math) # Build demo executable add_executable(demo src/c/main.c) target_link_libraries(demo math)
9. Import the compiled target file
The command add described earlier_ Subdirectory is actually equivalent to building the target file that the project depends on through the source file, but CMake can also import the compiled target file through the command.
To import a library file, use add_library, which indicates that this is an IMPORTED library file by specifying the IMPORTED option, and indicates its path by setting its attribute:
add_library(math STATIC IMPORTED) set_property(TARGET math PROPERTY IMPORTED_LOCATION "./lib/libmath.a")
For library file paths, you can also use find_library.
After the import is successful, you can link the library to other targets.