本次趟地雷来源: https://blog.csdn.net/w359593616/article/details/50345109 。吐槽:这位兄台的排版实在是难以令我接受,只能将就着看看。我将这位兄台的文字重新排版一下,并且加入我在编译和调试的过程中 趟过的雷尽数标出

前言

我所使用的编译系统为Ubuntu 14.04.2。考虑到AllWinner A20的rom也是上古时代的产物了,用18.04可能需要重新配置很多东西,为了避免一些不必要的麻烦,故选择了这个版本的系统。

在系统位数选择上,推荐使用64位系统。当然也可以使用32位系统,不过会有一些限制,比如说 12.04 的32位系统默认最大支持8个cpu核心(8c16t只能利用8个核心),内存大小也有限制,不能进行打包等等。之前我就是因为盲信rom是32位的,就应该用32位的ubuntu进行编译,结果到后面编译成功后准备打包的时候发现打包程序居然是个64位的程序。。。

搭建编译环境

安装必要的依赖

下面是基础的依赖:

root@ubuntu: ~# sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev  gcc-multilib  g++-multilib  libc6-dev-i386  lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip
root@ubuntu: ~# sudo apt-get install bison texinfo u-boot-tools flex libswitch-perl

链接一个so文件,不链接好像也没啥问题:(32位系统可能不需要这个操作)

sudo ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib/i386-linux-gnu/libGL.so

安装JDK 1.6

不要问为什么要jdk1.6,没有为什么,就是需要jdk1.6

这个jdk1.6也是相当古老了,在Oracle网站上找起来很费劲,不过在另外一篇博客的文章里找到了下载链接:http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-javase6-419409.html#jdk-6u41-oth-JPR

下载下来的文件是个bin文件,这里以 jdk1.6.0_45 为例,添加执行权限后直接在终端中执行,jdk会被解压到当前目录中,接下来就是把它放到一个找得到的位置,比如/usr/lib/jvm/jdk1.6.0_45,修改权限为755,所有者和所有人群组为root

然后修改/etc/profile,追加以下内容到文件末尾。注意:只要改profile即可,不要去修改/etc/environment,因为这个 environment 万一修改出错会导致开机卡登录界面,tty中找不到某些命令等问题(本质上是PATH路径损坏),修复起来会很麻烦

export JAVA_HOME=/usr/lib/jvm/jdk1.6.0_45
export JRE_HOME=$JAVA_HOME/jre
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/:$JRE_HOME/lib:$CLASEEPATH

请不要照抄那位兄台的export,要抄也要抄我提供的。因为他的排版格式问题,导致export后面的空格存在异常,不能被shell识别

接下来配置java,全程root权限执行:

#!/bin/bash
JAVA_PATH=/usr/lib/jvm/jdk1.6.0_45
update-alternatives --install /usr/bin/java java $JAVA_PATH/bin/java 300
update-alternatives --install /usr/bin/javac javac $JAVA_PATH/bin/javac 300
update-alternatives --install /usr/bin/jar jar $JAVA_PATH/bin/jar 300
update-alternatives --install /usr/bin/javah javah $JAVA_PATH/bin/javah 300
update-alternatives --install /usr/bin/javap javap $JAVA_PATH/bin/javap 300
update-alternatives --install /usr/bin/javadoc javadoc $JAVA_PATH/bin/javadoc 300
update-alternatives --config java
update-alternatives --config javac
ln -s $JAVA_PATH/bin/jar  /bin/jar
ln -s $JAVA_PATH/bin/java  /bin/java
ln -s $JAVA_PATH/bin/javac  /bin/javac
ln -s $JAVA_PATH/bin/javah  /bin/javah
ln -s $JAVA_PATH/bin/javadoc  /bin/javadoc

配置Swap分区

为了保证能成功编译,需要调整swap分区的大小。

以M为单位查看swap的大小

free -m

在当前用户home目录创建一个2GB大小的swap文件

dd if=/dev/zero of=~/swapfile bs=1024 count=2000000

建立交换分区

mkswap ~/swapfile

转化并激活swap分区文件

swapon swapfile

取消分区

swapoff ~/swapfile

替换gcc和g++

更新:咨询了厂商,得到的回复是14.04中不需要替换!替换之后反而会出现各种编译不过去的问题,所以这个到底要不要替换,看个人,可以多尝试尝试,记得做好备份,万一不行可以回档重来

gcc和g++版本问题,需要降为4.4 (不知道是否必须要这样做,反正先这样做着),下载完成之后替换系统原有的链接至4.4的版本

apt-get install gcc-4.4
apt-get install g++-4.4
cd /usr/bin
mv gcc gcc.bak
ln -s gcc-4.4 gcc
mv g++ g++.bak
ln -s g++-4.4 g++
# 查看两者版本
gcc -v
g++ -v

最后还需要安装:

apt-get install g++-4.4-multilib
apt-get install libc6-dev-i386

下载源码

我这边源码是合作厂商基于AllWinner A20的源码定制过后的版本,不过和网络上流传的版本基本一致,源码中分为android文件夹和lichee文件夹两个目录。

