2015年、エンジニア界隈で話題になった事といえばなんでしょうか。
自分は「進捗どうですか」が印象に残っています。
いろんな言語で実装されましたね。
(golang の進捗どうですか)もすでにあって、自分は乗り遅れたので傍観者として見ていたのですが、今年を代表するネタですので今年最後、自分も乗っかろうとcgoで乗ってみました。
cgo
端的に言えばgolangとC言語の間で相互に関数を使い合うためのパッケージです。
package main
/*
#include <stdio.h>
void hello_world() {
printf("%s\n", "Hello World!!");
}
*/
import "C"
func main() {
C.hello_world()
}
上記はgolangからC言語の一方通行です。
最初はこんな感じで作ろうかと血迷ってましたが「それじゃC言語のアドベントカレンダーだろ!」と理性を取り戻し、使った事が無かったstringerと組み合わせてみることにしました。
stringer
端的に言えばgolangの定数(iotaを使ったもの)の定数名を取得できるコマンドです。
「golangの進捗どうですか」でも使われています。
package main
import (
"fmt"
)
type マキシマムザホルモン int
const (
マキシマムザ亮君 マキシマムザホルモン = iota
上ちゃん
ダイスケはん
ナヲ
)
func main() {
var mth マキシマムザホルモン = ダイスケはん
fmt.Println(mth)
}
このままだと2
としか表示されません。
どうしてもダイスケはん
って表示したい!!
そんな時にstringer
$ go get -u -v golang.org/x/tools/cmd/stringer
$ stringer -type マキシマムザホルモン main.go
上記コマンドを打つと下記のような.go
ファイルが生成されます。
// Code generated by "stringer -type マキシマムザホルモン main.go"; DO NOT EDIT
package main
import "fmt"
const _マキシマムザホルモン_name = "マキシマムザ亮君上ちゃんダイスケはんナヲ"
var _マキシマムザホルモン_index = [...]uint8{0, 24, 36, 54, 60}
func (i マキシマムザホルモン) String() string {
if i < 0 || i >= マキシマムザホルモン(len(_マキシマムザホルモン_index)-1) {
return fmt.Sprintf("マキシマムザホルモン(%d)", i)
}
return _マキシマムザホルモン_name[_マキシマムザホルモン_index[i]:_マキシマムザホルモン_index[i+1]]
}
これで実行すればダイスケはん
が現れます。
$ go run *.go
ダイスケはん
余談ですが、ファイル名もコマンド実行時に-output
オプションで指定できるので、型名が日本語の時は指定することを強くオススメしますw
$ stringer -type マキシマムザホルモン -output mth_string.go main.go
作る
単にC言語で作ったプログラムを呼んでもなーと思ったので相互に呼び合うプログラムにしました。
package wap
/*
extern void wap(void);
*/
import "C"
import "fmt"
type word int
const (
進捗 word = iota
どう
です
か
)
//export printWord
func printWord(num C.int) C.int {
fmt.Print(word(num))
return num
}
// Wap is "what about progress?"
func Wap() {
C.wap()
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "_cgo_export.h"
void wap(void) {
srand(time(NULL));
int w = 0, n = 0;
for (;;) {
n++;
int s = printWord(rand() % 4);
if (w != s) {
if (s == 0) {
w = 1;
} else {
w = 0;
}
} else {
w++;
if (w == 4) {
break;
}
}
}
printf("%s",
"\n"
"_人人人人人人人_\n"
">進捗どうですか<\n"
" ̄Y^Y^Y^Y^Y^Y^Y ̄\n");
printf("%d回で煽られました\n", n);
}
golangから呼んでいるC言語関数がwap(void)
でC言語から呼んでいるgolang関数がprintWord(num C.int)
です。
stringer効果でfmt.Print(word(num))
と書くだけで「進捗」「どう」「です」「か」のどれかが表示されるようになっています。
苦労したというかできなかったのは、最初、mainパッケージで作っていたのですが、
下記のようなエラーが出て動かなくて困りました。
# command-line-arguments
Undefined symbols for architecture x86_64:
"_wap", referenced from:
__cgo_57c8a91b469e_Cfunc_wap in wap.cgo2.o
(maybe you meant: __cgo_57c8a91b469e_Cfunc_wap)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Re: [go-nuts] Cgo and libccv: "Undefined symbols"
とか読むとフラグがあれば行けるっぽいけど
とりあえず、cgo · golang/go Wikiを読んでmainとは別のパッケージにするという方法で実装しました。
パッケージにできたので誰でも使えるようになったのはよかったかなと思います。(誰が使うんだ!)
できた
即試したい場合はexampleディレクトリでgo run main.go
をしてもらうと進捗を聞いてくれます。
$ go get -u github.com/178inaba/wap
$ cd $GOPATH/src/github.com/178inaba/wap/example
$ go run main.go
進捗進捗どう進捗ですか進捗進捗ですかですです進捗ですですです進捗かですかか進捗か進捗どうですどう進捗進捗進捗ですどうどうどうどうどう進捗どうか進捗どうかです進捗ですですですかかかです進捗どうです進捗かかかどう進捗進捗どうどうか進捗ですか進捗かかか進捗どうかですですか進捗どう進捗どうどう進捗進捗どうですか
_人人人人人人人_
>進捗どうですか<
 ̄Y^Y^Y^Y^Y^Y^Y ̄
87回で煽られました
パッケージ化してあるのでexampleのmain.go
の中身はwap.Wap()
を呼んでいるだけです。
package main
import "github.com/178inaba/wap"
func main() {
wap.Wap()
}
みなさんのプログラム内でもwap.Wap()
と書いていただければ進捗を聞きますよw
コマンドラインツールにいかがでしょうか?www
ちなみに「wap」は「what about progress? (進捗どうですか?)」の略です。
最後に
みなさん、2015年の進捗どうですか?