ふるいPerlをいれる

perlbrew を導入したのでもりもりテスト環境を作れるようになったわけですが、perl-5.8.8 をいれようとしたら

    Can't open makefile: No such file or directory.
    Can't open x2p/makefile: No such file or directory.
    make: *** No rule to make target `<command-line>', needed by `miniperlmain.o'.  Stop.
    make: *** No rule to make target `<command-line>', needed by `miniperlmain.o'.  Stop.

のように make がこけてしまってインストールできなかった。 ググってみるとどうも新しいgccだと古いPerlはうまくビルドできないらしい。

解決法としては makefile (OSXではGNUmakefile) の command-line を含む行は消してあげるというのでなんとかなるみたい。

以下のようにしてみた:

$ ./Configure -de -Dprefix=$HOME/perl5/perlbrew/perls/5.8.8
$ perl -i~ -nle 'print unless /command-line/' GNUmakefile x2p/GNUmakefile
$ make
$ make test
$ make install

これでちゃんとperlbrewからも認識できてて

$ perlbrew switch 5.8.8

とかでswitchできました。まる。

by typester / at 2010-08-13T09:05:00 / osx · perl / Comment

ユニバーサルバイナリ作成用シェルスクリプト

iPhone用にビルドしたライブラリは実機用(armv6/armv7)とシミュレータ用(i386)のユニバーサルバイナリとして作成しておくと使い勝手が良いです。 その分ビルドは面倒になるのですが。。

僕は通常以下のようにしてユニバーサルバイナリを作成してます。

  1. まずprefixをそれぞれ ~/dev/iphone/lib/curl-7.20.1-armv6 ~/dev/iphone/lib/curl-7.20.1-armv7 ~/dev/iphone/lib/curl-7.20.1-i386 などとしてそれぞれのアーキテクチャ用にビルドをする
  2. 適当に書いた bundle.sh でユニバーサルバイナリ化

この bundle.sh は上の例だと

./bundle.sh ~/dev/iphone/lib/curl-7.20.1

として実行すると ~/dev/iphone/lib/curl-7.20.1-armv6 ~/dev/iphone/lib/curl-7.20.1-armv7 ~/dev/iphone/lib/curl-7.20.1-i386 が全部がっちゃんこした ~/dev/iphone/lib/curl-7.20.1 ができるという寸法です。

この方法だとまだ3つ分手動でビルドするのがめんどくさいので、そこも自動化したいところですね。

by typester / at 2010-07-27T14:52:00 / osx · iphone / Comment

Text::MicroTemplate::DataSection

__DATA__

__DATA__

@@ index.mt
<html>
 <body>Hello</body>
</html>

@@ bar.mt
? if ($true) {
  Foo
? }

こう言うのが書いてあるとき、Data::Section::Simple を使うと

get_data_section('index.mt');

とすることで該当セクションだけのデータを簡単に取得することができます。 なので普通の Text::MicroTemplate と組み合わせても

render_mt(get_data_section('index.mt'));

って感じで使えてそんなに苦じゃないわけですが、どうせなら中で include とか extends とかで他のセクションのデータとも連携できるようにしたら便利だなーと思い3分クッキングして Text::MicroTemplate::DataSection と言うのを書いてみました。

使い方は簡単、

use Text::MicroTemplate::DataSection 'render_mt';

とすると Text::MicroTemplate::File ベース、

use Text::MicroTemplate::DataSectionEx 'render_mt';

とすると Text::MicroTemplate::Extended ベースの機能が使えるようになります。

あとは render_mt('index.mt') などとすれば __DATA__ からテンプレート出力が行えます。基本ベースクラスのすべての機能がつかえますので、Exを使っている場合は、

? extends 'base';

? block content => sub {
Hello!
? }

とか

?= include 'hoge'

とかもそのまま __DATA__ のなかのテンプレートで使用することができます。Enjoy!

by typester / at 2010-07-03T12:20:00 / perl / Comment

PerlエンジニアのためのObjective-C Blocks入門

OS X 10.6 以降の xcode では Objective-C に Blocks というシンタックスが追加されている。

Blocks Programming Topics: Introduction

Perl でいうところの無名関数(コードブロック)を作ることができる機能で、Perlでいうところの

my $f = sub { ... };
$f->();

void (^f)() = ^{ ... };
f();

のように書ける。書式がきもいのはObjective-Cの定めなのであきらめましょう。 より詳しい書式については上記ドキュメントを見ると良い。

しかしデフォルトではPerlのコードブロックとはレキシカル変数の扱いが異なる。

my $i = 0;
my $f = sub { return $i + 1 };

$i++;

$f->(); # 2 を返す

perlではこのようにレキシカル変数はコードブロック内と共有されるが、Objective-Cの場合は

int i = 0;
int (^f)() = ^{ return i + 1; };

i++;

f(); // 1 を返す

このようになる。これはブロックを作成するときのレキシカル変数がコピーされるからである。 Perlとおなじような挙動を望む場合は __block ストレージタイプを指定すればいいようだ。

__block int i = 0;
int (^f)() = ^{ return i + 1; };

i++;

f(); // 2

ここまでわかればObjective-CでBlockの再帰を書くことができる。

__block void (^f)();
f = ^{ f(); };
f();

これは以下とおなじ、

my $f;
$f = sub { $f->() };
$f->();

というようにPerlエンジニアにとっては割と直感的なコードブロックが使えるようになっております。 書式がきもいことをのぞけばいい感じです。

次回は「PerlエンジニアのためのGrand Central Dispatch」の予定です。

追記@2010-05-11T19:12:48+09:00

はてなブックマーク - PerlエンジニアのためのObjetive-C Blocks - unknownplace.org

lyokato 「Objective-Cの仕様というよりは、Blocks拡張に対応したCコンパイラの仕様かな」

ってことでやってみたら

#include <stdio.h>

int main(int argc, char** argv) {
    void (^f)() = ^{ printf("Hello Blocks!\n"); };
    f();

    return 0;
}

// $ gcc foo.c
// $ ./a.out

でも行けました。gcc の拡張なんですね。あざっす!

by typester / at 2010-05-11T14:29:00 / objc · perl / Comment

qpsmtpd を Server::Starter 化するなど

Perl 製 SMTP サーバーとして qpsmtpd というものがあり、僕もいろいろなところで利用している。主な用途としてはメール連動の Web アプリケーションのメール機能の部分。実際のメール配送などでは使用してない。

フロントに qpsmtpd を置き、アプリで制御する宛先の場合のみ qpsmtpd からジョブキューに流したりする。 それ以外の通常のメールは queue/postfix プラグインなどを使用して裏側の postfix にまかせちゃう。というような使い方をしている。

qpsmtpd 自体は apache.org や perl.org の SMTP として採用されており、パフォーマンスに関しては問題ないのだが、プラグインを書き換えたり設定を変更したりした場合に再起動が必要になるところが、フロントに立てるサーバーとしては不安な部分であった。

なので前々から Server::Starter 対応はしたいとおもっていたが安定動作している既存のサーバーで作業する機会も特になく放置していた。

そしてこのたびめでたく新しく qpsmtpd を設置することになったためいっちょやったるか、となった次第である。

この辺で作業:

http://github.com/typester/qpsmtpd/commits/topic/server_starter

使い方は:

# start_server --port=25 --port=127.0.0.1:20025 -- ./qpsmtpd-async-server-starter

このような感じで、SMTP用のポートと、qpsmtpd 制御用の contig ポートを同時に渡して起動する。その後 Server::Starter の superdaemon にたいし HUP シグナルを送ると graceful restart できる。

古い worker プロセスでは最大 $TIMEOUT 秒(デフォルト60)だけ既存の接続を終了まで待つ、graceful shutdown 機能も併せて実装したので完全にダウンタイムをなくせているはず。

とりあえずあまりテストしきれてないけどドッグフードを食べてがんばろうと思います。

by typester / at 2010-03-24T22:38:00 / perl · qpsmtpd / Comment

GNU screen の裏にいる Window で完了したコマンドを Growl 通知したい

というようなことをつぶやいていたら、

Twitter / hchbaw: @typester 最近になって screen -Q windows とできるようになってますね。

と教えていただいた。

-Q コマンドというのは -X と同じようなものだけど、コマンド結果を screen 内のステータス領域ではなく標準出力で得ることができる。また、-X はつねに実行時にそれ自体がアクティブな screen セッションになるのに対し -Q はアクティブなセッションにクエリを投げる感じで、セッションが切り替わらない。(この辺は理解が怪しいので突っ込み歓迎)

それでそれを使うと

screen -Q windows

と実行することで :windows で echo されるのとおなじ文字列を標準出力で得ることができる。その出力をパースすれば、自分が screen の裏にいるかどうか判断することができるというわけ。

zsh でコマンド完了時(正確にはプロンプトが表示される直前)に呼ばれるフックは precmd なので以下のように定義:

function precmd() {
    $HOME/bin/precmd.pl `history -n -1 | head -1`
}

シェルスクリプトかけないので Perl に逃げています。 で、precmd.pl は以下のような感じ:

#!/usr/bin/perl

use strict;
use warnings;
use FileHandle;

my $lastcmd = join ' ', @ARGV;

my $window = $ENV{WINDOW};

my $windows = qx{ screen -Q windows } or die "Your screen doesn't support -Q";
qx{ screen -X redisplay };

my $active;
for my $win (split "\x20\x20", $windows) {
    my ($num, $flag, $title) = $win =~ /^(\d+)(.)? (.+)/;

    if ($flag and $flag eq '*') {
        $active = $num;
        last;
    }
}

if ($window != $active) {
    open my $fh, "|/usr/local/bin/growlnotify -t 'GNU screen window $window'" or die $!;
    print $fh sprintf 'command done: "%s"', $lastcmd;
    print $fh "\n";
    close $fh;
}

これで、コマンドが完了した場合にピコーンと通知が来るようになりました。

長い make や wget の時に超絶便利ですね!

書き忘れましたが、現在この機能をつかうためには開発版の screen を使用する必要があります。

by typester / at 2010-03-23T11:22:00 / screen · zsh / Comment

yokohama.pm tech talk #5

OpenSocial なモバイルアプリを書く場合、アプリ単体でテストできるようにしてくれる Moxy の OpenSocial プラグインの話と、外部 API 呼び出しを専用に行う非同期なプロクシサーバーの話をしました。

資料はこちら:

OpenSocial mobile application development

前者に関しては、個人的には OpenSocial モバイルアプリ開発には必須なツールなので良い感じにしていきたいところ。 &してくれるひと募集。

後者のプロクシサーバーは「あんまり頭よくない」だけれども、現在のウェブアプリケーションの構成で、API呼び出しの待ち時間をうまく使おうとするときにはこうなるのかなぁと思った。同じようなことをしているところもあるらしい!

個人的にはそれ〜でできるよ!ってのがないかなーと思っていたのだけど、ないっぽいのかなー。

nginx でおしいところまではできるので、モジュール書いたら出来るのか調べてみようと思う。

by typester / at 2010-03-06T13:19:00 / perl · yokohama.pm / Comment

local::lib を切り替える

レガシーなアプリをメンテするのにレガシーな Perl モジュールが必要になることがあり、そのために古いアプリ用には専用の local::lib ディレクトリを切っているわけですが、普段から日常的に local::lib を使用しているため shell が上がったタイミングではデフォルトの local::lib 環境変数がセットされていて切り替えが非常に面倒だった。

これまではそれほど頻繁に使用しなかったので放置していたのだが、ここのところ頻繁に必要になるためいい加減うざくなってきて簡単に local::lib を切り替えられるよう設定をしてみた。

zsh に次のような関数をつくり、それで local::lib を切り替えるようにする。

function locallib () {
    INSTALL_BASE=$1
    if [ -d $INSTALL_BASE ]; then
        eval $(~/bin/use-locallib $INSTALL_BASE)
    fi
}

これは

$ locallib ~/perl5

などのように INSTALL_BASE を指定して使う。指定されたパスが存在したら use-locallib というコマンドを使用して環境変数を切り替えるという内容。

この use-locallib コマンドは以下のようなソースになっていて、古い local::lib の環境変数をクリアするとともに、新しい local::lib の環境変数を print するというものになっている。

#!/usr/bin/env perl

use strict;
use warnings;
use Pod::Usage;

use Config;
use File::Spec;

my $install_base = $ARGV[0]
    or pod2usage(-1);

$install_base = File::Spec->rel2abs($install_base);

my $path     = $ENV{PATH};
my $perl5lib = $ENV{PERL5LIB};

push @INC, File::Spec->catdir($install_base, 'lib', 'perl5');

require local::lib;
my %env = local::lib->build_environment_vars_for($install_base, 1);

# remove $PERL5LIB set by old local::lib if it exists.
if (my $old_base = $ENV{PERL_MM_OPT}) {
    my %mmopt;
    for my $opt (split /:+/, $old_base) {
        my ($k, $v) = split /=/, $opt;
        $mmopt{$k} = $v;
    }

    if (my $old_installbase = $mmopt{INSTALL_BASE}) {
        if ($old_installbase eq $install_base) {
            # do nothing if install_base is equal to old one
            exit;
        }

        my @old_perl5lib = (
            File::Spec->catdir($old_installbase, 'lib', 'perl5'),
            File::Spec->catdir($old_installbase, 'lib', 'perl5', $Config{archname}),
        );

        $env{PERL5LIB} = do {
            my @env;
            ENV: for my $e (grep { $_ } split $Config{path_sep}, $env{PERL5LIB}) {
                for my $old (@old_perl5lib) {
                    next ENV if $old eq $e;
                }
                push @env, $e;
            }
            join $Config{path_sep}, @env;
        };

        my $old_path = File::Spec->catdir($old_installbase, 'bin');
        $env{PATH} = do {
            my @p;
            for my $p (grep {$_} split $Config{path_sep}, $env{PATH}) {
                next if $p eq $old_path;
                push @p, $p;
            }
            join $Config{path_sep}, @p;
        };
    }
}

while (my ($k, $v) = each %env) {
    print qq[export $k="$v"\n];
}

=head1 NAME

use-locallib - set/switch local::lib environment

=head1 SYNOPSIS

use-locallib (MODULE INSTALL BASE)

これで local::lib を簡単に切り替えられるようになるけれど、複数の local::lib 環境を同時に使用しているとどのシェルがどの local::lib を使用しているかわからなくなってしまう。

そのためシェルのプロンプトに INSTALL_BASE を表示されるようにしてしのいだ。

show INSTALL_BASE in terminal prompt

これは単純に以下のような PERL_MM_OPTINSTALL_BASE をプリントするスクリプトを PROMPT 設定から読んでいるだけである。

#!/usr/bin/env perl

use strict;
use warnings;

my %mm_opt;
for my $opt (split /:+/, $ENV{PERL_MM_OPT} || '') {
    my ($k, $v) = split /=/, $opt;
    $mm_opt{$k} = $v;
}

my $install_base = $mm_opt{INSTALL_BASE};
if ($ENV{HOME}) {
    $install_base =~ s/^$ENV{HOME}/~/;
}

print $install_base || 'none';
by typester / at 2010-03-01T17:17:00 / perl · zsh / Comment

ライブラリをユニバーサルバイナリでインストールする

以下のサイトが詳しい

http://macwiki.sourceforge.jp/wiki/index.php/UniversalBinary

Imager に必要な libjpeg などをユニバーサルバイナリにしてみた時のメモ

-M などがついていて -arch が複数指定できない場合以外は

CFLAGS='-arch x86_64 -arch i386 -isysroot /Developer/SDKs/MacOSX10.6.sdk' CXXFLAGS=$CFLAGS

とかすればいいということだが、libjpeg-M られていて無理だったので、amd64 と i386 という二つのディレクトリにソースコードを展開、それぞれ以下のオプションで make まで終わらす:

$ cd amd64
$ CFLAGS='-arch x86_64 -isysroot /Developer/SDKs/MacOSX10.6.sdk' CXXFLAGS=$CFLAGS ./configure ...
$ make

$ cd ../i386
$ CFLAGS='-arch i386 -isysroot /Developer/SDKs/MacOSX10.6.sdk' CXXFLAGS=$CFLAGS ./configure ...
$ make

make されてできたバイナリを lipo コマンドでユニバーサルバイナリ化する。 上記サイトを参考にして、

#!/bin/sh

filelist=$(find ./amd64 -type f |grep -v \\.o$ | xargs file | sed -e 's,^\./amd64/,,g' | \
               grep -E \(Mach-O\)\|\(ar\ archive\) |sed -e 's,:.*,,g' -e '/\for\ architecture/d')

for i in $filelist
do
    echo $i
    /usr/bin/lipo -create amd64/$i i386/$i -output `basename $i`
    mv -f `basename $i` amd64/$i
done

このようなスクリプトを書いて、amd64 などのディレクトリの一つ上の階層で実行すると、amd64 ディレクトリのバイナリがユニバーサルバイナリ化されるという仕組みを作ってみた。

その後、amd64 のほうで make install してやれば OK。

by typester / at 2010-01-08T11:28:00 / osx / Comment

Snow Leopard の Perl とアーキテクチャ

Snow Leopard には二つの Perl がインストールされている

  • /usr/bin/perl5.10.0
  • /usr/bin/perl5.8.9

デフォルトの /usr/bin/perl は 5.10.0 のほう。それぞれユニバーサルバイナリになっていて、

$ file /usr/bin/perl5.10.0
/usr/bin/perl5.10.0: Mach-O universal binary with 3 architectures
/usr/bin/perl5.10.0 (for architecture x86_64):  Mach-O 64-bit executable x86_64
/usr/bin/perl5.10.0 (for architecture i386):    Mach-O executable i386
/usr/bin/perl5.10.0 (for architecture ppc7400): Mach-O executable ppc

$ file /usr/bin/perl5.8.9
/usr/bin/perl5.8.9: Mach-O universal binary with 2 architectures
/usr/bin/perl5.8.9 (for architecture i386):     Mach-O executable i386
/usr/bin/perl5.8.9 (for architecture ppc7400):  Mach-O executable ppc

という感じで、5.10 は 64bit 版があるが、5.8 にはない。

で、普通に perl を実行すると perl5.10.0 は x86_64 で実行され、perl5.8.9 は i386 で実行される。

このアーキテクチャの差が結構くせ者で Snow Leopard 上で普通にライブラリなどを make すると x86_64 だけでビルドされてしまうため、そのようにして作ったライブラリはそのままでは perl5.8.9 からは使えないということになる。

デフォルトの 5.10.0 だけ使っている分にはなにも問題はないのだが、残念なことにこの 5.10.0 というのはいろいろな問題があり、開発に使用することはおすすめできない状況。(せめて 5.10.1 にしてくれればいいのに)

したがって無用なトラブルを避けるためにも 5.8.9 の方を使用するか、自前でビルドした perl を使用するのが良い。

またこのように x86_64i386 両方のアーキテクチャの実行ファイルがあり得る Snow Leopard に対して自分でライブラリをインストールする場合それらもユニバーサルバイナリにしておくと良い。

念のため追記@2010-01-08T15:19:23+09:00: もちろんこれは 64bit 対応の CPU の場合の話。そうでない場合はどちらも i386 で実行されるのでこの問題は起こらない。

by typester / at 2010-01-08T10:51:00 / osx · perl / Comment

5 6 7 8 9 10 11 12 13 14

(Page 9 of 203)