EmacsのAndroidポートのビルド

:::note info
**2024-04-07追記**
Github Actions上でのビルドに挑戦してきて、やっと最近どうにか満足できるapkをビルドできるようになりました。詳細については[レポジトリ](https://github.com/ayatakesi/my-emacs)の`README.md`に記載してあります。
:::

# EmacsのAndroidポートのビルド

[0. 前書き](#0-前書き)

[1. 手順](#1-手順): ビルド用レポジトリを用意手順をさっくり説明
[1.1 レポジトリの準備](#11-レポジトリの準備)
[1.2 forkする](#12-forkする)
[1.3 ローカルにclone](#13-ローカルにclone)
[1.4 作業用ブランチのcut](#14-作業用ブランチのcut)
[1.5 リモートにpush](#15-リモートにpush)
[1.6 デフォルトブランチの設定](#16-デフォルトブランチの設定)

[2. ワークフローファイル](#2-ワークフローファイル)
[2.1 ワークフローファイルのadd](#21-ワークフローファイルのadd)
[2.2 リモートにpush](#22-リモートにpush)

[3. ビルド](#3-ビルド): ビルドする手順(詳細略)
[3.1 ワークフローをrun](#31-ワークフローをrun)

[4. ワークフローで行っていることの説明](#4-ワークフローで行っていることの説明)
[4.1 ワークフローの定義](#41-ワークフローの定義)
[4.2 サードパーティライブラリの取得とかpatch適用](#42-サードパーティライブラリの取得とかpatch適用)
[4.2.1 tiff](#421-tiff)
[4.2.2 webp](#422-webp)
[4.2.3 icu](#423-icu)
[4.2.4 libxml2](#424-libxml2)
[4.2.5 gnutls関連](#425-gnutls関連)
[4.2.6 treesitter](#426-treesitter)
[4.2.7 harfbuzz](#427-harfbuzz)
[4.2.8 sqlite3](#428-sqlite3)
[4.2.9 giflib](#429-giflib)
[4.2.10 json](#4210-json)
[4.2.11 libjpeg](#4211-libjpeg)
[4.2.12 ImageMagick](#4212-ImageMagick)
[4.2.13 selinux関連](#4213-selinux関連)
[4.3 ビルドする](#43-ビルドする)
[4.3.1 レポジトリの作成とモジュールのダウンロード](#431-レポジトリの作成とモジュールのダウンロード)
[4.3.2 環境のセットアップとautogen.shの実行](#432-環境のセットアップとautogenshの実行)
[4.3.3  configureの実行](#433-configureの実行)
[4.3.4 makeとか](#434-makeとか)

[5 インストール](#5-インストール)

# 0. 前書き
2022年の大晦日にEmacsメンテナのPo LuさんによりAndroidネイティブアプリとしてEmacsを配布するためのブランチfeature/androidが立ち上がりました([過去記事](https://qiita.com/ayatakesi/items/be1868d2f394d39f1e76))。その後、emacs-develでの幾ばくかの議論の末に、feature/androidブランチはめでたくmasterブランチへとマージされました。これはどういうことかというと、ユーザー視点に限って言えば今まではfeature/androidブランチを取得してビルドする必要があったのが、今後はmasterブランチ(いずれemacs-30、emacs-31、…となる)を取得してconfigureのオプションで指定すればAndroidポートをビルドできるようになったことを意味しています。さて、このAndroidポートですが主要開発者のPo Luさんによって当初からドキュメントが非常に充実しています。この記事ではそれらのドキュメントにしたがって、2023年10月時点におけるすべての機能を取り込んだEmacs for Androidのビルド手順を説明します。

- ビルド環境
Emacsに含まれているAndroidポート用ドキュメントの核となる[java/INSTALL](https://github.com/ayatakesi/my-emacs/blob/my/master/java/INSTALL) ([適当訳](https://github.com/ayatakesi/my-emacs/blob/my/master/java/INSTALL.summary.ja)、ちょっと訳が古く[現時点ではAPI 34が必要](https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=253f1aff1ab00e9794f3cfcf50e86e335f411242)です)でも触れられている通り、Android用のソフトウェアはインストールおよび実行されるデバイスではなく別のOS(LinuxとかMacとかWindowsとか)を実行する別のデバイスでビルドされるという特徴があるようです。わたしが所有するAndroid以外の環境としてLinuxはあるものの、これは色々な事をやっている汚れきった環境(その癖仮想化はHW的に不可)なので、例によってGithub Actionsを用いました。

- ターゲット
このAndroidポートですが可能な限り古いAndroidバージョンにも対応したいというPo Luさんの意向により、Android 2.2以降であれば対応しているようです(SourceForgeで[配布](https://sourceforge.net/projects/android-ports-for-gnu-emacs/files/)されてます)。当初はGithub Actionsのmatrixを用いて色々なバージョンを作ろうかとも思ったんですが多重度にも制限(256だったか?)があること、自分が所有する実機のバージョンでなければ検証できない、ということでターゲットAPIレベルは22と33に絞りました(33とか持ってませんが最新版くらいはビルドしておこうかなー、と)。

- サードパーティライブラリ
[java/INSTALL](https://github.com/ayatakesi/my-emacs/blob/my/master/java/INSTALL)にはjson(Emacs 28より)、treesitterやsqlite(Emacs 29より)といった外部ライブラリをリンクしたバージョンのビルド手順が記載されているので、これらはすべて取り込むことにします(正直自分はselinuxとか「見かけたらすぐに無効化しなさい!」と教えられてきたのでいらないんですけどね)。

- 共有ユーザーID
Emacsで著名なmagitといったパッケージを使うには背後にLinux環境が必要になりますが、root化端末でない限りAndroid自体のLinux基盤は使えません。そのためこのAndroidポートではAndroidにおけるLinuxエミュレーションアプリとして実績があるtermuxとの併用についても考慮されています([SourceForgeのREADME](https://sourceforge.net/projects/android-ports-for-gnu-emacs/files/)や[Emacs 30になる予定のマニュアル](https://git.savannah.gnu.org/cgit/emacs.git/tree/doc/emacs/android.texi?id=253f1aff1ab00e9794f3cfcf50e86e335f411242#n798)を参照)。この記事で説明する手順でもTermuxと共存できるように共有ユーザーIDは`com.termux`としましたが、署名キーが異なるためF-DroidやGoogle PlayからインストールしたTermuxとは共存できません。前述のSourceForge版Termuxをインストールする必要があります(もちろん自分でビルドして[java/emacs.keystore](https://git.savannah.gnu.org/cgit/emacs.git/tree/java/emacs.keystore?id=253f1aff1ab00e9794f3cfcf50e86e335f411242)で署名したバージョンでも可)。

- Githubのレポジトリについて
以降で説明していくわたしのレポジトリにはビルドした結果がartifactsとしてアップロードしてあるのでそれをダウンロード、インストールすればよいのですが、実際にわたしが行っているのは
1. [emacs-mirror](https://github.com/emacs-mirror/emacs)をfork
2. masterブランチから自分用のブランチ(my/master)をcutしてGithubのデフォルトブランチに設定(わたしはmasterとconflictするような変更をforkで行った際(たとえばconfigure.acにprintf デバッグ仕込むとか)のconflict解決をGithubのweb UIで行うのは余りにもキツいので別ブランチ切ってます)
3. `.github/workflows`にビルド用のYAMLファイルをaddしてGithubのweb UIよりrun

だけなので、上記1.と2.をご自身のgithubアカウントで行い3.の`.github/workflows`を持っていけば同じことができます(Githubのweb UIでemacs-mirrorのmasterと自分のforkのmasterをsync、ローカルにmasterをpullしてmy/masterにmerge、pushしてワークフローをrunすれば新鮮なEmacsが随時ビルドできます)。そもそもわたしのレポジトリのActionsはくだらないミスや適当なrunで履歴が汚なすぎるのでおすすめできませぬ。

- Github
上述してきた通り、Githubのアカウントお持ちであることを前提とします。ただ、Github Actionsのワークフローファイルで行っているのは、ご覧になれば判ると思いますがLinuxのコマンドプロンプトで行う処理ばかりなので流用は容易いのではないか、と願います(他の環境はよく判りませぬ故)。

# 1. 手順

## 1.1 レポジトリの準備
Emacsの本家レポジトリは[savannahのemacs.git](https://git.savannah.gnu.org/cgit/emacs.git/)ですが、Github外部から直接fork/mirrorする手段は用意されていない(ローカルにcloneしてgithubにpushとかcron組む必要がある)ので、非公式ミラーであるemacs-mirror/emacsをfork元にします。

## 1.2 forkする
Githubにログインして[emacs-mirror/emacs](https://github.com/emacs-mirror/emacs)をforkします(わたしは[my-emacs](https://github.com/ayatakesi/my-emacs)という名前でforkしましたが、名前は何でも良いと思います)。

## 1.3 ローカルにclone
gitコマンドでローカルにcloneしてください。

## 1.4 作業用ブランチのcut
デフォルトブランチは`master`になってる筈なので、そのまま`git checkout -b my/master`(わたしの場合は`my/master`ですが、以下これを例とします)のように自分用master追随ブランチをcutしましょう。

## 1.5 リモートにpush
ブランチは`my/master`になっていると思いますので、そのブランチをリモートにpushします。`git push`すると`git push --set-upstream origin my/master`しろと怒られるのでしたがいましょう。Githubに`my/master`ブランチが登録される筈です。

## 1.6 デフォルトブランチの設定
:::note alert
Githubのワークフローはデフォルトブランチのワークフローを対象とするので、必ず設定してください。
たとえばデフォルトの`master`ブランチがデフォルトのまま`my/master`ブランチにワークフローを追加しても認識してくれない→実行できません。
:::
Githubのweb UIから`Settings`で`Default Branch`を`my/emacs`に変更します。

# 2. ワークフローファイル
ローカルのcloneにAndroid版のEmacsをビルドするためのワークフローファイルを追加、commit、pushします。

## 2.1 ワークフローファイルのadd
cloneしたレポジトリに`.github/workflows`というディレクトリーを作成して[全部のせビルドワークフロー](https://github.com/ayatakesi/my-emacs/blob/my/master/.github/workflows/build_emacs_for_android.yml)をコピー、gitでaddしてcommit(行末スペースを拒絶するGithubと相性が悪いpatchコードが含まれているので`--no-verify`オプションが必要かもしれません)。

## 2.2 リモートにpush
普通にpushしてください。

# 3. ビルド
ちょっと記憶が曖昧ですが、もしかしたらGithubの`Settings`でActionsを有効にする必要があるかもしれません。

## 3.1 ワークフローをrun
Githubの`Actions`に`run configure and make Emacs`というワークフローがある筈なので、それを選択して`Run workflow`(ブランチはデフォルトの`my/master`でおｋ)を実行します。正常に終了すればartifactsとしてEmacs.apk.zipができる筈です(120MBくらい)

# 4. ワークフローで行っていることの説明
基本的には`java/INSTALL`に記載されたpatchをあてているだけですが、Po Luさんの環境も開発中ということもあり汚れている(素のLinuxではインストールされていないライブラリとかがインストール済みだったり)と思われ、若干の手直しが必要でした。以下順を追って説明します。

## 4.1 ワークフローの定義
冒頭では名前と起動方法を定義します。重要なのは`workflow_dispatch`で、これはこのワークフローがpush等レポジトリに発生するイベントによって自動的に走行するのではなく、GithubのActionsでこのワークフローを選択して`Run workflow`を選択することにより手動で実行する必要があることを意味しています。

```yaml:build_emacs_for_android.yml
name: run configure and make Emacs
on:
  workflow_dispatch:
```

## 4.2 サードパーティライブラリの取得とかpatch適用
以下、`java/INSTALL`のpatchと比較しつつ説明していきます(わたしの[全部のせビルドワークフロー](https://github.com/ayatakesi/my-emacs/blob/my/master/.github/workflows/build_emacs_for_android.yml)では試行錯誤しつつトライしてるので`java/INSTALL`の順とは異なりますが`get-tiff`から`get-boringssl`までのjob、`download tiff`から`download boringssl`のstepとそれぞれの直後にある`expand archives`のstepの対にたいして、job単位/step対単位であれば並べ替えできます(気持ち悪い人は並べ替えられます; ちなみにわたしも気持ち悪いです)。あとビルドするためにサードパーティライブラリのAndroid.mkを利用しています。このAndroid.mkを使う仕組みはAndroid開発においては古い手法らしく、現在ではAndroid.bpが主流のようです。ということで`java/INSTALL`に記載されているように、Android.mkが存在する古いブランチ(nougat-release近辺の模様)を取得しています。

### 4.2.1 tiff

tiffについてはEmacs for Androidとビルド可能なバージョンがすでに用意されています。

```text:java/INSTALL
libtiff    	- https://sourceforge.net/projects/android-ports-for-gnu-emacs
(Extract and point ``--with-ndk-path'' to tiff-4.5.0-emacs.tar.gz.)
```

ダウンロードしてartifactsとしてアップロード、
```yaml:build_emacs_for_android.yml
  get-tiff:
    #
    # get TIFF from Android ports for GNU Emacs
    runs-on: ubuntu-latest
    steps:
    - name: get tiff from Android ports for GNU Emacs
      run: |
        wget https://sourceforge.net/projects/android-ports-for-gnu-emacs/files/tiff-4.5.0-emacs.tar.gz
    # upload as artifacts
    - name: upload source archives
      uses: actions/upload-artifact@v3
      with:
        name: tiff
        path: |
          tiff-4.5.0-emacs.tar.gz
```

次ジョブでダウンロードして`my_sub_modules`というディレクトリー配下に解凍しているだけです。

```yaml:build_emacs_for_android.yml
    # download tiff
    - name: download tiff
      uses: actions/download-artifact@v3
      with:
        name: tiff
        path: my_sub_modules
    - name: expand archives
      run: |
        cd my_sub_modules
        tar xvfz tiff-4.5.0-emacs.tar.gz
        rm -f *gz
        cd -
```

### 4.2.2 webp
webpについては本来ならarmv7というデバイス以外はpatchをあてる必要はありません。ただ全部のせする場合にはImageMagickをビルドする際に静的ライブラリが衝突してしまい、ビルドには成功するもののデバイスにインストールするとクラッシュしてしまう(起動できない)ので、モジュール名を弄りました。尚サードパーティライブラリのバージョンについてはImageMagick版webpのv1.0.3の最終コミットを採用しました(ライブラリ衝突の際に「同じバージョン使えばどっちのライブラリでも大丈夫では!?」と思ってこのコミットを選んだんですが、結局駄目で名前変更したのでnougat-releaseでも問題ないと思います)。

```text:java/INSTALL
libwebp	- https://android.googlesource.com/platform/external/webp
(You must apply the patch at the end of this file for the resulting
 binary to work on armv7 devices.)
```

cloneしてお目当てのコミットをcheckout

```yaml:build_emacs_for_android.yml
  ##########################
  # Get webp, then upload it
  get-webp:
    runs-on: ubuntu-latest
    steps:
    - name: get webp, patch and upload
      run: |
        git clone https://android.googlesource.com/platform/external/webp
        # use v1.0.3 latest(just before v1.1.0) same as imagemagick version.
        git -C webp checkout a76694a1
```

以下、ライブラリ名を変えるパッチをあてます。

```diff:build_emacs_for_android.yml
diff --git a/Android.mk b/Android.mk
index 8f0cb756..e6268645 100644
--- a/Android.mk
+++ b/Android.mk
@@ -183,16 +183,16 @@ ifeq ($(USE_CPUFEATURES),yes)
   LOCAL_STATIC_LIBRARIES := cpufeatures
 endif
 
-LOCAL_MODULE := webpdecoder_static
+LOCAL_MODULE := webpdecoder_static_webp
 
 include $(BUILD_STATIC_LIBRARY)
 
 ifeq ($(ENABLE_SHARED),1)
 include $(CLEAR_VARS)
 
-LOCAL_WHOLE_STATIC_LIBRARIES := webpdecoder_static
+LOCAL_WHOLE_STATIC_LIBRARIES := webpdecoder_static_webp
 
-LOCAL_MODULE := webpdecoder
+LOCAL_MODULE := webpdecoder_webp
 
 include $(BUILD_SHARED_LIBRARY)
 endif  # ENABLE_SHARED=1
@@ -213,7 +213,7 @@ LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/src
 # prefer arm over thumb mode for performance gains
 LOCAL_ARM_MODE := arm
 
-LOCAL_WHOLE_STATIC_LIBRARIES := webpdecoder_static
+LOCAL_WHOLE_STATIC_LIBRARIES := webpdecoder_static_webp
 
 LOCAL_MODULE := webp
```

そしたらartifactsとしてアップロード(委細略)。

```yaml:build_emacs_for_android.yml
        tar cvfz webp.tar.gz ./webp
    # upload as artifacts
    - name: upload source archives
```

`my_sub_modules`というディレクトリー配下に解凍するだけです(委細略)。

```yaml:build_emacs_for_android.yml
    # download webp
    - name: download webp
```

### 4.2.3 icu

パッチを当てる必要があるとのこと。

```text:java/INSTALL
  icu4c		- https://android.googlesource.com/platform/external/icu/
     (You must apply the patch at the end of this file.)
```

ダウンロードします(当初は何処らへんのバージョンを使えばよいか探りつつだったのでcloneして探ってましたが、段々判ってきた時点で該当するブランチであろうnougat-releaseのアーカイブをダウンロードしたりしてます)。

```yaml:build_emacs_for_android.yml
  # Get icu4c, then upload it
  get-icu4c:
    runs-on: ubuntu-latest
    steps:
    - name: get icu4c and upload it
      run: |
        wget https://android.googlesource.com/platform/external/icu/+archive/refs/heads/nougat-release.tar.gz
```

`java/INSTALL`のpatchをそのままあてます。ライブラリの名前はそのまま(imagemagick側のicuの名前を変えます)。あてたらアーカイブしてartifactsとしてアップロード、次ジョブでダウンロードして解凍とかは他と同じです(コード略)。

```diff:build_emacs_for_android.yml
diff --git a/icu4j/Android.mk b/icu4j/Android.mk
index d1ab3d5..69eff81 100644
--- a/icu4j/Android.mk
+++ b/icu4j/Android.mk
@@ -69,7 +69,7 @@ include $(BUILD_STATIC_JAVA_LIBRARY)
 # Path to the ICU4C data files in the Android device file system:
 icu4c_data := /system/usr/icu
 icu4j_config_root := $(LOCAL_PATH)/main/classes/core/src
-include external/icu/icu4j/adjust_icudt_path.mk
+include $(LOCAL_PATH)/adjust_icudt_path.mk

 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(icu4j_src_files)

diff --git a/icu4c/source/common/Android.mk b/icu4c/source/common/Android.mk
index 8e5f757..44bb130 100644
--- a/icu4c/source/common/Android.mk
+++ b/icu4c/source/common/Android.mk
@@ -231,7 +231,7 @@ include $(CLEAR_VARS)
 LOCAL_SRC_FILES += $(src_files)
 LOCAL_C_INCLUDES += $(c_includes) $(optional_android_logging_includes)
 LOCAL_CFLAGS += $(local_cflags) -DPIC -fPIC
-LOCAL_SHARED_LIBRARIES += libdl $(optional_android_logging_libraries)
+LOCAL_SHARED_LIBRARIES += libdl libstdc++ $(optional_android_logging_libraries)
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := libicuuc
         LOCAL_RTTI_FLAG := -frtti
```

### 4.2.4 libxml2

patchをあてる前にコミット`edb5870767fed8712a9b77ef34097209b61ab2db'`をrevertするよう記されています。

```text:java/INSTALL
libxml2	- https://android.googlesource.com/platform/external/libxml2/
(You must also place the dependency icu4c in ``--with-ndk-path'',
 and apply the patch at the end of this file.)
 ...
 This patch must be applied to the Android.mk in Google's version of
libxml2 before it can be built for Emacs.  In addition, you must also
revert the commit `edb5870767fed8712a9b77ef34097209b61ab2db'.
```

cloneしてrevertします。ちなみにrevertするのはHTMLサポートを無効にしたコミットとのことです。

```yaml:build_emacs_for_android.yml
  # Get libxml2 and upload it
  get-libxml2:
    runs-on: ubuntu-latest
    steps:
    # Clone libxml2 and upload it
    - name: clone libxml2 and upload as tar.gz
      run: |
        git clone https://android.googlesource.com/platform/external/libxml2/
        git -C libxml2 checkout nougat-release
        git -C libxml2 config user.email "you@example.com"
        git -C libxml2 config user.name "Your Name"
        git -C libxml2 revert edb5870767fed8712a9b77ef34097209b61ab2db
```

ここでは`java/INSTALL`のpatchに加えて、更に`LOCAL_EXPORT_CFLAGS := -isystem $(LOCAL_PATH)/include`という行を追加しています。C言語におけるヘッダのincludeでは`#include <aaa.h>`と`#include "bbb.h"`という書き方があります。この`<aaa.h>`で指定されているヘッダファイルはシステムのインクルードファイル用ディレクトリーからヘッダを読み込むよう指定する書き方で、元々ソースに記述されている`LOCAL_C_INCLUDES`では指定できないようです。`java/INSTALL`を手がかりに、どうやら`-isystem path/to/system_include_dir`という情報をコンパイラに渡せばヘッダを見つけてくれる事が判りましたが、ここでコンパイルしているlibxml2はicu4cの56、imagemagickのlibxml2は64というバージョンのicu4cを使う別バージョンだったため、`configer ANDROID_CFLAGS=-isystem path/to/system_include_dir`としてしまうと、どちらかで実行時エラーを起こしてクラッシュするバージョンがビルドされてしまいます。結局[cross/ndk-build/README](https://github.com/ayatakesi/my-emacs/blob/my/master/cross/ndk-build/README)から[cross/ndk-build/ndk-build-static-library.mk](https://github.com/ayatakesi/my-emacs/blob/my/master/cross/ndk-build/ndk-build-static-library.mk)と辿って、モジュールのAndroid.mkで`LOCAL_EXPORT_CFLAGS`を設定すれば、モジュール毎にコンパイラにCFLAGを渡せる事が判ったので、正にそれを行っています。

```diff:build_emacs_for_android.yml
diff --git a/Android.mk b/Android.mk
index 6ec80122..3c0c2e13 100644
--- a/Android.mk
+++ b/Android.mk
@@ -63,6 +63,7 @@ include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(common_SRC_FILES)
 LOCAL_C_INCLUDES += $(common_C_INCLUDES)
 LOCAL_CFLAGS += $(common_CFLAGS) -fvisibility=hidden
+LOCAL_EXPORT_CFLAGS := -isystem $(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES += libicuuc
 LOCAL_MODULE := libxml2
 LOCAL_CLANG := true
@@ -76,10 +77,12 @@ include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(common_SRC_FILES)
 LOCAL_C_INCLUDES := $(common_C_INCLUDES)
 LOCAL_CFLAGS += $(common_CFLAGS)
+LOCAL_EXPORT_CFLAGS := -isystem $(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES := libicuuc
 LOCAL_MODULE:= libxml2
 LOCAL_CLANG := true
 LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)
 include $(BUILD_SHARED_LIBRARY)
 
 # For the host
@@ -89,8 +92,11 @@ include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(common_SRC_FILES)
 LOCAL_C_INCLUDES += $(common_C_INCLUDES)
 LOCAL_CFLAGS += $(common_CFLAGS) -fvisibility=hidden
+LOCAL_EXPORT_CFLAGS := -isystem $(LOCAL_PATH)/include
 LOCAL_SHARED_LIBRARIES += libicuuc-host
 LOCAL_MODULE := libxml2
 LOCAL_CLANG := true
 LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_STATIC_LIBRARY)
+
+$(call import-module,libicuuc)
```

アーカイブしてartifactsとしてアップロード、次ジョブでダウンロードと解凍は他と一緒なので割愛します。

### 4.2.5 gnutls関連
`java/INSTALL`の以下の部分です。バージョンは限定されるようですが、わたしの実機であるAndroid 8.0のarm(aarch64とも呼ぶらしい)については依存関係も含めてすべてEmacs for Androidとビルド可能なバージョンがすでに用意されています。`get-gnutls-and-dependencies`というジョブで取得してます。コードは割愛。

```text:java/INSTALL
Modified copies of GnuTLS and its dependencies (such as libgmp,
libtasn1, p11-kit) which can be built with the ndk-build system can be
found at https://sourceforge.net/projects/android-ports-for-gnu-emacs.

They have only been tested on arm64 Android systems running Android
5.0 or later, and armv7l systems running Android 13 or later, so your
mileage may vary, especially if you are trying to build Emacs for
another kind of machine.

To build Emacs with GnuTLS, you must unpack each of the following tar
archives in that site:

  gmp-6.2.1-emacs.tgz
  gnutls-3.7.8-emacs.tar.gz
  libtasn1-4.19.0-emacs.tar.gz
  p11-kit-0.24.1-emacs.tar.gz
  nettle-3.8-emacs.tar.gz
```

### 4.2.6 treesitter

これも対応版が用意されてました。ダウンロードとかの処理はジョブ`get-treesiter`で行っています
。

```text:java/INSTALL
A copy of tree-sitter modified to build with the ndk-build system can
also be found that URL.  To build Emacs with tree-sitter, you must
unpack the following tar archive in that site:

  tree-sitter-0.20.7-emacs.tar.gz
```

### 4.2.7 harfbuzz

。これも対応版が用意されてました。ジョブは`get-harfbuzz`です。

```text:java/INSTALL
A copy of HarfBuzz modified to build with the ndk-build system can
also be found at that URL.  To build Emacs with HarfBuzz, you must
unpack the following tar archive in that site:

  harfbuzz-7.1.0-emacs.tar.gz
```

### 4.2.8 sqlite3


モジュールのサブディレクトリーdistをconfigureのオプションで指定せよとのこと。これはダウンロード、artifacts経由で渡した次ジョブで行います。

```text:java/INSTALL
sqlite3	- https://android.googlesource.com/platform/external/sqlite/
(You must apply the patch at the end of this file, and add the `dist'
 directory to ``--with-ndk-path''.)
```

cloneしてコミットハッシュ`f63e8d96e298783c310c08030d4c51a875dae4cd`をチェックアウトします。コミットはパッチにあった`LOCAL_SDK_VERSION := 23`という記述から探しました(多分nougat-releaseでも大丈夫かなあ)。

```yaml:build_emacs_for_android.yml
  # Get sqlite3 and upload it
  get-sqlite3:
    runs-on: ubuntu-latest
    steps:
    - name: clone sqlite3 and upload as tar.gz
      run: |
        git clone https://android.googlesource.com/platform/external/sqlite
        # commit hash had guessed by `LOCAL_SDK_VERSION := 23'
        git -C sqlite checkout f63e8d96e298783c310c08030d4c51a875dae4cd
```

`java/INSTALL`のパッチをそのままあてます。

```diff:build_emacs_for_android.yml
diff --git a/dist/Android.mk b/dist/Android.mk
index bf277d2..36734d9 100644
--- a/dist/Android.mk
+++ b/dist/Android.mk
@@ -141,6 +141,7 @@ include $(BUILD_HOST_EXECUTABLE)
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(common_src_files)
 LOCAL_CFLAGS += $(minimal_sqlite_flags)
+LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)
 LOCAL_MODULE:= libsqlite_static_minimal
 LOCAL_SDK_VERSION := 23
 include $(BUILD_STATIC_LIBRARY)

diff --git a/dist/sqlite3.c b/dist/sqlite3.c
index b0536a4..8fa1ee9 100644
--- a/dist/sqlite3.c
+++ b/dist/sqlite3.c
@@ -26474,7 +26474,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
 */
 #if !defined(HAVE_POSIX_FALLOCATE) \
       && (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L)
-# define HAVE_POSIX_FALLOCATE 1
+/* # define HAVE_POSIX_FALLOCATE 1 */
 #endif

 /*
```

### 4.2.9 giflib

ジョブは`get-giflib`です。`java/INSTALL`にはAndroid.mkに`LOCAL_EXPORT_CFLAGS := -I$(LOCAL_PATH)`を追加するよう記述されています。

```text:java/INSTALL
giflib	- https://android.googlesource.com/platform/external/giflib
(You must add LOCAL_EXPORT_CFLAGS := -I$(LOCAL_PATH) before
 its Android.mk includes $(BUILD_STATIC_LIBRARY))
```

これもパッチで行いました。

```diff:build_emacs_for_android.yml
diff --git a/Android.mk b/Android.mk
index 03a9355..13a93d0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,4 +14,5 @@ LOCAL_SRC_FILES := \
 LOCAL_CFLAGS += -Wno-format -Wno-sign-compare -Wno-unused-parameter -DHAVE_CONFIG_H
 LOCAL_MODULE:= libgif

+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
```

### 4.2.10 json

`get-jansson`というジョブです。`java/INSTALL`によるとAndroid.mkに`LOCAL_EXPORT_INCLUDES := $(LOCAL_C_INCLUDES)`を追加して、`android/jansson_config.h`を`android/jansson_private_config.h`にコピーするとあります。

```text:java/INSTALL
libjansson	- https://github.com/akheron/jansson
(You must add LOCAL_EXPORT_INCLUDES := $(LOCAL_C_INCLUDES) before
 its Android.mk includes $(BUILD_SHARED_LIBRARY), then copy
 android/jansson_config.h to android/jansson_private_config.h.)
```

今回もコピーを含めてパッチで処理しましたが、それだけだとヘッダが見つからず`make`でこけてしまったので、ヘッダのディレクトリー指定を追加しました(`LOCAL_EXPORT_INCLUDES`と`LOCAL_EXPORT_CFLAGS`)。

```diff:build_emacs_for_android.yml
diff --git a/Android.mk b/Android.mk
index e3b09e7..c0aa047 100644
--- a/Android.mk
+++ b/Android.mk
@@ -27,4 +27,6 @@ LOCAL_CFLAGS += -O3 -DHAVE_STDINT_H=1
 
 LOCAL_MODULE:= libjansson
 
+LOCAL_EXPORT_INCLUDES := $(LOCAL_C_INCLUDES)
+LOCAL_EXPORT_CFLAGS := -isystem $(LOCAL_PATH)/src -I $(LOCAL_PATH)/android
 include $(BUILD_SHARED_LIBRARY)
diff --git a/android/jansson_private_config.h b/android/jansson_private_config.h
new file mode 100644
index 0000000..618a0da
--- /dev/null
+++ b/android/jansson_private_config.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010-2016 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ *
+ *
+ * This file specifies a part of the site-specific configuration for
+ * Jansson, namely those things that affect the public API in
+ * jansson.h.
+ *
+ * The configure script copies this file to jansson_config.h and
+ * replaces @var@ substitutions by values that fit your system. If you
+ * cannot run the configure script, you can do the value substitution
+ * by hand.
+ */
+
+#ifndef JANSSON_CONFIG_H
+#define JANSSON_CONFIG_H
+
+/* If your compiler supports the inline keyword in C, JSON_INLINE is
+   defined to `inline', otherwise empty. In C++, the inline is always
+   supported. */
+#ifdef __cplusplus
+#define JSON_INLINE inline
+#else
+#define JSON_INLINE inline
+#endif
+
+/* If your compiler supports the `long long` type and the strtoll()
+   library function, JSON_INTEGER_IS_LONG_LONG is defined to 1,
+   otherwise to 0. */
+#define JSON_INTEGER_IS_LONG_LONG 1
+
+/* If locale.h and localeconv() are available, define to 1,
+   otherwise to 0. */
+#define JSON_HAVE_LOCALECONV 0
+
+/* Maximum recursion depth for parsing JSON input.
+   This limits the depth of e.g. array-within-array constructions. */
+#define JSON_PARSER_MAX_DEPTH 2048
+
+#endif
```

### 4.2.11 libjpeg
 
ジョブは`get-libjpeg`です。`java/INSTALL`には`LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)`を追加するよう記載されています。
 
 ```text:java/INSTALL
libjpeg-turbo - https://android.googlesource.com/platform/external/libjpeg-turbo
(You must add LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) before
 its Android.mk includes $(BUILD_SHARED_LIBRARY))
 ```
 
 その通りパッチを当てました。
 
 ```yaml:build_emacs_for_android.yml
  get-libjpeg:
    runs-on: ubuntu-latest
    steps:
    - name: get libjpeg-turbo and patch it
      run: |
        git clone https://android.googlesource.com/platform/external/libjpeg-turbo
        git -C libjpeg-turbo checkout nougat-release
        patch --directory=libjpeg-turbo -p1<<'EOS'
        diff --git a/Android.mk b/Android.mk
        index 2801805f..ab94028e 100644
        --- a/Android.mk
        +++ b/Android.mk
        @@ -75,6 +75,9 @@ ifneq (,$(TARGET_BUILD_APPS))
          LOCAL_SDK_VERSION := 17
         endif
         
        +# Added to build with GNU Emacs on Android
        +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
        +
         # Build as a static library.
         LOCAL_MODULE := libjpeg_static
         include $(BUILD_STATIC_LIBRARY)
        EOS
        tar cvfz libjpeg-turbo.tar.gz ./libjpeg-turbo
 ```

### 4.2.12 ImageMagick
 
次はImageMagickです。今まで追加してきたライブラリの独自バージョンがいくつか含まれている大物です。まずは`java/INSTALL`の記載より。
 
 ```text:java/INSTALL
 There is a third party port of ImageMagick to Android.  Unfortunately,
the port also uses its own patched versions of libpng, libjpeg,
libtiff and libwebp, which conflict with those used by Emacs.  Its
Makefiles were also written for MS Windows, so you must also apply the
patch at the end of this file.
```
 つまりパッチを沢山当てる必要があるとのこと。更にlibxml2とともにビルドする場合には異なるバージョンで同じファイル名をもつ静的ライブラリの衝突を回避するためのパッチの追加も必要でした。でかいので全部は載せません。`java/INSTALL`のパッチに加えて、以下のように名前を弄っています。ジョブは`get-imagemagick`です。
 
 ```diff:build_emacs_for_android.yml
-LOCAL_STATIC_LIBRARIES += libicuuc
+LOCAL_STATIC_LIBRARIES += libicuucmagick 
```

### 4.2.13 selinux関連

最後はselinuxとその依存関係です。

```text:java/INSTALL
libselinux	- https://android.googlesource.com/platform/external/libselinux
(You must apply the patches at the end of the file, and obtain
 the following three dependencies.)
libpackagelistparser
    https://android.googlesource.com/platform/system/core/+/refs/heads/nougat-mr1-dev/libpackagelistparser/
libpcre	- https://android.googlesource.com/platform/external/pcre
libcrypto	- https://android.googlesource.com/platform/external/boringssl
(You must apply the patch at the end of this file when building for
 ARM systems.)
```

まずはselinuxから。

```yaml:build_emacs_for_android.yml
  get-libselinux:
    runs-on: ubuntu-latest
    steps:
    - name: get selinux and archive it
      run: |
        git clone https://android.googlesource.com/platform/external/libselinux
        git -C libselinux checkout nougat-release
        patch --directory libselinux -p1 << 'EOS'
        diff --git a/Android.mk b/Android.mk
      # ...
      # 以下 java/INSTALLのパッチをそのまま当ててます
```

次にAndroidのcoreライブラリに含まれているpackagelistparserです。ブランチは指定通り`nougat-mr1-dev`をチェックアウトします。

```yaml:build_emacs_for_android.yml
  get-core:
    runs-on: ubuntu-latest
    steps:
    - name: get core and archive it
      run: |
        git clone https://android.googlesource.com/platform/system/core
        git -C core checkout nougat-mr1-dev
```

システムヘッダファイルを`make`が見つけられなかったので、`LOCAL_EXPORT_CFLAGS := -isystem $(LOCAL_PATH)/../include`を追加するパッチを当てます。

```diff:build_emacs_for_android.yml
diff --git a/libpackagelistparser/Android.mk b/libpackagelistparser/Android.mk
index c8be050e0..563fdc66a 100644
--- a/libpackagelistparser/Android.mk
+++ b/libpackagelistparser/Android.mk
@@ -13,6 +13,7 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CLANG := true
 LOCAL_SANITIZE := integer
 
+LOCAL_EXPORT_CFLAGS := -isystem $(LOCAL_PATH)/../include
 include $(BUILD_SHARED_LIBRARY)
 
 #########################
@@ -29,4 +30,5 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_CLANG := true
 LOCAL_SANITIZE := integer
 
+LOCAL_EXPORT_CFLAGS := -isystem $(LOCAL_PATH)/../include
 include $(BUILD_STATIC_LIBRARY)
```

次はpcreです。cloneしてnougat-releaseをチェックアウトするだけです。

```yaml:build_emacs_for_android.yml
  # get pcre from google
  get-pcre:
    runs-on: ubuntu-latest
    steps:
    - name: get pcre and archive it
      run: |
        git clone https://android.googlesource.com/platform/external/pcre
        git -C pcre checkout nougat-release
```

最後はboringsslです。cloneしてnougat-releaseをチェックアウト、artifacts経由で次ジョブに渡して

```yaml:build_emacs_for_android.yml
  # get boringssl from google
  get-boringssl:
    runs-on: ubuntu-latest
    steps:
    - name: get boringssl and archive it
      run: |
        git clone https://android.googlesource.com/platform/external/boringssl
        git -C boringssl checkout nougat-release
```

次ジョブにてターゲットが`arm`なら`java/INSTALL`のパッチをそのまま当てます。

```yaml:build_emacs_for_android.yml
    # download boringssl
    - name: download boringssl
      uses: actions/download-artifact@v3
      with:
        name: boringssl
        path: my_sub_modules
    - name: expand archives
      run: |
        cd my_sub_modules
        tar xvfz boringssl.tar.gz
        # patch if ARM
        if [ ${{ matrix.abi }} == "arm" ]
        then
          patch --directory boringssl -p1 << 'EOS'
        # ...
	# コードは省略します
```

## 4.3 ビルドする

[4.2 サードパーティライブラリの取得とかpatch適用](#42-サードパーティライブラリの取得とかpatch適用)が終わったらそれらと一緒にEmacsをビルドします。`needs:`に記した前提条件は、正常終了が実行の条件となるジョブであり、それらのジョブというのがすなわち[4.2 サードパーティライブラリの取得とかpatch適用](#42-サードパーティライブラリの取得とかpatch適用)ということです。

`strategy`の`matrix`ですが、これらはビルドする環境や配布先のデバイスを指定します。当初は「一片にビルド走って壮観だろうなあ」とか思って書きましたが、200以上のジョブの赤い異常終了ステータスを目にするのはあまり面白くなく、自分がもっている環境じゃないとテストもできないので、実績2つのmatrixだけです。

```yaml:build_emacs_for_android.yml
  job1:
    runs-on: ubuntu-latest
    needs: [get-libselinux, get-core, get-pcre, get-boringssl, get-tiff, get-webp, get-libxml2, get-icu4c, get-gnutls-and-dependencies, get-treesiter, get-harfbuzz, get-sqlite3, get-giflib, get-jansson, get-libjpeg, get-imagemagick]
    strategy:
      matrix:
        api-version: [34]
        # ndk-version: [23.2.8568313, 24.0.8215888, 25.2.9519653]
        ndk-version: [25.2.9519653]
        # abi: [i686, x86_64, aarch64, armv7a, mips64, mips, arm]
        abi: [aarch64]
        # minsdk: [22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
        minsdk: [22, 33]
```

- api-version:Android SDK同梱の`android.jar'のパス。api levelとも呼ばれるもので、最新バージョンの指定が必須。先頃33から34に更新されました。

- ndk-version: ビルドしたEmacsを実行するCPUに応じたAndroid NDKのCコンパイラーのパス。古かったりバージョンが違ったりで色々問題が発生するらしいです。

- abi: ビルドしてインストール先となるCPU。configureとかパッチではaarch64がarm64-v8aとかになってます。対応は`configure.ac`に書いてあります。

```shell:configure.ac
  AC_MSG_CHECKING([for the kind of Android system Emacs is being built for])
  cc_target=`${ANDROID_CC} -v 2>&1 | sed -n 's/Target: //p'`
  case "$cc_target" in
[
    *i[3-6]86*) android_abi=x86
      ;;
    *x86_64*) android_abi=x86_64
      ;;
    *aarch64*) android_abi=arm64-v8a
      ;;
    *arm*v7a*) android_abi=armeabi-v7a
      ;;
    *mips64*) android_abi=mips64
      ;;
    *mips*) android_abi=mips
      ;;
    *arm*) android_abi=armeabi
      ;;
]
```

- minsdk: アプリが実行できるAndroidの最低バージョン。ユーザーにとってはいちばん気のなるところだと思います(たとえばわたしのAndroid 8.0端末では先だってのslackのバージョンアップにより対象バージョンから漏れて、アプリによるアクセスができなくなりました)。

### 4.3.1 レポジトリの作成とモジュールのダウンロード

レポジトリ自体をチェックアウトしてからartifactsとしてモジュールをダウンロードするためのディレクトリーを作成します。最初はレポジトリのルートにそのままダウンロードしてたんですが、core/libpackagelistparserのビルドが何をどーやって指定しても上手くゆかず、ログをひっくり返してやっとEmacs自体のビルド処理がレポジトリルートのcoreというファイルを削除しているらしい事がわかったので、別途フォルダを作成するよう変更しました。このフォルダに[4.2 サードパーティライブラリの取得とかpatch適用](#42-サードパーティライブラリの取得とかpatch適用)のモジュール達をダウンロードして展開します。

```yaml:build_emacs_for_android.yml
    steps:
    #
    # Checkout source.
    - name: Checkout source
      uses: actions/checkout@v3
    #
    # make directory for sub modules
    - name: make directory for sub modules
      run: |
        mkdir my_sub_modules
```

### 4.3.2 環境のセットアップとautogen.shの実行

どこかで見つけた例の通りにjavaとandroidの環境をセットアップして、Emacsをレポジトリから直接ビルドする際に通常実行する`autogen.sh`を実行します(これによって`configure`スクリプトが作成される)。

```yaml:build_emacs_for_android.yml
    # Setup java/jdk.
    - name: Setup java environment
      uses: actions/setup-java@v3
      with:
        distribution: zulu
        java-version: 11
    #
    # Setup android environment.
    - name: Setup android
      uses: android-actions/setup-android@v2
    #
    # Run autogen.sh
    - name: run autogen.sh
      run: |
        ./autogen.sh
```

### 4.3.3 configureの実行

やっと`configure`を実行します。モジュールを指定したり通常のEmacsのconfigure時のように有効にするライブラリとかを指定してます。configureの前後にある`sh -x`と`2>&1 | tee configure.out`は上手く行かなかったとき用のログ収集のため。`sh -x`を削除すれば出力はぐっと減ります。

指定しているオプションについて説明すると

- --with-android: matrixのapi-version、すなわち34です
- ANDROID_CC: matrixのndk-versionからCPUがmatrixのabi、対象とする最低バージョンのAndroid APIレベルがmatrixのminsdkであることを指定しています。
- SDK\_BUILD\_TOOLS: これはapi-versionと同じにしてます(定数になってますが意味はありません)。
- --with-ndk-path: artifacts経由でダウンロード、解凍したモジュールのAndroid.mkがあるディレクトリーです。
- --with-shared-user: Termuxと互いにディレクトリーを参照できるように`com.termux`を指定しています。

:::note warn
Google PlayやF-DroidのTermuxはそれぞれその配布元のキーで署名されているので、それらがインストールされている場合には、共有ユーザーIDに`com.termux`を指定するとインストールができません(不明なキーで署名された同一ユーザー名を騙るアプリとして認識されるからです)。ここで共存先として想定しているのは、[Emacs for Android](https://sourceforge.net/projects/android-ports-for-gnu-emacs/files/termux/)で配布されているバージョンのTermuxです。Termuxもオープンソースであり、Githubにレポジトリもあるのでforkして署名だけ`java/emacs.keystore`を使って自分でビルドすることもできます。他のプラグイン(Termux:bootとか)も使いたい人は自前でビルドする方がよいかもしれません。
:::

- その他の--with-XXX: Emacsのいつものビルドで指定するオプションと同じ。`--with-ndk-path`で指定したモジュールについては`yes`を指定しましょう(`--with-x-toolkit=no`は不要かもしれません; 最小構成で実験的にビルドしてたときの名残りです)。

```yaml:build_emacs_for_android.yml
        MODULE_ROOT=$(pwd)/my_sub_modules
        sh -x ./configure \
          --with-android=$ANDROID_HOME/platforms/android-${{ matrix.api-version }}/android.jar \
          ANDROID_CC="$ANDROID_HOME/ndk/${{ matrix.ndk-version }}/toolchains/llvm/prebuilt/linux-x86_64/bin/${{ matrix.abi }}-linux-android${{ matrix.minsdk }}-clang" \
          SDK_BUILD_TOOLS=$ANDROID_HOME/build-tools/34.0.0 \
          "--with-ndk-path=$MODULE_ROOT/libselinux $MODULE_ROOT/core/libpackagelistparser $MODULE_ROOT/pcre $MODULE_ROOT/boringssl $MODULE_ROOT/tiff-4.5.0 $MODULE_ROOT/webp $MODULE_ROOT/libxml2 $MODULE_ROOT/icu $MODULE_ROOT/gmp-6.2.1 $MODULE_ROOT/gnutls-3.7.8 $MODULE_ROOT/libtasn1-4.19.0 $MODULE_ROOT/nettle-3.8 $MODULE_ROOT/p11-kit-0.24.1 $MODULE_ROOT/tree-sitter-0.20.7 $MODULE_ROOT/harfbuzz-7.1.0 $MODULE_ROOT/sqlite/dist $MODULE_ROOT/giflib $MODULE_ROOT/jansson $MODULE_ROOT/libjpeg-turbo $MODULE_ROOT/Android-ImageMagick7"  \
        --with-x-toolkit=no \
        --with-shared-user-id=com.termux \
        --with-gnutls=yes \
        --with-tree-sitter=yes \
        --with-harfbuzz=yes \
        --with-sqlite3=yes \
        --with-xml2=yes \
        --with-gif=yes \
        --with-json=yes \
        --with-tiff=yes \
        --with-jpeg=yes \
        --with-webp=yes \
        --with-png=yes \
        --with-imagemagick=yes \
        --with-selinux=yes 2>&1 | tee configure.out
```
### 4.3.4 makeとか

makeして成功したら`*.apk`をartifactsとしてアップロードします。makeのオプション`V=1`はデバッグ用に沢山出力させるたねのオプションかな? `-j$(nproc)`は多重度を上げて高速化するためのオプション。とるとスピードは遅くなるが出力は読みやすくなります。

```yaml:build_emacs_for_android.yml
    #
    # Run make to build apk.
    - name: run make
      run: |
        make V=1 -j$(nproc) ||
          for F in cross/ndk-build/*.a
          do
            echo "ayatakesi_debug: nm $F"
            nm $F
            echo
          done
    #
    # Upload apk as artifacts.
    - name: upload apk
      uses: actions/upload-artifact@v3
      with:
        name: Emacs.apk
        path: ./java/*.apk
```

# 5 インストール

ダウンロードして解凍して*.apkをタップすればインストールできる筈です。

実行して確認するとビルドできたみたいです。

![Screenshot_20231011-071339.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134669/d496ebf8-6586-e529-649a-691121e21391.jpeg)

ewwも動きます

![Screenshot_20231011-071704.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134669/09bfec0c-2632-853a-a9e2-212832ee468f.jpeg)

次記事ではEmacsとTermuxを共存させるために行った環境設定について説明します。

おしまい