arch g++ linux

2019-01-30 15:05:13 CrazyMo_ 阅读数 1241

引言

前一篇文章Android NDK——必知必会之Makefile和CMake基本使用语法概述(七)简单介绍了MakeFile和CMake的相关知识,这篇就从小结下在Linux下交叉编译的基本流程。

一、在Linux下通过gcc/g++编译运行C/C++

1、编译的基本流程

一个C/C++源文件通常需要经过预处理(preprocessing)编译(compilation)、**汇编(assembly)**和 链接(linking) 四个流程才会变成可以在系统平台上的可执行文件,但是并不意味着必须要执行四个过程所有对应的命令,以编译main.c为例:
这里写图片描述

  • 预处理阶段主要处理include和define等,它把#include包含进来的.h 文件插入到#include所在的位置,把源程序中使用到的用#define定义的宏用实际的字符串代替。
//其中 -E的作用是让gcc在预处理结束后停止编译。
root@Mo-vm:/usr/local/src/share# gcc -E main.c -o mainclient.i
root@Mo-vm:/usr/local/src/share# ls
main.c  mainclient.i

  • 编译阶段时,gcc首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc把代码翻译成汇编语言。
// -S的作用是编译后结束,编译生成了汇编文件。
root@Mo-vm:/usr/local/src/share# gcc -S mainclient.i -o mainclient.s
root@Mo-vm:/usr/local/src/share# ls
main.c  mainclient.i  mainclient.s

  • ​ 汇编阶段把 .s文件翻译成二进制机器指令文件.o,这个阶段接收.c, .i, .s的文件都没有问题。
root@Mo-vm:/usr/local/src/share# gcc -c mainclient.s -o mainclient.o
root@Mo-vm:/usr/local/src/share# ls
main.c  mainclient.i  mainclient.o  mainclient.s

  • 链接阶段是链接的是函数库(包含静态库和动态库),在main.c中并没有定义”printf”的函数实现,且在预编译中包含进的”stdio.h”中也只有该函数的声明,系统把这些函数实现都被做到名为libc.so的动态库。
root@Mo-vm:/usr/local/src/share# gcc -o mainclient mainclient.s
root@Mo-vm:/usr/local/src/share# ls
main.c  mainclient  mainclient.i  mainclient.o  mainclient.s
root@Mo-vm:/usr/local/src/share# ./mainclient 
excute c in linux 
root@Mo-vm:/usr/local/src/share# 

默认情况下,gcc编译器只会使用/lib和/usr/lib这两个目录下的库文件,如果存在一个so不在这两个目录,在编译时候就会出现找不到的情况,幸好还可以在**/etc/ld.so.conf文件中可以指定而外的编译链接库路径**,需要引入第三方的库时也可以在**/etc/ld.so.conf**文件里更新

