Docker上のalpineでhts_engineがmakeできない

最近、Japanese TTS Botで使用している各種のソフトウェアやらなんやらがアップデートした関係で、Botを作り直そうといろいろやっています。

んで、読み上げBotの機能の中枢を担う、Open JTalkを使用するのに必要なhts_engineって言うものがあるんですが、これがどうもalpineではインストールできない。ubuntuだと一発でうまくいく。どうして?

C言語とかLinuxつよつよな人、助けて。fpos_tってなに。

何をしようとしていたか

Botの環境はめんどくさい。

Dockerを使って、地味〜に面倒なBot(自作)に必要な環境を全部自動でインストールできるようにしたかったんです。

現在、Japanese TTS Botで使用している主な前提ソフトウェア類は、Python3、ffmpeg、そしてOpen JTalk 。

 Python3とffmpegに関してはパッケージマネージャでインストールできるので問題ないんですが、OpenJTalkに関しては、

  1. hts_engine(前提環境)のソースコードのダウンロード、コンパイル
  2. Open JTalkのソースコードのダウンロード、コンパイル
  3. OpenJTalk用の音声データのダウンロード
  4. Open JTalk用の辞書ファイルのダウンロード

という手順があるので、サクッと環境構築…というわけにもいかない。

そうだ、Dockerを使おう

いつぞやの記事でサクッと調べたことをまとめたDockerですが、今私が直面している「環境構築の煩雑さ」という問題は、Dockerの得意分野なはずです。

勉強材料として、自分が管理するDiscordサーバーに導入しているMusicBotのDockerfileを見ました。その冒頭も冒頭、1行目に気になる記述を発見しました。

FROM alpine:edge

調べてみると、alpineというのはbusybox(高速・低サイズ化されたLinux用コマンド集)とパッケージマネージャを組み合わせたようなものらしく、めちゃくちゃサイズが小さいです。

Dcokerのベースイメージが小さいということは、それだけビルドに時間やコンピュータリソースを割く必要がないということ。小さいことはいいことなのだ。

Dockerのベースイメージの比較

試しに、よく使うOSのDockerイメージのサイズを比較するとこんな感じ(2019年2月18日時点)

alpine
5.53MB
ubuntu
86.7MB
debian101MB
opensuse110MB
centos202MB
fedora275MB

RedHat系だけ2〜3倍近くサイズが違うことにも驚きますが、何より驚異的なのはalpineのサイズ。ubuntuの15分の1以下です。TTS Botやそれに付随するソフトウェアを合計しただけで5MB以上にはなると思うのですが、それ以下のサイズでOSが構成されてるって一体…

ubuntuではなくalpineを使うだけで80MB以上節約できちゃうなんて言われたら、使ってみたくなりますよね?というわけで、alpine上にOpenJTalkをインストールするために、htc_engineとかを一気にインストールするDockerfileを書いていきます。

よし、alpineにhts_voiceをインストールするぞ!

Dockerfileとの戦い

実は自分でDockerfileを書くのは初めてなので、勉強しながら書いている部分が多いです。確実にベストプラクティスではありませんが、なんとか動くはず。

とりあえず、hts_engineをインストールするところまでのDockerfileを以下のような感じに書いてみました。

FROM alpine:latest

# Settings
ARG OPENJTALK_VERSION=1.11
ARG HTS_VERSION=1.10

# Add project source
WORKDIR /usr/src/ttsbot
COPY . ./

# Init
RUN apk update && apk upgrade \
# Install build dependancies with apk
    && apk add --no-cache --virtual .build-deps \
        curl \
        build-base \
# Install hts_engine
    && mkdir /usr/local/src/ \
    && cd /usr/local/src/ \
    && curl -SLO http://downloads.sourceforge.net/hts-engine/hts_engine_API-${HTS_VERSION}.tar.gz\
    && tar -zxvf hts_engine_API-${HTS_VERSION}.tar.gz \
    && cd hts_engine_API-${HTS_VERSION} \
    && ./configure \
    && make \
    && make install 

ちなみに、build-baseというパッケージは、

  • gcc
  • g++
  • libc-dev
  • make

とかが入ってます。詳しくはalpine公式のパッケージ詳細でどうぞ。

