From 5a9a0eda6aae850b9d75ed513f6c51a1bb962b38 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 25 May 2014 15:36:50 -0400 Subject: Moved windowsconstgen.go out of the experiments/ folder and into a new tools/ folder. --- experiments/windowsconstgen.go | 197 ----------------------------------------- tools/windowsconstgen.go | 197 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+), 197 deletions(-) delete mode 100644 experiments/windowsconstgen.go create mode 100644 tools/windowsconstgen.go diff --git a/experiments/windowsconstgen.go b/experiments/windowsconstgen.go deleted file mode 100644 index 448b549..0000000 --- a/experiments/windowsconstgen.go +++ /dev/null @@ -1,197 +0,0 @@ -// 24 may 2014 -package main - -import ( - "fmt" - "os" - "strings" - "go/token" - "go/ast" - "go/parser" - "sort" - "io/ioutil" - "path/filepath" - "os/exec" -) - -func getPackage(path string) (pkg *ast.Package) { - fileset := token.NewFileSet() // parser.ParseDir() actually writes to this; not sure why it doesn't return one instead - filter := func(i os.FileInfo) bool { - return strings.HasSuffix(i.Name(), "_windows.go") - } - pkgs, err := parser.ParseDir(fileset, path, filter, parser.AllErrors) - if err != nil { - panic(err) - } - if len(pkgs) != 1 { - panic("more than one package found") - } - for k, _ := range pkgs { // get the sole key - pkg = pkgs[k] - } - return pkg -} - -type walker struct { - desired func(string) bool -} - -var known = map[string]string{} -var unknown = map[string]struct{}{} - -func (w *walker) Visit(node ast.Node) ast.Visitor { - if n, ok := node.(*ast.Ident); ok { - if w.desired(n.Name) { - if n.Obj != nil { - delete(unknown, n.Name) - kind := n.Obj.Kind.String() - if known[n.Name] != "" && known[n.Name] != kind { - panic(n.Name + "(" + kind + ") already known to be a " + known[n.Name]) - } - known[n.Name] = kind - } else if _, ok := known[n.Name]; !ok { // only if not known - unknown[n.Name] = struct{}{} - } - } - } - return w -} - -func gatherNames(pkg *ast.Package) { - desired := func(name string) bool { - if strings.HasPrefix(name, "_") && len(name) > 1 { - return !strings.ContainsAny(name, - "abcdefghijklmnopqrstuvwxyz") - } - return false - } - for _, f := range pkg.Files { - for _, d := range f.Decls { - ast.Walk(&walker{desired}, d) - } - } -} - -// some constants confuse cgo into thinking they're external symbols for some reason -// fortunately all these constants are pointers -// TODO debug cgo -var hacknames = map[string]string{ - "_INVALID_HANDLE_VALUE": "x_INVALID_HANDLE_VALUE", - "_NULL": "x_NULL", - "_IDI_APPLICATION": "x_IDI_APPLICATION", - "_IDC_ARROW": "x_IDC_ARROW", - "_HWND_MESSAGE": "x_HWND_MESSAGE", -} - -func hacknamesPreamble() string { - if len(hacknames) == 0 { - return "" - } - // keep sorted for git - hn := make([]string, 0, len(hacknames)) - for origname, _ := range hacknames { - hn = append(hn, origname) - } - sort.Strings(hn) - s := "// /* because cgo has issues with these */\n" - s += "// #include \n" - for _, origname := range hn { - s += "// uintptr_t " + hacknames[origname] + " = (uintptr_t) (" + - origname[1:] + ");\n" // strip leading _ - } - return s -} - -func preamble(pkg string) string { - return "// autogenerated by windowsconstgen; do not edit\n" + - "package " + pkg + "\n" -} - -func main() { - if len(os.Args) < 3 { - panic("usage: " + os.Args[0] + " path goarch [go-command-options...]") - } - pkgpath := os.Args[1] - targetarch := os.Args[2] - goopts := os.Args[3:] // valid if len(os.Args) == 3; in that case this will just be a slice of length zero - - pkg := getPackage(pkgpath) - gatherNames(pkg) - - // if we still have some known, I didn't clean things up completely - knowns := "" - for ident, kind := range known { - if kind != "var" && kind != "const" { - continue - } - knowns += "\n" + ident + " (" + kind + ")" - } - if knowns != "" { - panic("error: the following are still known!" + knowns) // has a newline already - } - - // keep sorted for git - consts := make([]string, 0, len(unknown)) - for ident, _ := range unknown { - if hackname, ok := hacknames[ident]; ok { - consts = append(consts, hackname) - continue - } - consts = append(consts, ident) - } - sort.Strings(consts) - - // thanks to james4k in irc.freenode.net/#go-nuts - tmpdir, err := ioutil.TempDir("", "windowsconstgen") - if err != nil { - panic(err) - } - genoutname := filepath.Join(tmpdir, "gen.go") - f, err := os.Create(genoutname) - if err != nil { - panic(err) - } - fmt.Fprintf(f, "%s" + - "import \"fmt\"\n" + - "// #include \n" + - "// #include \n" + - "%s" + - "import \"C\"\n" + - "func main() {\n" + - " fmt.Print(%q)\n", - preamble("main"), hacknamesPreamble(), preamble("ui")) - for _, ident := range consts { - if ident[0] == 'x' { - // hack name; strip the leading x (but not the _ after it) from the constant name but keep the value name unchanged - fmt.Fprintf(f, " fmt.Println(\"const %s =\", C.%s)\n", ident[1:], ident) - continue - } - // not a hack name; strip the leading _ from the value name but keep the constant name unchanged - fmt.Fprintf(f, " fmt.Println(\"const %s =\", C.%s)\n", ident, ident[1:]) - } - fmt.Fprintf(f, "}\n") - f.Close() - - cmd := exec.Command("go", "run") - cmd.Args = append(cmd.Args, goopts...) // valid if len(goopts) == 0; in that case this will just be a no-op - cmd.Args = append(cmd.Args, genoutname) - f, err = os.Create(filepath.Join(pkgpath, "zconstants_windows_" + targetarch + ".go")) - if err != nil { - panic(err) - } - defer f.Close() - cmd.Stdout = f - cmd.Stderr = os.Stderr - cmd.Env = append(cmd.Env, os.Environ()...) // otherwise $PATH doesn't get carried over and things mysteriously fail - cmd.Env = append(cmd.Env, - "GOOS=windows", - "GOARCH=" + targetarch, - "CGO_ENABLED=1") // needed as it's not set by default in cross-compiles - err = cmd.Run() - if err != nil { - // TODO find a way to get the exit code - os.Exit(1) - } - - // TODO remove the temporary directory -} diff --git a/tools/windowsconstgen.go b/tools/windowsconstgen.go new file mode 100644 index 0000000..448b549 --- /dev/null +++ b/tools/windowsconstgen.go @@ -0,0 +1,197 @@ +// 24 may 2014 +package main + +import ( + "fmt" + "os" + "strings" + "go/token" + "go/ast" + "go/parser" + "sort" + "io/ioutil" + "path/filepath" + "os/exec" +) + +func getPackage(path string) (pkg *ast.Package) { + fileset := token.NewFileSet() // parser.ParseDir() actually writes to this; not sure why it doesn't return one instead + filter := func(i os.FileInfo) bool { + return strings.HasSuffix(i.Name(), "_windows.go") + } + pkgs, err := parser.ParseDir(fileset, path, filter, parser.AllErrors) + if err != nil { + panic(err) + } + if len(pkgs) != 1 { + panic("more than one package found") + } + for k, _ := range pkgs { // get the sole key + pkg = pkgs[k] + } + return pkg +} + +type walker struct { + desired func(string) bool +} + +var known = map[string]string{} +var unknown = map[string]struct{}{} + +func (w *walker) Visit(node ast.Node) ast.Visitor { + if n, ok := node.(*ast.Ident); ok { + if w.desired(n.Name) { + if n.Obj != nil { + delete(unknown, n.Name) + kind := n.Obj.Kind.String() + if known[n.Name] != "" && known[n.Name] != kind { + panic(n.Name + "(" + kind + ") already known to be a " + known[n.Name]) + } + known[n.Name] = kind + } else if _, ok := known[n.Name]; !ok { // only if not known + unknown[n.Name] = struct{}{} + } + } + } + return w +} + +func gatherNames(pkg *ast.Package) { + desired := func(name string) bool { + if strings.HasPrefix(name, "_") && len(name) > 1 { + return !strings.ContainsAny(name, + "abcdefghijklmnopqrstuvwxyz") + } + return false + } + for _, f := range pkg.Files { + for _, d := range f.Decls { + ast.Walk(&walker{desired}, d) + } + } +} + +// some constants confuse cgo into thinking they're external symbols for some reason +// fortunately all these constants are pointers +// TODO debug cgo +var hacknames = map[string]string{ + "_INVALID_HANDLE_VALUE": "x_INVALID_HANDLE_VALUE", + "_NULL": "x_NULL", + "_IDI_APPLICATION": "x_IDI_APPLICATION", + "_IDC_ARROW": "x_IDC_ARROW", + "_HWND_MESSAGE": "x_HWND_MESSAGE", +} + +func hacknamesPreamble() string { + if len(hacknames) == 0 { + return "" + } + // keep sorted for git + hn := make([]string, 0, len(hacknames)) + for origname, _ := range hacknames { + hn = append(hn, origname) + } + sort.Strings(hn) + s := "// /* because cgo has issues with these */\n" + s += "// #include \n" + for _, origname := range hn { + s += "// uintptr_t " + hacknames[origname] + " = (uintptr_t) (" + + origname[1:] + ");\n" // strip leading _ + } + return s +} + +func preamble(pkg string) string { + return "// autogenerated by windowsconstgen; do not edit\n" + + "package " + pkg + "\n" +} + +func main() { + if len(os.Args) < 3 { + panic("usage: " + os.Args[0] + " path goarch [go-command-options...]") + } + pkgpath := os.Args[1] + targetarch := os.Args[2] + goopts := os.Args[3:] // valid if len(os.Args) == 3; in that case this will just be a slice of length zero + + pkg := getPackage(pkgpath) + gatherNames(pkg) + + // if we still have some known, I didn't clean things up completely + knowns := "" + for ident, kind := range known { + if kind != "var" && kind != "const" { + continue + } + knowns += "\n" + ident + " (" + kind + ")" + } + if knowns != "" { + panic("error: the following are still known!" + knowns) // has a newline already + } + + // keep sorted for git + consts := make([]string, 0, len(unknown)) + for ident, _ := range unknown { + if hackname, ok := hacknames[ident]; ok { + consts = append(consts, hackname) + continue + } + consts = append(consts, ident) + } + sort.Strings(consts) + + // thanks to james4k in irc.freenode.net/#go-nuts + tmpdir, err := ioutil.TempDir("", "windowsconstgen") + if err != nil { + panic(err) + } + genoutname := filepath.Join(tmpdir, "gen.go") + f, err := os.Create(genoutname) + if err != nil { + panic(err) + } + fmt.Fprintf(f, "%s" + + "import \"fmt\"\n" + + "// #include \n" + + "// #include \n" + + "%s" + + "import \"C\"\n" + + "func main() {\n" + + " fmt.Print(%q)\n", + preamble("main"), hacknamesPreamble(), preamble("ui")) + for _, ident := range consts { + if ident[0] == 'x' { + // hack name; strip the leading x (but not the _ after it) from the constant name but keep the value name unchanged + fmt.Fprintf(f, " fmt.Println(\"const %s =\", C.%s)\n", ident[1:], ident) + continue + } + // not a hack name; strip the leading _ from the value name but keep the constant name unchanged + fmt.Fprintf(f, " fmt.Println(\"const %s =\", C.%s)\n", ident, ident[1:]) + } + fmt.Fprintf(f, "}\n") + f.Close() + + cmd := exec.Command("go", "run") + cmd.Args = append(cmd.Args, goopts...) // valid if len(goopts) == 0; in that case this will just be a no-op + cmd.Args = append(cmd.Args, genoutname) + f, err = os.Create(filepath.Join(pkgpath, "zconstants_windows_" + targetarch + ".go")) + if err != nil { + panic(err) + } + defer f.Close() + cmd.Stdout = f + cmd.Stderr = os.Stderr + cmd.Env = append(cmd.Env, os.Environ()...) // otherwise $PATH doesn't get carried over and things mysteriously fail + cmd.Env = append(cmd.Env, + "GOOS=windows", + "GOARCH=" + targetarch, + "CGO_ENABLED=1") // needed as it's not set by default in cross-compiles + err = cmd.Run() + if err != nil { + // TODO find a way to get the exit code + os.Exit(1) + } + + // TODO remove the temporary directory +} -- cgit v1.2.3