include /etc/ld.so.conf.d/*.conf #引入其他的conf文件
/usr/local/lib  #增加库搜索目录

#编辑完成后 使用 ldconfig 更新

2、在Linux环境下通过gcc/g++把C/C++源文件,编译成可执行的文件(CPU指令集)。

这里写图片描述
如上图所示,生成了两个可执行的文件(仅隶属于与当前编译环境所支持的CPU指令集),但是这两个都无法在Android平台上运行(要验证也很简单找一台root了的手机然后把生成的可执行文件push到手机里,接着就像在Linux执行一样直接用命令行运行即可),虽然Android系统也是基于Linux系统的,但是在Linux上编译出来的可执行文件仅支持当前的CPU,很明显不同平台的CPU所支持的指令集是不一样的(即C/C++不跨平台)。这也是前面我们介绍NDK目录下的子目录platforms下每个系统下都有不同架构的子目录,通过NDK提供的这些工具我们就可以编译对应架构的函数库。

#生成静态库
# -fPIC 产生与位置无关代码 
#可能会被不同的进程加载到不同的位置上,如果共享对象中的指令使用了绝对地址。那么在共享对象被加载时就必须根据相关模块的加载位置对这个地址做调整,也就是修改这些地址,让它在对应进程中能正确访问,那么就不能实现多进程共享一份物理内存(无法动态共享)
gcc -fPIC -c  Test.c -o Test.o
ar r libTest.a Test.o 

#生成动态库
gcc -fPIC -shared Test.c -o libTest.so
#或者
gcc -fPIC -c Test.c  #生成.o
gcc -shared Test.o -o libTest.so

#使用库
#默认优先使用动态库
gcc main.c -L. -lTest -o main
#强制使用静态库
#-Wl 表示传递给 ld 链接器的参数
#最后的 -Bdynamic 表示 默认仍然使用动态库 
gcc main.c -L. -Wl,-Bstatic  -lTest -Wl,-Bdynamic -o main
#使用动态库链接的程序,linux运行需要将动态库路径加入/etc/ld.so.conf
#mac(dylib)和windows(dll)可以将动态库和程序(main)放在一起
#mac 中gcc会被默认链接到xcode的llvm,不支持上面的指定链接动态库

#查看可执行文件符号
nm main

#打包 .a 到so
#--whole-archive: 将未使用的静态库符号(函数实现)也链接进动态库 
#--no-whole-archive : 默认,未使用不链接进入动态库

二、通过NDK进行交叉编译

所谓交叉编译可以简单理解为在一个平台环境下编译出另一个平台可运行的CPU 指令集的过程(这个概念仅仅是我个人的理解)而NDK 中的toolchains\xxx-linux-androideabi-4.9\prebuilt\windows-x86_64\bin目录则提供了一些列不同CPU 架构的交叉编译工具,我们只要合理配置使用即可,如下图所示:
这里写图片描述
以上图形只做了两步工作,配置局部环境变量(非必须步骤),使用NDK中提供的工具进行编译,原本我也以为就是需要使用对应的工作进行编译就可以了,而却提示找不到标准库中的头文件,这是因为在C/C++源码中默认链接到的标准库的(相当于是javac 中会有个classpath的环境变量),而当我们使用NDK中的工具进行编译的时候,需要使用NDK提供的对应的头文件,只要在执行编译命令的时候添加上对应的参数即可。所以总结起来使用NDK进行交叉编译主要步骤有:

1、指定要链接的头文件和库文件

/**
*使用xx作为这一次编译的头文件与库文件的查找目录,配置了之后就会在编译的时候自动去查找XX目录下的usr/include的头文件和usr/lib目录下的库文件,如gcc --sysroot=目录1 main.c 编译时就会去 目录1/usr/include查找头文件和目录1/usr/lib找库文件(一般是.a和.so)
*/
--sysroot=XX   

/**
*指定头文件查找目录,配置之后会自动覆盖--sysroot中的头文件查找目录,查找XX/usr/include的头文件,如gcc --sysroot=目录1 -isysroot 目录2 main.c 编译时就不会去 目录1/usr/include下找头文件而是去 目录2/user/include下查找头文件和到目录1/usr/lib下查找库文件
*/
-isysroot XX   

/**
*指定头文件查找目录,配置之后会直接查找查找XX目录下的头文件,如gcc --sysroot=目录1 -isysroot 目录2  -isystem 目录3 main.c 编译时就不会去 目录1/usr/include下找头文件而是到 目录2/user/include和目录3下查找头文件和到目录1/usr/lib下查找库文件
*/
-isystem XX   

/**
*指定头文件查找目录,配置之后会直接查找查找XX目录下的头文件,如gcc --sysroot=目录1 -isysroot 目录2  -isystem 目录3 -I 目录4 main.c 编译时就不会去 目录1/usr/include下找头文件而是到 目录2/user/include和目录3及目录4下查找头文件和到目录1/usr/lib下查找库文件
*/
-I XX         
/*****其中优先级: -I > -isystem > -isysroot所谓优先级指的是同时配置了这些指令的话编译时会先到优先级大的目录下查找,找到了就不会去查找其他目录的头文件了,所以以上的注释都是在优先级高的找不到的时候再继续往低一级的查找,而且不会去递归去查找指定目录下的子目录********/

/**
*链接指定XX目录下的xx.so,gcc -L目录1 -l库名,比如连接到NDK的日志库和libEGL库可以使用gcc -LC:\AndroidIDE\SDK\ndk-bundle\platforms\android-26\arch-arm\usr\lib -llog.so -lEGL.so(当然也可以使用--sysroot来指定)
*/
-L:XX  -lxx.so  

只要在编译时配置上对应的头文件和库文件目录,即可编译出能成功在Android上可执行的文件,不过这里需要注意的是不同版本的NDK 编译的指令有所不同,我的是在NDK_r16b下编译的,一开始使用 -isystem /usr/local/ndk/android-ndk-r16b/sysroot/usr/include/arm-linux-androideabi/asm 配置时编译报asm/types.h: No such file or directory,原因就是因为 -isystem /usr/local/ndk/android-ndk-r16b/sysroot/usr/include/arm-linux-androideabi/asm这样配置的时候,就回去xxx/asm下去找,
而代码中是include asm/types.h 这样引入的就会去 xxx/asm/asm/types.h查找所以自然出错。简单来说:指定为xxxx, include asm/types.h 就是去xxxx/asm/types.h

这里写图片描述

2、打包成配置成静态库和动态库

库本质上是一种可执行的二进制代码,可以被OS载入到内存中去执行,根据载入内存的时间和流程可以分为静态库(Linux中后缀名为”.a”)和动态库(Linux中后缀名为”.so”)两种:

2.1、静态库

静态库包含了所有执行的代码,库中所有的函数机器码在编译链接时全部被拷贝到可执行的文件中并被添加到和它链接的每一个程序中,简单来说就是把库文件的代码全部加入到可执行文件中,因此生成的文件比较大(打包成APK也较大),但在运行时也就不再需要库文件了,所以静态库节省时间,不需要再进行动态链接,需要调用的代码直接就在代码内部。不过当静态库中某一个函数改变生活,所有使用这个静态库的程序都得重新编译,适用于内部使用。

2.2、动态库

动态库在编译链接时并没有把库文件的全部代码加入到可执行文件中,而是在程序运行时由运行时的链接文件加载库,即运行时再动态申请调用进行链接拷贝,gcc在编译时默认使用动态库,动态库能节省空间,如果一个动态库被两个程序调用,那么这个动态库只需要在内存中即可(因为加载器在加载动态库时,OS会先检查对应的动态库是否已经因为其他程序把这个动态库信息加载到了内存中,若没有加载到内存中,OS会将动态库载入内存,并将它的引用计数设置为1;如果已经加载到内存,仅将动态库的引用计数加1,无需重新加载),而且Java在不经过封装的情况下只能直接使用动态库,因此动态库又称为共享库

2.3、Linux 编译创建静态库和动态库

ldd命令可以查看一个可执行程序依赖的共享库
ldd + 路径/可执行程序

编译创建静态库和动态库的步骤:

  • 首先创建.o文件,可以把java源文件通过编译命令先生成.o文件(编译创建动态库时需要要使用-fpic选项)

“-fpic”的作用是告诉gcc产生的代码不要包含对函数和变量具体内存位置的引用,因为现在还无法知道使用该代码的应用程序会将它连接到哪一段内存地址空间。只有这样编译出的xxx.o才可以被用于建立共享链接库。

  • ar -cr lib库名.a * .o 创建静态库 或者 gcc -shared -o lib库名.so * .o创建动态库

2.4、Linux 使用静态库和动态库

对于静态库:

  • 若静态库放在系统目录**/lib或者/usr/lib**下则执行方式为 gcc xxxx.c -l库名
  • 若静态库没放在系统目录下则执行方式为执行 gcc xxxx.c -L 静态库路径 -l库名或者gcc xxxx.c 路径/整个静态库(大写i)

对于动态库:

  • 若动态库存放在系统目录**/lib或者/usr/lib**下则执行方式为 gcc xxxx.c -l库名
  • 若动态库没有放在系统目录下则先执行 gcc main.c -L 动态库路径 -l 库名

不过这种方式在执行可执行程序的时候可能出现如下错误
./a.out: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory

解决步骤如下

  1. 在/etc/bash.bashrc文件中添加export LD_LIBRARY_PATH=$LD_LRBRARY_PATH:动态库的绝对路径。后source /etc/bash.bashrc

  2. 在/etc/ld.so.conf.d目录下创建一个以.conf为后缀的文件,在这个文件中添加上动态库的绝对路径,后执行sudo ldconfig

ldconfig命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库.

如果第一种的方式都配置完之后出现如下错误

/usr/bin/ld: cannot find -laddsub
collect2: ld returned 1 exit status

这种错误说明编译器找不到需要链接的库,则还需要执行gcc xxxx.c 动态库完整路径/动态库

2.5、Android 5.0以以下 与Android6.0及以上版本关于动态库的依赖链接区别

Android 5.0及以下与6.0及以上时需要注意:若存在两个动态库libhello-jni.so 与 libTest.so。libhello-jni.so依赖于libTest.so (使用NDK下的ndk-depends可查看依赖关系),则:

