go runに引数として.goのファイルを渡す方法について

通常go runは以下の様にして使う。

$ go run my/main.go my/xxx.go

このときxxx.goはソースコードとして扱われてbuild時のpackageに含まれる。

ところで、go/astなどのコードを試しているときには、.goのファイルを入力として扱いたいときがある。このような時にどうすれば良いかというメモ。

go runに.goを渡したときの挙動

go runに.goを渡したときは以下の様になる。

# これは my/main.go my/xxx.go を使ってbuildされる
$ go run my/main.go my/xxx.go
[/tmp/go-build476556577/b001/exe/main]

# これは `--` がそのまま引数として解釈される
$ go run my/main.go -- my/xxx.go
[/tmp/go-build852746362/b001/exe/main -- my/xxx.go]

unixのコマンドの幾つかでは -- を区切りにするものがあるが、go runはそんなことはない。

go runの引数にはpackageを渡せる

とりあえずヘルプを見る。

$ go help run
usage: go run [build flags] [-exec xprog] package [arguments...]

Run compiles and runs the named main Go package.
Typically the package is specified as a list of .go source files,
but it may also be an import path, file system path, or pattern
matching a single known package, as in 'go run .' or 'go run my/cmd'.

By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
If the -exec flag is given, 'go run' invokes the binary using xprog:
    'xprog a.out arguments...'.
If the -exec flag is not given, GOOS or GOARCH is different from the system
default, and a program named go_$GOOS_$GOARCH_exec can be found
on the current search path, 'go run' invokes the binary using that program,
for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
cross-compiled programs when a simulator or other execution method is
available.

The exit status of Run is not the exit status of the compiled binary.

For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.

See also: go build.

注目する部分はこの部分。

Typically the package is specified as a list of .go source files, but it may also be an import path, file system path, or pattern matching a single known package, as in 'go run .' or 'go run my/cmd'.

実は.goではなくpackageを指定してよかった。

以下の様にも書ける。ただしこれはエラー。

$ go run my my/xxx.go
package my: cannot find package "my" in any of:
    /usr/lib/go/src/my (from $GOROOT)
    $GOPATH/src/my (from $GOPATH)

GOPATHに含まれていないものであれば、相対パスとして認識できるように./myと書く必要がある。my./myは別物。

$ go run ./my my/xxx.go
[/tmp/go-build222364313/b001/exe/main my/xxx.go]

これが期待通りに動作。

この時に使ったコード

my/main.go

package main

import (
    "fmt"
    "log"
    "os"
)

func main() {
    if err := run(); err != nil {
        log.Fatalf("%+v", err)
    }
}

func run() error {
    fmt.Println(os.Args)
    return nil
}

my/xxx.go

package main

const xxx = 1