开始编译

编译lichee

这里有个小技巧,在改动必要文件之后,开始编译之前,利用git命令创建个本地仓库,将所有文件添加进版本控制。万一编译出了什么问题,可以通过git将文件夹中的内容完全重置回最初的状态,这样就省的去clean的工作了

接下来开始编译:

cd lichee
./build.sh -p sun7i_android

中途过程中可能会跳出若干选项,比如选择wifi驱动,3g/4g模块驱动等,按照实际需求进行选择即可

若看到以下输出,即表示lichee编译成功:

INFO: build u-boot OK.
INFO: build rootfs ...
INFO: skip make rootfs for android
INFO: build rootfs OK.
INFO: build lichee OK.

编译android

进入源码的另一个目录android,然后执行以下命令:

cd android
source build/envsetup.sh

注意,不要直接执行 ./build/envsetup.sh,据说会有问题

lunch
admin@ubuntu:android$ lunch

You're building on Linux

Lunch menu... pick a combo:
     1. full-eng
     2. full_x86-eng
     3. vbox_x86-eng
     4. full_mips-eng
     5. full_grouper-userdebug
     6. full_tilapia-userdebug
     7. mini_armv7a_neon-userdebug
     8. mini_armv7a-userdebug
     9. mini_mips-userdebug
     10. mini_x86-userdebug
     11. full_maguro-userdebug
     12. full_manta-userdebug
     13. full_toroplus-userdebug
     14. full_toro-userdebug
     15. sugar_evb-eng
     16. sugar_ref001-eng
     17. sugar_standard-eng
     18. wing_evb_v10-eng
     19. full_panda-userdebug

Which would you like? [full-eng]

根据自己开发平台选择方案,接下来的操作是 “拷贝内核和模块到Android中”,据传编译内核 一般需要接近1个小时???完成后将会在out/target/product/sun7i-xxx/目录下生成boot.img、recovery.img、system.img三个文件镜像。Boot.img包括kernel和ramdisk,system.img为系统文件

extract-bsp
make clean
make -j8

如果编译环境没有什么大的问题的话,应该就能编译成功。如果出现make提示源码中有什么东西找不到,请先确认源码是否完整,其次就是编译环境问题了。如果提示少了什么依赖,就按照提示安装即可

打包镜像

用pack命令打包出编译好的镜像文件

pack

完成后会提示你,出来的镜像文件是保存在哪里的

编译android过程中出现的各种问题

make: *** No rule to make target `out/target/product/sugar-ref001/obj/STATIC_LIBRARIES/libv8_intermediates/export_includes', needed by `out/target/product/sugar-ref001/obj/SHARED_LIBRARIES/libwebcore_intermediates/import_includes'.  Stop.

这就是降级了gcc和g++后使用多线程编译可能会出现的奇葩问题。这种情况下,使用单线程make不会有这个错误。如果不嫌编译慢,可以慢慢等。


Can't Locate Switch.pm in @INC (you may need to install the Switch module) (@INC contains: /etc/perl /usr/local/lib/perl/5.18.2 /usr / Local/share/perl/5.18.2 /usr/lib/perl5 /usr /share/perl5 /usr/Lib/perl/5.18 /usr /share/perl/5.18 /usr/Local/lib/site_ perl .) at external/webkit/Source/WebCore/make -hash- tools.pl line 23.
BEGIN failed-- compilation aborted at external/webki t/Source /WebCore /make-hash- tools.pl line 23.
target Generated: libwebcore <= external/webkit/ Sour ce/WebCore / dom/make_ names. pl
make: *** [out/target/product/sugar-ref001/obj/STATIC LIBRARIES/libwebcore intermediates/Source/WebCore/html/DocTypestr ings.cpp] Error 2

缺少了 libswitch-perl ,安装上即可解决问题


external/dbus/bus/activation.c:26:20: fatal error: config.h: No such file or directory
compilation terminated.

这个还是编译环境问题,具体是什么情况我也没搞清楚

环境:两块机械硬盘组LVM,500GB+1TB的配置;一块nvme固态硬盘安装了windows10,系统重新安装为:Ubuntu 18.04 Desktop

最近因为主机重新配置,需要重装系统,然而在重装系统之前,没有进行lvm配置备份,结果安装完毕后发现悲剧了,系统找不到lvm卷。

慌张了几秒后开始冷静思考:我只是在nvme固态上重新安装了系统,并没有动lvm卷的硬盘,所以理论上应该是可以恢复的。 然后开始搜索怎么来恢复它,结果还真被我找到了:

桌面级的ubuntu默认不带lvm,所以要先安装lvm:sudo apt install lvm2

用pvscan或者pvdisplay看看pv还在不在:

root@ubuntu:~# pvscan
  PV /dev/sdb1   VG lvmdata         lvm2 [<931.51 GiB / 0    free]
  PV /dev/sdc1   VG lvmdata         lvm2 [<465.76 GiB / 996.00 MiB free]
  Total: 2 [1.36 TiB] / in use: 2 [1.36 TiB] / in no VG: 0 [0   ]

