Please follow xiaobaiai.net or my CSDN blog.csdn.net/freeape

[TOC]

First show is this article from the syntax of cmake, but from an actual building of the project, to understand how to build a software project, elegant building a basic C/C + + software project depends on the components, and form a building C/C + + software project template, convenient behind the repeated use of the new project. I believe that our daily software project construction will have a good harvest. Let’s go. Let’s go.

1 We need to know the basis

By familiarizing ourselves with the basics of CMake, we can build a project elegantly and effortlessly, avoiding unnecessary pitfalls. It involves:

  • Cmake variable scope?
  • Data structures in Cmake?
  • Macros and functions?
  • How to build and find dynamic and static libraries?
  • How to build projects that support multiple platforms?
  • How to build an application?
  • How to implement the final install of the project?
  • How to present the various levels of information about the build process in a friendly way?
  • How to adapt cmake-GUI, using friendly CCmake or cmake-GUI implementation build?

Cmake allows you to find dependent headers and library files, compile source files, link object files (static libraries are also a collection of object files), and finally generate executable files or dynamic/static libraries:

  • INCLUDE_DIRECTORIES add the given directory to the directory the compiler uses to search for files such as header directories, and the relative path is interpreted as relative to the current source directory. Note that directories are only added to the current CMakeLists file, and are not used for libraries, executables, or submodule compilations associated with the current CMakeLists file. Unlike TARGET_INCLUDE_DIRECTORIES, the effect of this command is to add a search path for the specified target. Similarly, the TARGET_LINK_LIBRARIES command adds the library file directory to which you want to link.

  • PROJECT_SOURCE_DIR: no doubt any cmakelists.txt containing the latest PROJECT() command declaration is relative to the cmakelists.txt path.

  • CMAKE_SOURCE_DIR: The value of this variable is the path to the topmost cmakelists.txt, which you may depend on when building the entire project.

  • In find_path and find_library and find_package, some default paths are searched. Cmake will not be able to find lib when we install some lib in a path other than the default search path.

    • SET(CMAKE_INCLUDE_PATH “include_path”) // find_path to find headers
    • SET(CMAKE_LIBRARY_PATH “lib_path”) // find_library, find library file
    • SET(CMAKE_MODULE_PATH “module_path”) // find_package
  • You can also use include(xxx.cmake) and find_file to find the dependent library. The result found by find_file will be stored in the CACHE variable, for example:

# Once done, this will define # # NANOMSG_INCLUDE_DIR - the NANOMSG include directory # NANOMSG_LIBRARY_DIR - the SPDLOG library directory # NANOMSG_LIBS - link these to use NANOMSG # # SPDLOG_INCLUDE_DIR - the SPDLOG include directory # SPDLOG_LIBRARY_DIR - the SPDLOG library directory # SPDLG_LIBS - link these to use SPDLOG MACRO(LOAD_LIBNANOMSG os arch)  SET(3RDPARTY_DIR ${PROJECT_SOURCE_DIR}/3rdparty/target/${${os}}_${${arch}}) MESSAGE(STATUS "3RDPARTY_DIR: ${3RDPARTY_DIR}") FIND_FILE(NANOMSG_INCLUDE_DIR include ${3RDPARTY_DIR} NO_DEFAULT_PATH) FIND_FILE(NANOMSG_LIBRARY_DIR lib ${3RDPARTY_DIR} NO_DEFAULT_PATH) SET(NANOMSG_LIBS nanomsg pthread anl PARENT_SCOPE ) IF(NANOMSG_INCLUDE_DIR) MESSAGE(STATUS "NANOMSG_LIBS : ${NANOMSG_LIBS}") ELSE() MESSAGE(FATAL_ERROR "NANOMSG_LIBS not found!" ) ENDIF() ENDMACRO()Copy the code
  • Conditional control switch example:
# set target
if (NOT YOUR_TARGET_OS)
    set(YOUR_TARGET_OS linux)
endif()

if (NOT YOUR_TARGET_ARCH)
    set(YOUR_TARGET_ARCH x86_64)
endif()

if (NOT YOUR_BUILD_TYPE)
    set (YOUR_BUILD_TYPE Release)
endif()

......

if(${YOUR_TARGET_ARCH} MATCHES "(arm*)|(aarch64)")
    ......
elseif(${YOUR_TARGET_ARCH} MATCHES x86*)
    ......Copy the code
  • Cross-compilation:CMAKE_TOOLCHAIN_FILEVariables,
