goでも

上野駅あたりは昔、海のほとりだったらしい。江戸は水の都。縦横に運河が有って、船で 荷物運びをやってたらしい。

それが、いつの間には海は埋め立てられ、神田川はよく氾濫するって事で、東京へ 入る手前で分流されて新しい荒川が作られたとか。そして、東京オリンピックで、川には 蓋をされ、あるいは川の上に首都高が作られて。。東京は自然を制圧して出来た街でも あります。そんな東京に自然が牙を剥いたら、どういう事になるか?

勝てっこない。それをソフトに知らせる為、もし富士山が爆発したら、、、とか、大地震が 襲ったら、、、とか、さかんにTVで啓蒙してる。啓蒙と言えば、たまに見るニュートンでも やってますな。正しい知識を身に付けるのは重要。

そう、東京を巨大台風が襲ったら、、、今年の台風シーズンはほぼ終わり、もう今年は 大きな台風来ないよね。よかったね。で、来年は?

『ジェミニの方舟・東京大洪水』(集英社)なんて本を読んだ。

台風23号が沖縄を直撃。その後、大きく進路を東に変えた為、本土上陸は無くなった。 ほっとしたのもつかの間、24号が発生。それが23号に近寄って行く。アベック台風。 藤原効果で、精力を得た。

そして、そいつが、東京へと近寄ってきた。防災研に勤める研究者とその家族、その周辺人物を 中心に物語は進んで行く。

その研究者は、荒川が氾濫した場合にどうなるか? 過去の例を丹念に収集してシュミレーションの 上、警告を発するため、学術論文を上梓していた。それを事前入手していた都知事は 関係部署に参考のために流していた。

一方、研究者の女房は、一級建築士、荒川のスーパー堤防ほとりに建てている、高層マンションに 情熱を注いでいる。小供の面倒はおばあちゃん任せ。そんなこんなで、夫婦間には ちょっとぎくしゃくした所が。

台風は、シュミレーション通りに甚大な勢力を得て、東京へ近寄ってくる。氾濫しそうに なる荒川、強烈な風で神田川の水壁が飛んできたタンクで破損。そこから壁の破損拡大が 始まる。

地下街、地下鉄に浸水したら、被害は数十兆円では済まないだろう。高潮の影響があって、 海面が通常よりは1m以上上昇の予報。下町の人を何処に非難させる? 堤防が決壊すれば、深い所で6mも水没する。昔、三重県を視察した時、伊勢湾台風で、 ここまで水に埋もれましたって碑がたってた。その浸水度にびっくりした記憶が有り、 小説とは言え臨場感たっぷり。

こうして、阿鼻叫喚な物語が進行してく。東京沈没で日本沈没にならないように、地方が 元気になっておくれ。一極集中は脆いよ。なんて事を考えました。

読書メーター 6冊 / 1980頁 / 13100円

でも

前回はschemeだった。その中でたまたまHaskell由来のマクロが出たきたんで、今回は、 カタカタ(型型)と五月蝿く言う haskellでも ってなるかな。

XXXでもってタイトルを何回か使ってきた。でもの用法その1は、XXXデモかな。その2は、 (clojure | python | gaucne)にも飽きたんでXXXしようかな。その3は、同じ課題を、XXXでも、 やってみよう。

さて、オイラーの意図は? 決して用法2ではありません。きっぱりと用法3です。 haskellの機能がschemeにやって来るって事は、親戚関係なんだな。

この間読んだ本『虎の巻』ってのが有るんだけど、虎とライオンとかは同じ猫科。繁殖は 容易らしい。そうでしょう、そうでしょう。虎にまつわる成句もたくさんあるのね。

大虎になるとか、虎の子とか、、、いっぱいあって覚えきれなかったぞ。強烈な印象に 残ったのが、虎の子渡し。

値渡しとか名前渡しってのは、プログラミングを多少かじった事がある人なら知ってると 思うけど、虎の子渡しは初聞でした。

虎は一度に2から4頭の子を生むそうです。母虎は子をとても大切に扱うので、それが転じて、 大事な物を虎の子と言うそうな。嗚呼、話が逸れた。子の中に1頭は悪餓鬼が居て、母虎が 居ないと、兄弟を食べてしまうそうです。

3頭の子を連れた母虎が大河を渡る事になりました。子は一度に1頭しか運べません。 (首根っこを咥えて運ぶから当然)、母虎はどうやって3頭の子虎を対岸に運んだんでしょうか?