root@ubuntu:~# pvdisplay
  --- Physical volume ---
  PV Name               /dev/sdb1
  VG Name               lvmdata
  PV Size               931.51 GiB / not usable 4.69 MiB
  Allocatable           yes (but full)
  PE Size               4.00 MiB
  Total PE              238466
  Free PE               0
  Allocated PE          238466
  PV UUID               wr9hSs-arh6-1kcE-NcDa-1PaT-J1de-ab4d0k

  --- Physical volume ---
  PV Name               /dev/sdc1
  VG Name               lvmdata
  PV Size               465.76 GiB / not usable <3.01 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              119234
  Free PE               249
  Allocated PE          118985
  PV UUID               Ql5uAu-CwSO-xjM8-A8z7-toY1-E7GQ-QEUBRy

这个结果表示pv还在,接下来来看看vg还在不在:

root@ubuntu:~# vgscan
  Reading volume groups from cache.
  Found volume group "lvmdata" using metadata type lvm2

root@ubuntu:~# vgdisplay
  --- Volume group ---
  VG Name               lvmdata
  System ID
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  5
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                1
  Open LV               1
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               1.36 TiB
  PE Size               4.00 MiB
  Total PE              357700
  Alloc PE / Size       357451 / 1.36 TiB
  Free  PE / Size       249 / 996.00 MiB
  VG UUID               qJKMJQ-B9Wg-ieJw-th3d-IOUZ-KhLW-OTePci

不错,vg没有丢失,接下来来重新激活它:

root@ubuntu:~# vgchange -ay
  1 logical volume(s) in volume group "lvmdata" now active

接下来检查,是否出现了lvm:(我的lvm group名字叫lvmdata)

root@ubuntu:~# ls -l /dev | grep lvmdata
drwxr-xr-x  2 root root          60 3月  30 16:56 lvmdata

接下来就是用mount命令挂载上去就可以了:

root@ubuntu:~# mount /dev/mapper/lvmdata-xx /mnt/lvm

因为我只在lvm上面建立了一块分区,所以在/dev/mapper下只能看到一个设备节点,找个目录挂载下就可以继续访问之前的数据了

Linux真他么坑爹,配置个dns,到处都是配置,你还不知道应该配置哪个才有效。

之前我的ubuntu 18.04 server配置成了dsl-provider直接进行pppoe拨号上网的,改用路由器进行dhcp之后,就出现了各种问题,先是不知道怎么停掉pppoe拨号,接着就是dns时不时的给你故障一下(真是B了狗了)

pppoe那个问题好解决的,直接修改/etc/network/interfaces文件,把里面的关于dsl-provider的都注释掉,然后 /etc/init.d/networking restart 即可

为了保险起见,同时修改了/etc/netplan/xxxxxxx.yaml配置文件:(ens5改成你自己的)

network:
 version: 2
 renderer: networkd
 ethernets:
  ens5:
  Addresses: []
  dhcp4: true
  optional: true

关于dns,下面是从网上搜集而来的各种办法:

最后,终于通过这个方式解决了:

  • /etc/resolv.conf,这是一般修改的文件,但这次改了以后,重启系统后又被改回去了。系统提示该文件是由networkmanager创建的。
  • /etc/systemd/resolved.conf,是resolv服务的配置,改了以后重启服务,好像没啥变化。
  • /run/resolveconf/resolv.conf,有人说是/etc/resolv.conf的连接指向文件,但我的系统没有。
  • dnsmasq,虽然系统安装了,但是配置都是空的,应该没有作用。
  • netplan,这是Ubuntu 18.04的主流配置,大部分人(大概)通过这个进行dns配置就应该能起作用,可惜在我的机器上无效,这很奇怪,不知道改坏了什么,居然不起作用
  • 通过/etc/network/interfaces,在它的最后增加一句:

    dns-nameservers 8.8.8.8     (复制就好,很多人拼写错误)。。。这个好像也不起作用

编辑 /etc/systemd/resolved.conf 这个文件:

[Resolve]
DNS=<用dns地址替换这个等号的右边内容>

重启下 systemd-resolved服务 就ok了😓

VMware Player现在版本已经更新到15了,说说目前的使用体验。

VMware Player不知道从什么版本开始改名成VMware Workstation Player了(也许是战略调整?),对于个人非商业用途依旧是免费使用,所以可放心下载,在安装完成的界面和workstation pro一样有一个输入许可证的按钮,可以无视之。打开程序之后选择个人非商业用途,即可无需许可证序列号,程序标题栏中也会有“仅用于非商业用途”的字样。

VMware Player中相比workstation pro,少了很多很多功能,以下为我探索到被阉割的功能:

  • 快照。这个功能很鸡肋,从产品的定位角度来看,被阉割了也正常
  • 虚拟网络编辑器。该功能用于创建/修改/删除vmware的网络适配器,一般来说也不太会用到这个功能。多网卡等高级玩法可能会用到它
  • 虚拟化物理机,连接服务器,映射虚拟磁盘等。这些个功能在workstation pro中位于“ 文件 ”菜单下,除了个“ 映射虚拟磁盘 ”还有点用处之外,其余的基本也不会去碰的
  • 虚拟机的选项中的客户机隔离,访问控制,自动保护,还有高级选项(更改固件类型,UEFI还是BIOS,调试信息,进程优先级等)等。其中固件类型这个挺有用的功能被阉割了还是挺可惜的。之前做了一个UEFI引导的Ubuntu,结果发现没有地方设置虚拟机为UEFI导致开不了机,只得作罢
  • 可能还有很多,就不一一列举了

有些功能看似被阉割掉了,但其实还是存在的,比如说:

  • 使用物理磁盘。在创建虚拟的时候,没有使用物理磁盘的选项,但是可以在创建完虚拟机之后再编辑它,移除之前创建的虚拟磁盘,再添加磁盘,这个时候就可以选择使用物理磁盘了

如果只是用它来玩玩虚拟机,不涉及高级功能的话,VMware Player已经可以满足需求了。但如果像我这样玩转物理磁盘的,Ubuntu to go的,还是得上workstation pro

在Windows下,jvm默认是使用GBK的,这会导致使用utf-8的jar文件调用输入输出方法,尤其是写文件的时候出现乱码的情况。

为了避免乱码的出现,现汇总一下办法:

  1. 大部分方法是修改IDE/项目配置的。这个适用于有源代码的情况,对于只有一个jar文件来说不适用;
  2. 直接修改cmd的代码页为65001,即UTF-8,可修复乱码问题。这个确实是可以的,但是存在几个问题:首先是其他程序可能使用该代码页会出现乱码情况(GBK?UTF-8?),其次是cmd不支持UNC路径,即网络路径。为了支持UNC路径,你得使用powershell
  3. 在cmd中执行 java -Dfile.encoding=UTF-8 -jar .\xxxx.jar。这个也是一种可行的方案。正如上面一点所述,cmd不支持UNC路径,所以如果要在网络路径下执行,还是得用powershell,但是,powershell中似乎执行会出错,提示:错误: 找不到或无法加载主类 .encoding=UTF-8
  4. 这个方法是修改环境变量,在环境变量中增加一条环境变量配置:变量名为: JAVA_TOOL_OPTIONS ,变量值为:-Dfile.encoding=UTF-8。再次启动时jvm就会默认先改变初始化字符集为UTF-8,既解决了乱码问题,同时也可以正常使用powershell,是比较推荐的一种做法

准备工作

在开始前,需要准备好下面这些东西:

开始编译

生成 standalone toolchains

这个freetype也是比较坑的,如果直接使用下载下来的ndk中prebuild目录里面提供的gcc,会报各种奇怪的错误。能力有限,不能一个一个的去研究是怎么回事,那就弄个standalone的toolchains出来

进入到下载解压好的ndk目录中,找到build/tools/make-standalone-toolchain.sh 。这个脚本就是帮助构建standalone的toolchain用的。可以看一下它的帮助信息:

root@ubuntu:/home/mkxx/android-ndk-r17c/build/tools# ./make-standalone-toolchain.sh --help                                                                                                                  
HOST_OS=linux                                                                                                                                                                                               
HOST_EXE=                                                                                                                                                                                                   
HOST_ARCH=x86_64                                                                                                                                                                                            
HOST_TAG=linux-x86_64                                                                                                                                                                                       
HOST_NUM_CPUS=4                                                                                                                                                                                             
BUILD_NUM_CPUS=8                                                                                                                                                                                            
Usage: make-standalone-toolchain.sh [options]                                                                                                                                                               
                                                                                                                                                                                                            
Generate a customized Android toolchain installation that includes                                                                                                                                          
a working sysroot. The result is something that can more easily be                                                                                                                                          
used as a standalone cross-compiler, e.g. to run configure and                                                                                                                                              
make scripts.                                                                                                                                                                                               
                                                                                                                                                                                                            
Valid options (defaults are in brackets):                                                                                                                                                                   
                                                                                                                                                                                                            
  --help                   Print this help.                                                                                                                                                                 
  --verbose                Enable verbose mode.                                                                                                                                                             
  --dryrun                 Unsupported.                                                                                                                                                                     
  --toolchain=<name>       Specify toolchain name                                                                                                                                                           
  --use-llvm               No-op. Clang is always available.                                                                                                                                                
  --stl=<name>             Specify C++ STL [gnustl]                                                                                                                                                         
  --arch=<name>            Specify target architecture                                                                                                                                                      
  --abis=<list>            No-op. Derived from --arch or --toolchain.                                                                                                                                       
  --ndk-dir=<path>         Unsupported.                                                                                                                                                                     
  --package-dir=<path>     Place package file in <path> [/tmp/ndk-]                                                                                                                                         
  --install-dir=<path>     Don't create package, install files to <path> instead.                                                                                                                           
  --dryrun                 Unsupported.                                                                                                                                                                     
  --platform=<name>        Specify target Android platform/API level. [android-14]                                                                                                                          
  --force                  Remove existing install directory.

编译toolchain的时候,建议打开verbose开关,可以方便的看到具体出错信息。 以arm64平台为例:

root@ubuntu:/home/mkxx/android-ndk-r17c/build/tools# ./make-standalone-toolchain.sh --platform=android-21 --install-dir=/home/mkxx/ndk-r17c-standalone --arch=arm64 --verbose                               
HOST_OS=linux                                                                                                                                                                                               
HOST_EXE=                                                                                                                                                                                                   
HOST_ARCH=x86_64                                                                                                                                                                                            
HOST_TAG=linux-x86_64                                                                                                                                                                                       
HOST_NUM_CPUS=4                                                                                                                                                                                             
BUILD_NUM_CPUS=8                                                                                                                                                                                            
## COMMAND: python ./make_standalone_toolchain.py --arch arm64 --api 21 --stl gnustl --install-dir=/home/mkxx/ndk-r17c-standalone                                                                           
WARNING:__main__:gnustl is deprecated and will be removed in the next release. Please switch to libc++. See https://developer.android.com/ndk/guides/cpp-support.html for more information.                 
Toolchain installed to /home/mkxx/ndk-r17c-standalone.

注意事项

  • –arch接受的参数在r17c中只有arm,arm64,x86,x86_64 这四个 ,而且不能同时指定多个
  • 如果–arch指定的是arm64,则–platform至少要为android-21,否则会报错: xx is less than minimum platform for arm64 (21)
  • 若想要多个架构,最好指定不同的路径,分多次进行处理;使用–force参数后,原有路径会被删除
  • 如果提示找不到python, 可以通过apt install python命令解决(注意不是python3 )

编译Freetype

在开始前,需要安装几个依赖:(可能还不止这几个)

apt install libtool autoconf automake

把源码包下载下来后解压,然后执行目录中的autogen.sh

root@ubuntu:/home/mkxx/freetype-2.9# ./autogen.sh 
generating `configure.ac'
running `aclocal -I . --force'
running `libtoolize --force --copy --install'
libtoolize: putting auxiliary files in '.'.
libtoolize: copying file './config.guess'
libtoolize: copying file './config.sub'
libtoolize: copying file './install-sh'
libtoolize: copying file './ltmain.sh'
libtoolize: Consider adding 'AC_CONFIG_MACRO_DIRS([m4])' to configure.ac,
libtoolize: and rerunning libtoolize and aclocal.
libtoolize: Consider adding '-I m4' to ACLOCAL_AMFLAGS in Makefile.am.
running `autoconf --force'

接下来编写编译脚本,此处使用arm64:

#!/bin/sh

NDK=/home/mkxx/ndk-r17c-standalone
PLATFORM=aarch64-linux-android

export CC="$NDK/bin/aarch64-linux-android-gcc"
export CXX="$NDK/bin/aarch64-linux-android-g++"
export AR="$NDK/bin/aarch64-linux-android-ar"
export LD="$NDK/bin/aarch64-linux-android-ld"
export STRIP="$NDK/bin/aarch64-linux-android-strip"
export CFLAGS="-fPIE -fpie"

./configure \
--prefix="/home/mkxx/libfreetype2" \
--without-zlib \
--with-sysroot=$NDK/sysroot \
--host="$PLATFORM"

如果没有看到明显的输出错误,就可以继续make & make install了

root@ubuntu:/home/mkxx/libfreetype2# ls -la
total 0
drwxr-xr-x 1 root root  36 Oct 16 07:30 .
drwxr-xr-x 1 root root 156 Oct 16 07:30 ..
drwxr-xr-x 1 root root  30 Oct 16 07:30 bin
drwxr-xr-x 1 root root  18 Oct 16 07:30 include
drwxr-xr-x 1 root root 100 Oct 16 07:30 lib
drwxr-xr-x 1 root root  20 Oct 16 07:30 share

至此,freetype for android编译成功

解决方案参考: https://forum.xda-developers.com/pixel-c/help/device-resource-busy-t3449240

正常将只读的/system分区变成可读写是用下面这个命令:

mount -o remount,rw /system

一般情况下,/system就变成可读写了。但是在某些设备上,会提示Device or resource busy错误。这个时候只需要将-o的两个参数顺序调换一下即可,也就是这样:

mount -o rw,remount /system

本文的创作参考了很多前辈们的博文。没有这些前辈们,估计现在我还在ffmpeg的坑里面打转。。

首先要感谢这位前辈的博文:https://www.cnblogs.com/tplusy/p/11012149.html。本文的思路就是源自于Ta。虽然Ta是在Windows上进行处理的,但是却给我了启发。好了,下面开始正题。

事前工作

准备一台运行Ubuntu的电脑/虚拟机。我这边使用的是vmware虚拟机,系统为ubuntu 18.04 Server。同时安装好必要的依赖。

下载NDK

这里下载NDK。我这边选择了NDK r19c的版本。下载完成后解压到目录中备用。

下载FFmpeg源码

FFmpeg的官网地址: https://ffmpeg.org/download.html 。找到右下角的source code,通过git clone下来,然后可以直接进行使用,或者也可以直接下载打包好的tar.bz2,但是建议还是通过git去clone源码。我这边clone后选择的是切换到release/4.2的分支上进行编译操作。

题外废话

