# Cross compile mtd-utils
###### tags: `blog`
因為工作的 kernel only 環境沒有用整合好的 build system,像是 yocto 之類的。想要使用 mtd-utils 這類 busybox 沒有提供的工具,就只能自己來 build 了。
## Target board 環境
使用的 cross-compile toolchain 是 gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu。
target board 上跑的是 busybox。
## References
1. https://wiki.beyondlogic.org/index.php/Cross_Compiling_MTD_Utils_for_ARM
2. https://elinux.org/CompilingMTDUtils
e2fsprogs
3. https://www.cnblogs.com/schips/p/porting_e2fsprogs_on_arm_linux_with_usage.html
4. https://tldp.org/LDP/lfs/LFS-BOOK-6.1.1-HTML/chapter06/e2fsprogs.html
exec mtd-utils fail
5. https://busybox.busybox.narkive.com/rSkeBEdC/how-to-execute-binary-other-than-busybox
linker information
7. https://medium.com/fcamels-notes/linux-%E5%9F%B7%E8%A1%8C%E6%99%82%E5%B0%8B%E6%89%BE-symbol-%E7%9A%84%E6%B5%81%E7%A8%8B%E4%BB%A5%E5%8F%8A-shared-library-%E7%9B%B8%E9%97%9C%E7%9F%A5%E8%AD%98-b0cf1e19cbf3
8. https://stackoverflow.com/questions/11524820/what-is-the-difference-between-ldd-and-objdump
find linked libraries
9. https://gist.github.com/jerome-pouiller/c403786c1394f53f44a3b61214489e6f
## Source Links
zlib-1.2.11 http://www.zlib.net/zlib-1.2.11.tar.gz
lzo-2.10 http://www.oberhumer.com/opensource/lzo/download/lzo-2.10.tar.gz
e2fsprogs 1.45.6 https://kernel.googlesource.com/pub/scm/fs/ext2/e2fsprogs.git
mtd-utils v2.1.2 https://github.com/sigma-star/mtd-utils
## Prepare working folder
準備給 `make install` 安裝的 folder (`MTD_OUTPUT_PATH`)。
~~~
mkdir -p ~/mtd-build/install
cd ~/mtd-build
export MTD_SRC_PATH=$PWD
export MTD_OUTPUT_PATH=$PWD/install
echo $MTD_SRC_PATH; echo $MTD_OUTPUT_PATH
~~~
另外也記得把 toolchain 加入到 PATH 裡。
~~~
echo PATH=<path to toolchain>/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH
~~~
## Build zlib
參考 1. 裡面的步驟。
> Download, cross compile and install the zlib compression libraries. Configure doesn't accept the --host parameter (reports unknown option), so you need to hack the makefile.
~~~
wget http://www.zlib.net/zlib-1.2.11.tar.gz
tar -xzf zlib-1.2.11.tar.gz
cd zlib-1.2.11/
./configure --prefix=$MTD_OUTPUT_PATH --host=aarch64-linux-gnu
~~~
> Edit the makefile and prefix the build tools with arm-none-linux-gnueabi-.
修改 Makefile,在底下這些參數前面加入 `aarch64-linux-gnu-`,下面是參數修改後的樣子。
```
CC=aarch64-linux-gnu-gcc
LDSHARED=arm-linux-gnueabi-gcc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map
CPP=aarch64-linux-gnu-gcc -E
AR=aarch64-linux-gnu-ar
RANLIB=aarch64-linux-gnu-ranlib
```
改完 Makefile 後就可以 build 了。`make install` 如上面講的,會安裝到 `MTD_OUTPUT_PATH` 裡。
```
make
make install
```
## Build LZO
同樣是參考 1. 裡面的步驟。
```
cd $MTD_SRC_PATH
wget http://www.oberhumer.com/opensource/lzo/download/lzo-2.10.tar.gz
tar -xzf lzo-2.10.tar.gz
cd lzo-2.10/
./configure --host=aarch64-linux-gnu --prefix=$MTD_OUTPUT_PATH
make
make install
```
## Build e2fsprogs
參考 1,2 裡面的步驟。這邊使用的是 clone git。
在做 configure 時,若只依照 1,2 的指令,在有鎖使用權限的 server 上 `make install` 會碰到如下的錯誤。
所以我需要也參考 3,4 去指定其他的安裝路徑。
~~~
make[1]: Entering directory `<WORKING_PATH>/mtd-build/e2fsprogs/scrub'
MKDIR_P /lib/udev/rules.d
MKDIR_P /etc/cron.d
MKDIR_P <WORKING_PATH>/mtd-build/install/lib/e2fsprogs
MKDIR_P <WORKING_PATH>/mtd-build/install/sbin <WORKING_PATH>/mtd-build/install/share/man/man8 <WORKING_PATH>/mtd-build/install/etc
INSTALL /lib/udev/rules.d/e2scrub.rules
/usr/bin/install: cannot create regular file ‘/lib/udev/rules.d/96-e2scrub.rules’: Permission denied
~~~
另外也有在 4 看到這個是必要的。
>--enable-elf-shlibs
This creates the shared libraries which some programs in this package use.
如果有碰到這個 error 的話就先 `make clean` 後在試一次,可能是因為用別的 toolchain build 過。
~~~
../lib/libsupport.a: error adding symbols: File in wrong format
collect2: error: ld returned 1 exit status
make[2]: *** [e2fsck] Error 1
~~~
完整步驟如下。
:::warning
每次 configure 參數有改變時,先做 make clean 後在 make。
:::
```
cd $MTD_SRC_PATH
git clone https://kernel.googlesource.com/pub/scm/fs/ext2/e2fsprogs.git
cd e2fsprogs
git checkout v1.45.6
./configure --host=aarch64-linux-gnu \
--prefix=$MTD_OUTPUT_PATH \
--with-udev-rules-dir=$MTD_OUTPUT_PATH \
--with-crond-dir=$MTD_OUTPUT_PATH \
--with-systemd-unit-dir=$MTD_OUTPUT_PATH \
--enable-elf-shlibs
make
make install
cd lib/uuid/
make install
```
## Build mtd-utils
在 v2.1.2 的 mtd-utils 有支援 configure 了。就不用像 1,2 的做法要去修改 Makefile。
build 的方式可以參考一下 make_a_relaease.sh 的作法。
`autogen.sh` 就直接 call 就可以了,沒有要傳參數。
因為需要用到上面 build 好的 library,所以需要在 configure 時把 MTD_OUTPUT_PATH 給傳進去。
`./configure --help` 可以看到我們有哪些參數可以用。
```
cd $MTD_SRC_PATH
git clone https://github.com/sigma-star/mtd-utils.git
cd mtd-utils
git checkout v2.1.2
export PREFIX=$MTD_OUTPUT_PATH
export LDFLAGS=-L$PREFIX/lib
export CPPFLAGS=-I$PREFIX/include
./autogen.sh
./configure --host=aarch64-linux-gnu \
--prefix=$MTD_OUTPUT_PATH \
--with-sysroot=$MTD_OUTPUT_PATH \
--without-xattr \
--without-zstd \
--without-crypto \
LDFLAGS=-L$MTD_OUTPUT_PATH/lib \
CPPFLAGS=-I$MTD_OUTPUT_PATH/include
make
make install
```
這一步完 mtd-utils 就 build 成功了!
接下來就是要放到 target board 上面跑囉。
## Copy mtd-utils to rootfs
copy $MTD_OUTPUT_PATH/sbin 到 target board rootfs 的 /sbin。
$MTD_OUTPUT_PATH/lib 就 copy 到 /lib。
## Copy necessary libraries
若跟我一樣 rootfs 是從零開始建,只有把 busybox 放進來的話,應該是甚麼 lib 都沒有的。
我推薦可以看一下 6,7 知道一下 link 相關的東西。
使用 8 的 script 來幫助我們檢查 cross-compile 出來的 binary 需要哪些 lib。
把 8 的 script 存成一個檔案後放到 toolchain 中的 bin,命名成 <toolchain>-ldd,來方便使用。
以我的環境來說,輸出如下。
```
$ aarch64-linux-gnu-ldd sbin/flash_erase
libc.so.6 => /lib/libc.so.6 (0xdeadbeef)
ld-linux-aarch64.so.1 => /lib/ld-linux-aarch64.so.1 (0xdeadbeef)
```