こういう頭を抱えるような問題の事を、虎の子渡しと言うそうな。

goの開発環境

Haskellに型々言われる前に、今回は趣き変えてgoしてみます。 The Go Programming Languageですな。 (日本語版)マスコットが何となくPlan9の バニーちゃんに見えるのは、目の錯覚? 今年の6月だかに、1.3が出たそうですんで、事例も いろいろと揃っている事でしょう。たまたま、技評のWeb+DBなんて雑誌でも取り上げられていましたから。

万次郎Linuxにも最新版が来てましたんで、emacsと組み合わせる事にしました。 Goプログラミングの環境構築 とか、 Emacs で Go を書く あたりを参考にすればいいです。興が乗ったら、helm-go-packageとかgo-direxあたりも 試してみたいです。

開発拠点として、自分のhome-dir内に場所を確保します。

mkdir godev
cd godev
export GOPATH=`pwd`
export PATH=$PATH:$GOPATH/bin

とかをしとくそうです。ああ、正確には、上のemacs関連を入れる前に拠点を用意しとく 必要が有ります。ちょっと動作試験

[sakae@manjaro helo-go]$ go run hello.go
hello, world
[sakae@manjaro helo-go]$ go build hello.go
[sakae@manjaro helo-go]$ ls
hello*  hello.go
[sakae@manjaro helo-go]$ file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
[sakae@manjaro helo-go]$ ./hello
hello, world

大丈夫そうなので、goの環境を一応確認

[sakae@manjaro helo-go]$ go env
GOARCH="386"
GOBIN=""
GOCHAR="8"
GOEXE=""
GOHOSTARCH="386"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/sakae/godev"
GORACE=""
GOROOT="/usr/lib/go"
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_386"
CC="gcc"
GOGCCFLAGS="-fPIC -m32 -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"

windows7でもgo

goはWindowsでも動くってさ。インストーラ付きのやつと圧縮版が用意されてた。圧縮版を 入れてみた。

C:\homes\godev>go env
set GOARCH=386
set GOBIN=
set GOCHAR=8
set GOEXE=.exe
set GOHOSTARCH=386
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=C:\homes\godev
set GORACE=
set GOROOT=C:\app\go
set GOTOOLDIR=C:\app\go\pkg\tool\windows_386
set CC=gcc
set GOGCCFLAGS=-m32 -mthreads -fmessage-length=0
set CXX=g++
set CGO_ENABLED=1

デフォだとCドライブ直下を想定してるようで、GOROOTも設定しないと駄目なのね。 こういう環境変数は、PATHを設定する要領でやればいいんだ。gccは昔入れたmingw 4.5.2版と 古い物だけど、大丈夫かな。

そして、emacsからも使えるようにしよと設定を始めた。まずは、ggocodeってんで、go get したら、gitが入ってねえぞと怒られた。

Windows7でコマンドラインでgitを使う を参考に入れた。何とかgocodeは出来上がったよ。

次はgodefだなと思って、go getしたら、今度はhgが無いと抜かす。hgってpythonで書かれた git対抗品だな。ぐぐる様では推奨品? しょうがないのでpipでいれようとしたら、pythonが古すぎると 言われた。ならば、eazy_installかと思って試したら、どうも余計な物が必要みたい。 Windowsでunixの真似事をしようと思うと面倒臭い。

で、go help getして、オプションで、データが揃った所からパッケージを作れないかと 探してみたよ。そしたら有ったんで、喜びいさんで、万次郎Linuxからソースを転送。 そのオプションってのは、fixだってさ。gitで取ってきたソースに自分なりに改造を施し、 それから続きをやる時に使うものらしい。

C:\homes\godev>go get  code.google.com/p/rog-go/exp/cmd/godef
go: missing Mercurial command. See http://golang.org/s/gogetcmd
package code.google.com/p/rog-go/exp/cmd/godef: exec: "hg": executable file not
found in %PATH%
;;; ここで、godefをWindowsへ転送しとく
C:\homes\godev>go get -fix code.google.com/p/rog-go/exp/cmd/godef
C:\homes\godev>ls bin
gocode.exe* godef.exe*

こんな具合にやっと特製コマンドが出来上がったよ。やれやれ。 折角Windowsを使ってるのにemacsじゃヤダと言う新人類なら、 WindowsでのGo開発環境(IDE) とか、 IDEs and Plugins for Go を見て、好きなのを入れればいいよ。