最开始我用了r13b的NDK,打算用gcc去进行编译。后来发现搞不灵光,总是有莫名其妙的错误。后来参考前辈的博文,就去下了r19c的NDK,用llvm的clang进行编译。说实话clang确实方便,可以完全不用改动FFmpeg的源码,而且FFmpeg也已经在configure文件中加入了android平台的支持。经研究,当前的分支release/4.2中,如果编译平台为android,则默认使用clang进行编译。

编写编译脚本

我用的脚本如下(llvm的clang编译),仅供参考:

#!/bin/bash

#Android System API Level,你要运行在什么系统上,就填写系统API Level
#但是这个API Level必须要能够在NDK中找得到,详见下面的ANDROID_CROSS_PREFIX
API_LEVEL=23

#设置ndk目录
NDK=<改成你的ndk路径>/android-ndk-r19c

#llvm toolchain路径。linux下是linux-x86_64,windows下则是windows开头的。
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64

#sysroot 这个一定要设置成 ndk的llvm 路径下的 sysroot 
#这里有个坑要注意,sysroot文件夹在r19c后才存在,r18b中是没有的!
SYSROOT=$TOOLCHAIN/sysroot

#ar nm 的prefix。这里一定要保证和编译的系统位数保持一致
PLATFORM=aarch64-linux-android

#ASM 路径, 同上必须是llvm 目录下的 asm
#说实话,我不知道为啥要ASM。。
ASM=$SYSROOT/usr/include/$PLATFORM

#完整的 cross prefix
CROSS_PREFIX=$TOOLCHAIN/bin/$PLATFORM-

#专门给ndk clang/clang++ 的 cross prefix
ANDROID_CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android$API_LEVEL-

#临时文件目录
TMPDIR="./temp"

#CPU架构
#64位arm:aarch64
#32位arm:armv7-a
#64位intel/amd:x86_64
#32位intel/amd:x86
ARCH=aarch64

#操作系统
OS=android

#安装位置
PREFIX=~/ffmpeg_out/android/$ARCH

#额外C参数
ADDI_CFLAGS=""

#这里面不能写注释,否则会报错
./configure \
--prefix=$PREFIX \
--enable-cross-compile \
--cross-prefix=$CROSS_PREFIX \
--target-os=$OS \
--arch=$ARCH \
--pkg-config=$(which pkg-config) \
--cc=${ANDROID_CROSS_PREFIX}clang \
--cxx=${ANDROID_CROSS_PREFIX}clang++ \
--disable-asm \
--disable-x86asm \
--disable-stripping \
--sysroot=$SYSROOT \
--fatal-warnings \
--enable-gpl \
--enable-version3 \
--enable-nonfree \
--disable-ffplay \
--disable-ffprobe \
--enable-pic \
--enable-jni \
--enable-shared \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-decoder=hevc_mediacodec \
--enable-decoder=mpeg4_mediacodec \
--enable-decoder=vp8_mediacodec \
--enable-decoder=vp9_mediacodec \
--extra-cflags="-Os -fpic -I$ASM -isysroot $SYSROOT" \
--extra-ldflags="$ADDI_LDFLAGS"
make clean
make -j 4
make install

因为我这边的测试平台是A64的开发板,cpu是64位的,系统是android6,所以我这边选择编译的是aarch64平台(性能更好),同时手动指定了cc和cxx。为什么要手动指定?请看下面:

set_default target_os
if test "$target_os" = android; then
    cc_default="clang"
fi

ar_default="${cross_prefix}${ar_default}"
cc_default="${cross_prefix}${cc_default}"
cxx_default="${cross_prefix}${cxx_default}"
nm_default="${cross_prefix}${nm_default}"
pkg_config_default="${cross_prefix}${pkg_config_default}"

cc和cxx默认和ar,nm等使用同一个cross_prefix。而在NDK中,他俩的prefix和其他的可是不一样的,cc和cxx的文件名后面有个api level的数字。这就会导致找不到cc和cxx。为了解决这个问题,这位前辈在configure文件中添加了一个单独的clang的prefix:点我去看 。他这么做确实可以,但是需要改动源码,比较麻烦。所以我选择手动指定,偷懒成功。

编译

脚本弄好后,编译就很简单了,直接执行脚本,然后看着屏幕不停的滚动,然后惬意的等一小会儿就好了。完成之后就可以到输出文件夹里面找到ffmpeg和一堆so文件,把so拷贝到/system/lib64中,ffmpeg拷贝到/system/bin下面,修正权限,然后就可以直接执行ffmpeg啦!

后记

在android 4.4之后,添加了新的保护机制,可执行文件必须是采用PIE编译的,即必须为地址无关代码,否则会提示:error: only position independent executables (PIE) are supported.。但是我上述的编译脚本中并未加上-fPIE -pie,却也能在A64开发板上运行。这个问题有待后续在别的平台上进行考证。 已经确认编译器会自动加上-fPIE fpie选项

遇到的坑

坑一号:makefile找不到

表现为类似下面的情况:

./android_config.sh: line 36: --enable-shared: command not found
Makefile:2: ffbuild/config.mak: No such file or directory
Makefile:40: /tools/Makefile: No such file or directory
Makefile:41: /ffbuild/common.mak: No such file or directory
Makefile:91: /libavutil/Makefile: No such file or directory
Makefile:91: /ffbuild/library.mak: No such file or directory
Makefile:93: /fftools/Makefile: No such file or directory
Makefile:94: /doc/Makefile: No such file or directory
Makefile:95: /doc/examples/Makefile: No such file or directory
Makefile:160: /tests/Makefile: No such file or directory
make: *** No rule to make target `/tests/Makefile'. Stop.
Makefile:2: ffbuild/config.mak: No such file or directory
Makefile:40: /tools/Makefile: No such file or directory
Makefile:41: /ffbuild/common.mak: No such file or directory
Makefile:91: /libavutil/Makefile: No such file or directory
Makefile:91: /ffbuild/library.mak: No such file or directory
Makefile:93: /fftools/Makefile: No such file or directory
Makefile:94: /doc/Makefile: No such file or directory
Makefile:95: /doc/examples/Makefile: No such file or directory
Makefile:160: /tests/Makefile: No such file or directory

这位前辈对于这个问题的解决方法不对,我在这个问题上研究了好久才发现根本不是那么一回事,希望不要再有人被他坑了(他总结的第2条): https://www.laoyuyu.me/2019/05/23/android/clang_compile_ffmpeg/

这个问题产生的原因是编译脚本路径或者脚本执行的路径不正确。即使你在脚本里面cd到了ffmpeg的文件夹中也没用,非得把编译脚本放进ffmpeg的文件夹中才行。也许还有其他的办法,但是最省事的还是放一块儿吧。。。

坑二号:xxxxxx is unable to create an executable file

  1. 检查是否设置了临时目录。
  2. 检查ndk版本,android官方从r18b开始,已经移除了gcc这个编译工具,推荐clang。详情见ndk r18b修订内容

坑三号:/android_config.sh: line xx: xxxxx No such file or directory

configure命令之后如果使用了反斜杠进行换行的话,是不可以在其中添加注释的。把注释删除即可。

坑四号:xxxxx : not executable: 64-bit ELF file

这位前辈的博文:https://blog.csdn.net/u010651541/article/details/50177867,里面提到了关于64-bit ELF的问题,其实并不仅仅是Ta所描述的- c 的问题。如果编译的平台是x86_64的程序,放到aarch64的Android上去运行也是会提示这个错误的。

还有更多的坑,等待被发掘……

下载与安装

首先在docker的注册表中搜索mysql,点击下载, 然后选择版本。我这里选择的是8.0.16的版本

选这个版本的进行下载

下载完成之后,点击启动。这里要注意,配置一个MYSQL_ROOT_PASSWORD的环境变量,否则启动会失败。

记得要设置MYSQL_ROOT_PASSWORD变量(新窗口看大图)

完全启动完成需要等待一段时间,一般3分钟左右,具体可以观察容器详情中的进程一栏,如果mysqld –initialize-insecure进程没有了,取而代之的是mysqld,则表示启动完成。

正在初始化
初始化完成

现在mysql虽然已经启动,但接下来还是要进行配置的。切换到容器详情的终端机一栏,点击新增按钮来创建一个bash,然后就可以像操作linux的shell一样和docker内部进行交互。

设置远程访问

mysql> use mysql;
Reading table information for completion of table and column names                                                                                                   
You can turn off this feature to get a quicker startup with -A                                                                                                       
                                                                                                                                                                     
Database changed
mysql> select host, user, plugin from user;
+-----------+------------------+-----------------------+                                                                                                             
| host      | user             | plugin                |                                                                                                             
+-----------+------------------+-----------------------+                                                                                                             
| %         | root             | caching_sha2_password |                                                                                                             
| localhost | mysql.infoschema | caching_sha2_password |                                                                                                             
| localhost | mysql.session    | caching_sha2_password |                                                                                                             
| localhost | mysql.sys        | caching_sha2_password |                                                                                                             
| localhost | root             | caching_sha2_password |                                                                                                             
+-----------+------------------+-----------------------+                                                                                                             
5 rows in set (0.00 sec)

如果上面关于root的输出只有一个localhost的话,那么这个mysql只能进行本机登录;你需要做的是下面这样处理:(不要相信网上的什么with options,那个已经过时了,在mysql8.0.16中执行会报错)

mysql> CREATE USER 'root'@'%' IDENTIFIED BY '111111';//创建root账户,同时指定密码为111111
// mysql> ALTER USER 'root' IDENTIFIED BY 'password';//这行可以不要
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
mysql> flush privileges;

如果像我上面这样的输出,关于root的输出有一个% ,则代表已经可以进行远程登录了,不需要上述操作。

修改默认的加密方式

mysql8中引入了新的加密方式 caching_sha2_password,而且被设置成了默认的加密方式,这就有可能导致客户端连接出现问题。据我所知,phpMyAdmin即使是4.9版本也不支持这种加密方式,虽然他们在GitHub上把这口锅漂亮的甩给了php。而php版本据说低于7.4的也是不支持的;Navicat Premium 12.0.29版本已经支持这种加密方式了,其他客户端未经测试。所以如果要使用phpMyAdmin等其他客户端的话,建议修改加密方式。

首先要确认,当前的加密方式是什么:

mysql> use mysql;
Reading table information for completion of table and column names                                                                                                   
You can turn off this feature to get a quicker startup with -A                                                                                                       
                                                                                                                                                                     
Database changed
mysql> select host, user, plugin from user;
+-----------+------------------+-----------------------+                                                                                                             
| host      | user             | plugin                |                                                                                                             
+-----------+------------------+-----------------------+                                                                                                             
| %         | root             | caching_sha2_password |                                                                                                             
| localhost | mysql.infoschema | caching_sha2_password |                                                                                                             
| localhost | mysql.session    | caching_sha2_password |                                                                                                             
| localhost | mysql.sys        | caching_sha2_password |                                                                                                             
| localhost | root             | caching_sha2_password |                                                                                                             
+-----------+------------------+-----------------------+                                                                                                             
5 rows in set (0.00 sec)

关于root的两行显示的plugin是caching_sha2_password,我们要将它改成mysql_native_password

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '111111'; 
Query OK, 0 rows affected (0.25 sec)

mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '111111'; 
Query OK, 0 rows affected (0.22 sec)
//这里的111111是指密码,可以自定义

光这样改过之后还不能用,这个就是很坑爹的地方了。需要另外再给它弄个配置文件,就像这样:

[mysqld]
default-authentication-plugin=mysql_native_password

把它保存成一个文件,然后上传到群晖上(建议另外弄个文件夹保存),把这个文件所在目录挂载到/etc/mysql/conf.d目录上,再启动mysql就能彻底解决问题

就像这样

演示环境:Windows 10 主机 + Ubuntu 18.04 客户机 + VMware Workstation Pro 15,虚拟机磁盘设置在一块256G的SSD上

目标:虚拟机磁盘占用了Windows 10主机的SSD大量空间,现在要压缩这块vmdk来减少磁盘占用

这块vmdk的设置如下,并没有预分配磁盘空间:

虚拟磁盘的设定

看,它占了95GB的SSD空间!简直不可思议!实际上:

实际上这个盘只用了9.5GB

实际上他喵的才仅仅用了9.5GB啊!那么问题来了,该如何才能把那么大的磁盘空间压缩压缩?

接下来就是痛苦的尝试各种 解决方案:

  • 1. 很自然的就想到直接去点击设置里面的那个压缩按钮,然后1秒钟,提示压缩完成。满心欢喜原来压缩这么快,然后看了一下windows资源管理器中的文件大小就知道,根本就没给你压缩
  • 2. dd命令填充0,然后删除文件,然后关闭客户机,然后再去点击那个压缩按钮。过程我就不罗嗦了,dd的过程花了好几分钟,结果还然是1秒钟提示压缩完成。
  • 3. 首先先做个defrag。 sudo e4defrag / 执行完之后再重复2中的步骤,结果依旧是1秒钟。 fuck you~
  • 4. 在3的步骤中执行到删除文件后,再加上一个压缩命令 sudo vmware-toolbox-cmd disk shrinkonly 。结果是不支持?
emm…..?

为什么他喵的不支持???看了一下这个错误的搜索结果,大致分为两种情况:有磁盘快照或者是预分配磁盘。然而我并没有使用任何磁盘快照,也不可能去预分配磁盘。

  • 5. 既然上面这些办法都不好使,那么就用vmware宿主机中的vmware-vdiskmanager吧!执行结果是:Failed to shrink the disk ‘D:\xxx.vmdk’ : An error occurred while writing a file; the disk is full. Data has not been saved. Free some disk space and try again (0x8).

disk is full。。。嗯,什么意思?是说我宿主机的磁盘空间不够了吗?

于是我默默的查看了一下D盘的可用空间,提示为79GB。难道说我得有150GB剩余空间才能成功压缩吗?

抱着试试看的想法,把SSD盘中的乱七八糟的文件搬到其他盘中,现在剩余空间是135GB,先来试试看好不好用。

剩余135GB,试一下看看

首先是关闭客户机 ,以防万一,我把vmware也给X了,重新执行命令。。。

开始压缩了。。。

喔激动一下,它开始shrink了,看来确实是宿主机磁盘空间不够了,所以shrink不了?

压缩完成之后,这个vmdk的大小变成了:

成功压缩了

吃惊,大小居然能压缩到8.83GB这么小!


总结:通过上述实践过程,发现一个要压缩Linux格式的vmdk文件大小的前提条件,而这个前提条件却是各种高票回答都没有提及的:存放vmdk文件的磁盘一定要有足够大的可用空间才能压缩,否则就会1秒钟或者压缩失败。由于磁盘已经被我压缩掉了,而且还是那么多操作都做过来的,所以有些疑问:是否真的需要这么多步骤?是否只要dd后删除dd出来的文件,然后直接点击vmware设置中的压缩按钮就可以了?这些就留待日后有时间吃饱了撑的慢慢测试了