いざdocker build

Dockerfileも書けたので、試しにビルドします。

$ docker build --force-rm -t test:0.1 .
...この上にもいっぱいのアルファベット...
config.status: creating lib/Makefile
config.status: executing depfiles commands
Making all in lib
make[1]: Entering directory '/usr/local/src/hts_engine_API-1.10/lib'
gcc -DPACKAGE_NAME=\"hts_engine_API\" -DPACKAGE_TARNAME=\"hts_engine_API\" -DPACKAGE_VERSION=\"1.10\" -DPACKAGE_STRING=\"hts_engine_API\ 1.10\" -DPACKAGE_BUGREPORT=\"hts-engine-users@lists.sourceforge.net\" -DPACKAGE_URL=\"\" -DPACKAGE=\"hts_engine_API\" -DVERSION=\"1.10\" -DHAVE_LIBM=1 -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_VPRINTF=1 -DHAVE_SQRT=1 -DHAVE_STRCHR=1 -DHAVE_STRRCHR=1 -DHAVE_STRSTR=1 -I.  -I ../include   -g -O2 -MT HTS_audio.o -MD -MP -MF .deps/HTS_audio.Tpo -c -o HTS_audio.o HTS_audio.c
mv -f .deps/HTS_audio.Tpo .deps/HTS_audio.Po
gcc -DPACKAGE_NAME=\"hts_engine_API\" -DPACKAGE_TARNAME=\"hts_engine_API\" -DPACKAGE_VERSION=\"1.10\" -DPACKAGE_STRING=\"hts_engine_API\ 1.10\" -DPACKAGE_BUGREPORT=\"hts-engine-users@lists.sourceforge.net\" -DPACKAGE_URL=\"\" -DPACKAGE=\"hts_engine_API\" -DVERSION=\"1.10\" -DHAVE_LIBM=1 -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_VPRINTF=1 -DHAVE_SQRT=1 -DHAVE_STRCHR=1 -DHAVE_STRRCHR=1 -DHAVE_STRSTR=1 -I.  -I ../include   -g -O2 -MT HTS_engine.o -MD -MP -MF .deps/HTS_engine.Tpo -c -o HTS_engine.o HTS_engine.c
mv -f .deps/HTS_engine.Tpo .deps/HTS_engine.Po
gcc -DPACKAGE_NAME=\"hts_engine_API\" -DPACKAGE_TARNAME=\"hts_engine_API\" -DPACKAGE_VERSION=\"1.10\" -DPACKAGE_STRING=\"hts_engine_API\ 1.10\" -DPACKAGE_BUGREPORT=\"hts-engine-users@lists.sourceforge.net\" -DPACKAGE_URL=\"\" -DPACKAGE=\"hts_engine_API\" -DVERSION=\"1.10\" -DHAVE_LIBM=1 -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_VPRINTF=1 -DHAVE_SQRT=1 -DHAVE_STRCHR=1 -DHAVE_STRRCHR=1 -DHAVE_STRSTR=1 -I.  -I ../include   -g -O2 -MT HTS_misc.o -MD -MP -MF .deps/HTS_misc.Tpo -c -o HTS_misc.o HTS_misc.c
HTS_misc.c: In function 'HTS_ftell':
HTS_misc.c:251:26: error: 'fpos_t' {aka 'union _G_fpos64_t'} has no member named '__pos'
       return (size_t) pos.__pos;
                          ^
