/usr/lib以下に入っているlibicucore.dylibを自分のコードから使う方法

libicucore.dylib。どう見てもICUのダイナミックライブラリ。存在は知りつつも、どういうわけかヘッダファイルが添付されていないため、自分のコードから使うことができず、歯がゆい思いをしている人も多いんじゃないだろうか。

-rw-r--r--  1 root  wheel  6941856  7 31 14:16 /usr/lib/libicucore.A.dylib
lrwxr-xr-x  1 root  wheel       18 12 23  2007 /usr/lib/libicucore.dylib -> libicucore.A.dylib

ここなどを参考にこれを使う方法を考えてみたので書いてみます。

追記:make install DESTDIR=...がmake DESTDIR=...になっていたのを修正。

手順

  1. OSに添付されているICUのバージョンを調べる。
  2. 同じバージョンのICUをダウンロードし、ビルドする。
  3. ライブラリを除くファイルを/usrにコピーする。
1. OSに添付されているICUのバージョンを調べる

次のコードをコンパイル、リンクして実行するとバージョンを調べることができる。

check_icu_version.cpp

#include <iostream>

extern "C" void u_getVersion(char[4]);

main()
{
    char v[4];
    u_getVersion(v);
    std::cout << static_cast<int>(v[0]) << '.'
              << static_cast<int>(v[1]) << '.'
              << static_cast<int>(v[2]) << '.'
              << static_cast<int>(v[3]) << std::endl;
}

コンパイルとリンク:

$ g++ -o check_icu_version -licucore check_icu_version.cpp

実行例:

$ ./check_icu_version
3.6.0.0
2. 同じバージョンのICUをダウンロードし、ビルドする

ICUのダウンロードはここから。

ビルドオプションなどは以下。

$ tar xfz icu4c-3_6-src.tgz
$ cd icu/source
$ ./configure --prefix=/usr \
              --mandir=/usr/share/man \
              --disable-renaming \
              --disable-draft \
              --disable-icuio \
              --disable-layout \
              --disable-extra
$ make

ビルドが終わったら、DESTDIR=を使って、適当なステージングディレクトリにインストールする。

$ make install DESTDIR=/tmp/staging
3. ライブラリを除くファイルを/usrにコピーする。
$ sudo -s -H
# cp -R /tmp/staging/usr/share /usr
# cp -R /tmp/staging/usr/include /usr
# exit
$

ためしてみる

あんまいけてないコードだけど。

#include <memory>
#include <stdexcept>
#include <clocale>
#include <iostream>
#include <unicode/datefmt.h>
#include <unicode/calendar.h>
#include <unicode/ucnv.h>
#include <langinfo.h>


main()
{
    std::setlocale(LC_ALL, "");
    const char* codeset = nl_langinfo(CODESET);

    UDate date = Calendar::getNow();
    std::auto_ptr<DateFormat> dfmt(DateFormat::createInstance());
    UnicodeString str;

    dfmt->format(date, str);
    {
        char buf[1024];
        UErrorCode err;
        UConverter* cnv = NULL;
   
        try { 
            cnv  = ucnv_open(codeset, &err);
            if (!cnv)
                throw std::exception(); 

            int32_t len = str.extract(buf, sizeof(buf) - 1, cnv, err);
            if (U_FAILURE(err))
                throw std::exception();
            buf[len] = '\0';
            std::cout << buf << std::endl;
        } catch (std::exception const&) {
            std::cerr << "error" << std::endl;
        }

        if (cnv)
            ucnv_close(cnv);
    }
}

ビルドと実行結果は次のような感じ:

$ g++ -o /tmp/test /tmp/test.cpp -licucore
$ ./test
08/10/24 17:51