序
わたしはパッケージのビルドとかAndroid開発にはあまり詳しくなく、apt
やyum
などでインストールできるパッケージは素直にパッケージマネージャーでインストールする派です。しかし今回、Termux上でパッケージが見つからなかったアプリをインストールしたくなり、しょうがないのでやってみました(実はこれは辞書サーバーによる辞書環境の構築の後日譚であります。そのため、dictd
という世間ではあまり馴染みのないソフトがお題になってます。)
GNU autotools
パッケージのコンパイル手順 on Termux
Termuxのマニュアルを参照しました。以下にGNU autotools
アプリ(./configure && make &&make install
でインストールできるやつ)をビルドする手順を要約します。
環境の準備
必要なアプリのインストール
ビルドに必要なツールをインストールします。インストールする前に、pkg update
とpkg upgrade
をしといたほうが良いです。
$ 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
.....
環境変数の設定
以下の2行を.bashrc
に追加します。
export PREFIX=/data/data/com.termux/files/usr
export LD_PRELOAD=${PREFIX}/lib/libtermux-exec.so
依存関係の把握
マニュアルにはArchLinux package databaseで依存するパッケージを特定して
それからインストールするようにと記述されてます。身近にlinux機のある方はapt-get build-dep
の類いのコマンドで調べたほうが簡単でしょう。依存するパッケージがTermuxのパッケージリポジトリで提供されていればそれをpkg install
でインストールするだけですが、提供されていなければそれもソースからビルドする必要があります。
ソースコードなどの修正
ソース内で
/bin
/etc
/sbin
/tmp
/usr
/var
のような、ハードコーディングされがちな標準パスの前に、先程の$PREFIX
の値を付け加えます。「find
でgrep
かけて...」とか、「emacs
のDired
から...」とか、好きな方法で修正対象のファイルを見つけて修正します。マニュアルではag
(先の必要アプリインストールの中のsilversearcher-ag
のこと)が推奨されてます。
ビルド
config.sub
とconfig.guess
の置き換え
この2つを置き換えないとターゲットシステムを判断できないそうです。以下のコマンドで置き換えます。
find . -name 'config.sub' -exec chmod u+w '{}' \; -exec cp -f "${PREFIX}/share/libtool/build-aux/config.sub" '{}' \;
find . -name 'config.guess' -exec chmod u+w '{}' \; -exec cp -f "${PREFIX}/share/libtool/build-aux/config.guess" '{}' \;
configure
に必要なオプションを指定
Termuxでビルド、インストールできるように以下のオプションを指定します。
$ ./configure --prefix="${PREFIX}" CC=clang CXX=clang++
make
してインストール
特に問題がなければ普通にmake -j4 && make install
ソースtarball入手
dictd
はlibmaa
に依存しており、どちらも同じ開発元が提供しています。こちらからソースを入手しました。最新版はdictd-1.12.1.tar.gz
とlibmaa-1.3.2.tar.gz
です。
libmaaのビルドとインストール
$ tar xvfz libmaa-1.3.2.tar.gz #解凍
libmaa-1.3.2
libmaa-1.3.2/doc
libmaa-1.3.2/doc/Makefile.in
libmaa-1.3.2/doc/extract.pl
libmaa-1.3.2/doc/lgrindefs
.....
$ cd libmaa-1.3.2 #ソースディレクトリへcd
ソース内でハードコードされているディレクトリがないか調べる。libmaaは修正必要なしでした。
$ ag --cc /bin
$ ag --cc /etc
$ ag --cc /sbin
$ ag --cc /tmp
$ ag --cc /usr
$ ag --cc /var
configure
します。マニュアルに記載のないLIBS=-llog
は、これを指定しなくてもlibmaa
はビルドとインストールはできたんですけど、dictd
のconfigure
時に「libmaa
が未定義の__android_log_print
などを参照している」→「libmaa
がインストールされてない(誤解)」とかでコケるので、調べた結果これを追加しました。ちなみにこのliblog.so
はTermuxではなくAndroidシステムの/system/lib/liblog.so
らしいです。
$ ./configure --prefix="${PREFIX}" CC=clang CXX=clang++ LIBS=-llog Configuring for libmaa 1.3.2
.
checking build system type... aarch64-unknown-linux-gnu
checking host system type... aarch64-unknown-linux-gnu
checking for gawk... gawk
checking for gcc... clang
checking whether the C compiler works... yes
.....
終わったらmake
してインストール
$ make -j4 && make install
libtool --tag=CC --mode=compile clang -o obstack.o -c -DHAVE_CONFIG_H -g -O2 -DMAA_MAJOR=1 -DMAA_MINOR=3 -DMAA_TEENY=2 -I. -I. obstack.c
libtool --tag=CC --mode=compile clang -o xmalloc.o -c -DHAVE_CONFIG_H -g -O2 -DMAA_MAJOR=1 -DMAA_MINOR=3 -DMAA_TEENY=2 -I. -I. xmalloc.c
libtool --tag=CC --mode=compile clang -o hash.o -c -DHAVE_CONFIG_H -g -O2 -DMAA_MAJOR=1 -DMAA_MINOR=3 -DMAA_TEENY=2 -I. -I. hash.c
libtool --tag=CC --mode=compile clang -o set.o -c -DHAVE_CONFIG_H -g -O2 -DMAA_MAJOR=1 -DMAA_MINOR=3 -DMAA_TEENY=2 -I. -I. set.c
libtool: compile: clang -c -DHAVE_CONFIG_H -g -O2 -DMAA_MAJOR=1 -DMAA_MINOR=3 -DMAA_TEENY=2 -I. -I. hash.c -fPIC -DPIC -o .libs/hash.o
.....
dictdのビルドとインストール
$ tar xvfz dictd-1.12.1.tar.gz #解凍
dictd-1.12.1
dictd-1.12.1/doc
dictd-1.12.1/doc/Makefile.in
dictd-1.12.1/doc/dicf.ms
dictd-1.12.1/doc/rfc.ms
.....
$ cd dictd-1.12.1 #ソースディレクトリへcd
ソース内でハードコードされているディレクトリがないか調べる。parse.c
とdictd.c
が要修正です。
$ ag --cc /bin
$ ag --cc /etc
$ ag --cc /sbin
$ ag --cc /tmp
$ ag --cc /usr
parse.c
94: "/usr/lib/cpp",
95: "/usr/ccs/lib/cpp", /*Solaris */
96: "/usr/lang/cpp",
$ ag --cc /var
dictd.c
78:const char *pidFile = "/var/run/dictd.pid";
parse.c
を修正した結果です。
--- parse.c~ 2008-12-08 01:50:05.000000000 +0900
+++ parse.c 2018-01-23 05:51:09.760006028 +0900
@@ -90,10 +90,10 @@ void prs_file( const char *filename )
char *buffer;
const char **pt;
static const char *cpp = NULL;
- static const char *cpps[] = { "/lib/cpp",
- "/usr/lib/cpp",
- "/usr/ccs/lib/cpp", /* Solaris */
- "/usr/lang/cpp",
+ static const char *cpps[] = { "/data/data/com.termux/files/usr/lib/cpp",
+ "/data/data/com.termux/files/usr/usr/lib/cpp",
+ "/data/data/com.termux/files/usr/usr/ccs/lib/cpp", /* Solaris */
+ "/data/data/com.termux/files/usr/usr/lang/cpp",
0 };
static const char *extra_options = "";
FILE *tmp;
そしてこちらがdictd.c
の修正後
--- dictd.c~ 2011-01-10 01:53:27.000000000 +0900
+++ dictd.c 2018-01-23 05:51:01.530006030 +0900
@@ -75,7 +75,7 @@ int logOptions = 0;
const char *logFile = NULL;
int logFile_set; /* 1 if set by command line option */
-const char *pidFile = "/var/run/dictd.pid";
+const char *pidFile = "/data/data/com.termux/files/usr/var/run/dictd.pid";
int pidFile_set; /* 1 if set by command line option */
const char *daemon_service = DICT_DEFAULT_SERVICE;
ここまでは、マニュアルに記載されていたTermuxでのビルド方法を踏襲しました。しかし、これだけではやはり上手くビルド、またはビルドできても正常に動作させることができなかったので、その対応を書きます。
Makefile.in
の修正
libtool
というのはmode=compile
のときはソースディレクトリに.libs
というディレクトリを作成してそこにオブジェクトファイル*.o
をコンパイルし、ソースディレクトリのルートには、(多分)それらのオブジェクトファイルを参照する*.lo
というファイルを作成するようです。そしてmode=link
のときはルートディレクトリの*.lo
を参照する感じなのでしょうか。自分も他のMakefile
とかルールなどと比較して推測してるんで、あやふやで申し訳ないんですが。以下が修正後です。
diff -u -r ../dictd-1.12.1.orig/Makefile.in ./Makefile.in
--- ../dictd-1.12.1.orig/Makefile.in 2011-03-07 02:52:54.000000000 +0900
+++ ./Makefile.in 2018-02-08 18:50:15.790039388 +0900
@@ -123,7 +123,7 @@
%: %.o
$(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ -static \
- $^ $(OBJS) $(LDFLAGS) -lz ${LIBS}
+ $(^:.o=.lo) $(OBJS) $(LDFLAGS) -lz ${LIBS}
include $(srcdir)/deps
しかし同じコマンドでmode=compile
のときは勝手に.libs
なるディレクトリを作成して、mode=link
のときはルートの*.lo
を参照するのはいいとしても、ユーザーが毎回いちいち:.o=.lo
とか記述しなきゃいけないのは何か釈然としません。こーゆーものなのでしょうか?(だとしたらdictd
のMakefile.in
のバグということになりますが、他のプラットフォームで検証してないので、よく解りません)。
net.c
の修正
ここまでの対応で無事にビルド、インストールできたのですが、実行するとCan't get "tcp" protocol entry
というエラーで起動してくれません。ググった結果、Androidでは/etc/protocols
の内容をハードコーディングしなくてはならないようです。以下はその対応です。
--- net.c~ 2010-08-22 02:55:40.000000000 +0900
+++ net.c 2018-01-23 07:20:49.070005208 +0900
@@ -65,7 +65,9 @@ int net_connect_tcp( const char *host, c
{
struct hostent *hostEntry;
struct servent *serviceEntry;
+ /*
struct protoent *protocolEntry;
+ */
struct sockaddr_in ssin;
int s;
int hosts = 0;
@@ -79,8 +81,10 @@ int net_connect_tcp( const char *host, c
} else if (!(ssin.sin_port = htons(atoi(service))))
return NET_NOSERVICE;
+ /*
if (!(protocolEntry = getprotobyname("tcp")))
return NET_NOPROTOCOL;
+ */
if ((hostEntry = gethostbyname(host))) {
++hosts;
@@ -92,7 +96,7 @@ int net_connect_tcp( const char *host, c
memcpy( &ssin.sin_addr.s_addr, *current, hostEntry->h_length );
PRINTF(DBG_VERBOSE,
("Trying %s (%s)\n",host,inet_ntoa(ssin.sin_addr)));
- if ((s = socket(PF_INET, SOCK_STREAM, protocolEntry->p_proto)) < 0)
+ if ((s = socket(PF_INET, SOCK_STREAM, 6)) < 0)
err_fatal_errno( __func__, "Can't open socket on port %d\n",
ntohs(ssin.sin_port) );
if (connect(s, (struct sockaddr *)&ssin, sizeof(ssin)) >= 0)
@@ -100,7 +104,7 @@ int net_connect_tcp( const char *host, c
close(s);
}
} else {
- if ((s = socket(PF_INET, SOCK_STREAM, protocolEntry->p_proto)) < 0)
+ if ((s = socket(PF_INET, SOCK_STREAM, 6)) < 0)
err_fatal_errno( __func__, "Can't open socket on port %d\n",
ntohs(ssin.sin_port) );
if (connect(s, (struct sockaddr *)&ssin, sizeof(ssin)) >= 0)
@@ -117,7 +121,10 @@ int net_open_tcp (
int queueLength)
{
struct servent *serviceEntry;
+ /*
struct protoent *protocolEntry;
+ */
+
struct sockaddr_in ssin;
int s;
const int one = 1;
@@ -131,10 +138,12 @@ int net_open_tcp (
} else if (!(ssin.sin_port = htons(atoi(service))))
err_fatal( __func__, "Can't get \"%s\" service entry\n", service );
+ /*
if (!(protocolEntry = getprotobyname("tcp")))
err_fatal( __func__, "Can't get \"tcp\" protocol entry\n" );
+ */
- if ((s = socket(PF_INET, SOCK_STREAM, protocolEntry->p_proto)) < 0)
+ if ((s = socket(PF_INET, SOCK_STREAM, 6)) < 0)
err_fatal_errno( __func__, "Can't open socket on port %d\n",
ntohs(ssin.sin_port) );
これでソースへの対応は終了です。マニュアルどおりにインストールします。
$ find . -name 'config.sub' -exec chmod u+w '{}' \; -exec cp -f "${PREFIX}/share/libtoo\
l/build-aux/config.sub" '{}' \;
$ find . -name 'config.guess' -exec chmod u+w '{}' \; -exec cp -f "${PREFIX}/share/libt\
ool/build-aux/config.guess" '{}' \;
$ ./configure --prefix="${PREFIX}" CC=clang CXX=clang++
Configuring for dict
.
checking build system type... aarch64-unknown-linux-gnu
checking host system type... aarch64-unknown-linux-gnu
checking for gcc... clang
checking whether the C compiler works... yes
.....
$ make -j4
libtool --tag=CC --mode=compile clang -c -DHAVE_CONFIG_H -g -O2 -DUSE_PLUGIN -DDICT_PLUGIN_PATH=\"/data/data/com.termux/files/usr/libexec/\" -DDICT_DICTIONARY_PATH=\"/data/data/com.termux/files/usr/share/\" -DDICT_VERSION=\"1.12.1\" -DDICT_CONFIG_PATH=\"/data/data/com.termux/files/usr/etc/\" -I. -I. net.c -o net.o
flex -oclientscan.c clientscan.l
bison -y -dv clientparse.y; \
cmp -s y.tab.h clientparse.h || mv y.tab.h clientparse.h; \
cmp -s y.tab.c clientparse.c || mv y.tab.c clientparse.c; \
rm -f y.tab.h y.tab.c
bison -y -dv clientparse.y; \
cmp -s y.tab.h clientparse.h || mv y.tab.h clientparse.h; \
cmp -s y.tab.c clientparse.c || mv y.tab.c clientparse.c; \
rm -f y.tab.h y.tab.c
libtool --tag=CC --mode=compile clang -c -DHAVE_CONFIG_H -g -O2 -DUSE_PLUGIN -DDICT_PLUGIN_PATH=\"/data/data/com.termux/files/usr/libexec/\" -DDICT_DICTIONARY_PATH=\"/data/data/com.termux/files/usr/share/\" -DDICT_VERSION=\"1.12.1\" -DDICT_CONFIG_PATH=\"/data/data/com.termux/files/usr/etc/\" -I. -I. md5.c -o md5.o
.....
$ make install
libtool --tag=CC --mode=compile clang -c -DHAVE_CONFIG_H -g -O2 -DUSE_PLUGIN -DDICT_PLUGIN_PATH=\"/data/data/com.termux/files/usr/libexec/\" -DDICT_DICTIONARY_PATH=\"/data/data/com.termux/files/usr/share/\" -DDICT_VERSION=\"1.12.1\" -DDICT_CONFIG_PATH=\"/data/data/com.termux/files/usr/etc/\" -I. -I. net.c -o net.o
libtool: compile: clang -c -DHAVE_CONFIG_H -g -O2 -DUSE_PLUGIN -DDICT_PLUGIN_PATH=\"/data/data/com.termux/files/usr/libexec/\" -DDICT_DICTIONARY_PATH=\"/data/data/com.termux/files/usr/share/\" -DDICT_VERSION=\"1.12.1\" -DDICT_CONFIG_PATH=\"/data/data/com.termux/files/usr/etc/\" -I. -I. net.c -fPIC -DPIC -o .libs/net.o
libtool --tag=CC --mode=compile clang -c -DHAVE_CONFIG_H -g -O2 -DUSE_PLUGIN -DDICT_PLUGIN_PATH=\"/data/data/com.termux/files/usr/libexec/\" -DDICT_DICTIONARY_PATH=\"/data/data/com.termux/files/usr/share/\" -DDICT_VERSION=\"1.12.1\" -DDICT_CONFIG_PATH=\"/data/data/com.termux/files/usr/etc/\" -I. -I. clientparse.c -o clientparse.o
libtool: compile: clang -c -DHAVE_CONFIG_H -g -O2 -DUSE_PLUGIN -DDICT_PLUGIN_PATH=\"/data/data/com.termux/files/usr/libexec/\" -DDICT_DICTIONARY_PATH=\"/data/data/com.termux/files/usr/share/\" -DDICT_VERSION=\"1.12.1\" -DDICT_CONFIG_PATH=\"/data/data/com.termux/files/usr/etc/\" -I. -I. clientparse.c -fPIC -DPIC -o .libs/clientparse.o
.....
辞書や設定ファイルなどの準備
わたしの目的はGNURootからTermuxへの運用移行なので、そこまで書いておきます。一応ここまででTermuxでソースからビルドする、というのは終わりなのでdictd
とか興味ない人は読む必要ないです。
辞書ファイルの準備
GNURootで運用してた辞書ファイルを流用します。辞書変換ツールdictfmt
はdictd
と一緒にインストールされているので、多分テキスト形式の辞書ファイルからdictd
形式への変換はできるでしょう。後日余力があったら検証します。
$ ls -l $PREFIX/share/dict/
total 87924
-rwxr--r-- 1 u0_a132 u0_a132 62649479 Jan 22 23:54 eijiro.dict
-rwxr--r-- 1 u0_a132 u0_a132 27278900 Jan 22 23:54 eijiro.index
pid
ファイル用のディレクトリ作成
dictd.c
の修正で/var/run/dictd.pid
を/data/data/com.termux/files/usr/var/run/dictd.pid
に修正しましたが、$PREFIX/var
にrun
というディレクトリがないので作成します。
$ mkdir $PREFIX/var/run
設定ファイルの準備
設定ファイルを準備します。コマンドにはフルパスを指定するのでどこにどんな名前で作ってもいいんですが、GNURootと合わせるため、$PREFIX/etc
にdictd
というディレクトリを作って、設定ファイル名もdictd.conf
にしました。
global {
listen_to 127.0.0.1
# bind to local interfacea only
}
# Access section here:
access {
allow localhost
allow 127.0.0.1
# this allows access only from local host
allow inetd
# this allows access from inetd server
}
# Database section here:
#include /var/lib/dictd/db.list
# User section here:
database eijiro {
data "/data/data/com.termux/files/usr/share/dict/eijiro.dict"
index "/data/data/com.termux/files/usr/share/dict/eijiro.index" }
起動
起動します。うまく起動しないときログが役に立ったので情報を多く出力するよう指定してます。あとAndroidのsyslogがどこに吐かれるか解らなかったので、出力ファイル名も指定してます。
$ $PREFIX/sbin/dictd -c $PREFIX/etc/dictd/dictd.conf -v -d verbose -L $PREFIX/var/log/dictd.log
$ cat $PREFIX/var/log/dictd.log
:I: 9079 starting dictd 1.12.1/rf on Linux 3.10.94 Tue Jan 23 01:17:18 2018
:I: eijiro 1016642 27278900 62649479 62649479
$ dict -h localhost 'heavy snow'
1 definition found
From eiwa [eijiro]:
heavy snow
豪雪、ひどい雪、大雪、まとまった雪
結び
マニュアルを見たときは「こりゃ簡単!」と思ったんですが、結局朝までかかりました。GNU autotools
難しいですね。おわり