実例

何とか環境は整った。後は慣れる事だな。既にgocodeとかのソースが有るのでそれを見れば いいんでないかい。でも、ちょっと大きすぎて追いきれない。少し小ぶりなものがいいな。 探してきたのは、柿。

A Tour of Go

Go言語 例文辞典

38日間Go言語を書いて学んだこと

Golang Sampes

goz go's news

Golang JP(Google+)

お気楽 Go 言語プログラミング入門

Pythonista向けGo言語入門

タグ「golang」が付けられた記事の一覧

Golangでの文字列・数値変換

taknb2nchのメモ (Go)

Block Rockin’ Codes(Web+DBの著者のページ)

LiteIDE

Windowsでemacsもいいんだけど、IDEも試してみるか。軽いIDEとわざわざ名前にしてるんだから 軽いんだろ? Hi, LiteIDE。 逆に言えば、対抗品は重いって事だな。

zipファイルを取ってきて展開。binの中にあるexeを起動。軽く上がってきた。buildメニューから コンパイルしようとしたら、goが無いとか言ってきた。ちゃんとemacsでもCUIなターミナル からも動く事を確認してるのに、そりゃないでしょ。

きっとconfigメニューが有るはずと探してみたけど、見当たらず。後は、あちこちにある ボタンを押してみたら、ようこそのタブの左側のボタンが、configファイルの呼び出しに なってた。GOROOTがCドライブ直下になってたので、編集。

ようこそ画面の右下にある、オプションボタンから、色々なシーンの設定を編集出来る。 おいらはeditorの背景色とフォントサイズを変えておいた。マニュアルも見ないで、 あちこち突き回したけど、ようこそ画面内がそれぞれの項目のマニュアルなんで、眺めて おくと吉。

早速、Go Walkerなんて言うサイトを紹介された。これを 使って、色々な試みを探せるな。統計は、統計は、statisticsぐらいで良いかと思って 探してみたら、34個見つかった。沢山あり過ぎて困っちゃうなーと思ったら、ランクが 付いてた。これはもう、有り難く使わせてもらう鹿。

あっ、こんなのも有った。便利^2 ですよ。Search for Go Packages

Hello goっていうコンソールアプリをBuild-runすると、初回は、一瞬画面が出て消えた。 これって、コンソール画面が消えないように、input文でも実行させないといけないかと 思ったぞ。 でも、2回目にIDEを起動したら、hello.exeなんてアプリが 出来てて、それのおかげで、IDEの出力画面に、helloの結果が出てきた。親切だな。

入力の補完が使えるか試してみた。ちゃんと補完候補が出てきたぞ。これもemacsの設定で 苦労したおかげでしょうかね。(後で調べたら、自前でいろいろなパッケージを同梱してた。)

候補を選ぶ時、矢印キーを使わせられるのには閉口。CTL-Nとか CTL-Pで出来るようになって欲しい。まあ、コードを書く時は、emacsを使っておいて、debug をする時は、IDEって言う戦略が良いかな。

それはそうと、補完の初回時、火壁に穴を開けるけどって言ってきた。これって何者よ? 変なパケットがぐぐる様にでも流れて行って、goの改良に利用させて貰います、なんて事には ならないだろうな。ちょいと心配。

ならば、何処とやり取りしてるか、パケモニすればいいんでないかい。生憎、Windowsに 入れていたWiresharkは消しちゃったしなあ。そうか、万次郎Linuxで調べればいいじゃん。

舞台をLinuxに移します。emacsを起動して、補完を働かせた途端に、とあるプロセスが動き 初めました。

  329 pts/2    S+     0:03 emacs hello.go
  338 ?        Sl     0:00 /home/sakae/godev/bin/gocode -s -sock unix -addr localhost:37373

これを見ると、パケットは外とはやり取りしてなかった。安心々。

ついでなんで、gocodeのソースを見とく。mainは、gocode.go。そうか、アプリ名を付けた ソースファイルにmain関数を収納するのが流儀なんだな。 ちょいと実行

[sakae@manjaro bin]$ ./gocode -h
Usage: ./gocode [-s] [-f=<format>] [-in=<path>] [-sock=<type>] [-addr=<addr>]
       <command> [<args>]

Flags:
  -addr="localhost:37373": address for tcp socket
  -debug=false: enable server-side debug mode
  -f="nice": output format (vim | emacs | nice | csv | json)
  -in="": use this file instead of stdin input
  -profile=0: port on which to expose profiling information for pprof; 0 to disable profiling
  -s=false: run a server instead of a client
  -sock="unix": socket type (unix | tcp)

