Installation and use of CMake and cross tool compilation chain

1. Principle

  • Cmake is a cross platform compilation tool, which is more advanced than make and is much more convenient to use. Cmake mainly writes CMakeLists.txt file, then uses cmake command to convert CMakeLists.txt file into makefile file required by make, and finally uses make command to compile source code to generate executable program or shared library.
  • Cross compilation refers to the use of cross compilation tool chain to compile and link on the host machine to generate programs or shared libraries running on the target machine (embedded arm)

2. Test environment

Host system: ubantu18.04

Target machine: arm

Cross compilation tool chain version: gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi

Download address of cross compilation tool chain: https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabi/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz

3. Install cmake and configure the cross compilation environment

  • Installing cmake
$ sudo apt update
$ sudo apt insatall cmake
  • Install make
$ sudo apt install make
  • Download cross compilation tool chain

    Download the cross compilation tool chain according to your needs. If it is available locally, it can be copied directly without downloading.

$ wget -c https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabi/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz # download cross compilation tool chain
$ tar xvf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz   # Decompress the cross compilation tool chain

The decompressed cross compilation tool chain. According to individual needs. For ease of use, this article is placed in * * / usr/local/arm_4.9.4 * * directory

$ sudo cp -rf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi  /usr/local/arm_4.9.4

Add the cross compilation environment configuration to the system path * * (if this step is not performed, the global path needs to be written) * *.

Add export PATH="$PATH:/usr/local/arm_4.9.4/bin" at the end of the. bashrc file

$ cd 
$ sudo vim .bashrc    # Open the. bashrc file 
# Add export PATH="$PATH:/usr/local/arm_4.9.4/bin" at the end

After adding, reopen the terminal. Or execute

$ source .bashrc

Execute the following command to see if the installation is successful

 $ arm-linux-gnueabi-gcc -v   # A pile of information appears to prove that the installation was successful.

The environment is configured. Like gcc, you can use arm linux gnueabi gcc and arm linux gnueabi-g + + to compile programs running on arm

For example:

$ arm-linux-gnueabi-gcc -o test test.cpp   # Compile test.cpp into a program running on arm

4. Use of cmake

Cmake mainly writes CMakeLists.txt file, then uses cmake command to convert CMakeLists.txt file into makefile file required by make, and finally uses make command to compile source code to generate executable program or shared library.

4.1 examples

If you compile the project under the Test folder, write the CMakelists.txt file required for cross compilation. First, under the Test project, create a new CMakelists.txt file.

Test/CMakelists.txt

# Specifies the minimum version of cmake required
cmake_minimum_required(VERSION 3.0)

#Setting the environment for cross compilation
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

#Specify GCC G + + for cross compilation. If the environment variable is not configured, write the absolute path here
set(CMAKE_C_COMPILER "arm-linux-gnueabi-gcc")
set(CMAKE_CXX_COMPILER "arm-linux-gnueabi-g++")

############## The following items can not be set(Measured can)´╝îSteps on official documents ############
#Specifies the directory of the cross compilation environment
set(CMAKE_FIND_ROOT_PATH "/usr/local/arm_4.9.4/arm-linux-gnueabi")
#Never look for tool programs in the specified directory (cross compilation). (compiled using the host's tools)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
#Find library files only in the specified directory (cross compilation)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
#Find header files only in the specified directory (cross compilation)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
#Find dependent packages only in the specified directory (cross compilation)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
###################################################################

#Set the parameters of C + + compilation (set them yourself as needed)
set(CMAKE_CXX_FLAGS "-std=c++11 -DTEST -pthread -Wall -O0 -g3 -Wall  -fmessage-length=0 -fPIC")
set(CMAKE_C_FLAGS "-std=c99 -Wall -O0 -g3 -Wall -fmessage-length=0")
# -Wall: display warnings at compile time
# -O: Select the compiler optimization level, - O0 does not optimize - O1 -O2 -O3 to varying degrees
# -G: generate debugging information, which will be used in debug. The level of debugging information- g3 
#			    Generate debugging information that gdb can use as much as possible. The default is - g2. The more information, the larger the compiled program.
# -std=c++11: compiled according to the C + + standard
# -Fmessage length = 0: the output information will automatically wrap according to the width of the console, so you can see the full output information
# -fPIC: used at the compilation stage to tell the compiler to generate location independent code
#			    (Position-Independent Code).  It can be loaded anywhere
# -DTEST 	 :   Set the macro definition of TEST. Another way to set the macro definition is to use add directly_ Definitions (- D TEST) add

