我收集了一些学习用的材料,其中蕴含了很多学习,面试,中高进阶fluuter材料,还有很多视频详解,如果有同学想进一步理解,详情请看文末。也欢送各路大神门前来装X。
穿插编译
穿插编译就是程序的编译环境和理论运行环境不统一,即在一个平台上生成另一个平台上的可执行代码。
比方NDK,你在Mac、Win或者Linux上生成的C/C++的代码要在Android平台上运行,就须要应用到穿插编译了。
艰深点说就是你的电脑和手机应用的CPU不同,所以CPU的指令集就不同,比方arm的指令集在X86上就不能运行。
罕用的编译工具链
gcc
GNU C编译器。本来只能解决C语言,很快扩大,变得可解决C++。(GNU打算,又称革奴打算。指标是创立一套齐全自在的操作系统)
Android在之后彻底移除了gcc,默认应用clang编译,所以应用不同版本的ndk对ffmpeg进行穿插编译时会呈现同样的脚本在旧版的ndk能编译通过,然而旧版的就不编译不通过的问题。
笔者会在前面的学习过程中应用最新的ndk对最新版的ffmpeg进行穿插编译,并且会通过文章记录学习过程,感兴趣的同学能够继续关注。
g++
GNU c++编译器
gcc和g++都可能编译c/c++,然而编译时候行为不同。
对于gcc与g++会有以下区别:
后缀为.c的源文件,gcc把它当作是C程序,而g++当作是C++程序;后缀为.cpp的,两者都会认为是c++程序
g++会主动链接c++规范库stl,gcc不会
gcc不会定义__cplusplus宏,而g++会
clang
clang 是一个C、C++、Object-C的轻量级编译器。基于LLVM (LLVM是以C++编写而成的构架编译器的框架零碎,能够说是一个用于开发编译器相干的库)
比照gcc,clang具备编译速度更快、编译产出更小等长处,然而某些软件在应用clang编译时候因为源码中内容的问题会呈现谬误。
另外clang++也是一个编译器,clang++与clang就相当于gcc与g++的区别。
动态库和动静库
动态库是指编译链接时,把库文件的代码全副退出到可执行文件中,因而生成的文件比拟大,但在运行时也就不再须要库文件了。Linux中后缀名为”.a”。
动静库则与动态库相同,在编译链接时并没有把库文件的代码退出到可执行文件中,而是在程序执行时由运行时链接文件加载库。Linux中后缀名为”.so”。gcc在编译时默认应用动静库。
总结起来就是动态库节俭运行工夫,动静库节俭运行空间,典型的工夫换空间,在开发过程中可依据状况自行抉择。
Java中在不通过封装的状况下只能间接应用动静库。
编译器过程
一个C/C++文件要通过预处理(preprocessing)、编译(compilation)、汇编(assembly)、和连贯(linking)能力变成可执行文件。
咱们以最简略的一个c语言程序来做一个例子:
预处理
gcc -E main.c -o main.i
-E的作用是让gcc在预处理完结后进行编译。
预处理阶段次要解决include和define等。它把#include蕴含进来的.h 文件插入到#include所在的地位,把源程序中应用到的用#define定义的宏用理论的字符串代替。
编译阶段
gcc -S main.i -o main.s
-S的作用是编译后完结,编译生成了汇编文件。
在这个阶段中,gcc首先要查看代码的规范性、是否有语法错误等,以确定代码的理论要做的工作,在查看无误后,gcc把代码翻译成汇编语言。
汇编阶段
gcc -c main.s -o main.o
汇编阶段把 .s文件翻译成二进制机器指令文件.o,这个阶段接管.c, .i, .s的文件都没有问题。
链接阶段
gcc -o main main.s
链接阶段,链接的是函数库。在main.c中并没有定义”printf”的函数实现,且在预编译中蕴含进的”stdio.h”中也只有该函数的申明。零碎把这些函数实现都被做到名为libc.so的动静库。
一步到位:
gcc main.c -o main
到这里咱们胜利的在 mac 平台生成了可执行文件,运行即可看到输入。试想一下咱们能够将这个可执行文件拷贝到安卓手机上执行吗?
必定是不行的,次要起因是两个平台的 CPU 指令集不一样,基本就无奈辨认指令,这时候穿插编译就排上用场了。
如果你不信能够把 main 可执行文件 push 到手机 /data/local/tmp 外面执行验证一下是否正确输入。
也不肯定必须要是/data/local/tmp这个门路,push到任意一个有可读可写可执行的权限的目录下测试均可。
穿插编译试验
上面咱们应用ndk来对main.c进行穿插编译,看看编译后的可执行文件是不是真的能在Android上运行。
笔者这里以armeabi为例,在mac平台上进行穿插编译。
既然是gcc被移除了,那咱们应用clang来进行穿插编译。
首先找到clang工具链
执行命令
在mac平台能能失常生成可执行文件,咱们将可执行文件用push到这个目录下,而后应用adb执行即可看到输入。阐明咱们的穿插编译胜利了。
如果不应用clang,如何gcc进行穿插编译呢?
首先也是先找到gcc的工具链
而后执行gcc编译命令
咱们发现报错了
找不到stdio.h头文件
这种谬误是说在咱们编的时候编译器找不到咱们引入的 stdio.h 头文件,那怎么通知编译器 stdio.h 头文件在哪里呢? 上面知识点阐明怎么指定这些报错的头文件
咱们通过参数通知gcc工具链到那个目录上来寻找头文件,传递参数进去再次试一下
还是报错
找不到types.h头文件
因为找不到头文件,咱们进去-isystem配置的头文件查找目录中发现aarch64-linux-android和arm-linux-androideabi都存在asm的子目录,所以编译器就不晓得用那个了,咱们再指定一下即可。
终于胜利了,咱们将可执行文件push到手机的这个目录下,而后应用adb执行即可看到输入。
在这里咱们应用了clang和gcc进行了穿插编译发现clang更加的简略,间接找到工具链的门路即可进行编译了,然而gcc就比较复杂了,须要指定多个参数。
这里须要须要咱们明确每个参数的意思是什么:
例如 gcc –sysroot=目录1 -isysroot 目录2 -isystem 目录3 -I目录4 main.c
的意思就是 查找 目录1/usr/lib 的库文件、
查找目录2 /usr/include 的头文件、
查找 目录3 下的头文件、
查找 目录4 下的头文件。
例如:
gcc -L目录1 -l库名
链接ndk的日志库:
gcc -LC:NDK门路\platforms\android-21\arch-arm\usr\lib
-llog -lGLESv2
或者是
gcc –sysroot=NDK门路\platforms\android-21\arch-arm
-llog -lGLESv2
生成动静库
gcc -fPIC -shared main.c -o libTest.so
或者
clang -fPIC -shared main.c -o libTest.so
即便不加-fPIC也能够生成.so文件,然而对于源文件有要求,
因为不加fPIC编译的so必须要在加载到用户程序的地址空间时重定向所有指标地址,所以在它外面不能引用其它中央的代码。
要想验证编译进去的so动静库能不能失常应用,通过JNI调用测试即可。