Linuxbrewでgccが入っている状況で、外側にあるライブラリを使ってビルドしたかった

Linuxbrewを使っててちょっとはまることがあった。

  1. Linuxbrewが入っていて、Linuxbrewでgccその他ビルド関連ツールが入っている。
  2. Linuxbrew関係のパスが通っており、gccなどはLinuxbrew以下のものが使われる。
  3. Linuxbrewの外、/usr/local/libにライブラリがある。
  4. 3のライブラリを使ってプログラムをビルドしたい。

具体的にはcmigemoを使って、migemoを有効にしてVimをビルドしようとした。

まず普通にやるとLinuxbrewのgcc(というかld)が、cmigemoを見つけてくれなかったようで、以下のようなエラーが出た。

/home/linuxbrew/.linuxbrew/bin/ld: cannot find -lmigemo

これは当たり前っちゃ当たり前。Linuxbrewのgccは同じくLinuxbrew内のld使ってて、そっちにはcmigemoは登録されてなかったので。

ということでとりあえずLinuxbrewのldからcmigemoというか、/usr/local/lib内のライブラリを使えるようにしようとした。Linuxbrew内のld.so.conf/usr/local/libのパスを追加した上でldconfig. これでldconfig -pなどすると、cmigemo(というかlibmigemo.so)が見えるようになった。

だがこれでもビルドできなかった。

未だに原因はよくわかってないんだけど、試行錯誤の上、最終的には以下のように対応して、とりあえずビルドできた。

  1. cmigemoを手動でLinuxbrew以下に入れた。./configure --prefix=/home/linuxbrew/.linuxbrew/Cellar/cmigemo/0みたいな感じ。
  2. brew link cmigemoでシンボリック・リンク作った。

ただこれは、Linuxbrew下に手動で突っ込むというのがイケてないのであまりやらない方がよさそう。もうちょっとマシな方法としては、

  • そもそもcmigemoやVim用のFormula書いちゃって、ぜんぶLinuxbrew任せにできるようにする。
  • そこまではしなくても、brew diyくらいは使っといた方がいいかも。ここの記事が参考になる。
  • Linuxbrewのパスは使わないときは通さずにしておいて、無関係のものはシステムのgccでビルドする。
    • これするとLinuxbrewの意味があまりない気がするのがネック。

なおそもそも元ネタのHomebrewは、/usr/local下にぜんぶ突っ込むっぽく、そのせいで問題になってないのではないかと思うんだけど、ではなんでLinuxbrewはそうしないのだろう。その辺がまずわかってない。

とりあえずLinuxbrewいろいろ難しい。日本語での情報少ないのもつらい。

日記

案件Aが終わって、案件Bが中断して、みたいな感じで絶賛無職中。仕方ないので久々にお仕事探ししてる。

こんなところで募集しても意味ないと思うけど一応募集しとくと、フルリモートでやってる自営プログラマです。Perl, PHPがちょっとできます。別に言語にこだわりないし環境にこだわりないしやることにこだわりないので、合法的な仕事なら条件面で折り合えばなんでもやります。お仕事ください。

それはいいとして。

やることはあるけど暇っちゃ暇なんで、働き方の見直しなんかもしてて。去年後半くらいからかな? に、やれるだけやるみたいな働き方から、週の労働時間を20時間に固定する形に変更してみたんだけど、それでもまだ長いなあとか思うこともあって。

で、最近読んだ「シリコンバレー式 よい休息」って本の影響なんかもあって働き方をまたちょっと変えてみようと思った。この本タイトルはアレだけど割といい本なんで、みんな読もう。

新しい働き方は、午前と夕方に1時間半~2時間くらいを1回ずつ、あと午後に軽めの、主にメール対応など事務処理や、勉強に使う時間を1時間の、計4~5時間を1日に。

それを週4日くらい働く感じでどうかなー、とか。

いい感じだったら今度もっと詳しくブログに書くかも。

Linuxbrewに日本語のロケールを入れる

tmuxはデフォルトではUnicodeの曖昧な文字幅に対応していないので、パッチを入れるかあきらめるかで対処しなければならなかったのだが、最近はLinuxbrewというMacのHomebrew互換のパッケージマネージャ用にパッチ済みのtmuxの設定(Formula)を用意してくれている人がいるようだ。

最高なのでそれを使わせてもらおうとLinuxbrewを入れるところから始めたら、ロケール周りではまった。

tmuxは変なロケールで起動しようとすると、フォールバックなどせず以下のようなメッセージを出して落ちる。

tmux: invalid LC_ALL, LC_CTYPE or LANG

Linuxbrewで、こちらのFormulaを使ってtmuxを入れると、なぜかこの問題が起きる。試しにlocaleを実行して確認してみると、以下のような警告が出た。

locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=ja_JP.UTF-8
LC_CTYPE="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER="ja_JP.UTF-8"
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT="ja_JP.UTF-8"
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=

結論から言うと、システムではja_JP.UTF-8が存在するが、Linuxbrewで入ったglibc周りでは存在しないということだった。

Linuxbrewでは、glibcが入るときにロケールを無視するらしい。詳しくはわからないのだが、どうもLinuxbrewは環境変数をフィルタリングするらしい。

以下のようにして、glibcインストール後のlocaledefなどの処理を再実行すると必要なロケールが入る。

HOMEBREW_NO_ENV_FILTERING=1 brew postinstall glibc

なおこの機能にはちょっとしたバグがあり、環境変数から雑にcharmap, localeの名前を取得しているため、ja_JP.utf8のような設定になっていると上記のコマンドがエラーになる。

この場合は、ロケールを再設定する。あるいは以下のようにlocaledefを手動で実行してもいいかもしれない。

localedef -i ja_JP -f UTF-8 ja_JP.utf8

ちなみに入れたパッチ済みtmuxはこちら。便利。あとLinuxbrewもバグったところ以外は便利な感じなので今後もいろいろ使ってみたい。

Test::DifferencesでUTF-8文字列をエスケープせずに出力する方法

ドキュメントに書いてある、 Text::Diff の設定をどうこうする方法では駄目だったのでいろいろ調べた感じ、以下のようにすれば行けた。

use strict;
use warnings;
use utf8;

use Data::Dumper;
{
    package Data::Dumper;

    our $Useperl = 1;

    no warnings 'redefine';

    sub qquote {
        shift;
    }
}

use Term::Encoding qw(term_encoding);
use Test::More;
{
    my $builder       = Test::More->builder;
    my $term_encoding = term_encoding;

    binmode $builder->output,         ":encoding($term_encoding)";
    binmode $builder->failure_output, ":encoding($term_encoding)";
    binmode $builder->todo_output,    ":encoding($term_encoding)";
}

use Text::Diff::Config;
$Text::Diff::Config::Output_Unicode = 1;

use Test::Differences;
eq_or_diff 'あいうえお', 'かきくけこ';
done_testing;

Data::Dumperがまず問題

Test::Differences では内部的に Data::Dumper を使用しており、そこで確実にエスケープされてしまうので、まずはその対処をしなければならない。

これはまともな方法ではどうにもならないので、以下のページを参考に qquote() をハックする方法で対処した。

Data::DumperでUTF-8フラグつき文字列をエスケープさせないようにするには - ku

Test::Moreの出力をなんとかしないと、 Wide character in print... が出ます

これはいつものアレ。最近 Test::More も中身が Test2 になったりしてるみたいでよくわからないが、まだこのやり方でとりあえず通用した。

Test::Moreでマルチバイト文字列を出力する可能性がある場合。 - 遠い叫び

Text::Diffの設定をなんとかする

$Text::Diff::Config::Output_Unicode を真にするだけ。なおこの設定、table_diff 以外では不要なので、 unified_diff とかを使う場合はなくてもよい。

Test::Differences使わない方がいいんじゃないか説

あまりちゃんとメンテされてない感じだし、使わなくて済むならそうした方がいいかも。今は似たようなのでもっといいのあるんじゃない?

use_okがprove -lで実行すると通るのにperl -Ilibで実行すると通らなかった話

use Test::More;

use_ok 'Foo::Bar';

done_testing;

みたいなテストを実行するとき、まあ普通は prove -l する。1アサートごとの結果を見たい場合も prove -lv とかでいいんだけど、このときは忘れてて perl -Ilib で実行した。

上のようなテストだと通るんだけど、今回下のようなテストになってて通らなかった。

use File::Basename qw(dirname);
use Test::More;

chdir dirname __FILE__;

use_ok 'Foo::Bar';

done_testing;

こうして最低限のコードにするとわかりやすいんだけど、 'lib' の指し示す先が変わってしまうので通らないわけだ。

ただそうなると、なぜ prove -l では通るのか?

軽く App::Prove を読んでみると、 'lib'絶対パスにして処理していたのでそのせいで chdir の影響を受けなかったっぽい。

(当然 lib/Foo/Bar.pm は存在し、かつ use できる前提)

今日はたまたまそれほど解決にそれほど時間かからなかったからいいけど、勘でデバッグするのって駄目だよなあ。バグ見つけたらとにかく二分探索しつつ問題の最小化していかないと。そういう癖つけないと。

ansible-lintのルールに関するメモ

ansible-lintを使ってみているのだが、ルールの一部がよくわからなかったりしたので調べて簡単にまとめてみた。

ANSIBLE0002: Trailing whitespace

これはほんとそのまんま。いずれかの行の末尾に空白があれば警告が出る。

ANSIBLE0004: Git checkouts must contain explicit version

gitモジュールでversionを指定しなかったり、HEADに指定したりすると警告が出る。

ANSIBLE0005: Mercurial checkouts must contain explicit revision

ANSIBLE0004のhg版。revisionを指定しなかったり、defaultに指定したりすると警告が出る。

ANSIBLE0006: Using command rather than module

git, curl, serviceその他、Ansibleモジュールが使えるところでcommand, shellを直接叩いてると警告が出る。

ANSIBLE0007: Using command rather than an argument to e.g. file

chmod, mkdir, rmその他、fileモジュールの引数でできることでcommand, shellを直接叩いていると警告が出る。

ANSIBLE0008: Deprecated sudo

become, become_userでなくsudo, sudo_userを使っていると警告が出る。

ANSIBLE0009: Octal file permissions must contain leading zero

fileモジュールなどでmodeの指定時に0666のような表記ではなく666のような表記をしていると警告が出る。

ANSIBLE0010: Package installs should not use latest

ANSIBLE0004のパッケージ管理システム版。statelatestを指定していると警告が出る。ANSIBLE0004などでは未指定の場合も警告が出るが、yumなどのstateはデフォルトがlatestではなくpresentなので、未指定の場合は警告が出ない。

ANSIBLE0011: All tasks should be named

すべてのタスクにnameをつけろというルール。そこは問題ないのだがこのルールバグってて、yumのように引数にnameがあるものだと、偽陰性になってしまう……。

ANSIBLE0012: Commands should not change things if nothing needs doing

command, shellなどがwhen, createsなどで条件つき実行になっていない場合警告される。

ANSIBLE0013: Use shell only when shell functionality is required

パイプやリダイレクトなどを使うわけでもないのにshellを使ってると警告される。

ANSIBLE0014: Environment variables don't work as part of command

command, shellのコマンド内でPATH+=XXX commandみたいなのはできないよ、という警告だと思うのだが自信がない……。

ANSIBLE0015: Using bare variables is deprecated

{{ var }}形式じゃない生の変数を使った場合に警告される。この「生の変数」を俺はそもそも知らなかったんだが、以下みたいな感じらしい。

---
- tasks:
  - name: example for "Using bare variables is deprecated" rule
    yum:
      name: item
    with_items: items
ANSIBLE0016: Tasks that run when changed should likely be handlers

when: result.changedみたいなことやるなら普通にhandlers使えば変更あった場合のタスク実行できるからそうしよう、みたいなルール。

ANSIBLE0017: become_user requires become to work as expected

becomeなしでbecome_userしてると警告される。

ANSIBLE0018: Deprecated always_run

always_runを使っていると警告される。check_modeが代替とのこと。

Nginxでtypesは上書きできるのか

nginx実践入門をちまちま進めている。今日は第3章を進めていたのだが、いくつか気になることがあったので検証してみた。

typesディレクティブの設定値は上書きできるか?

実践入門には、基本mime.typesincludeして、別途指定したい場合はmime.typesを直接修正する、みたいな感じで書いてあった。

個人的にはそういうのはmime.typesはそのままにしておいて、必要なものだけ上書きする形でできたらいいなあと思ったので、できないのか試してみた。

# ...

http {
    include mime.types;

    types {
        text/html txt;
    }
}

# ...

結果、Nginxを起動した時点で以下の警告が出た。その上で上書きはされるようだ。うーん、その仕様はどうなのか……。

2018/04/19 11:27:35 [warn] 1833#1833: duplicate extension "txt", content type: "text/html", previous content type: "text/plain" in ./etc/nginx.conf:17

ググったところ、以下のようにする感じでハックできると出てきた。

# ...

http {
    include mime.types;

    server {
        # ...

        location ~ \.txt$ {
            types {
                text/html txt;
            }
        }
    }
}

# ...

https://serverfault.com/questions/678673/nginx-how-to-override-add-single-mime-type

その後調べると、公式リファレンスにもあった。上記のとは違い、typesは空にして、default_typeを使ってる。

http://nginx.org/en/docs/http/ngx_http_core_module.html#types

これはこれで微妙……。

access_logは複数設定するとどうなるのか?

access_logを同じように複数設定した場合の挙動が気になったのでこれも一応確認してみた。予想通り、複数のファイルにアクセスログを出力してくれる。便利。

複数回同じディレクティブを書いた場合の挙動もちゃんと公式リファレンスに書かれてるとよかったんだが。