MESSAGE(STATUS "Configure Cross Compiler") IF(NOT TOOLCHAIN_ROOTDIR) MESSAGE(STATUS "Cross-Compiler defaut root path: $ENV{HOME}/Softwares/arm-himix200-linux") SET(TOOLCHAIN_ROOTDIR "$ENV{HOME}/Softwares/arm-himix200-linux") ENDIF() SET(CMAKE_SYSTEM_NAME Linux) SET(CMAKE_SYSTEM_PROCESSOR arm) SET(CMAKE_C_COMPILER ${TOOLCHAIN_ROOTDIR}/bin/arm-himix200-linux-gcc) SET(CMAKE_CXX_COMPILER ${TOOLCHAIN_ROOTDIR}/bin/arm-himix200-linux-g++)  # set searching rules for cross-compiler SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) SET(YOUR_TARGET_OS linux) SET(YOUR_TARGET_ARCH armv7-a) SET(CMAKE_CXX_FLAGS "-std=c++11 -march=armv7-a -mfloat-abi=softfp -mfpu=neon-vfpv4 ${CMAKE_CXX_FLAGS}")Copy the code
  • AUX_SOURCE_DIRECTORYDoes not recursively include subdirectories, only the specified dir directory
  • ADD_SUBDIRECTORYThe compilation of submodules can be performed in subfolders or specified external folder cmakelists. TXT.
  • ADD_LIBRARYCompile a static/dynamic library or module with a name that is unique to the entire project and independent of the parent/child folder path within the entire projectTARGET_LINK_LIBRARIESDepend on this module.
  • ADD_DEFINITIONS(-DTEST -DFOO="foo")addFOOandTESTMacro definition.

2 we want to build gracefully

For a large software project, we will rely on many third-party projects, including source code dependencies or library dependencies, and then complete the construction of our own software project, we need to build dependencies or find the library we need; In addition, software projects are built with portability in mind, the ability to build projects on different platforms in a friendly manner, and the ability to quickly start building projects when moving them to another development environment.

In addition to the above mentioned, we also need to consider the architectural structure of our actual software project, the source code structure, so that developers can more clearly, more quickly understand the whole project.

In addition, C/C++ programmers have long managed dependencies manually by manually finding, installing, and configuring build tools (such as Cmake) to use them. Cmake also provides a set of find_package methods to help simplify configuration dependencies. Cmake also supports multi-project/module management, which is much easier if dependent source code is simultaneously built by Cmake management, known as source-level dependency management. With the advent and widespread use of the code management tool Git, the Git subModule provides a good way to manage source-level dependencies.

To sum up, elegantly build software projects, we achieve:

  • Software project source code depends on third-party projects
  • The software project library relies on third-party projects
  • The software project structure is clear
  • Software project builds are built quickly in a transformational new environment
  • Information friendly presentation during software project construction
  • Software projects are built and packaged for release
  • Software projects can be built across platforms
  • Software projects support cross-builds
  • Git subModule & cmake manages/builds source-level dependencies

In addition, we implemented a reusable C/C++ minimal development framework (described in a future article) :

  • Logging support
  • Task pools/thread pools are supported
  • Supports common basic operation components
    • Time date operation
    • File read and write operations
  • Support valGrind memory leak check tool
  • Static code inspection is supported
  • Support project document automation
  • .

Elegant software project structure template

3.1 a template

For a standalone application, application modules are interconnected and difficult to separate from each other. Simply putting all source files together and header files together is a quick way to start building and modifying source files for less complex applications:

.├ ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ─Copy the code

3.2 the template 2

The source file and header file are stored in functional modules, which is relatively simple. However, if it becomes the 3RDParty of other projects, the header file needs to be separated from the installation, which can not be directly referenced by other projects. Personally, I think it is suitable for App class projects. For example, nanomsg is an open source messaging middleware library that puts header files and source files together, but as an SDK for external links is not very straightforward and convenient, you need to do the install operation before you can or set the search scope of header files to the SRC level of the dependent project. And SRC directory module classification is clear) :