Commands:
  autocomplete [<path>] <offset>     main autocompletion command
  close                              close the gocode daemon
  status                             gocode daemon status report
  drop-cache                         drop gocode daemon's cache
  set [<name> [<value>]]             list or set config options

sock typeをtcpに変えると、tcpdumpでパケットモニター出来るな。gocodeを何処で呼び出して いるか調べて、パケモニしてみるかな。

ソースをちらちら見てたら、プロファイルのやり方も出てた。

// Use the following commands to profile the binary:
// go tool pprof http://localhost:6060/debug/pprof/profile   # 30-second CPU profile
// go tool pprof http://localhost:6060/debug/pprof/heap      # heap profile
// go tool pprof http://localhost:6060/debug/pprof/block     # goroutine blocking profile
// See http://blog.golang.org/profiling-go-programs for more info.

それはそうと、gocodeはどうやって起動してるんだろう? 探してみたけど見つからず。 何か、見落としがあるのかな?

調査

gocodeがどんな風にemacsから起動されてるか調べれば、gocodeの挙動を探る事も出来るだろう。 まずは、基本の調査だな。

[sakae@manjaro helo-go]$ strace -o LOG emacs hello.go

こうして、ログを取って、gocodeの発射の瞬間を捉えようとしたけど、引っかかってこない。 困ってしまうな。lsofでどうなってるか、確認してみる。

先に、gocodeの方

[sakae@manjaro ~]$ lsof -p 561
COMMAND PID  USER   FD      TYPE     DEVICE SIZE/OFF  NODE NAME
gocode  561 sakae  cwd       DIR        8,4      160 18254 /home/sakae/godev/helo-go
gocode  561 sakae  rtd       DIR        8,3      592     2 /
gocode  561 sakae  txt       REG        8,4  7774392 31717 /home/sakae/godev/bin/gocode
gocode  561 sakae  mem       REG        8,3  2092079 33033 /usr/lib/libc-2.19.so
gocode  561 sakae  mem       REG        8,3   141475 33051 /usr/lib/libpthread-2.19.so
gocode  561 sakae  mem       REG        8,3   159872 33010 /usr/lib/ld-2.19.so
gocode  561 sakae    0u     unix 0xf5821b00      0t0 10216 /tmp/gocode-daemon.sakae
gocode  561 sakae    1u  a_inode        0,9        0  4023 [eventpoll]
gocode  561 sakae    4u      CHR        5,0      0t0  4034 /dev/tty

unixドメインの口が開いているなあ。対するemacsの方は、何も出ていなかった。あれ? もしかして、これかな。

emacs   551 sakae    0u   CHR  136,2      0t0      5 /dev/pts/2
emacs   551 sakae    1u   CHR  136,2      0t0      5 /dev/pts/2
emacs   551 sakae    2u   CHR  136,2      0t0      5 /dev/pts/2

さて、どうしたものか?

突然、CERNを思い出した。核の研究をやっている所。httpdの 故郷。物質の成り立ちを調べるには、原子核に弾丸を撃ち込んで、飛び出す破片を分析 すれば良い。例えて言うと、自動車の構成物を調べるには、壁に衝突させれば良い。 時速10kmぐらいじゃ、ばらばらにならないので、サーキット場で最大に加速してから、衝突 させる。CERNのある所では、山の手線の円周ぐらいの、サーキット場が有り、そこで陽子 やらを加速、衝突させてる。

それと同じで、今の場合なら、gocodeが起動しないようにして、どんなエラーが出て くるか調べればいいんでないかい! 騒ぎを起して、その間にってやつ。

やってみた。gocodeを破壊するのは偲びないので、実行属性を落とした。

[sakae@manjaro bin]$ chmod 444 gocode
[sakae@manjaro bin]$ ./gocode -h
bash: ./gocode: 許可がありません

これで破壊完了。で、emacsを動かして補完をやってみると、、、、動いてる。psで調べると 、ちゃんとgocodeのプロセスが立ち上がってる!!! でも、使われているのが、/usr/bin/gocodeだ。 いつの間にか golangide が入っていて、その片割れだった。golangideってWindowsに入れた、 LightIDEね。

これ幸いとばかり golangide を起動したら、

  834 ?        Sl     0:00 /usr/bin/gocode -s -sock unix -addr localhost:37373

上記のように使われていた。これじゃ、手出しが出来ないなってんで、-sockをtcpにして telnetで叩いてみるも反応無し。そうだ、コマンドを送ればいいんかとばかり、 再起動したら、

panic: listen tcp 127.0.0.1:37373: bind: address already in use

goroutine 16 [running]:
runtime.panic(0x8362440, 0x187727c0)
        /usr/lib/go/src/pkg/runtime/panic.c:279 +0xe9
main.new_daemon(0xbff077a2, 0x3, 0xbff077ac, 0xf, 0x807f35a)
        /home/sakae/godev/src/github.com/nsf/gocode/server.go:57 +0xc3
main.do_server(0x0)
        /home/sakae/godev/src/github.com/nsf/gocode/server.go:26 +0x193
main.main()
        /home/sakae/godev/src/github.com/nsf/gocode/gocode.go:67 +0x50
    :
goroutine 17 [syscall]:
runtime.goexit()
        /usr/lib/go/src/pkg/runtime/proc.c:1445

おめでとう。初めて見る(これから頻繁に見る出あろう)panic画面にご対面。 ちゃんと行番号を示しているって事は、debugもどうぞって事なんだな。

[sakae@manjaro bin]$ gdb gocode
  :
(gdb) b main
Breakpoint 1 at 0x8096d40: file /usr/lib/go/src/pkg/runtime/rt0_linux_386.s, line 17.
(gdb) b main.do_server
Breakpoint 2 at 0x8066a70: file /home/sakae/godev/src/github.com/nsf/gocode/server.go, line 15.
(gdb) run  -s -sock tcp -addr localhost:37373
Breakpoint 1, main () at /usr/lib/go/src/pkg/runtime/rt0_linux_386.s:17
17              JMP     _rt0_go(SB)
(gdb) c
Continuing.
[New Thread 0xb7cc8b40 (LWP 858)]
[New Thread 0xb73c7b40 (LWP 859)]
[New Thread 0xb69ffb40 (LWP 860)]

Breakpoint 2, main.do_server (~r0=1)
    at /home/sakae/godev/src/github.com/nsf/gocode/server.go:15
15      func do_server() int {
(gdb) bt
#0  main.do_server (~r0=1)
    at /home/sakae/godev/src/github.com/nsf/gocode/server.go:15
#1  0x080602f0 in main.main ()
    at /home/sakae/godev/src/github.com/nsf/gocode/gocode.go:67

BPは、package.func っていう風に設定するんか。ただのmainだとcrt0相当のmainになる んだな。これは思わぬ拾いものですよ。

だけど、go得意のスレッド一杯は、苦労しそうだな。まあ、goは ベターC言語って事で 宜しいでしょうか。それとも、、、。

元に戻って、 一時的に/usr/bin/gocodeの方も不能にして、補完を実行すると、エラーを捉えたぞ。

eldoc error: (file-error Searching for program そのようなファイルやディレクトリ
はありません gocode)

これは、go-eldoc.elの中の

;; Same as 'ac-go-invoke-autocomplete'
(defun go-eldoc--invoke-autocomplete ()
  (let ((temp-buffer (generate-new-buffer "*go-eldoc*")))
    (prog2
        (call-process-region (point-min)
                             (point-max)
                             "gocode"
                             nil
                             temp-buffer
                             nil
                             "-f=emacs"
                             "autocomplete"
                             (or (buffer-file-name) "")
                             (concat "c" (int-to-string (- (point) 1))))

だな。gocodeに対するargは、何処で設定してんだろう? 謎だ! ああ、straceのログを見てると

open("/tmp/emacsnWeQiK", O_RDONLY|O_LARGEFILE) = 5
stat64("/home/sakae/godev/bin/gocode", {st_mode=S_IFREG|0755, st_size=7774392, ...}) = 0
access("/home/sakae/godev/bin/gocode", X_OK) = 0
pipe([6, 7])                            = 0
vfork()                                 = 525
close(7)                                = 0
close(5)                                = 0
read(6, "Errorf,,func(format string, a .."..., 16384) = 52
read(6, "Fprint,,func(w io.Writer, a ...i"..., 16332) = 1221
read(6, "", 15111)                      = 0

こんなのが出てきてる。unixドメインだから、パイプか。そして、Errorfなんてのは、正に補完の 結果になっている訳だし、、もう訳わかめ。