//<=5.0:
	System.loadLibrary("Test");
	System.loadLibrary("hello-jni");
//>=6.0:
	System.loadLibrary("hello-jni");

比如在已经编译好的静态库clib.a(或者动态库clib.so)中有一个test方法,而现在需要在另一个源文件crazy.c中使用clib.a中的test2方法中使用clib.a中的test方法,最后再把crazy.c打包成一个静态库或者动态库crazy.a或者crazy.so,如果clib是被以静态库引用的话则最终的crazy.a或者crazy.so库都会存在clib.a的所有方法实现(因为编译时就将所有符号加载到输出库),反之则只存在crazy.c的方法实现而不存在clib中的test方法(因为使用动态库是通过在运行时动态加载动态库的方法)

三、CPU架构类型APP_ABI

不同架构的CPU的指令集有所不同,不同 Android 设备可能会使用不同的 CPU,因此支持不同的指令集而需要生成的不同的CPU架构(ndk r17 只支持:armeabi-v7a, arm64-v8a, x86, x86_64)

指令集
基于 ARMv7 的设备上的硬件 FPU 指令 APP_ABI := armeabi-v7a
ARMv8 AArch64 APP_ABI := arm64-v8a
IA-32 APP_ABI := x86
Intel64 APP_ABI := x86_64
MIPS32 APP_ABI := mips
MIPS64 (r6) APP_ABI := mips64
所有支持的指令集 APP_ABI := all

查看Android设备 CPU架构的命令
adb shell cat /proc/cpuinfo
adb shell getprop ro.product.cpu.abi

apk在安装的时候,如果手机是armeabi-v7a的,则会首先查看apk中是否存在armeabi-v7a目录,如果没有就会查找armeabi。所以必须保证cpu目录下so数量一致,如果目标是armeabi-v7a,但是拥有一个armeabi的,也可以把它放到armeabi-v7a目录下,但是反过来不行。

ABI(横 so)/CPU(竖 手机) armeabi armeabi-v7a arm64-v8a x86 x86_64
ARMV5 支持
ARMV7 支持 支持
ARMV8 支持 支持 支持
X86 支持
X86_64 支持 支持

四、配置Android Studio NDK 项目

如果一开始新建Module时没有配置支持NDK,也可以在中途自己配置支持NDK,因为Gradle脚本中各种节点名称是BaseExtension.class中对应的方法名称,通过Groovy语法编写。
在这里插入图片描述
另外如果不知道各节点可以配置哪些属性,可以通过Java的形式来确定,其实就是Java对象的成员变量:

        externalNativeBuild.ndkBuild(new Action<CoreExternalNativeCmakeOptions>() {
            @Override
            void execute(CoreExternalNativeCmakeOptions ndkBuildOptions) {
                ndkBuildOptions.abiFilters=...
                ndkBuildOptions.targets=...
            }
        })

需要注意的是同一节点所在的层次不一样效果也会有所不同,比如在defaultConfig节点中的
externalNativeBuild的作用是指导编译源文件,而与defaultConfig同级的externalNativeBuild的作用是配置Native 构建监本的路径。

1、通过ndkBuild使用Android.mk方式进行配置

import com.android.build.gradle.internal.dsl.CoreExternalNativeCmakeOptions
import com.android.build.gradle.internal.dsl.NdkBuildOptions

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        ...
        // 指导我们的 源文件 编译
        externalNativeBuild{
            ndkBuild{
                // armeabi-v7a
                abiFilters "armeabi-v7a"
            }
        }
// (注释部分的Java形式为说明原理Gradle里貌似不直接支持)       
// externalNativeBuild.ndkBuild(new Action<CoreExternalNativeCmakeOptions>() {
//            @Override
//            void execute(CoreExternalNativeCmakeOptions ndkBuildOptions) {
//                // 你希望编译你的 c/c++ 源文件 编译几种cpu(arm、x86 )
//                ndkBuildOptions.abiFilters.add("armeabi-v7a")
//                ndkBuildOptions.abiFilters.add("x86")
//            }
//        })
        //externalNativeBuild.cmake

        // 应该打包几种cpu,比如: 集成了第三方库 ,第三方库中提供了 arm的 提供了 x86的可以在此处 指导 只打包 arm,生成出来的apk 就只会包含 arm的
        ndk{
            abiFilters "armeabi-v7a"
        }
    }
    // externalNativeBuild.cmake
    //配置 native 的编译脚本路径
