Termuxポート済みのemacs-26.1をわざわざビルドする

# 序

androidアプリの[Termux](https://termux.com)をインストールすると、Linuxの色々なCUIアプリをスマホ上で使うことができます。ところで、元となるLinuxを使う動機は何でしょう？ MSやAppleなどの商用OSが嫌いだから？、無料だから？、使いやすいから？
わたしの場合は優れたアプリのソースを入手して、それをビルドして、必要ならデバッガで追って、のようなことができるのが一番の魅力です。その欲求をTermux上で満たすためには、クロスコンパイルされたバイナリではなく、Termux上でアプリをビルドする必要があります。その手順は[Termuxのマニュアル](https://wiki.termux.com/wiki/Package_Management#Compiling_packages_on_device)に記載されています。ただ、いくつかビルドを試みて「意外に躓くことが多いな」というのがわたしの感想です(そもそも未だTermuxにポートされてないアプリ導入なのでデフォ人柱だし、成功すれば本家にpullリクエスト出せる、というレベルの話しですから)。

ところで、Termuxにポート済みのアプリのリポジトリとして[termux-packages](https://github.com/termux/termux-packages)というのがあるんですが、そのリポジトリにはDocker環境でアプリソースのダウンロードからパッチ適用、ビルドまでを行うためのシェルや設定ファイルが多数(=ポート済みアプリ総数)含まれています。デバッグのためにTermuxポート済みアプリをわざわざTermux上でビルドするとき、これらを参考にさせて頂いたことで、各アプリに共通するようなknown issueを知ることができました。そして、ポートされてないアプリの野良ビルド時にそれが結構重宝だったので、書いときます。

# 前準備

## マニュアル手順の実行

[Termuxのマニュアル](https://wiki.termux.com/wiki/Package_Management#Compiling_packages_on_device)に記載された手順のうち環境準備部分を行います。

### 必要なパッケージのインストール

```shell-session
[~] pkg install autoconf automake bison bzip2 \
 clang cmake coreutils diffutils \
 flex gawk git grep gzip libtool \
 make patch perl sed silversearcher-ag \
 tar termux-exec wget 

Hit:1 https://termux.net stable InRelease Reading package lists... Done 
Building dependency tree Reading state information... Done 
All packages are up to date. Reading package lists... Done
Building dependency tree Reading state information... Done
...
```

### 環境変数の設定

```shell-session
[~] export PREFIX=/data/data/com.termux/files/usr
[~] export LD_PRELOAD=${PREFIX}/lib/libtermux-exec.so
```

## termux-packagesの取得

適当なディレクトリーにtermux-packagesをクローンします。全部で18MB位です。

```shell-session
[~/qiita]$ git clone https://github.com/termux/termux-packages
Cloning into 'termux-packages'...
remote: Counting objects: 29931, done.
remote: Compressing objects: 100% (67/67), done.
remote: Total 29931 (delta 41), reused 56 (delta 26), pack-reused 29835
Receiving objects: 100% (29931/29931), 6.05 MiB | 5.73 MiB/s, done.
Resolving deltas: 100% (17474/17474), done.
...
```

# ポート済みアプリの野良ビルド on Android

docker環境などでアプリをビルドするために`termux-packages/build-package.sh`と`termux-packages/{アプリ}/build.sh`というスクリプトがあるんですが、以降はそれらのスクリプト内容から必要な処理をAndroid上で手作業で行っていきます(知識のある人ならAndroid上でのビルド用に`termux-packages/build-package.sh`を改造することもできるはずです)。現時点でメジャーアップデート(バージョン26.1)されたばかりのemacsで実際に試していきます。

## アプリ固有のビルド用設定を頂く

アプリのディレクトリー(`termux-packages/packages/{アプリ名}`)に`build.sh`というshellスクリプトがあります。

```shell:build.sh
TERMUX_PKG_HOMEPAGE=https://www.gnu.org/software/emacs/
TERMUX_PKG_DESCRIPTION="Extensible, customizable text editor-and more"
TERMUX_PKG_VERSION=26.1
TERMUX_PKG_SHA256=1cf4fc240cd77c25309d15e18593789c8dbfba5c2b44d8f77c886542300fd32c
TERMUX_PKG_SRCURL=https://mirrors.kernel.org/gnu/emacs/emacs-${TERMUX_PKG_VERSION}.tar.xz
TERMUX_PKG_DEPENDS="ncurses, gnutls, libxml2"
TERMUX_PKG_EXTRA_CONFIGURE_ARGS="
--disable-autodepend
--with-gif=no
--with-gnutls
--with-jpeg=no
--without-gconf
--without-gsettings
--without-lcms2
--without-x
--with-png=no
--with-tiff=no
--with-xml2
--with-xpm=no
"
# Ensure use of system malloc:
TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" emacs_cv_sanitize_address=yes"
# Prevent configure from adding -nopie:
TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" emacs_cv_prog_cc_no_pie=no"
# Prevent linking against libelf:
TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" ac_cv_lib_elf_elf_begin=no"
# implemented using dup3(), which fails if oldfd == newfd
TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" gl_cv_func_dup2_works=no"
# disable setrlimit function to make termux-am work from within emacs
TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" ac_cv_func_setrlimit=no"
TERMUX_PKG_HOSTBUILD=yes
TERMUX_PKG_KEEP_INFOPAGES=yes

# Remove some irrelevant files:
TERMUX_PKG_RM_AFTER_INSTALL="share/icons share/emacs/${TERMUX_PKG_VERSION}/etc/images share/applications/emacs.desktop share/emacs/${TERMUX_PKG_VERSION}/etc/emacs.desktop share/emacs/${TERMUX_PKG_VERSION}/etc/emacs.icon bin/grep-changelog share/man/man1/grep-changelog.1.gz share/emacs/${TERMUX_PKG_VERSION}/etc/refcards share/emacs/${TERMUX_PKG_VERSION}/etc/tutorials/TUTORIAL.*"

# Remove ctags from the emacs package to prevent conflicting with
# the Universal Ctags from the 'ctags' package (the bin/etags
# program still remain in the emacs package):
TERMUX_PKG_RM_AFTER_INSTALL+=" bin/ctags share/man/man1/ctags.1"

termux_step_post_extract_package () {
	# XXX: We have to start with new host build each time
	#      to avoid build error when cross compiling.
	rm -Rf $TERMUX_PKG_HOSTBUILD_DIR

	# Termux only use info pages for emacs. Remove the info directory
	# to get a clean Info directory file dir.
	rm -Rf $TERMUX_PREFIX/share/info

	# We cannot run a dumped emacs on Android 5.0+ due to the pie requirement.
	# Also, the native emacs we build (bootstrap-emacs) cannot used dumps when
	# building inside docker: https://github.com/docker/docker/issues/22801
	export CANNOT_DUMP=yes
}

termux_step_host_build () {
	# Build a bootstrap-emacs binary to be used in termux_step_post_configure.
	local NATIVE_PREFIX=$TERMUX_PKG_TMPDIR/emacs-native
	mkdir -p $NATIVE_PREFIX/share/emacs/$TERMUX_PKG_VERSION
	ln -s $TERMUX_PKG_SRCDIR/lisp $NATIVE_PREFIX/share/emacs/$TERMUX_PKG_VERSION/lisp

	$TERMUX_PKG_SRCDIR/configure --prefix=$NATIVE_PREFIX --without-all --with-x-toolkit=no
	make -j $TERMUX_MAKE_PROCESSES
}

termux_step_post_configure () {
	cp $TERMUX_PKG_HOSTBUILD_DIR/src/bootstrap-emacs $TERMUX_PKG_BUILDDIR/src/bootstrap-emacs
	cp $TERMUX_PKG_HOSTBUILD_DIR/lib-src/make-docfile $TERMUX_PKG_BUILDDIR/lib-src/make-docfile
	# Update timestamps so that the binaries does not get rebuilt:
	touch -d "next hour" $TERMUX_PKG_BUILDDIR/src/bootstrap-emacs $TERMUX_PKG_BUILDDIR/lib-src/make-docfile
}

termux_step_post_make_install () {
	cp $TERMUX_PKG_BUILDER_DIR/site-init.el $TERMUX_PREFIX/share/emacs/${TERMUX_PKG_VERSION}/lisp/emacs-lisp/
}
```

これはdocker上で`termux-packages/build-package.sh`から使用されるスクリプトなのでそのまま使用できませんが、ビルドするための設定が多く含まれています。頂きたい設定や実施タイミングはシェル関数名で、おおよそ当たりがつきます。これの内容を`source`コマンドで取り込みます。

```shell-session
[~/qiita]$ cd termux-packages/packages/emacs/
[~/qiita/termux-packages/packages/emacs]$ source build.sh
```

## 依存パッケージのインストール

依存パッケージをインストールします。`TERMUX_PKG_DEPENDS`を見ると、`ncurses`、`gnutls`、`libxml2`が必要なので、これらを`pkg search`で探して開発版がインストールされていなければ、`pkg install`でインストールしてください(libxml2-devは既定でインストール済みのようです)。

```shell-session
[~/qiita/termux-packages/packages/emacs]$ pkg search ncurses
...
ncurses-dev/stable,now 6.1.20180512 aarch64 [installed]
  Development files for ncurses
...
[~/qiita/termux-packages/packages/emacs]$ pkg search gnutls
...
libgnutls-dev/stable,now 3.5.18-2 aarch64 [installed]
  Development files for libgnutls
...
[~/qiita/termux-packages/packages/emacs]$ pkg search libxml2
...
libxml2-dev/stable,now 2.9.8 aarch64 [installed,automatic]
  Development files for libxml2
...
```

## アプリのソース取得

アプリのソースをダウンロードします。アプリの`build.sh`を取り込んであれば、どのアプリでも以下のコマンドでダウンロードできるはずです。

```shell-session
[~/qiita/termux-packages/packages/emacs]$ wget ${TERMUX_PKG_SRCURL}
--2018-06-05 21:31:05--  https://mirrors.kernel.org/gnu/emacs/emacs-26.1.tar.xz
Resolving mirrors.kernel.org... 198.145.21.9
Connecting to mirrors.kernel.org|198.145.21.9|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 44258932 (42M) [application/x-xz]
Saving to: ‘emacs-26.1.tar.xz’

emacs-26.1.tar.x 100%[=========>]  42.21M  11.2MBs    in 4.4s

2018-06-05 21:31:12 (9.61 MB/s) - ‘emacs-26.1.tar.xz’ saved [44258932/44258932]
...
```

ダウンロードしたらアーカイブの種類に応じたコマンドで解凍してください。

```shell-session
[~/qiita/termux-packages/packages/emacs]$ tar xvfJ $(basename ${TERMUX_PKG_SRCURL})
emacs-26.1/
emacs-26.1/lib-src/
emacs-26.1/lib-src/COPYING
emacs-26.1/lib-src/Makefile.in
emacs-26.1/lib-src/profile.c
...
```

## 解凍後の処理

`build.sh`の`termux_step_post_extract_package`の中を調べて、必要な部分を適用します。emacs-26 .1
では`${PREFIX}/share/info/*`削除といった、おっかない処理が入ってるので必要なところだけ手作業で貼り付けて適用します。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ export CANNOT_DUMP=yes
```

## 手直し

本来はここでビルドしてみて、駄目ならその対応をしてから再ビルド、という手順となりますが、ここでそれを踏襲するのも冗長なので、わたしがビルドして駄目だった点にたいして行った対応を先に書きます。

### `Makefile.in`の修正

Emacsのビルドではdump絡みの箇所で`ln -f`してるんですが、Androidの制限によりハードリンクできないらしいので、`Makefile`(の元の`Makefile.in`)を修正しました。以下のようなパッチを他のパッチと同じディレクトリーに作ってください。

```shell:Makefile.in.patch
--- ../emacs-26.1.orig/src/Makefile.in	2018-06-11 00:53:22.710989226 +0900
+++ src/Makefile.in	2018-06-11 01:22:36.560988557 +0900
@@ -532,13 +532,13 @@
                 lisp.mk $(etc)/DOC $(lisp) \
                 $(lispsource)/international/charprop.el ${charsets}
 ifeq ($(CANNOT_DUMP),yes)
-	ln -f temacs$(EXEEXT) $@
+	rm -f $@ && ln -s temacs$(EXEEXT) $@
 else
 	LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup dump
   ifneq ($(PAXCTL_dumped),)
 	$(PAXCTL_dumped) $@
   endif
-	ln -f $@ bootstrap-emacs$(EXEEXT)
+	rm -f bootstrap-emacs$(EXEEXT) && ln -s $@ bootstrap-emacs$(EXEEXT)
 endif
 
 ## We run make-docfile twice because the command line may get too long
@@ -736,13 +736,13 @@
 bootstrap-emacs$(EXEEXT): temacs$(EXEEXT)
 	$(MAKE) -C ../lisp update-subdirs
 ifeq ($(CANNOT_DUMP),yes)
-	ln -f temacs$(EXEEXT) $@
+	rm -f  $@ && ln -s temacs$(EXEEXT) $@
 else
 	$(RUN_TEMACS) --batch $(BUILD_DETAILS) --load loadup bootstrap
   ifneq ($(PAXCTL_dumped),)
 	$(PAXCTL_dumped) emacs$(EXEEXT)
   endif
-	mv -f emacs$(EXEEXT) $@
+	rm -f  $@ && mv -f emacs$(EXEEXT) $@
 endif
 	@: Compile some files earlier to speed up further compilation.
 	$(MAKE) -C ../lisp compile-first EMACS="$(bootstrap_exe)"
```

## パッチの適用

patchを適用します。patchファイルはアプリのディレクトリーの`*.patch`と`*.patch.*`です。やり方は`termux-packages/build-package.sh`の`termux_step_setup_toolchain`などの処理を参照しました。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ \
for patch in ../*.patch*
> do
> sed "s%\@TERMUX_PREFIX\@%${PREFIX}%g" "$patch" |
> sed "s%\@TERMUX_HOME\@%${HOME}%g" |
> patch -p1
> done
patching file lib-src/emacsclient.c
Hunk #1 succeeded at 1287 (offset 77 lines).
patching file lisp/cus-start.el
Hunk #1 succeeded at 290 (offset 13 lines).
patching file lisp/loadup.el
Hunk #1 succeeded at 393 (offset 15 lines).
patching file lisp/net/tramp.el
patching file lisp/server.el
Hunk #1 succeeded at 264 (offset -3 lines).
patching file lisp/subr.el
Hunk #1 succeeded at 3143 (offset 168 lines).
Hunk #2 succeeded at 3187 (offset 168 lines).
patching file lisp/term.el
patching file lib-src/pop.c
Hunk #1 succeeded at 71 with fuzz 1 (offset 8 lines).
Hunk #2 succeeded at 130 with fuzz 2 (offset 3 lines).
patching file src/editfns.c
Hunk #1 succeeded at 1440 (offset 136 lines).
patching file src/callproc.c
Hunk #1 succeeded at 1612 with fuzz 2 (offset -7 lines).
patching file src/filelock.c
Hunk #1 succeeded at 127 (offset 1 line).
Hunk #2 succeeded at 170 (offset 1 line).
Hunk #3 succeeded at 232 (offset -5 lines).
patching file src/keyboard.c
```

## マニュアル手順の実行

[Termuxのマニュアル](https://wiki.termux.com/wiki/Package_Management#Compiling_packages_on_device)に記載された手順のうち`autotools`対応部分を行います。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ \
find . -name 'config.sub' -exec chmod u+w '{}' \; -exec cp -f "${PREFIX}/share/libtool/build-aux/config.sub" '{}' \;
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ \
find . -name 'config.guess' -exec chmod u+w '{}' \; -exec cp -f "${PREFIX}/share/libtool/build-aux/config.guess" '{}' \;
```

## ビルド

ビルドします。ここでインストール先を`prefix=...`で指定します。以下では`--prefix="${HOME}"`としていますが、Termuxのパッケージを野良ビルドで置き換える場合は`--prefix="${PREFIX}"`としてください。また、デバッグ用にビルドしたい場合は、`CFLAGS='-O0 -g3' `など([Emacs固有の話](https://qiita.com/ayatakesi/items/e399f530ed1090508d0c)になりますが、`--enable-checking='yes,glyphs' --enable-check-lisp-object-type`を指定すると、gccデバッガ内でelisp変数の値を確認するとき便利です。このようなビルド時のオプション指定は、ビルドするアプリごとに色々あると思うので確認してください)をここで追加指定します。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ \
./configure --prefix="${HOME}" CC=clang CXX=clang++ ${TERMUX_PKG_EXTRA_CONFIGURE_ARGS}

...

Configured for 'aarch64-unknown-linux-gnu'.

  Where should the build process find the source code?    .
  What compiler should emacs be built with?               clang -g3 -O2
  Should Emacs use the GNU version of malloc?             no
    (The GNU allocators don't work with this system configuration.)
  Should Emacs use a relocating allocator for buffers?    no
  Should Emacs use mmap(2) for buffer allocation?         no
  What window system should Emacs use?                    none
  What toolkit should Emacs use?                          none
  Where do we find X Windows header files?                NONE
  Where do we find X Windows libraries?                   NONE
  Does Emacs use -lXaw3d?                                 no
  Does Emacs use -lXpm?                                   no
  Does Emacs use -ljpeg?                                  no
  Does Emacs use -ltiff?                                  no
  Does Emacs use a gif library?                           no
  Does Emacs use a png library?                           no
  Does Emacs use -lrsvg-2?                                no
  Does Emacs use cairo?                                   no         Does Emacs use -llcms2?                                 no
  Does Emacs use imagemagick (version 6)?                 no
  Does Emacs support sound?                               no
  Does Emacs use -lgpm?                                   no
  Does Emacs use -ldbus?                                  no
  Does Emacs use -lgconf?                                 no
  Does Emacs use GSettings?                               no
  Does Emacs use a file notification library?             yes -lglibc (inotify)
  Does Emacs use access control lists?                    no
  Does Emacs use -lselinux?                               no
  Does Emacs use -lgnutls?                                yes
  Does Emacs use -lxml2?                                  yes
  Does Emacs use -lfreetype?                              no
  Does Emacs use -lm17n-flt?                              no
  Does Emacs use -lotf?                                   no
  Does Emacs use -lxft?                                   no
  Does Emacs use -lsystemd?                               no
  Does Emacs directly use zlib?                           yes
  Does Emacs have dynamic modules support?                no
  Does Emacs use toolkit scroll bars?                     no
  Does Emacs support Xwidgets (requires gtk3)?            no
  Does Emacs have threading support in lisp?              yes
                                                                   
configure: creating ./config.status
config.status: creating src/emacs-module.h
config.status: creating Makefile
config.status: creating lib/gnulib.mk
config.status: creating ./doc/man/emacs.1
config.status: creating lib/Makefile
config.status: creating lib-src/Makefile
config.status: creating oldXMenu/Makefile
config.status: creating doc/emacs/Makefile
config.status: creating doc/misc/Makefile
config.status: creating doc/lispintro/Makefile
config.status: creating doc/lispref/Makefile
config.status: creating src/Makefile
config.status: creating lwlib/Makefile
config.status: creating lisp/Makefile
config.status: creating leim/Makefile
config.status: creating nextstep/Makefile
config.status: creating nt/Makefile                                config.status: creating admin/charsets/Makefile
config.status: creating admin/unidata/Makefile
config.status: creating admin/grammars/Makefile
config.status: creating src/config.h
config.status: executing src/epaths.h commands
config.status: executing src/.gdbinit commands
config.status: executing doc/emacs/emacsver.texi commands          config.status: executing etc-refcards-emacsver.tex commands
configure: WARNING: This configuration installs a 'movemail' program
that does not retrieve POP3 email.  By default, Emacs 25 and earlier
installed a 'movemail' program that retrieved POP3 email via only
insecure channels, a practice that is no longer recommended but that
you can continue to support by using './configure --with-pop'.
configure: You might want to install GNU Mailutils
<https://mailutils.org> and use './configure --with-mailutils'.
```

`configure`が通れば`Makefile`などが作成されて、ビルドする準備が整います。`make`して、

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ make
...
```

インストールします。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ make install
make -C lib all
make[1]: Entering directory '/data/data/com.termux/files/home/qiita/termux-packages/packages/emacs/emacs-26.1/lib'
...
```

インストールが終わったら、`build.sh`の`termux_step_post_make_install`の処理を行います。

```shell:build.sh
termux_step_post_make_install () {
	cp $TERMUX_PKG_BUILDER_DIR/site-init.el $TERMUX_PREFIX/share/emacs/${TERMUX_PKG_VERSION}/lisp/emacs-lisp/
}

```

`TERMUX_PKG_BUILDER_DIR`という環境変数は`termux-packages`の`build-package.sh`の中で定義されています。これを調べても良いのですが、大抵はパッケージを解凍したディレクトリーだし、サブディレクトリーとかファイル名と突き合わせて探す方が早いでしょう。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ export TERMUX_PKG_BUILDER_DIR=..; cp $TERMUX_PKG_BUILDER_DIR/site-init.el $HOME/share/emacs/${TERMUX_PKG_VERSION}/lisp/emacs-lisp/
```

これで終わりです。 ![Screenshot_20180630-052415.png](https://qiita-image-store.s3.amazonaws.com/0/134669/00a0b157-a5e5-75d7-27a2-ad515cb0d909.png) 


# 結び

このように、Termuxにポート済みのアプリは、リポジトリのバージョンのアプリと同じバージョンのソースアーカイブを取得して、`build-package.sh`とアプリの`build.sh`の中から必要な処理を行い、ビルド時におけるDocker環境とAndroid環境の違いに対応してやるだけでビルドできるので、ポートされていないアプリをビルドするより若干楽だと思います。
また、デスクトップでLinuxを使っている人たちには、`apt`や`yum`でインストールしたアプリがインストールされていても、冒頭書いた理由などにより自分でソースを取得してビルドするのを好む人が結構居ると思います。
そのような場合に参考になれば幸いです、おわり。
# 序

androidアプリの[Termux](https://termux.com)をインストールすると、Linuxの色々なCUIアプリをスマホ上で使うことができます。ところで、元となるLinuxを使う動機は何でしょう？ MSやAppleなどの商用OSが嫌いだから？、無料だから？、使いやすいから？
わたしの場合は優れたアプリのソースを入手して、それをビルドして、必要ならデバッガで追って、のようなことができるのが一番の魅力です。その欲求をTermux上で満たすためには、クロスコンパイルされたバイナリではなく、Termux上でアプリをビルドする必要があります。その手順は[Termuxのマニュアル](https://wiki.termux.com/wiki/Package_Management#Compiling_packages_on_device)に記載されています。ただ、いくつかビルドを試みて「意外に躓くことが多いな」というのがわたしの感想です(そもそも未だTermuxにポートされてないアプリ導入なのでデフォ人柱だし、成功すれば本家にpullリクエスト出せる、というレベルの話しですから)。

ところで、Termuxにポート済みのアプリのリポジトリとして[termux-packages](https://github.com/termux/termux-packages)というのがあるんですが、そのリポジトリにはDocker環境でアプリソースのダウンロードからパッチ適用、ビルドまでを行うためのシェルや設定ファイルが多数(=ポート済みアプリ総数)含まれています。デバッグのためにTermuxポート済みアプリをわざわざTermux上でビルドするとき、これらを参考にさせて頂いたことで、各アプリに共通するようなknown issueを知ることができました。そして、ポートされてないアプリの野良ビルド時にそれが結構重宝だったので、書いときます。

# 前準備

## マニュアル手順の実行

[Termuxのマニュアル](https://wiki.termux.com/wiki/Package_Management#Compiling_packages_on_device)に記載された手順のうち環境準備部分を行います。

### 必要なパッケージのインストール

```shell-session
[~] pkg install autoconf automake bison bzip2 \
 clang cmake coreutils diffutils \
 flex gawk git grep gzip libtool \
 make patch perl sed silversearcher-ag \
 tar termux-exec wget 

Hit:1 https://termux.net stable InRelease Reading package lists... Done 
Building dependency tree Reading state information... Done 
All packages are up to date. Reading package lists... Done
Building dependency tree Reading state information... Done
...
```

### 環境変数の設定

```shell-session
[~] export PREFIX=/data/data/com.termux/files/usr
[~] export LD_PRELOAD=${PREFIX}/lib/libtermux-exec.so
```

## termux-packagesの取得

適当なディレクトリーにtermux-packagesをクローンします。全部で18MB位です。

```shell-session
[~/qiita]$ git clone https://github.com/termux/termux-packages
Cloning into 'termux-packages'...
remote: Counting objects: 29931, done.
remote: Compressing objects: 100% (67/67), done.
remote: Total 29931 (delta 41), reused 56 (delta 26), pack-reused 29835
Receiving objects: 100% (29931/29931), 6.05 MiB | 5.73 MiB/s, done.
Resolving deltas: 100% (17474/17474), done.
...
```

# ポート済みアプリの野良ビルド on Android

docker環境などでアプリをビルドするために`termux-packages/build-package.sh`と`termux-packages/{アプリ}/build.sh`というスクリプトがあるんですが、以降はそれらのスクリプト内容から必要な処理をAndroid上で手作業で行っていきます(知識のある人ならAndroid上でのビルド用に`termux-packages/build-package.sh`を改造することもできるはずです)。現時点でメジャーアップデート(バージョン26.1)されたばかりのemacsで実際に試していきます。

## アプリ固有のビルド用設定を頂く

アプリのディレクトリー(`termux-packages/packages/{アプリ名}`)に`build.sh`というshellスクリプトがあります。

```shell:build.sh
TERMUX_PKG_HOMEPAGE=https://www.gnu.org/software/emacs/
TERMUX_PKG_DESCRIPTION="Extensible, customizable text editor-and more"
TERMUX_PKG_VERSION=26.1
TERMUX_PKG_SHA256=1cf4fc240cd77c25309d15e18593789c8dbfba5c2b44d8f77c886542300fd32c
TERMUX_PKG_SRCURL=https://mirrors.kernel.org/gnu/emacs/emacs-${TERMUX_PKG_VERSION}.tar.xz
TERMUX_PKG_DEPENDS="ncurses, gnutls, libxml2"
TERMUX_PKG_EXTRA_CONFIGURE_ARGS="
--disable-autodepend
--with-gif=no
--with-gnutls
--with-jpeg=no
--without-gconf
--without-gsettings
--without-lcms2
--without-x
--with-png=no
--with-tiff=no
--with-xml2
--with-xpm=no
"
# Ensure use of system malloc:
TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" emacs_cv_sanitize_address=yes"
# Prevent configure from adding -nopie:
TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" emacs_cv_prog_cc_no_pie=no"
# Prevent linking against libelf:
TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" ac_cv_lib_elf_elf_begin=no"
# implemented using dup3(), which fails if oldfd == newfd
TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" gl_cv_func_dup2_works=no"
# disable setrlimit function to make termux-am work from within emacs
TERMUX_PKG_EXTRA_CONFIGURE_ARGS+=" ac_cv_func_setrlimit=no"
TERMUX_PKG_HOSTBUILD=yes
TERMUX_PKG_KEEP_INFOPAGES=yes

# Remove some irrelevant files:
TERMUX_PKG_RM_AFTER_INSTALL="share/icons share/emacs/${TERMUX_PKG_VERSION}/etc/images share/applications/emacs.desktop share/emacs/${TERMUX_PKG_VERSION}/etc/emacs.desktop share/emacs/${TERMUX_PKG_VERSION}/etc/emacs.icon bin/grep-changelog share/man/man1/grep-changelog.1.gz share/emacs/${TERMUX_PKG_VERSION}/etc/refcards share/emacs/${TERMUX_PKG_VERSION}/etc/tutorials/TUTORIAL.*"

# Remove ctags from the emacs package to prevent conflicting with
# the Universal Ctags from the 'ctags' package (the bin/etags
# program still remain in the emacs package):
TERMUX_PKG_RM_AFTER_INSTALL+=" bin/ctags share/man/man1/ctags.1"

termux_step_post_extract_package () {
	# XXX: We have to start with new host build each time
	#      to avoid build error when cross compiling.
	rm -Rf $TERMUX_PKG_HOSTBUILD_DIR

	# Termux only use info pages for emacs. Remove the info directory
	# to get a clean Info directory file dir.
	rm -Rf $TERMUX_PREFIX/share/info

	# We cannot run a dumped emacs on Android 5.0+ due to the pie requirement.
	# Also, the native emacs we build (bootstrap-emacs) cannot used dumps when
	# building inside docker: https://github.com/docker/docker/issues/22801
	export CANNOT_DUMP=yes
}

termux_step_host_build () {
	# Build a bootstrap-emacs binary to be used in termux_step_post_configure.
	local NATIVE_PREFIX=$TERMUX_PKG_TMPDIR/emacs-native
	mkdir -p $NATIVE_PREFIX/share/emacs/$TERMUX_PKG_VERSION
	ln -s $TERMUX_PKG_SRCDIR/lisp $NATIVE_PREFIX/share/emacs/$TERMUX_PKG_VERSION/lisp

	$TERMUX_PKG_SRCDIR/configure --prefix=$NATIVE_PREFIX --without-all --with-x-toolkit=no
	make -j $TERMUX_MAKE_PROCESSES
}

termux_step_post_configure () {
	cp $TERMUX_PKG_HOSTBUILD_DIR/src/bootstrap-emacs $TERMUX_PKG_BUILDDIR/src/bootstrap-emacs
	cp $TERMUX_PKG_HOSTBUILD_DIR/lib-src/make-docfile $TERMUX_PKG_BUILDDIR/lib-src/make-docfile
	# Update timestamps so that the binaries does not get rebuilt:
	touch -d "next hour" $TERMUX_PKG_BUILDDIR/src/bootstrap-emacs $TERMUX_PKG_BUILDDIR/lib-src/make-docfile
}

termux_step_post_make_install () {
	cp $TERMUX_PKG_BUILDER_DIR/site-init.el $TERMUX_PREFIX/share/emacs/${TERMUX_PKG_VERSION}/lisp/emacs-lisp/
}
```

これはdocker上で`termux-packages/build-package.sh`から使用されるスクリプトなのでそのまま使用できませんが、ビルドするための設定が多く含まれています。頂きたい設定や実施タイミングはシェル関数名で、おおよそ当たりがつきます。これの内容を`source`コマンドで取り込みます。

```shell-session
[~/qiita]$ cd termux-packages/packages/emacs/
[~/qiita/termux-packages/packages/emacs]$ source build.sh
```

## 依存パッケージのインストール

依存パッケージをインストールします。`TERMUX_PKG_DEPENDS`を見ると、`ncurses`、`gnutls`、`libxml2`が必要なので、これらを`pkg search`で探して開発版がインストールされていなければ、`pkg install`でインストールしてください(libxml2-devは既定でインストール済みのようです)。

```shell-session
[~/qiita/termux-packages/packages/emacs]$ pkg search ncurses
...
ncurses-dev/stable,now 6.1.20180512 aarch64 [installed]
  Development files for ncurses
...
[~/qiita/termux-packages/packages/emacs]$ pkg search gnutls
...
libgnutls-dev/stable,now 3.5.18-2 aarch64 [installed]
  Development files for libgnutls
...
[~/qiita/termux-packages/packages/emacs]$ pkg search libxml2
...
libxml2-dev/stable,now 2.9.8 aarch64 [installed,automatic]
  Development files for libxml2
...
```

## アプリのソース取得

アプリのソースをダウンロードします。アプリの`build.sh`を取り込んであれば、どのアプリでも以下のコマンドでダウンロードできるはずです。

```shell-session
[~/qiita/termux-packages/packages/emacs]$ wget ${TERMUX_PKG_SRCURL}
--2018-06-05 21:31:05--  https://mirrors.kernel.org/gnu/emacs/emacs-26.1.tar.xz
Resolving mirrors.kernel.org... 198.145.21.9
Connecting to mirrors.kernel.org|198.145.21.9|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 44258932 (42M) [application/x-xz]
Saving to: ‘emacs-26.1.tar.xz’

emacs-26.1.tar.x 100%[=========>]  42.21M  11.2MBs    in 4.4s

2018-06-05 21:31:12 (9.61 MB/s) - ‘emacs-26.1.tar.xz’ saved [44258932/44258932]
...
```

ダウンロードしたらアーカイブの種類に応じたコマンドで解凍してください。

```shell-session
[~/qiita/termux-packages/packages/emacs]$ tar xvfJ $(basename ${TERMUX_PKG_SRCURL})
emacs-26.1/
emacs-26.1/lib-src/
emacs-26.1/lib-src/COPYING
emacs-26.1/lib-src/Makefile.in
emacs-26.1/lib-src/profile.c
...
```

## 解凍後の処理

`build.sh`の`termux_step_post_extract_package`の中を調べて、必要な部分を適用します。emacs-26 .1
では`${PREFIX}/share/info/*`削除といった、おっかない処理が入ってるので必要なところだけ手作業で貼り付けて適用します。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ export CANNOT_DUMP=yes
```

## 手直し

本来はここでビルドしてみて、駄目ならその対応をしてから再ビルド、という手順となりますが、ここでそれを踏襲するのも冗長なので、わたしがビルドして駄目だった点にたいして行った対応を先に書きます。

### `Makefile.in`の修正

Emacsのビルドではdump絡みの箇所で`ln -f`してるんですが、Androidの制限によりハードリンクできないらしいので、`Makefile`(の元の`Makefile.in`)を修正しました。以下のようなパッチを他のパッチと同じディレクトリーに作ってください。

```shell:Makefile.in.patch
--- ../emacs-26.1.orig/src/Makefile.in	2018-06-30 20:03:22.517530041 +0900
+++ ./src/Makefile.in	2018-06-30 20:09:07.067529910 +0900
@@ -532,13 +532,13 @@
                 lisp.mk $(etc)/DOC $(lisp) \
                 $(lispsource)/international/charprop.el ${charsets}
 ifeq ($(CANNOT_DUMP),yes)
-	ln -f temacs$(EXEEXT) $@
+	rm -f $@ && ln -s temacs$(EXEEXT) $@
 else
 	LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup dump
   ifneq ($(PAXCTL_dumped),)
 	$(PAXCTL_dumped) $@
   endif
-	ln -f $@ bootstrap-emacs$(EXEEXT)
+	rm -f bootstrap-emacs$(EXEEXT) && ln -s $@ bootstrap-emacs$(EXEEXT)
 endif
 
 ## We run make-docfile twice because the command line may get too long
@@ -736,13 +736,13 @@
 bootstrap-emacs$(EXEEXT): temacs$(EXEEXT)
 	$(MAKE) -C ../lisp update-subdirs
 ifeq ($(CANNOT_DUMP),yes)
-	ln -f temacs$(EXEEXT) $@
+	rm -f  $@ && ln -s temacs$(EXEEXT) $@
 else
 	$(RUN_TEMACS) --batch $(BUILD_DETAILS) --load loadup bootstrap
   ifneq ($(PAXCTL_dumped),)
 	$(PAXCTL_dumped) emacs$(EXEEXT)
   endif
-	mv -f emacs$(EXEEXT) $@
+	rm -f  $@ && mv -f emacs$(EXEEXT) $@
 endif
 	@: Compile some files earlier to speed up further compilation.
 	$(MAKE) -C ../lisp compile-first EMACS="$(bootstrap_exe)"
```

## パッチの適用

patchを適用します。patchファイルはアプリのディレクトリーの`*.patch`と`*.patch.*`です。やり方は`termux-packages/build-package.sh`の`termux_step_setup_toolchain`などの処理を参照しました。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ \
for patch in ../*.patch*
> do
> sed "s%\@TERMUX_PREFIX\@%${PREFIX}%g" "$patch" |
> sed "s%\@TERMUX_HOME\@%${HOME}%g" |
> patch -p1
> done
patching file lib-src/emacsclient.c
Hunk #1 succeeded at 1287 (offset 77 lines).
patching file lisp/cus-start.el
Hunk #1 succeeded at 290 (offset 13 lines).
patching file lisp/loadup.el
Hunk #1 succeeded at 393 (offset 15 lines).
patching file lisp/net/tramp.el
patching file lisp/server.el
Hunk #1 succeeded at 264 (offset -3 lines).
patching file lisp/subr.el
Hunk #1 succeeded at 3143 (offset 168 lines).
Hunk #2 succeeded at 3187 (offset 168 lines).
patching file lisp/term.el
patching file lib-src/pop.c
Hunk #1 succeeded at 71 with fuzz 1 (offset 8 lines).
Hunk #2 succeeded at 130 with fuzz 2 (offset 3 lines).
patching file src/editfns.c
Hunk #1 succeeded at 1440 (offset 136 lines).
patching file src/callproc.c
Hunk #1 succeeded at 1612 with fuzz 2 (offset -7 lines).
patching file src/filelock.c
Hunk #1 succeeded at 127 (offset 1 line).
Hunk #2 succeeded at 170 (offset 1 line).
Hunk #3 succeeded at 232 (offset -5 lines).
patching file src/keyboard.c
```

## マニュアル手順の実行

[Termuxのマニュアル](https://wiki.termux.com/wiki/Package_Management#Compiling_packages_on_device)に記載された手順のうち`autotools`対応部分を行います。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ \
find . -name 'config.sub' -exec chmod u+w '{}' \; -exec cp -f "${PREFIX}/share/libtool/build-aux/config.sub" '{}' \;
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ \
find . -name 'config.guess' -exec chmod u+w '{}' \; -exec cp -f "${PREFIX}/share/libtool/build-aux/config.guess" '{}' \;
```

## ビルド

ビルドします。ここでインストール先を`prefix=...`で指定します。以下では`--prefix="${HOME}"`としていますが、Termuxのパッケージを野良ビルドで置き換える場合は`--prefix="${PREFIX}"`としてください。また、デバッグ用にビルドしたい場合は、`CFLAGS='-O0 -g3' `など([Emacs固有の話](https://qiita.com/ayatakesi/items/e399f530ed1090508d0c)になりますが、`--enable-checking='yes,glyphs' --enable-check-lisp-object-type`を指定すると、gccデバッガ内でelisp変数の値を確認するとき便利です。このようなビルド時のオプション指定は、ビルドするアプリごとに色々あると思うので確認してください)をここで追加指定します。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ \
./configure --prefix="${HOME}" CC=clang CXX=clang++ ${TERMUX_PKG_EXTRA_CONFIGURE_ARGS}

...

Configured for 'aarch64-unknown-linux-gnu'.

  Where should the build process find the source code?    .
  What compiler should emacs be built with?               clang -g3 -O2
  Should Emacs use the GNU version of malloc?             no
    (The GNU allocators don't work with this system configuration.)
  Should Emacs use a relocating allocator for buffers?    no
  Should Emacs use mmap(2) for buffer allocation?         no
  What window system should Emacs use?                    none
  What toolkit should Emacs use?                          none
  Where do we find X Windows header files?                NONE
  Where do we find X Windows libraries?                   NONE
  Does Emacs use -lXaw3d?                                 no
  Does Emacs use -lXpm?                                   no
  Does Emacs use -ljpeg?                                  no
  Does Emacs use -ltiff?                                  no
  Does Emacs use a gif library?                           no
  Does Emacs use a png library?                           no
  Does Emacs use -lrsvg-2?                                no
  Does Emacs use cairo?                                   no         Does Emacs use -llcms2?                                 no
  Does Emacs use imagemagick (version 6)?                 no
  Does Emacs support sound?                               no
  Does Emacs use -lgpm?                                   no
  Does Emacs use -ldbus?                                  no
  Does Emacs use -lgconf?                                 no
  Does Emacs use GSettings?                               no
  Does Emacs use a file notification library?             yes -lglibc (inotify)
  Does Emacs use access control lists?                    no
  Does Emacs use -lselinux?                               no
  Does Emacs use -lgnutls?                                yes
  Does Emacs use -lxml2?                                  yes
  Does Emacs use -lfreetype?                              no
  Does Emacs use -lm17n-flt?                              no
  Does Emacs use -lotf?                                   no
  Does Emacs use -lxft?                                   no
  Does Emacs use -lsystemd?                               no
  Does Emacs directly use zlib?                           yes
  Does Emacs have dynamic modules support?                no
  Does Emacs use toolkit scroll bars?                     no
  Does Emacs support Xwidgets (requires gtk3)?            no
  Does Emacs have threading support in lisp?              yes
                                                                   
configure: creating ./config.status
config.status: creating src/emacs-module.h
config.status: creating Makefile
config.status: creating lib/gnulib.mk
config.status: creating ./doc/man/emacs.1
config.status: creating lib/Makefile
config.status: creating lib-src/Makefile
config.status: creating oldXMenu/Makefile
config.status: creating doc/emacs/Makefile
config.status: creating doc/misc/Makefile
config.status: creating doc/lispintro/Makefile
config.status: creating doc/lispref/Makefile
config.status: creating src/Makefile
config.status: creating lwlib/Makefile
config.status: creating lisp/Makefile
config.status: creating leim/Makefile
config.status: creating nextstep/Makefile
config.status: creating nt/Makefile                                config.status: creating admin/charsets/Makefile
config.status: creating admin/unidata/Makefile
config.status: creating admin/grammars/Makefile
config.status: creating src/config.h
config.status: executing src/epaths.h commands
config.status: executing src/.gdbinit commands
config.status: executing doc/emacs/emacsver.texi commands          config.status: executing etc-refcards-emacsver.tex commands
configure: WARNING: This configuration installs a 'movemail' program
that does not retrieve POP3 email.  By default, Emacs 25 and earlier
installed a 'movemail' program that retrieved POP3 email via only
insecure channels, a practice that is no longer recommended but that
you can continue to support by using './configure --with-pop'.
configure: You might want to install GNU Mailutils
<https://mailutils.org> and use './configure --with-mailutils'.
```

`configure`が通れば`Makefile`などが作成されて、ビルドする準備が整います。`make`して、

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ make
...
```

インストールします。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ make install
make -C lib all
make[1]: Entering directory '/data/data/com.termux/files/home/qiita/termux-packages/packages/emacs/emacs-26.1/lib'
...
```

インストールが終わったら、`build.sh`の`termux_step_post_make_install`の処理を行います。

```shell:build.sh
termux_step_post_make_install () {
	cp $TERMUX_PKG_BUILDER_DIR/site-init.el $TERMUX_PREFIX/share/emacs/${TERMUX_PKG_VERSION}/lisp/emacs-lisp/
}

```

`TERMUX_PKG_BUILDER_DIR`という環境変数は`termux-packages`の`build-package.sh`の中で定義されています。これを調べても良いのですが、大抵はパッケージを解凍したディレクトリーだし、サブディレクトリーとかファイル名と突き合わせて探す方が早いでしょう。

```shell-session
[~/qiita/termux-packages/packages/emacs/emacs-26.1]$ export TERMUX_PKG_BUILDER_DIR=..; cp $TERMUX_PKG_BUILDER_DIR/site-init.el $HOME/share/emacs/${TERMUX_PKG_VERSION}/lisp/emacs-lisp/
```

これで終わりです。 ![Screenshot_20180630-052415.png](https://qiita-image-store.s3.amazonaws.com/0/134669/00a0b157-a5e5-75d7-27a2-ad515cb0d909.png) 


# 結び

このように、Termuxにポート済みのアプリは、リポジトリのバージョンのアプリと同じバージョンのソースアーカイブを取得して、`build-package.sh`とアプリの`build.sh`の中から必要な処理を行い、ビルド時におけるDocker環境とAndroid環境の違いに対応してやるだけでビルドできるので、ポートされていないアプリをビルドするより若干楽だと思います。
また、デスクトップでLinuxを使っている人たちには、`apt`や`yum`でインストールしたアプリがインストールされていても、冒頭書いた理由などにより自分でソースを取得してビルドするのを好む人が結構居ると思います。
そのような場合に参考になれば幸いです、おわり。