Shogo's Blog

Jul 2, 2019 - 1 minute read - polyglot go golang perl php ruby

GoのバイナリをRubyスクリプトとしても扱う

$ ruby --help
Usage: ruby [switches] [--] [programfile] [arguments]
(中略)
  -x[directory]   strip off text before #!ruby line and perhaps cd to directory
(後略)

なんか Ruby にも -x あるらしいので。

package main

import (
	"fmt"
	"runtime"
)

const script = `
#!ruby
puts "Hello Ruby World!!\n"
__END__
`

func init() {
	runtime.KeepAlive([]byte(script))
}

func main() {
	fmt.Println("This is Go world!!")
}

はい。

$ go build -o main main.go
$ ./main
This is Go world!!
$ ruby -x main
Hello Ruby World!!

runtime.KeepAlive なら最適化で削除されないことが保証されているので、問題なく動く、はず。 runtime.KeepAlive(script) でも良さそうなものだけど、なぜかうまくいかない。 ただの遊びなので、そこまで深く調べてない・・・。

おまけ

各言語は独立なので、全部混ぜても動くわけですね。

package main

import (
	"fmt"
	"runtime"
)

const script = `
# 何故かこのコメントが無いと動かない
#!ruby
puts "Hello Ruby World!!\n"
__END__
#!perl
print "Hello, Perl World!!\n";
__END__
<?php
file_put_contents("php://stderr", "This is PHP world!!!".PHP_EOL);
__halt_compiler();
`

func init() {
	runtime.KeepAlive([]byte(script))
}

func main() {
	fmt.Println("This is Go world!!")
}
$ go build -o main main.go
$ ruby -x main
Hello Ruby World!!
$ perl -x main
Hello, Perl World!!
$ php ./main 2>&1 > /dev/null
This is PHP world!!!

「# 何故かこのコメントが無いと動かない」の行を削除すると、なぜか動かない。

$ ruby -x main
main:1112: invalid multibyte char (UTF-8)

#!ruby が何故か二回登場している、ということまではわかったけど、ここで飽きたので誰か任せた。

実行環境は以下の通り

$ go version
go version go1.12.6 darwin/amd64