│ ├─ 3rdParty │ ├─ SubModule │ ├─ target │ ├─ cmakelists.txt │ ├─ cmake │ ├─ cmake │ ├ ─ ─ platforms │ └ ─ ─ Linux │ └ ─ ─ arm toolchain. Cmake ├ ─ ─ the SRC ├ ─ ─ moudle1 ├ ─ ─ the source & the include file ├ ─ ─ moudle2 ├ ─ ─ the source & Include File ├─...... ├ ─ ─ doc ├ ─ ─ tests ├ ─ ─ samples ├ ─ ─ benchmarks ├ ─ ─ docker ├ ─ ─ CMakeLists. TXTCopy the code

3.3 template three

The software project can be divided into many modules, each module can be independent of each other, can also be combined together, such as the typical OpencV project, of course, this is also applicable to the application project, but the application project directory structure is too deep, development and editing slightly inconvenient:

├ ─ ─ 3 rdparty ├ ─ ─ cmake ├ ─ ─ platforms │ └ ─ ─ Linux │ └ ─ ─ arm toolchain. Cmake ├ ─ ─ the include the directory only each function module header file contains a summary ├ ─ ─ modules ├ ─ ─ moudle1 ├ ─ ─ the SRC ├ ─ ─ the include ├ ─ ─ moudle2 ├ ─ ─... ├ ─ ─ doc ├ ─ ─ tests ├ ─ ─ samples ├ ─ ─ benchmarks ├ ─ ─ docker ├ ─ ─ CMakeLists. TXTCopy the code

4 elegant software project structure template CMake implementation

Here we only implement template 2, the other templates are pretty much the same. As described in the template section above, we

4.1 Determining the directory structure

.├ ── ├─ Cmakelists.txt │ ├─ cmakelists.txt │ ├─ spdlog(github searchable) │ └ ─ ─ target # libraries depend on the storage directory │ ├ ─ ─ linux_armv7 - a # to distinguish platform and architecture named │ │ ├ ─ ─ # include header files storage directory │ │ └ ─ ─ lib # library file storage directory │ └ ─ ─ │ ├─ Load_3rdparty. cmake │ ├─ Messagecolor ├ ─ ─ toolchain_options. Cmake │ └ ─ ─ utils. Cmake ├ ─ ─ CMakeLists. TXT # CMakeLists project root directory file, Cmake entry documents ├ ─ ─ the conf # project configuration file storage directory ├ ─ ─ doc # project's document directory ├ ─ ─ platforms # project platform sex related content storage directory, Including cross-compilation │ └ ─ ─ Linux │ └ ─ ─ arm himix200. Cmake ├ ─ ─ the README. Md # project description ├ ─ ─ scripts # deposit related script directory, │ ├─ Common │ ├─ Logger │ ├── main ├─ ├─ SRC # ├─ SRC # ├─ cmakelists. TXT │ ├─ common │ ├─ Logger │ ├─ main ├─ ├─ SRC # ├─ cmakelists. TXT CMakeLists. TXT └ ─ ─ test_logger. CPPCopy the code

4.2 Project version management

Whether it’s an SDK or APP project, there is a version that records every node of the software release. Software version can be convenient for users or their own clearly know each version has what content update, you can make the choice to use the version or solve the bugs encountered in the version. To achieve version management, you need to be able to clearly reflect the current version number in the compilation process and obtain the version number in the software. The major is the largest version number, minor is the second, and patch corresponds to the patch level in the minor version. When there is a major update, the version number of major will be added; when there is a major update but major will not be updated, the version number of Minor will be updated; if the update is relatively small, such as bug fixing, the version number of patch will be updated. Example Version number format: V1.0, V1.2.2, etc.

In the elegant build software template, we put the version information in the SRC /common/version.hpp file:

Note: All file paths are relative to the project root directory.

// 0.1.0 #define HELLO_APP_VER_MAJOR 0 #define HELLO_APP_VER_MINOR 1 #define HELLO_APP_VER_PATCH 0 #define HELLO_APP_VERSION (HELLO_APP_VER_MAJOR * 10000 + HELLO_APP_VER_MINOR * 100 + V0.1.0 #define _HELLO_APP_STR(s) #s #define HELLO_PROJECT_VERSION(major, minor, patch) "v" _HELLO_APP_STR(major.minor.patch)Copy the code

In the CMakeLists module file we go to parse the file to get the version number into the CMake variable and add the macro function to CMake /utils.cmake:

FUNCTION(hello_app_extract_version)                                 
    FILE(READ "${CMAKE_CURRENT_LIST_DIR}/src/common/version.hpp" file_contents) 
    STRING(REGEX MATCH "HELLO_APP_VER_MAJOR ([0-9]+)" _  "${file_contents}")       
    IF(NOT CMAKE_MATCH_COUNT EQUAL 1)                                           
        MESSAGE(FATAL_ERROR "Could not extract major version number from version.hpp")
    ENDIF()                                                                     
    SET(ver_major ${CMAKE_MATCH_1})                                             

    STRING(REGEX MATCH "HELLO_APP_VER_MINOR ([0-9]+)" _  "${file_contents}")       
    IF(NOT CMAKE_MATCH_COUNT EQUAL 1)                                           
        MESSAGE(FATAL_ERROR "Could not extract minor version number from version.hpp")
    ENDIF()                                                                     
    SET(ver_minor ${CMAKE_MATCH_1})                                             
    STRING(REGEX MATCH "HELLO_APP_VER_PATCH ([0-9]+)" _  "${file_contents}")       
    IF(NOT CMAKE_MATCH_COUNT EQUAL 1)                                           
        MESSAGE(FATAL_ERROR "Could not extract patch version number from version.hpp")
    ENDIF()                                                                     
    SET(ver_patch ${CMAKE_MATCH_1})                                             

    SET(HELLO_APP_VERSION_MAJOR ${ver_major} PARENT_SCOPE)                      
    SET (HELLO_APP_VERSION "${ver_major}.${ver_minor}.${ver_patch}" PARENT_SCOPE)
ENDFUNCTION()Copy the code

Call versioning macros in the root directory CMakeLists:

CMAKE_MINIMUM_REQUIRED (VERSION 3.4) # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # Project setting #-------------------------------------------- INCLUDE(cmake/utils.cmake) HELLO_APP_EXTRACT_VERSION() PROJECT(HelloApp VERSION ${HELLO_APP_VERSION} LANGUAGES CXX) MESSAGE(INFO "--------------------------------") MESSAGE(STATUS "Build HelloApp: ${HELLO_APP_VERSION}")Copy the code

SOVERSION can be set later in the static and dynamic library generation, for example:

SET_TARGET_PROPERTIES(MyLib PROPERTIES VERSION ${HELLO_APP_VERSION}
                                          SOVERSION ${HELLO_APP_VERSION_MAJOR})Copy the code

So => limylib.so.0 => libmylib.so.0.1.1 library and associated soft links. Use this with caution, however, as libraries with versions of JNI dependencies are not available on the Android platform.

4.3 Third-party Library Dependency

Third party library dependency requires us to write our own library and header file search function, third party inventory location is differentiated by platform and architecture, directory structure will not change with the creation of the project. The following is an example of a library discovery macro function:

# Once done, this will define # # SPDLOG_INCLUDE_DIR - the SPDLOG include directory # SPDLOG_LIBRARY_DIR - the SPDLOG library directory # SPDLG_LIBS - link these to use SPDLOG # # ...... MACRO(LOAD_LIBSPDLOG os arch) SET(3RDPARTY_DIR ${PROJECT_SOURCE_DIR}/3rdparty/target/${${os}}_${${arch}}) MESSAGE(STATUS  "3RDPARTY_DIR: ${3RDPARTY_DIR}") FIND_FILE(SPDLOG_INCLUDE_DIR include ${3RDPARTY_DIR} NO_DEFAULT_PATH) FIND_FILE(SPDLOG_LIBRARY_DIR lib  ${3RDPARTY_DIR} NO_DEFAULT_PATH) SET(SPDLOG_LIBS spdlog pthread #PARENT_SCOPE no parent ) IF(SPDLOG_INCLUDE_DIR) SET(SPDLOG_LIBRARY_DIR "${SPDLOG_LIBRARY_DIR}/spdlog") MESSAGE(STATUS "SPDLOG_INCLUDE_DIR : ${SPDLOG_INCLUDE_DIR}") MESSAGE(STATUS "SPDLOG_LIBRARY_DIR : ${SPDLOG_LIBRARY_DIR}") MESSAGE(STATUS "SPDLOG_LIBS : ${SPDLOG_LIBS}") ELSE() MESSAGE(FATAL_ERROR "SPDLOG_LIBS not found!" ) ENDIF() ENDMACRO()Copy the code

Note: for example, if the macro function SPDLOG_LIBS is called in the root directory CMakeLists, the variable scope can be applied to all subdirectories. If it is not called in the root directory, the PARENT_SCOPE property needs to be set.

Call macro function in main CMakeLists to implement information import of tripartite library:

INCLUDE(cmake/load_3rdparty.cmake)                                              

IF(NOT YOUR_TARGET_OS)                                                          
    SET(YOUR_TARGET_OS linux)                                                   
ENDIF()                                                                         
IF(NOT YOUR_TARGET_ARCH)                                                        
    SET(YOUR_TARGET_ARCH x86-64)                                                
ENDIF()                                                                         
MESSAGE(STATUS "Your target os : ${YOUR_TARGET_OS}")                            
MESSAGE(STATUS "Your target arch : ${YOUR_TARGET_ARCH}")                        

LOAD_LIBSPDLOG(YOUR_TARGET_OS YOUR_TARGET_ARCH)Copy the code

4.4 Third-party library source code Dependency

If you want to rely on third-party source code and compile it together, you can use git subModule to manage third-party source code, source dependencies and version management. Of course, you can manually put the source code into the 3rdparty directory without using git submodule.

Add a Git submodule:

# git add <url.git> <path> Root directory and create. Gitmodule in warehouse $git submodule add 3 rdparty/spdlog at https://github.com/gabime/spdlog.gitCopy the code

You can also add with a specified branch:

# note: The command needs to be executed in the project root directory, the first time will directly pull the source code, Don't have to update $git submodule add - b v1. https://github.com/gabime/spdlog.git 3 rdparty/spdlog $x git submodule update --remoteCopy the code

The final.gitmodules file is:

[submodule "3rdparty/spdlog"]
    path = 3rdparty/spdlog                                                   
    url = https://github.com/gabime/spdlog.git 
    branch = v1.xCopy the code

To compile the source code of the third party project (first you rely on the source code of the third party project to support the CMake build method), in 3rdparty/ cmakelists.txt:

CMAKE_MINIMUM_REQUIRED (VERSION 3.4) PROJECT (HiApp3rdparty) ADD_SUBDIRECTORY (spdlog)Copy the code

To compile a third-party library, include cmakelists. TXT in the root directory cmakelists. TXT from 3rdparty:

ADD_SUBDIRECTORY(3rdparty)Copy the code

The third-party project name can be specified to implement the link using TARGET_LINK_LIBRARIES.

4.5 Adding Function Modules

4.5.1 Compilation of Functional Modules

For example, if we want to add a log module to achieve a secondary encapsulation of the SPdlog project and better use it in our own project, we will set up the SRC /logger directory and create three files: logger. HPP, logger. CPP and cmakelists. TXT. Where cmakelists. TXT content is to achieve the compilation of the log module:

CMAKE_MINIMUM_REQUIRED(VERSION 3.4) AUX_SOURCE_DIRECTORY(.current_DIR_SRcs) ADD_LIBRARY(module_logger) TARGET_LINK_LIBRARIES(module_LOGGER ${SPDLOG_LIBS})Copy the code

Then include a compilation of the log module in SRC/cmakelists.txt:

ADD_SUBDIRECTORY(logger)Copy the code

The subdirectory SRC is included in the root directory cmakelists.txt to realize the construction of functional modules:

ADD_SUBDIRECTORY(src)Copy the code

Note: For demonstration purposes, both the library and source dependencies are spdlog, and you’ll need to choose one of these to implement the logging module.

4.5.2 Compiling executable files

If we need to implement executable calls to the logging module, we can add SRC /main/main.cpp file and add compilation to the executable file in SRC/cmakelists.txt:

Executable_executable (EXECUTABLE_OUTPUT_PATH) ADD_EXECUTABLE(HiApp ${SRC_LIST} ${PROJECT_BINARY_DIR}/bin) TARGET_LINK_LIBRARIES(HelloApp module_logger)Copy the code

Of course, if we use the c++11 feature, we can create a special cmake file cmake/toolchain_options.cmake to configure the c++11 compilation options, and include the cmake file in the main cmakelists.txt:

# compiler Configuration # CMAKE_CXX_STANDARD IF(CMAKE_VERSION VERSION_LESS "3.1") IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") ENDIF() ELSE() SET(CMAKE_CXX_STANDARD 11) ENDIF()Copy the code

4.6 Adding Test Examples

Put the test samples in the Tests directory and create a cmakelists. TXT file under that directory to build all the test demos and include the tests directory under the main cmakelists. TXT:

CMAKE_MINIMUM_REQUIRED(VERSION 3.4) PROJECT(Tests) INCLUDE_DIRECTORIES(${SPDLOG_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/ SRC) LINK_DIRECTORIES( ${SPDLOG_LIBRARY_DIR} ) FILE(GLOB APP_SOURCES *.cpp) FOREACH(testsourcefile ${APP_SOURCES}) STRING(REGEX MATCH "[^/]+$" testsourcefilewithoutpath ${testsourcefile}) STRING(REPLACE ".cpp" "" testname ${testsourcefilewithoutpath}) ADD_EXECUTABLE( ${testname} ${testsourcefile}) SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin/tests) TARGET_LINK_LIBRARIES(${testname} ${SPDLOG_LIBS} module_logger ) ENDFOREACH(testsourcefile ${APP_SOURCES})Copy the code

You can then add tests to the tests directory, such as test_logger. CPP or more, and tests/ cmakelists.txt will automatically build executable files one by one from all the source files in the Tests directory. The entire test sample build is complete.

4.7 Cross-Compiling and Configuration

CMake provides cross-compiled variable Settings, CMAKE_TOOLCHAIN_FILE. If we specify a cross-compiled CMake configuration file, CMake will import the compiler configuration, compiler option configuration, and so on. We design the cross compiler tool chain configuration file storage directory under/platforms, here we use a compilation of huawei haisi tools, we named by category, create a toolbar cmake configuration file platforms/Linux/arm himix200. Cmake:

MESSAGE(STATUS "Configure Cross Compiler") SET(CMAKE_SYSTEM_NAME Linux) SET(CMAKE_SYSTEM_PROCESSOR arm) SET(CMAKE_C_COMPILER arm-himix200-linux-gcc) SET(CMAKE_CXX_COMPILER arm-himix200-linux-g++) # set searching rules for cross-compiler SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) SET(YOUR_TARGET_OS linux) SET(YOUR_TARGET_ARCH armv7-a) SET(CMAKE_SKIP_BUILD_RPATH TRUE) SET(CMAKE_SKIP_RPATH TRUE) # set ${CMAKE_C_FLAGS} and ${CMAKE_CXX_FLAGS}flag for cross-compiled process #SET(CROSS_COMPILATION_ARM himix200) #SET(CROSS_COMPILATION_ARCHITECTURE armv7-a) # set g++ param  # -fopenmp link libgomp SET(CMAKE_CXX_FLAGS "-std=c++11 -march=armv7-a -mfloat-abi=softfp -mfpu=neon-vfpv4 \ -ffunction-sections \ -fdata-sections -O2 -fstack-protector-strong -lm -ldl -lstdc++\ ${CMAKE_CXX_FLAGS}")Copy the code

Note: The cross-compile toolchain needs to be installed on the compile host. Third party library dependencies also need to be compiled for toolchain versions (except source dependencies).

Command line cross-compilation:

$ mkdir build $ cd build $ cmake .. -DCMAKE_TOOLCHAIN_FILE=.. /platforms/linux/arm.himix200.cmake $ make -jCopy the code

This allows you to cross-compile, but you can also configure other cross-compile toolchains.

4.8 other

4.8.1 The cmake message command is highlighted in color

Cmake /messagecolor.cmake /messagecolor.cmake:

IF(NOT WIN32) STRING(ASCII 27 Esc) SET(ColourReset "${Esc}[m") SET(ColourBold "${Esc}[1m") SET(Red "${Esc}[31m") SET(Green "${Esc}[32m") SET(Yellow "${Esc}[33m") SET(Blue "${Esc}[34m") SET(MAGENTA "${Esc}[35m") SET(Cyan "${Esc}[36m")  SET(White "${Esc}[37m") SET(BoldRed "${Esc}[1;31m") SET(BoldGreen "${Esc}[1;32m") SET(BoldYellow "${Esc}[1; 33m") SET(BOLDBLUE "${Esc}[1;34m") SET(BOLDMAGENTA "${Esc}[1;35m") SET(BoldCyan "${Esc}[1;36m") SET(BOLDWHITE "${Esc}[1; 37m") ENDIF() FUNCTION(message) LIST(GET ARGV 0 MessageType) IF(MessageType STREQUAL FATAL_ERROR OR MessageType STREQUAL  SEND_ERROR) LIST(REMOVE_AT ARGV 0) _message(${MessageType} "${BoldRed}${ARGV}${ColourReset}") ELSEIF(MessageType STREQUAL WARNING) LIST(REMOVE_AT ARGV 0) _message(${MessageType} "${BoldYellow}${ARGV}${ColourReset}") ELSEIF(MessageType STREQUAL AUTHOR_WARNING) LIST(REMOVE_AT ARGV 0) _message(${MessageType} "${BoldCyan}${ARGV}${ColourReset}") ELSEIF(MessageType STREQUAL STATUS) LIST(REMOVE_AT ARGV 0) _message(${MessageType} "${Green}${ARGV}${ColourReset}") ELSEIF(MessageType STREQUAL INFO) LIST(REMOVE_AT ARGV 0) _message("${Blue}${ARGV}${ColourReset}") ELSE() _message("${ARGV}") ENDIF()Copy the code

Importing the cmake file in the main cmakelists.txt allows you to change the color display for each level of the message command print.

4.8.2 Debug and Release construction

In order to facilitate debugging, we usually compile the debug version of the library or application in the development process, you can use GDB debugging can easily find the specific error. In the main cmake file we just need to add the following Settings:

IF(NOT CMAKE_BUILD_TYPE)                                                        
    SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose Release or Debug" FORCE)  
ENDIF()                                                                         

MESSAGE(STATUS "Build type: " ${CMAKE_BUILD_TYPE})Copy the code

The CMAKE_BUILD_TYPE variable can be set to Debug or Release when executing cmake:

$ cmake .. -DCMAKE_BUILD_TYPE=ReleaseCopy the code

4.8.3 Installation after Construction

For the SDK project, we need to provide the header file and the library file after the compilation, we need to use the install command provided by cmake.

Our installation requirements are:

  • srcEach module header file in the directory can be installed and stored in the original directory
  • Library files are installed and placed inlibdirectory
  • Executable files including test files are placed inbindirectory

First, the installation of module header files is implemented in SRC /{module}/ cmakelists. TXT, which is the installation directory, and filters out. CPP or. C files and cmakelists. TXT files, taking logger module as an example:

INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    DESTINATION ${CMAKE_INSTALL_PREFIX}/include
    FILES_MATCHING 
    PATTERN "*.h"
    PATTERN "*.hpp"
    PATTERN "CMakeLists.txt" EXCLUDE
    )Copy the code

Note: The CMAKE_INSTALL_PREFIX variable defaults to /usr/local on UNIX systems, and c:/Program Files/${PROJECT_NAME} on Windows systems.

Then there is the installation of the library file, which is also related to the ADD_LIBRARY command after the call:

INSTALL(TARGETS module_logger
    ARCHIVE DESTINATION lib                                                     
    LIBRARY DESTINATION lib                                                     
    RUNTIME DESTINATION bin)Copy the code

Finally, the executable will be installed after the ADD_EXECUTABLE command, just as the executable is called after the RUNTIME command. Cmake will be automatically installed into the bin directory that we set up. Here is an example:

INSTALL(TARGETS HelloApp
    ARCHIVE DESTINATION lib                                                     
    LIBRARY DESTINATION lib                                                     
    RUNTIME DESTINATION bin)Copy the code

Execute the installation command:

$ make install DESTDIR=$PWD/installCopy the code

Install /usr/local relative to the current directory:

. ├ ─ ─ bin │ ├ ─ ─ HelloApp │ └ ─ ─ test_logger ├ ─ ─ the include │ ├ ─ ─ common │ │ ├ ─ ─ common. HPP │ │ └ ─ ─ version. The HPP │ └ ─ ─ the logger │ ├ ─ ├ ─ 08.08.00, ├ ─ 08.08.00Copy the code

The installation is complete.

5 concludes

It is also very important to build a good foundation in the software development process. Just as the requirements in the project are clear, in this article, I put the overall framework of C/C++ project development into a template, and continue to summarize and improve, so as to facilitate the rapid development of similar projects in the future. This article also focuses on project construction. The next article will prepare the basic modules necessary to implement a basic C/C++ framework, including logging module, thread pool, common basic function module, configuration import module, unit testing, memory leak checking, etc. If there is any problem or improvement, come to exchange and learn together, finally welcome everyone to follow my public account xiaobai. no advertising, no writing, just to share their learning process ^_^.

The entire build template source can be found on my Github, welcome to star: github.com/yicm/CMakeC…

6 Reference Materials

  • www.oolap.com/cxx-depende…
  • www.yeolar.com/note/2014/1…

Please follow CSDNfreeape or xiaobaiai’s wechat official account or xiaobai.net