make[1]: *** [Makefile:390: HTS_misc.o] Error 1
make[1]: Leaving directory '/usr/local/src/hts_engine_API-1.10/lib'
make: *** [Makefile:407: all-recursive] Error 1
Removing intermediate container d340a3889f3f
The command '/bin/sh -c apk update && apk upgrade     && apk add --no-cache         python3         ffmpeg     && python3 -m pip install discord.py    && apk add --no-cache --virtual .build-deps         curl         gcc         g++         make     && mkdir /usr/local/src/     && cd /usr/local/src/     && curl -SLO http://downloads.sourceforge.net/hts-engine/hts_engine_API-${HTS_VERSION}.tar.gz    && tar -zxvf hts_engine_API-${HTS_VERSION}.tar.gz     && cd hts_engine_API-${HTS_VERSION}     && ./configure     && make     && make install     && cd /usr/local/src/     && curl -SLO http://downloads.sourceforge.net/open-jtalk/open_jtalk-${OPENJTALK_VERSION}.tar.gz    && tar -zxvf open_jtalk-${OPENJTALK_VERSION}.tar.gz     && cd open_jtalk-${OPENJTALK_VERSION}     && ./configure --with-hts-engine-header-path=/usr/local/include --with-hts-engine-library-path=/usr/local/lib     && make     && make install     && cd /usr/local/src/     && curl -SLO http://downloads.sourceforge.net/open-jtalk/open_jtalk_dic_utf_8-${OPENJTALK_VERSION}.tar.gz     && tar -zxvf open_jtalk_dic_utf_8-${OPENJTALK_VERSION}.tar.gz     && cd open_jtalk_dic_utf_8-${OPENJTALK_VERSION}     && apk del .build-deps' returned a non-zero code: 2

なんでや!

とりあえずソースコードを見てみる

C言語はやってないので、そもそも何がいけないのかからわからん。コンパイルが通ってないっぽい。問題があると言われた部分である、”HTS_misc.c” 240-259行は以下のようになってます。

/* HTS_ftell: rapper for ftell */
size_t HTS_ftell(HTS_File * fp)
{
   if (fp == NULL) {
      return 0;
   } else if (fp->type == HTS_FILE) {
      fpos_t pos;
      fgetpos((FILE *) fp->pointer, &pos);
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__APPLE__) || defined(__ANDROID__)
      return (size_t) pos;
#else
      return (size_t) pos.__pos;
#endif                          /* _WIN32 || __CYGWIN__ || __APPLE__ || __ANDROID__ */
   } else if (fp->type == HTS_DATA) {
      HTS_Data *d = (HTS_Data *) fp->pointer;
      return d->index;
   }
   HTS_error(0, "HTS_ftell: Unknown file type.\n");
   return 0;
}

あ、ダメだこれわからん。#付きのものって#include みたいな特殊な命令だった気がする。

見た感じ、プラットフォームで分岐した先の、”pos.__pos” の部分で、posっていうオブジェクトに__posっていうメンバがいないからコンパイルが通らないっぽい?

んでそもそもposっていうのは、” fpos_t pos; “ってところでfpos_tっていう型の …変数…?調べてみると、ファイルの位置を表してるらしい。ここまで低レベルの話になってくると全然頭に入ってこない。

http://merry.whitesnow.jp/SEMI_C/SECTION14/s14_01/s14_01_7.html

でもstdio.hで定義されてるはずのものが食い違ってるってことにならない?C標準ライブラリとは一体…Google先生で調べると似たような問題がありそうなのはわかったけど、解決策まではわからなかった。

諦めの境地

大人しくubuntuを使う

ここから先は明らかに僕の技術力では無理なので、とりあえず普通のディストリビューションをベースイメージに使うことにしました。

使うのは、1番ポピュラーかつサイズの小さかったubuntuでいいでしょう。Dockerfileを書き換えていきます。

FROM ubuntu:latest

# Settings
ARG OPENJTALK_VERSION=1.11
ARG HTS_VERSION=1.10

# Add project source
WORKDIR /usr/src/ttsbot
COPY . ./

# Init
RUN apt-get update \
# Install build dependancies with apt-get
    && apt-get install -y \
        curl \
        build-essential \
# Install hts_engine
    && cd /usr/local/src/ \
    && curl -SLO http://downloads.sourceforge.net/hts-engine/hts_engine_API-${HTS_VERSION}.tar.gz\
    && tar -zxvf hts_engine_API-${HTS_VERSION}.tar.gz \
    && cd hts_engine_API-${HTS_VERSION} \
    && ./configure \
    && make \
    && make install 

一発でいけた

俺の時間を返してくれ。マジで。いろいろ調べたんだけど。

最初のapt-get updateに以外と時間かかるし、全体的に時間かかってるけど、これで動いたっぽいから良しとする。

教訓

俺みたいに、あんまり詳しくない人はUbuntuを使おう。ネットにめっちゃ情報もあるし、困ったことないもん。

かず猫

インターネット初心者です。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください