Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
16
Help us understand the problem. What is going on with this article?
@astronoka

packageに複数のinitがあるときの挙動

More than 5 years have passed since last update.

http://golang.org/doc/effective_go.html#init
ふと、呼び出される順番が気になったので調べてみました
versionは1.4(.2)

initが呼ばれるときのコードを眺める

で init 的な文字列を探すと
関数宣言でなんか分岐しているところが

src/cmd/gc/go.y#L1325
fndcl:
  sym '(' oarg_type_list_ocomma ')' fnres
  {
    Node *t;

    $$ = N;
    $3 = checkarglist($3, 1);

    if(strcmp($1->name, "init") == 0) {
      $1 = renameinit();
      if($3 != nil || $5 != nil)
        yyerror("func init must have no arguments and no return values");
    }
    if(strcmp(localpkg->name, "main") == 0 && strcmp($1->name, "main") == 0) {
      if($3 != nil || $5 != nil)
        yyerror("func main must have no arguments and no return values");
    }

    t = nod(OTFUNC, N, N);

renameinit ?
grepすると

src/cmd/gc/init.c
/*
 * a function named init is a special case.
 * it is called by the initialization before
 * main is run. to make it unique within a
 * package and also uncallable, the name,
 * normally "pkg.init", is altered to "pkg.init·1".
 */
Sym*
renameinit(void)
{
    static int initgen;

    snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
    return lookup(namebuf);
}

middle dotと連番をsuffixとしてつけたシンボルを探してる(作っている)
middle dotつけるから、普段書いているコードから呼ばれちゃう心配がないのか

そして、すぐ下の方には、実際に呼ばれるinit関数を組み立てているコードがあって
そこでinit·<n>をコールしているみたい

src/cmd/gc/init.c
/*
 * hand-craft the following initialization code
 *  var initdone· uint8                (1)
 *  func init()                 (2)
 *      if initdone· != 0 {            (3)
 *          if initdone· == 2      (4)
 *              return
 *          throw();            (5)
 *      }
 *      initdone· = 1;             (6)
 *      // over all matching imported symbols
 *          <pkg>.init()            (7)
 *      { <init stmts> }            (8)
 *      init·<n>() // if any           (9)
 *      initdone· = 2;             (10)
 *      return                  (11)
 *  }
 */
static int
anyinit(NodeList *n)
{
...
}

コメントはanyinitの方に付いているけど、実際は更に下のfninitの方でやっている
https://github.com/golang/go/blob/release-branch.go1.4/src/cmd/gc/init.c#L92

なるほろ

package内の複数ファイルにinitがあった場合は?

go build のソースをながめてみると
このへんでcompilerを呼んでいる

src/cmd/go/build.go
    // Prepare Go import path list.
    inc := b.includeArgs("-I", a.deps)

    // Compile Go.
    ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles)
    if len(out) > 0 {
        b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
        if err != nil {
            return errPrintedOutput
        }
    }

このbuildToolchain.gcに渡されているgofilesの出処を探すと

src/go/build/build.go
dirs, err := ctxt.readDir(p.Dir)

でpackage directory内のエントリ列挙
からの
なんやかんやテストがあって

src/go/build/build.go
      p.GoFiles = append(p.GoFiles, name)

されている
そして、ctxt.readDirの実装は↓

src/go/build/build.go
// readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir.
func (ctxt *Context) readDir(path string) ([]os.FileInfo, error) {
  if f := ctxt.ReadDir; f != nil {
    return f(path)
  }
  return ioutil.ReadDir(path)
}

ctxt.ReadDir は、コマンドラインでファイル列挙してビルドする場合と
swigのサポート時のintサイズ確認でつかわれているみたいなので
通常のパッケージビルドはioutil.ReadDirでよさそう

ファイル名のascii順ですね

_人人人人人人人人人人人人_
> じゃないかと思ってた <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

1.5が正式に出たら改めてソースを追ってみようと思いますん

16
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
astronoka
Everything is broken, everything is fine! (IT Archaeologist/FSMism)

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
16
Help us understand the problem. What is going on with this article?