//    externalNativeBuild.ndkBuild(new Action<NdkBuildOptions>() {
//        @Override
//        void execute(NdkBuildOptions ndkBuildOptions) {
//            ndkBuildOptions.path = "src/main/cpp/Android.mk"
//    }
//    })

    externalNativeBuild{
        ndkBuild{
            path  "Android.mk"
        }
    }
    
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0-rc01'
}

1.1、在Module目录下的Gradle脚本android里的defaultConfig节点下添加externalNativeBuild配置cpu的eabi架构

android {
    compileSdkVersion 26
    ...
	    defaultConfig {
	    	...
			externalNativeBuild{
			            ndkBuild{
			            //设置源文件只编译armeabi-v7a 架构的
			                abiFilters 'armeabi-v7a'
			            }
			        }
	        }
	        
			 ndkBuild{
            //设置只打包出包含armeabi-v7a 架构的apk
                abiFilters 'armeabi-v7a'
            }
		}
}

1.2、编写自己的Android.mk文件

Android.mk

#源文件在的位置。宏函数 my-dir 返回当前目录(包含 Android.mk 文件本身的目录)的路径。
LOCAL_PATH := $(call my-dir)

$(info "LOCAL_PATH:======== ${LOCAL_PATH}")

#引入其他makefile文件。CLEAR_VARS 变量指向特殊 GNU Makefile,可为您清除许多 LOCAL_XXX 变量
#不会清理 LOCAL_PATH 变量
include $(CLEAR_VARS)
#存储您要构建的模块的名称 每个模块名称必须唯一,且不含任何空格
#如果模块名称的开头已是 lib,则构建系统不会附加额外的前缀 lib;而是按原样采用模块名称,并添加 .so 扩展名。
LOCAL_MODULE := abc
#包含要构建到模块中的 C 和/或 C++ 源文件列表 以空格分开
LOCAL_SRC_FILES := native-lib.c \
c.c
#构建动态库
include $(BUILD_SHARED_LIBRARY)

1.3、在Module目录下的Gradle脚本android里的与defaultConfig节点同级的节点添加

android {
    compileSdkVersion 26
    ...
	    defaultConfig {
	    	...
			externalNativeBuild{
			            ndkBuild{
			                abiFilters 'armeabi-v7a'
			            }
			        }
	        }
		}
		...
		externalNativeBuild{
			            ndkBuild{
			           		//配置指向Android.mk文件的路径,如:path "Android.mk"代表与module下的build.gradle脚本同目录
			                path "xxxx/xxx/Android.mk"
			            }
			        }
	        }
}

2、通过CMakeList方式进行配置

1.1、在Module目录下的Gradle脚本android里的defaultConfig节点下添加externalNativeBuild配置cpu的eabi架构

android {
    compileSdkVersion 26
    ...
	    defaultConfig {
	    	...
			externalNativeBuild{
			            ndkBuild{
			                abiFilters 'armeabi-v7a'
			            }
			        }
	        }
		}
}

1.2、编写自己的CMakeList.txt文件


cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