add_definitions(-D TEST2)	# Add macro for TEST2

#Set the compiled version to debug. If you want to compile the realse version, you can write realse directly
set(CMAKE_BUILD_TYPE "debug")  

# The directory of the header file library referenced by the program.
include_directories(
    ${PROJECT_SOURCE_DIR}	# The file path of the current project. If you need another library, continue to write the path of the required library.
)

# Find the source file to compile.
# The file function recursively searches all. cpp and. c files in folders and subfolders into SRC
# The list function excludes the. cpp and. c files under build (in the process of making, the cpp and c files under bulid will be generated to avoid conflicts)
# In this way, we put the source files to be compiled into SRC
# There are many ways to search for source files. I think this is the most convenient one. Others are feasible
file(GLOB_RECURSE SRC *.cpp *.c)
file(GLOB_RECURSE SRC_EXPECT build/*.cpp build/*.c)
list(REMOVE_ITEM SRC ${SRC_EXPECT})


##################### If a shared library is generated ########################
# Set the name of the build library
set(LIB_NAME "test")
# Compile and generate shared libraries
add_library("${LIB_NAME}"  SHARED  ${SRC})
# ${LIB_NAME}: is the name of the library
# SHARED: indicates that the generated is a dynamic library. If you want to compile to a STATIC library, replace with the STATIC parameter
# ${SRC}: source file to compile

### Note: if the executable file is not generated, subsequent operations to connect to the dynamic library are not required.
###       When generating an executable file, a block is connected
###########################################################



#################### If an executable is generated#####################
# Set the name of the executable file to be generated
set(SRC_NAME "test")
# Compile to generate executable files
add_executable("${SRC_NAME}" ${SRC})
# ${SRC_NAME}: generate executable file
# ${SRC}: source file to compile

# Connect the executable file to the dynamic library. There are many ways to connect the dynamic library. You can baidu by yourself.
target_link_libraries("${SRC_NAME}" 
  	xxx.so			# For example, to connect xxx.so dynamic library
    )
###Note that if multiple dynamic libraries are connected, pay attention to the order and dependent libraries,
### Be sure to put it in front. Otherwise, the compilation passes and cannot be run on the device.
### If there is a problem with the sequence, BUSERROR or some other errors will be reported in the actual measurement, which is difficult to locate
#############################################################

During the running process of cmake, many temporary files will be generated. Usually, a new build folder will be created, where makefile s will be generated and compiled. (this is why we need to exclude. c and. cpp under build when searching for the source files to be compiled.)

Create a new build folder (Test/build /) under the Test directory.

$ cd build
$ cmake ..         # Generating makefile files using cmake

After executing the above program, you can see that the makefile file is generated. Then compile with make

$ make -j8		  # Compile simultaneously with 8 threads

After compilation, if the library is compiled, the libtest.so dynamic library file will be generated. View information about generating dynamic libraries

$ file libtest.so    # Use file to view the type of compiled dynamic library. Under normal circumstances, the following information will appear, indicating that the compilation is successful.

libtest.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=31bd40c56628e01d782f12adfb34bf9095619124, with debug_info, not stripped

Similarly, if the executable is compiled, the test executable is generated. You can also use file to view the type of its file.

be careful:

  • Case insensitive in CMakeLists file!!! Function variable case is OK!!! Sometimes it doesn't matter whether you put quotation marks or not!!!

  • During compilation, pay attention to the macros or parameters that may be added to different projects, and modify them as appropriate

  • After using cmake to generate a Makefile, if there are new files, you need to execute cmake again. If you just modify the contents of the file, just make it directly.

  • The number of threads used in make compilation is generally slightly larger than the number of your logical cores, and the compilation efficiency is the highest. If the number of threads is much larger than the number of logical cores, the number of switches between threads will increase, which will cause a waste of switching time. Too few threads and slow compilation efficiency. However, you need to consider your memory. If the memory is too small, too many threads will reduce the compilation efficiency and cause the computer to get stuck. Choose according to the actual situation.

Tags: Linux cmake Embedded system

Posted on Sun, 05 Dec 2021 13:33:22 -0500 by earl_dc10