Archive for category programming

MeCab 0.96でSegment fault。

Posted by admin on Tuesday, 5 January, 2010

みんな、Taggerにはnilとか”"(空文字)とかを引数に渡しちゃだめですよ!

>> MeCab::Tagger.new.parseToNode(nil)
(irb):1: [BUG] Segmentation fault
ruby 1.8.7 (2009-04-08 patchlevel 160) [x86_64-linux]

単体で動かしていればすぐに気が付いたんだろうけど、デプロイした後で起こっていたのでなかなか気付きませんでした。

HpricotのXPATHを使って属性名の小文字大文字を無視する

Posted by admin on Tuesday, 5 January, 2010

HpricotのXPATHではlower-caseとupper-caseは使えなかったんですね。アイター。

ということでさっくりとコードいじりました。

例えばmetaタグのdescriptionを取り出すときに、以下のように大文字になっていると

<meta NAME="DESCRIPTION" ...>

次のようなxpathでは取り出せません。

//head/meta[@name=description]

これを解決するには以下のようにxpathの関数を使うのが理想なのですが

//head/meta[lower-case(@name)=description]

Hpricotでの実現方法が分からなかったのでElem::Travを直でいじるという乱暴な方法で解決しました。

#
# 属性へのアクセスは全て小文字に揃えます。
#
module Hpricot
  module Elem::Trav
    def has_attribute?(name)
      self.raw_attributes && self.raw_attributes.has_key?(name.to_s.downcase)
    end
    def get_attribute(name)
      a = self.raw_attributes && self.raw_attributes[name.to_s.downcase]
      a = Hpricot.uxs(a) if a
      a = a.downcase if (a && self.name.downcase == "meta" && name == "name")
      a
    end
    alias_method :[], :get_attribute
    def set_attribute(name, val)
      altered!
      self.raw_attributes ||= {}
      self.raw_attributes[name.to_s.downcase] = val.fast_xs
    end
    alias_method :[]=, :set_attribute
    def remove_attribute(name)
      name = name.to_s.downcase
      if has_attribute? name
        altered!
        self.raw_attributes.delete(name)
      end
    end
  end
end

これでmetaタグのname属性だけが全て小文字に揃います。

Eclipseでさくっとrubyのソースコードを編集したい(RDTだけ入れたい)

Posted by admin on Friday, 18 September, 2009

この内容はEclipse3.4で行っています。

Eclipseでrubyのソースコードを編集するにはAptanaを使うのが一般的ですが、railsを使うわけでもなく、cssを編集するわけでもなく、ただ単純にrubyで10行程度のスクリプトを書くためにAptanaを入れるのはちょっと大げさですよね。

そんなときにはAptanaに含まれるRDTだけをインストールしてあげます。

公式での説明。

http://update1.aptana.org/rdt/3.2/index.html

プラグインのURL。

http://update1.aptana.org/rdt/3.2/site.xml

インストールが完了すれば、あとは Winodw > Open Perspective > Other から Ruby を選ぶだけ。eclipseでさくさくrubyのソースコードをいじれるようになり快適です。

nph-proxy.cgiのwrap_proxy_decode関数をjavaに移植。

Posted by admin on Thursday, 17 September, 2009

微妙な関数をperlからjavaに移植しました。前はrubyに移植しています。いったいどれだけnph-proxy.cgiが大好きなんだって話です。

public static String warpProxyDecode(String s) {

	Pattern p = Pattern.compile("^([^?#]*)([^#]*)(.*)");
	Matcher m = p.matcher(s);

	if (m.matches() == false) {
		throw new IllegalArgumentException(s);
	}
	String uri = m.group(1);
	String query = m.group(2);
	String frag = m.group(3);

	Pattern uriPattern = Pattern.compile("=(..)");
	Matcher uriMatcher = uriPattern.matcher(uri);

	StringBuffer buff = new StringBuffer();
	while (uriMatcher.find()) {
		uriMatcher.appendReplacement(buff, toHexChr(uriMatcher.group(1)));
	}
	uriMatcher.appendTail(buff);

	return buff + query + frag;
}

こうやって見るとjavaの正規表現って手間かかりますね。

元のperlのコード。

sub wrap_proxy_decode {
    my($enc_URL)= @_ ;

    my($uri, $query, $frag)= $enc_URL=~ /^([^?#]*)([^#]*)(.*)/ ;

    # First, un-encode =xx chars.
    $uri=~ s/=(..)/chr(hex($1))/ge ;

    $uri= &proxy_decode($uri) ;

    return $uri . $query . $frag ;
}

移植したrubyのコード。

def wrap_proxy_decode(arg)

  /^([^?#]*)([^#]*)(.*)/ =~ arg
   (uri, query, frag) = $1, $2, $3
  uri.gsub!(/=(..)/){$1.hex.chr}
  uri + query + frag

end

log4jでエラーメールをSMTPで送る

Posted by admin on Thursday, 17 September, 2009

log4jでエラーメールを送る必要があり、ささっと設定ファイルだけ書き足せば終るだろと思っていたのですがすんなりとは行きませんでした。

デフォルトの SMTPAppender を使うと、日本語でおくれなかったり、ポート番号の指定が設定ファイルにかけません。

ですのでこれを解決するために、SMTPAppender を拡張した SMTPAppenderEx を作りました。

以下設定ファイルの内容です。SMTPPortというのが増えています。

log4j.appender.mail=hoge.log.SMTPAppenderEx
log4j.appender.mail.threshold=ERROR
log4j.appender.mail.LocationInfo=true
log4j.appender.mail.SMTPHost=xxxx
log4j.appender.mail.SMTPUsername=xxxx
log4j.appender.mail.SMTPPassword=xxxx
log4j.appender.mail.SMTPPort=xxxx
log4j.appender.mail.Subject=xxxx
log4j.appender.mail.From=xxxx
log4j.appender.mail.To=xxxx
log4j.appender.mail.BufferSize=256
log4j.appender.mail.layout=org.apache.log4j.PatternLayout
log4j.appender.mail.layout.ConversionPattern=%d %5p %c{1} - %m%n

以下はソースコードです。charset=ISO-2022-JPを指定しているのと、hostnameを取り出している次にportも取り出すように変更を加えています。

package hoge.log;

import java.util.Date;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;

import org.apache.log4j.Layout;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.net.SMTPAppender;
import org.apache.log4j.spi.LoggingEvent;

public class SMTPAppenderEx extends SMTPAppender {

	private String smtpPort;

	@Override
	protected void sendBuffer() {
		try {
			MimeBodyPart part = new MimeBodyPart();
			StringBuffer sbuf = new StringBuffer();

			String t = super.layout.getHeader();
			if (t != null) {
				sbuf.append(t);
			}

			int len = cb.length();
			for (int i = 0; i < len; i++) {

				LoggingEvent event = cb.get();

				sbuf.append(super.layout.format(event));
				if (!super.layout.ignoresThrowable()) {
					continue;
				}

				String s[] = event.getThrowableStrRep();
				if (s == null) {
					continue;
				}

				for (int j = 0; j < s.length; j++) {
					sbuf.append(s[j]);
					sbuf.append(Layout.LINE_SEP);
				}
			}

			t = super.layout.getFooter();
			if (t != null) {
				sbuf.append(t);
			}

			part.setContent(sbuf.toString(), super.layout.getContentType() + "; charset=ISO-2022-JP");
			Multipart mp = new MimeMultipart();
			mp.addBodyPart(part);

			msg.setContent(mp);
			msg.setSentDate(new Date());

			Transport.send(msg);
		} catch (Exception e) {
			LogLog.error("Error occured while sending e-mail notification.", e);
		}
	}

	@Override
	protected Session createSession() {

		Properties props = null;

		try {
			props = new Properties(System.getProperties());
		} catch (SecurityException ex) {
			props = new Properties();
		}

		if (getSMTPHost() != null) {
			props.put("mail.smtp.host", getSMTPHost());
		}

		if (getSMTPPort() != null) {
			props.put("mail.smtp.port", getSMTPPort());
		}

		Authenticator auth = null;
		if (getSMTPPassword() != null && getSMTPUsername() != null) {
			props.put("mail.smtp.auth", "true");
			auth = new Authenticator() {

				protected PasswordAuthentication getPasswordAuthentication() {
					return new PasswordAuthentication(getSMTPUsername(), getSMTPPassword());
				}

			};
		}

		Session session = Session.getInstance(props, auth);
		if (getSMTPDebug()) {
			session.setDebug(getSMTPDebug());
		}
		return session;
	}

	public void setSMTPPort(String smtpPort) {
		this.smtpPort = smtpPort;
	}

	public String getSMTPPort() {
		return smtpPort;
	}
}

送られてくるメールのヘッダは以下のようになっています。

Return-Path: 
X-Original-To: xxxx@xxxx
Delivered-To: xxxx@xxxx
Received: from tkosuga2 (unknown [192.168.5.196])
	by xxxx (Postfix) with ESMTP id E193DF18001
	for ; Thu, 17 Sep 2009 12:17:54 +0900 (JST)
Date: Thu, 17 Sep 2009 12:16:12 +0900 (JST)
From: xxxx@xxxx
To: xxxx@xxxx
Message-ID: <12528990.1.1253157372727.JavaMail.tkosuga@tkosuga>
Subject: grisette.ambree Error
MIME-Version: 1.0
Content-Type: multipart/mixed;
	boundary="----=_Part_0_25392791.1253157372696"
X-Antivirus: avast! (VPS 090916-0, 2009/09/16), Inbound message
X-Antivirus-Status: Clean

------=_Part_0_25392791.1253157372696
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: quoted-printable

charsetがちゃんと書き換わっていますね。これでSMTPで、log4jから日本語エラーメールをさくっと送れるようになりました。

ピモッターをリリースしたよ!

Posted by admin on Sunday, 13 September, 2009

こんな会話があったのが、12日の夜。

[2009/09/12 22:58:25] えがちゃんの発言: ひまだなーw
[2009/09/12 22:58:27] えがちゃんの発言: なにします?w
[2009/09/12 22:58:29] えがちゃんの発言: なんかサービスつくりたいw
[2009/09/12 23:03:57] tkosugaの発言: なんのサービス?
[2009/09/12 23:04:07] tkosugaの発言: この話に食いつく
[2009/09/12 23:04:25] えがちゃんの発言: pimoteのAPIをつかったサービスですねー

そこからbuzzterみたいなのを作りたいと言う話になりましたので、

颯爽とpimotterをリリースしました!この公開が13日19時30分ですので、話しが始まってからリリースまで21時間という速さです。

精度はまだまだ低いのですが、雰囲気は十分に感じ取ってもられるのではないかなと思います。

pimoteで流行しているキーワードを自動的に抽出し、それをピックアップして見ることができます。これでどんな事が流行しているのか一目で分かりますね!

このウェブサービスはrails 2.3.2 を使って作られています。pimoteサーバーには5分間隔で最新のタイムラインを取得しに行っています。画面に表示されるタイムライン解析結果はmemcachedを使って3分間キャッシュしてます。タイムラインの解析にはMeCabを使いました。

pimoteといいますか、twitterで流れる文章はほとんど口語で流れてるプラス、名詞だけ抜きだせば良いというものではないという事が分かってきました。

アスキーアートも抜き出せると良いのですが、パターンで一致させるぐらいしか方法が思いつきませんでした(ここは未実装です)

さっくりと作る分には誰が作っても同じような実装になると思うので、ここにこのサービスの中核となるMeCabで構文解析された単語の取り捨てをするコードを貼り付けます。

  #
  # もっとちゃんと作らないと。後で時間かけてかなー。
  #
  def self.necessary?(surface, feature, prev_feature)

    #p surface + ", feature:" + feature + ", prev_feature: " + prev_feature.to_s

    return false if surface.blank?
    return false if surface.split(//u).collect{|c| MARKS.include?(c)}.all?
    return false if /[[:cntrl:]|[:blank:]|[:punct:]]+/ =~ surface

    return true if (/^名詞,(一般|固有名詞|サ変接続|形容動詞語幹|ナイ形容詞語幹)/ =~ feature)
    return true if (/^形容詞,(自立)/ =~ feature)
    return true if (/^接頭詞,名詞接続/ =~ feature)
    return true if (/^感動詞/ =~ feature)

    return false if prev_feature.blank?

    #
    # この2つ次は絶対に拾う
    #
    if (/^接頭詞,名詞接続/ =~ prev_feature)
      return true
    end

    if (/^名詞/ =~ prev_feature)
      return true if (/^助詞,(.*,連語|終助詞|係助詞)/ =~ feature)
      return true if (/^動詞,(非自立)/ =~ feature)
    end

    if (/^助詞,格助詞,連語/ =~ prev_feature)
      return true if (/^助動詞/ =~ feature)
    end

    if (/^助詞,係助詞/ =~ prev_feature)
      return true if (/^助詞,終助詞/ =~ feature)
    end

    if (/^動詞,非自立/ =~ prev_feature)
      return true if (/^動詞,非自立/ =~ feature)
    end

    false
  end

  ASCII_ART_MARKS = %w{゚ ノ Д 冫}
  ASCII_MARKS   = %w{… ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ ^ _ ` { | } ~ > <}
  ZENKAKU_MARKS = %w{  、 。 , . ・ : ; ? ! ゛ ゜ ´ ` ¨ ^  ̄ _ ヽ ヾ ゝ ゞ 〃 仝 々 〆 〇 ー ― ‐ / \ ~ ∥ | … ‥ ‘ ’ “ ” ( ) 〔 〕 [ ] { } 〈 〉 《 》 「 」 『 』 【 】 + - ± × ÷ = ≠ < > ≦ ≧ ∞ ∴ ♂ ♀ ° ′ ″ ℃ ¥ $ ¢ £ % # & * @ § ☆ ★ ○ ● ◎ ◇ ◆ □ ■ △ ▲ ▽ ▼ ※ 〒 → ← ↑ ↓ 〓 ∈ ∋ ⊆ ⊇ ⊂ ⊃ ∪ ∩ ∧ ∨ ¬ ⇒ ⇔ ∀ ∃ ∠ ⊥ ⌒ ∂ ∇ ≡ ≒ ≪ ≫ √ ∽ ∝ ∵ ∫ ∬ Å ‰ # ♭ ♪ † ‡ ¶ ◯ ─ │ ┌ ┐ ┘ └ ├ ┬ ┤ ┴ ┼ ━ ┃ ┏ ┓ ┛ ┗ ┣ ┳ ┫ ┻ ╋ ┠ ┯ ┨ ┷ ┿ ┝ ┰ ┥ ┸ ╂ ∮ ∑ ∟ ⊿ ¦ ' " }
  MARKS = ASCII_MARKS + ZENKAKU_MARKS + ASCII_ART_MARKS

よそで書かれたテキストを自分のサーバーにもってきて加工するだけのサービスって楽ですね。負荷の問題もありませんし。接続先は1つですし。次からのサービスを作るときに、このあまりの楽々さに溺れてしまわないよう気をつけたいと思います。

slicehostのcentos(5.2)にImageMagick(6.5.3-10)とRMagick(2.11.0)をインストール

Posted by admin on Sunday, 6 September, 2009

1つ前の記事と同じように、クレジットカード・メーカーが実稼動するcentos5.2でrmagickが動くようにします。

まず依存するライブラリをインストールします。

sudo yum install bzip2-devel freetype-devel libpng-devel libtiff-devel freetype-devel libjpeg-devel

ソースコードもってきてconfigureしてmakeしてinstall

wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick-6.5.3-10.tar.gz
tar xvfz ImageMagick-6.5.3-10.tar.gz
cd ImageMagick-6.5.3-10

./configure --disable-static --with-modules --without-perl \
     --without-magick-plus-plus --with-quantum-depth=8 --disable-openmp

make
sudo make install

共有ライブラリを認識させます。

ldconfig

あとは以下を~/.bashrcに追記します。

export LD_LIBRARY_PATH=/usr/local/lib

gemでRMagickをインストール。

gem install rmagick -v 2.11.0

以上です。centosに入れるのは特に問題なくできました。

UbuntuにImageMagick(6.5.3-10)とRMagick(2.11.0)をインストールする

Posted by admin on Sunday, 6 September, 2009

クレジットカード・メーカーの開発はUbuntuで行ないました。そこでRMagickをインストールできるまですんなりとは行かなかったので備忘録としてブログ記事にします。

まず依存するライブラリをインストール。

sudo apt-get install libfreetype6
sudo apt-get install libfreetype6-dev
sudo apt-get install libjpeg62-dev
sudo apt-get install libpng12-dev
sudo apt-get install libwmf-dev
sudo apt-get install libperl-dev
sudo apt-get install libbz2-dev
sudo apt-get install libz-dev
sudo apt-get install libx11-dev
sudo apt-get install libxt-dev
sudo apt-get install libxext-dev
sudo apt-get install libxml2-dev
sudo apt-get install liblcms1-dev
sudo apt-get install libexif-dev
sudo apt-get install libjasper-dev
sudo apt-get install libltdl3-dev
sudo apt-get install graphviz
sudo apt-get install gs-gpl
sudo apt-get install pkg-config

wgetでソースコードを取得します。

wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick-6.5.3-10.tar.gz
tar xvfz ImageMagick-6.5.3-10.tar.gz
cd ImageMagick-6.5.3-10

configure するときに –disable-openmpを足しました。

./configure --disable-static --with-modules --without-perl \
     --without-magick-plus-plus --with-quantum-depth=8 --disable-openmp

makeしてインストールします。

make
sudo make install

シンボリックリンクを更新します。

ldconfig

これをやらないとibMagickCore.so.2が見つからないとエラーがでます。

$ convert --version
convert: error while loading shared libraries: libMagickCore.so.2: cannot open shared object file: No such file or directory

正常にインストールできたことを確認。

$ convert --version
Version: ImageMagick 6.5.3-10 2009-08-04 Q8 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2009 ImageMagick Studio LLC

次にgemでRMagickをインストールします。

sudo gem install rmagick -v 2.11.0

irbから動作確認してみましょう。

require 'rubygems'
require 'RMagick'
require 'pp'

include Magick
pp colors

ずらーっと色情報が出力されれば完了です。

rails + passenger でファイルをアップロードするときに注意すること

Posted by admin on Sunday, 6 September, 2009

今回、クレジットカード・メーカーを作るにあたって、アップロードされたファイルの取り扱いに意外と気を使う必要がありました。上限を超えたばかでかいファイルが送られてくるケースや、ファイルの拡張子はpngでも内容はexeファイルであったりなどです。

ここではそれらに対して行なった設定と実装を説明します。

Apacheにアップロードするファイルサイズの上限を指定

クレジットカード・メーカーではアップロードできるファイルサイズの上限を1Mまでとしています。
このファイルサイズ以上をアップロードされても捨てるしかありませんので、リソースの無駄使いになってしまいます。

これを防ぐためにはApacheのLimitRequestBodyディレクティブを使います。

以下、上記ページからの抜粋です。

このディレクティブは、 管理者にクライアントからの異常なリクエストを制御できるようにし、 何らかの形のサービス拒否攻撃 (訳注:DoS) を避けるのに有効です。

ある場所へのファイルアップロードを許可する場合に、 アップロードできるファイルのサイズを 100K に制限したければ、 以下のように指定します:

LimitRequestBody 102400

アップロードされたファイルの種類を指定

アップロードされてきたファイルのMIMEタイプを判別し、それが背景画像として使えるかを判定しなければいけません。

MIMEタイプを判定するライブラリにはshared-mime-infoを使いました。

yumを使ってインストールするには以下のコマンドを実行します。

yum install shared-mime-info

rubyからshared-mime-infoを使えるように以下のコマンドを実行します。

gem install shared-mime-info

これでMIMEパッケージが使えるようになりますので、以下のコードでファイルの種類を知ることができます。

require 'rubygems'
require 'shared-mime-info'

MIME.check_magics('images/sample.jpg').type
=> "image/jpeg"

shared-mime-infoの仕様に、推奨するMIMEタイプのチェックする順番について書かれています。

簡単に書きますと、次の3ステップになります。

1. MIMEタイプを見る
2. glob(ファイルの拡張子)を見る
3. magic(ヘッダ部分のバイナリ)を見る

attachment-fuの使い方

クレジットカード・メーカーはカード画像の生成にImageMagickを使っています。railsプラグインのattachment-fuではサムネイルの生成にImageMagickを使っているためとても相性がよかったです。

以下のようにthumbnailsにファイルのサイズを書くだけでサムネイルを勝手に生成してくれます。

class PublishedImageFile < ActiveRecord::Base
  has_attachment(:content_type => :image,
                 :max_size => 1024.kilobytes,
                 :thumbnails => { :middle => '387x249', :small => '258x166'}
  )
end

このモデルのスキーマは以下のようになっています。

  create_table "published_image_files", :force => true do |t|
    t.integer  "parent_id"
    t.string   "content_type"
    t.string   "filename"
    t.string   "thumbnail"
    t.integer  "size"
    t.integer  "width"
    t.integer  "height"
    t.string   "name",                         :default => "オリジナルの"
    t.string   "comment",      :limit => 1024, :default => "自分だけのクレカ出来た!"
    t.boolean  "fixed"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "published_image_files", ["content_type"], :name => "index_published_image_files_on_content_type"
  add_index "published_image_files", ["created_at"], :name => "index_published_image_files_on_created_at"
  add_index "published_image_files", ["parent_id"], :name => "index_published_image_files_on_parent_id"

テーブル作って、モデル作って、has_attachmentと書くだけでアタッチメントの管理できるattachment-fuは素晴らしいです。モデルを削除すると保存先のストレージからも消してくれます。

以上です、railsでファイルをアップロードするサービスを作る方の参考になれば幸いです。

centOS 5.3でrubyのreadlineがコンパイルされなくてrailsのscript/consoleが動かない

Posted by admin on Thursday, 20 August, 2009

railsでscript/consoleを動かすとこのエラーがでる。うーんreadlineが入っていないらしい。

# ruby script/console
Loading development environment (Rails 2.2.2)
/usr/local/lib/ruby/1.8/irb/completion.rb:10:in `require': no such file to load -- readline (LoadError)
        from /usr/local/lib/ruby/1.8/irb/completion.rb:10
        from /usr/local/lib/ruby/1.8/irb/init.rb:252:in `require'
        from /usr/local/lib/ruby/1.8/irb/init.rb:252:in `load_modules'
        from /usr/local/lib/ruby/1.8/irb/init.rb:250:in `each'
        from /usr/local/lib/ruby/1.8/irb/init.rb:250:in `load_modules'
        from /usr/local/lib/ruby/1.8/irb/init.rb:21:in `setup'
        from /usr/local/lib/ruby/1.8/irb.rb:54:in `start'
        from /usr/local/bin/irb:13

rubyのソースコードのext/readlineに移動しておもむろにextconf.rb

# ruby extconf.rb
checking for tgetnum() in -lncurses... no
checking for tgetnum() in -ltermcap... no
checking for tgetnum() in -lcurses... no
checking for readline/readline.h... yes
checking for readline/history.h... yes
checking for readline() in -lreadline... no
checking for readline() in -ledit... no
checking for editline/readline.h... no

えええ?分かんないなあ。あれ?ncursesが入っていない?

yumでncurses-develを入れる。

yum install ncurses-devel

再度実行。

# ruby extconf.rb
checking for tgetnum() in -lncurses... yes
checking for readline/readline.h... yes
checking for readline/history.h... yes
checking for readline() in -lreadline... yes
checking for rl_filename_completion_function()... yes
checking for rl_username_completion_function()... yes
checking for rl_completion_matches()... yes
checking for rl_deprep_term_function in stdio.h,readline/readline.h,readline/history.h... yes
checking for rl_completion_append_character in stdio.h,readline/readline.h,readline/history.h... yes
checking for rl_basic_word_break_characters in stdio.h,readline/readline.h,readline/history.h... yes
checking for rl_completer_word_break_characters in stdio.h,readline/readline.h,readline/history.h... yes
checking for rl_basic_quote_characters in stdio.h,readline/readline.h,readline/history.h... yes
checking for rl_completer_quote_characters in stdio.h,readline/readline.h,readline/history.h... yes
checking for rl_filename_quote_characters in stdio.h,readline/readline.h,readline/history.h... yes
checking for rl_attempted_completion_over in stdio.h,readline/readline.h,readline/history.h... yes
checking for rl_library_version in stdio.h,readline/readline.h,readline/history.h... yes
checking for rl_event_hook in stdio.h,readline/readline.h,readline/history.h... yes
checking for rl_cleanup_after_signal()... yes
checking for rl_clear_signals()... yes
checking for rl_vi_editing_mode()... yes
checking for rl_emacs_editing_mode()... yes
checking for replace_history_entry()... yes
checking for remove_history()... yes
creating Makefile

あとはmake && make install。これで動きました。