file(GLOB LIBGIF_SOURCE src/main/cpp/*.c src/main/cpp/*.cpp)
set(LIBNAME crazygif)

add_library( # Sets the name of the library.
             ${LIBNAME}

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             ${LIBGIF_SOURCE})

include_directories(src/main/cpp)

target_link_libraries( # Specifies the target library.
                       ${LIBNAME}
                       # Links the target library to the log library included in the NDK.

                       jnigraphics
                       log )

1.3、在Module目录下的Gradle脚本android里的与defaultConfig节点同级的节点添加externalNativeBuild 节点

    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
2019-05-27 14:46:00 weixin_30725315 阅读数 223

# apt install g++-aarch64-linux-gnu
Reading package lists... 0%

Reading package lists... Done

Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
daemon linux-headers-4.4.0-141 linux-headers-4.4.0-141-generic linux-headers-4.4.0-142
linux-headers-4.4.0-142-generic linux-headers-4.4.0-143 linux-headers-4.4.0-143-generic linux-headers-4.4.0-21
linux-headers-4.4.0-21-generic linux-image-4.4.0-141-generic linux-image-4.4.0-142-generic
linux-image-4.4.0-143-generic linux-image-4.4.0-21-generic linux-image-extra-4.4.0-141-generic
linux-image-extra-4.4.0-142-generic linux-image-extra-4.4.0-21-generic linux-modules-4.4.0-143-generic
linux-modules-extra-4.4.0-143-generic
Use 'sudo apt autoremove' to remove them.
The following additional packages will be installed:
g++-5-aarch64-linux-gnu libstdc++-5-dev-arm64-cross
Suggested packages:
gcc-5-doc libstdc++6-5-dbg-arm64-cross
The following NEW packages will be installed:
g++-5-aarch64-linux-gnu g++-aarch64-linux-gnu libstdc++-5-dev-arm64-cross
0 upgraded, 3 newly installed, 0 to remove and 296 not upgraded.
Need to get 6,841 kB of archives.
After this operation, 32.6 MB of additional disk space will be used.
Get:1 http://mirrors.aliyun.com/ubuntu xenial-updates/main amd64 libstdc++-5-dev-arm64-cross all 5.4.0-6ubuntu1~16.04.9cross1 [1,357 kB]
Get:2 http://mirrors.aliyun.com/ubuntu xenial-updates/main amd64 g++-5-aarch64-linux-gnu amd64 5.4.0-6ubuntu1~16.04.9cross1 [5,483 kB]
Get:3 http://mirrors.aliyun.com/ubuntu xenial/main amd64 g++-aarch64-linux-gnu amd64 4:5.3.1-1ubuntu1 [1,024 B]
Fetched 6,841 kB in 4s (1,485 kB/s)
Selecting previously unselected package libstdc++-5-dev-arm64-cross.
(Reading database ... 422298 files and directories currently installed.)
Preparing to unpack .../libstdc++-5-dev-arm64-cross_5.4.0-6ubuntu1~16.04.9cross1_all.deb ...
Unpacking libstdc++-5-dev-arm64-cross (5.4.0-6ubuntu1~16.04.9cross1) ...
Selecting previously unselected package g++-5-aarch64-linux-gnu.
Preparing to unpack .../g++-5-aarch64-linux-gnu_5.4.0-6ubuntu1~16.04.9cross1_amd64.deb ...
Unpacking g++-5-aarch64-linux-gnu (5.4.0-6ubuntu1~16.04.9cross1) ...
Selecting previously unselected package g++-aarch64-linux-gnu.
Preparing to unpack .../g++-aarch64-linux-gnu_4%3a5.3.1-1ubuntu1_amd64.deb ...
Unpacking g++-aarch64-linux-gnu (4:5.3.1-1ubuntu1) ...
Processing triggers for man-db (2.7.5-1) ...
Setting up libstdc++-5-dev-arm64-cross (5.4.0-6ubuntu1~16.04.9cross1) ...
Setting up g++-5-aarch64-linux-gnu (5.4.0-6ubuntu1~16.04.9cross1) ...
Setting up g++-aarch64-linux-gnu (4:5.3.1-1ubuntu1) ...
root@vmuser-virtual-machine:/home/vmuser/sdd/svn_RK3328/trunk/rootfs/package/sntool# aarch64-linux-gnu-g
aarch64-linux-gnu-g++ aarch64-linux-gnu-gcc-ar-5 aarch64-linux-gnu-gcov
aarch64-linux-gnu-g++-5 aarch64-linux-gnu-gcc-nm aarch64-linux-gnu-gcov-5
aarch64-linux-gnu-gcc aarch64-linux-gnu-gcc-nm-5 aarch64-linux-gnu-gcov-tool
aarch64-linux-gnu-gcc-5 aarch64-linux-gnu-gcc-ranlib aarch64-linux-gnu-gcov-tool-5
aarch64-linux-gnu-gcc-ar aarch64-linux-gnu-gcc-ranlib-5 aarch64-linux-gnu-gprof

转载于:https://www.cnblogs.com/lianghong881018/p/10930655.html

2019-04-11 23:09:35 Guet_Kite 阅读数 1065

你好!这里是风筝的博客,

欢迎和我一起交流。


最近移植QT到arm板子上,发现一些问题,记录一下:
在ubuntu上交叉编译QT时执行./config之后发现错误:

 Failed to process makespec for platform 'linux-arm-gnueabi-g++'

也就是配置QT时候出现 Failed to process makespec for platform ‘linux-arm-gnueabi-g++’
因为移植QT时是参考这篇文章的:
移植QT5.6到嵌入式开发板(史上最详细的QT移植教程)
因为板子是A7板子,所以配置时:
vi qtbase/mkspecs/linux-arm-gnueabi-g++/qmake.conf

#关于arch部分:
QT_QPA_DEFAULT_PLATFORM = linuxfb 
QMAKE_CFLAGS  += -msoft-float -D__GCC_FLOAT_NOT_NEEDED -march=armv7-a -mtune=cortex-a9
QMAKE_CXXFLAGS += -msoft-float -D__GCC_FLOAT_NOT_NEEDED -march=armv7-a -mtune=cortex-a9

就是这里了导致的错误,应该配置为:

#关于arch部分:
QT_QPA_DEFAULT_PLATFORM = linuxfb 
QMAKE_CFLAGS_RELEASE += -O2 -march=armv7-a
QMAKE_CXXFLAGS_RELEASE += -O2 -march=armv7-a

这样配置就可以了,QT配置成功之后直接make && make install
等待漫长的编译安装即可。

然后把装好的QT放到板子文件系统里并设置环境即可,参考上面的文章。
我的配置如下:将配置写成了脚本,直接执行即可:

################################################
# File Name: build.sh
# Created Time: Tue 26 Mar 2019 08:07:01 AM PDT
################################################
#!/bin/bash
./configure -prefix /work/qt/qt_arm \
 -opensource \
 -release \
 -confirm-license \
 -xplatform linux-arm-gnueabi-g++ \
 -shared \
 -no-qml-debug \
 -no-gtkstyle \
 -qt-zlib \
 -no-gif \
 -qt-libjpeg \
 -no-nis \
 -no-opengl \
 -no-glib \
 -no-dbus \
 -no-rpath \
 -no-sse2 -no-sse3 -no-ssse3 -no-sse4.1 -no-sse4.2 \
 -no-avx \
 -no-openssl \
 -nomake tools \
 -qreal float \
 -qt-libpng \
 -nomake examples \
 -skip qtcanvas3d \
 -skip qt3d \
 -no-sql-sqlite \
 -no-sql-sqlite2 \
 -no-sql-db2 \
 -no-sql-ibase \
 -no-sql-oci \
 -no-sql-odbc \
 -no-sql-tds \
 -no-accessibility \
 -no-pkg-config \
 -no-xrandr \
 -no-xrender \
 -nomake tests \
 -v \

因为我没有触摸屏,所以没有用libts,这个配置把大部分东西都去掉了,这样QT比较精简。
最后我把这个配置脚本和安装好之后的QT上传一下吧:
交叉编译QT5.6

2019-08-17 11:21:03 weixin_40643198 阅读数 27

g++的安装
首先我们要确保linux上的g++编译器已经安装了,运行g++ -v查看g++版本号,也为测试是否有安装g++,如下所示:

$ g++ -v

如果已安装,会显示如下信息:

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04.4' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.4) 

没有安装的小伙伴使用命令安装即可,如下:

$ yum install gcc-c++ -y

g++的使用
程序 g++ 是将 gcc 默认语言设为 C++ 的一个特殊的版本,链接时它自动使用 C++ 标准库而不用 C 标准库。通过遵循源码的命名规范并指定对应库的名字,用 gcc 来编译链接 C++ 程序是可行的,如下例所示:

$ gcc main.cpp -lstdc++ -o main

下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码:

#include <iostream>
using namespace std;
int main()
{
    cout << "Hello, world!" << endl;
    return 0;
}

最简单的编译方式:

$ g++ helloworld.cpp

由于命令行中未指定可执行程序的文件名,编译器采用默认的 a.out。程序可以这样来运行:

$ ./a.out
Hello, world!

通常我们使用 -o 选项指定可执行程序的文件名,以下实例生成一个 helloworld 的可执行文件:

$ g++ helloworld.cpp -o helloworld

执行 helloworld:

$ ./helloworld
Hello, world!

如果是多个 C++ 代码文件,如 runoob1.cpp、runoob2.cpp,编译命令如下:

$ g++ runoob1.cpp runoob2.cpp -o runoob

生成一个 runoob 可执行文件。

g++ 有些系统默认是使用 C++98,我们可以指定使用 C++11 来编译 main.cpp 文件:

g++ -g -Wall -std=c++11 main.cpp

g++ 常用命令选项

选项 解释
-ansi 只支持 ANSI 标准的 C 语法。这一选项将禁止 GNU C 的某些特色, 例如 asm 或 typeof 关键词。
-c 只编译并生成目标文件。
-DMACRO 以字符串"1"定义 MACRO 宏。
-DMACRO=DEFN 以字符串"DEFN"定义 MACRO 宏。
-E 只运行 C 预编译器。
-g 生成调试信息。GNU 调试器可利用该信息。
-IDIRECTORY 指定额外的头文件搜索路径DIRECTORY。
-LDIRECTORY 指定额外的函数库搜索路径DIRECTORY。
-lLIBRARY 连接时搜索指定的函数库LIBRARY。
-m486 针对 486 进行代码优化。
-o FILE 生成指定的输出文件。用在生成可执行文件时。
-O0 不进行优化处理。
-O 或 -O1 优化生成代码。
-O2 进一步优化。
-O3 比 -O2 更进一步优化,包括 inline 函数。
-shared 生成共享目标文件。通常用在建立共享库时。
-static 禁止使用共享连接。
-UMACRO 取消对 MACRO 宏的定义。
-w 不生成任何警告信息。
-Wall 生成所有警告信息。
2018-03-29 15:58:31 u010921682 阅读数 7219

更新Ubuntu的gcc和g++版本

首先安装gcc和g++版本,依次进行如下操作:

sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install gcc-4.8
sudo apt-get install g++-4.8

进入/usr/bin/把gcc/g++文件夹删除,建立链接到gcc-4.8/g++-4.8:

cd /usr/bin
sudo rm gcc
sudo ln -s gcc-4.8 gcc
sudo rm g++
sudo ln -s g++-4.8 g++

查看gcc/g++版本号

linux@ubuntu:~$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.8/lto-wrapper
Target: i686-linux-gnu
Configured with: ../src/configure -v –with-pkgversion=’Ubuntu 4.8.1-2ubuntu1~12.04’ –with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs –enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ –prefix=/usr –program-suffix=-4.8 –enable-shared –enable-linker-build-id –libexecdir=/usr/lib –without-included-gettext –enable-threads=posix –with-gxx-include-dir=/usr/include/c++/4.8 –libdir=/usr/lib –enable-nls –with-sysroot=/ –enable-clocale=gnu –enable-libstdcxx-debug –enable-libstdcxx-time=yes –enable-gnu-unique-object –enable-plugin –with-system-zlib –disable-browser-plugin –enable-java-awt=gtk –enable-gtk-cairo –with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386/jre –enable-java-home –with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386 –with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-i386 –with-arch-directory=i386 –with-ecj-jar=/usr/share/java/eclipse-ecj.jar –enable-objc-gc –enable-targets=all –enable-multiarch –disable-werror –with-arch-32=i686 –with-multilib-list=m32,m64 –with-tune=generic –enable-checking=release –build=i686-linux-gnu –host=i686-linux-gnu –target=i686-linux-gnu
Thread model: posix
gcc version 4.8.1 (Ubuntu 4.8.1-2ubuntu1~12.04)

linux@ubuntu:~$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.8/lto-wrapper
Target: i686-linux-gnu
Configured with: ../src/configure -v –with-pkgversion=’Ubuntu 4.8.1-2ubuntu1~12.04’ –with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs –enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ –prefix=/usr –program-suffix=-4.8 –enable-shared –enable-linker-build-id –libexecdir=/usr/lib –without-included-gettext –enable-threads=posix –with-gxx-include-dir=/usr/include/c++/4.8 –libdir=/usr/lib –enable-nls –with-sysroot=/ –enable-clocale=gnu –enable-libstdcxx-debug –enable-libstdcxx-time=yes –enable-gnu-unique-object –enable-plugin –with-system-zlib –disable-browser-plugin –enable-java-awt=gtk –enable-gtk-cairo –with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386/jre –enable-java-home –with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386 –with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-i386 –with-arch-directory=i386 –with-ecj-jar=/usr/share/java/eclipse-ecj.jar –enable-objc-gc –enable-targets=all –enable-multiarch –disable-werror –with-arch-32=i686 –with-multilib-list=m32,m64 –with-tune=generic –enable-checking=release –build=i686-linux-gnu –host=i686-linux-gnu –target=i686-linux-gnu
Thread model: posix
gcc version 4.8.1 (Ubuntu 4.8.1-2ubuntu1~12.04)