• CMake及交叉工具编译链的安装使用


    1. 原理

    • CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists.txt文件,然后用cmake命令CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库
    • 交叉编译,是利用交叉编译工具链,在宿主机器执行编译链接生成目标机(嵌入式arm)运行的程序或者共享库

    2. 测试环境

    宿主系统: ubantu18.04

    目标机arm

    交叉编译工具链版本:gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi

    交叉编译工具链的下载地址: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. 安装cmake配置交叉编译环境

    • 安装cmake
    $ sudo apt update
    $ sudo apt insatall cmake
    • 安装make
    $ sudo apt install make
    • 下载交叉编译工具链

      根据自己的需要,下载交叉编译工具链。如果本地有,可以直接拷贝使用,无须再下载。

    $ 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 # 下载交叉编译工具链
    $ tar xvf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz   # 解压交叉编译工具链

    ​ 将解压后的交叉编译工具链。根据个人,自己需要的目录下。本文为了方便使用,放到**/usr/local/arm_4.9.4**目录下

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

    ​ 将交叉编译环境配置添加到系统的路径中**(如果不进行这一步,用到时需要写全局路径)**。

    ​ 在 .bashrc 文件最后添加 export PATH="$PATH:/usr/local/arm_4.9.4/bin"

    $ cd 
    $ sudo vim .bashrc    # 打开.bashrc 文件 
    # 在最后添加 export PATH="$PATH:/usr/local/arm_4.9.4/bin"

    ​ 添加完成后,重新打开终端。或者执行

    $ source .bashrc

    ​ 执行一下命令, 查看是否安装成功

     $ arm-linux-gnueabi-gcc -v   # 出现一堆信息证明安装成功。

    ​ 环境就配置完成了。和gcc一样,可以使用arm-linux-gnueabi-gcc 和 arm-linux-gnueabi-g++ 编译arm上运行的程序了

    如:

    $ arm-linux-gnueabi-gcc -o test test.cpp   # 将test.cpp 编译成arm上运行的程序了

    4. Cmake的使用

    CMake主要是编写CMakeLists.txt文件,然后用cmake命令CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库

    4.1 实例

    假如编译Test文件夹下面的工程,撰写交叉编译所需要的CMakelists.txt文件。首先在Test工程下面,新建CMakeLists.txt文件。

    Test/CMakeLists.txt

    # 指定要求cmake的最低版本
    cmake_minimum_required(VERSION 3.0)
    
    #设置交叉编译的环境
    set(CMAKE_SYSTEM_NAME Linux)
    set(CMAKE_SYSTEM_PROCESSOR arm)
    
    #指定交叉编译的gcc  g++。如果没有配置到环境变量,此处写绝对路径
    set(CMAKE_C_COMPILER "arm-linux-gnueabi-gcc")
    set(CMAKE_CXX_COMPILER "arm-linux-gnueabi-g++")
    
    ############## 以下几条可以不设置(实测可以),官方文档上步骤 ############
    #指定交叉编译环境的目录
    set(CMAKE_FIND_ROOT_PATH "/usr/local/arm_4.9.4/arm-linux-gnueabi")
    #从来不在指定目录(交叉编译)下查找工具程序。(编译时利用的是宿主的工具)
    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(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
    ###################################################################
    
    #设置C++ 编译的参数(根据需要自己设置)
    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       :  编译时显示警告信息
    # -O          : 选择编译器优化的级别,-O0 不优化  -O1 -O2 -O3 不同程度的优化
    # -g          :  生成调试信息,debug会用到。调试信息的级别。-g3 
    #			    尽可能的生成gdb的可以使用的调试信息。默认为-g2。信息越多,编译出的程序越大。
    # -std=c++11  : 编译所按照C++的标准
    # -fmessage-length=0 :输出信息会根据控制台的宽度自动换行,这样就能看全输出信息了
    # -fPIC       : 作用于编译阶段,告诉编译器产生与位置无关代码
    #			    (Position-Independent Code)。加载到任意位置都能执行
    # -DTEST	 : 设置TEST的宏定义,另外一种设置宏定义的方式可以直接使用 add_definitions(-D TEST) 添加
    
    add_definitions(-D TEST2)	# 添加TEST2的宏
    
    #设置编译的版本为debug版本。如果要编译realse版本,直接写realse即可
    set(CMAKE_BUILD_TYPE "debug")  
    
    # 程序所引用的头文件库目录。
    include_directories(
        ${PROJECT_SOURCE_DIR}	# 当前工程的文件路径。如果需要其他库,要继续写所需要库的路径。
    )
    
    # 查找要需要编译的源文件。
    # file函数将递归查文件夹及子文件夹下的所有.cpp 和 .c文件放到SRC中
    # list函数排除build下面的.cpp和.c文件(在make过程中,会在bulid下面产生测试的cpp和c文件,避免冲突)
    # 这样我们将所需要编译的源文件放到SRC中
    # 有很多种搜索源文件的方法,感觉这是最省事的一种,其他可行百度
    file(GLOB_RECURSE SRC *.cpp *.c)
    file(GLOB_RECURSE SRC_EXPECT build/*.cpp build/*.c)
    list(REMOVE_ITEM SRC ${SRC_EXPECT})
    
    
    ##################### 如果生成共享库 ########################
    # 设置生成库的名字
    set(LIB_NAME "test")
    # 编译生成共享库
    add_library("${LIB_NAME}"  SHARED  ${SRC})
    # ${LIB_NAME} : 为库的名字
    # SHARED :表示生成的是动态库。如果要编译成静态库替换成 STATIC 参数
    # ${SRC} :需要编译的源文件
    
    ### 注意: 如果不是生成可执行文件,则不需要进行后续的连接动态库的操作。
    ###       在生成可执行可执行文件时,一块进行连接
    ###########################################################
    
    
    
    #################### 如果生成可执行文件#####################
    # 设置生成可执型文件的名字
    set(SRC_NAME "test")
    # 编译生成可执型文件
    add_executable("${SRC_NAME}" ${SRC})
    # ${SRC_NAME} : 生成可执型文件
    # ${SRC} :需要编译的源文件
    
    # 将可执行文件连接动态库,连接动态库的方式有很多,可以自行百度。
    target_link_libraries("${SRC_NAME}" 
      	xxx.so			# 例如要连接xxx.so动态库
        )
    ###注意, 连接的多个动态库库如果有相互依赖关系,注意顺序,被依赖的库,
    ### 一定要放到前面。否则编译通过,放到设备上无法运行。
    ### 如果顺序有问题,实测会报BUSERROR或者一些其他的错误,很难定位
    #############################################################

    cmake在运行过程中,会产生很多临时文件。通常会新建一个build文件夹,在里面生成makefile,编译。(这也是我们刚在搜索需要编译的源文件时,需要把build下面的.c 和 .cpp排除在外)

    在Test目录下新建build文件夹(Test/build/)。

    $ cd build
    $ cmake ..         # 使用cmake 生成makefile 文件

    执行完上述程序,可以看到生成了makefile文件。随后利用make进行编译

    $ make -j8		  # 使用8个线程同时编译

    编译完成后,如果编译库的话会生成 libtest.so 动态库文件。查看生成动态库的信息

    $ file libtest.so    # 使用file查看编译动态库的类型。正常情况下会出现以下信息表示编译成功。
    
    libtest.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=31bd40c56628e01d782f12adfb34bf9095619124, with debug_info, not stripped

    同样,如果编译可执行文件,会生成test可执行程序。同样可以使用file查看其文件的类型。

    注意:

    • CMakeLists文件中不区分大小写!!!函数变量大小写都行!!!有时候加不加引号有时候也无所谓!!!

    • 编译时注意不同工程可能添加的宏或者参数不同,酌情修改

    • 使用cmake生成Makefile后,如果有新增文件,需要重新执行cmake。如果只是修改文件的内容,直接make就行。

    • make 编译时使用的线程数一般比你的逻辑核心数略大一点,编译效率最高。如果线程数远远大于逻辑核心数,线程之间切换次数增大,会造成切换时间的浪费。线程过少,编译效率慢。但是需要考虑你的内存情况,如果内存过小,过多线程反而会降低编译效率,造成电脑卡住,根据实际情况择情选择。

     
  • 相关阅读:
    对象遍历 for in ,数组遍历for in 与 for of 的区别
    计算一个数组中key值相同的数量
    VUE的两种跳转push和replace对比区别
    微信公众号二次分享ios分享失败问题
    获得对象中的键或值
    第一个table根据checkbox选择tr,在另一个table中显示对应索引的tr(jq遍历的运用)
    checkbox 全选反选 获得所有的checkbox
    为什么jQuery要return this.each()?
    用jq代码写出一个轮播图。
    页面滚动到一定位置,两个div 朝中间运动。
  • 原文地址:https://www.cnblogs.com/lidabo/p/16640210.html
Copyright © 2020-2023  润新知