func TestLLVMIRReadCloser(t *testing.T) { const input = `;abc\n;def\n;xyz` var buf bytes.Buffer buf.WriteString(input) r := build.NewLLVMIRReader(ioutil.NopCloser(&buf)) b, err := ioutil.ReadAll(iotest.OneByteReader(r)) if err != nil { t.Errorf("unexpected error: %s", err) } str := string(b) expected := strings.Replace(str, ";", "//", -1) if str != expected { t.Errorf("%q != %q", str, expected) } }
func getPackage(pkgpath string) (pkg *build.Package, err error) { // These packages are special: they're mostly written from // scratch, so we don't both with the overlay. if pkgpath == "runtime" || pkgpath == "runtime/cgo" { defer func(pkgpath string) { pkg.ImportPath = pkgpath }(pkgpath) pkgpath = llgoPkgPrefix + pkgpath } // Make a copy, as we'll be modifying ReadDir/OpenFile. buildctx := *buildctx // Attempt to find an overlay package path, // which we'll use in ReadDir below. overlayentries := make(map[string]bool) overlaypkgpath := llgoPkgPrefix + pkgpath overlaypkg, err := buildctx.Import(overlaypkgpath, "", build.FindOnly) if err != nil { overlaypkg = nil } // ReadDir is overridden to return a fake ".s" // file for each ".ll" file in the directory. buildctx.ReadDir = func(dir string) (fi []os.FileInfo, err error) { fi, err = ioutil.ReadDir(dir) if err != nil { return nil, err } entries := make(map[string]os.FileInfo) for _, info := range fi { entries[info.Name()] = info } // Overlay all files in the overlay package dir. // If we find any .ll files, replace the suffix // with .s. if overlaypkg != nil { fi, err = ioutil.ReadDir(overlaypkg.Dir) } if err == nil { // Check for .ll files in the overlay dir if // we have one, else in the standard package dir. for _, info := range fi { name := info.Name() if strings.HasSuffix(name, ".ll") { name = name[:len(name)-3] + ".s" info = &renamedFileInfo{info, name} } overlayentries[name] = true entries[name] = info } } fi = make([]os.FileInfo, 0, len(entries)) for _, info := range entries { fi = append(fi, info) } return fi, nil } // OpenFile is overridden to return the contents // of the ".ll" file found in ReadDir above. The // returned ReadCloser is wrapped to transform // LLVM IR comments to use "//", as expected by // go/build when looking for build tags. buildctx.OpenFile = func(path string) (io.ReadCloser, error) { base := filepath.Base(path) overlay := overlayentries[base] if overlay { if overlaypkg != nil { path = filepath.Join(overlaypkg.Dir, base) } if strings.HasSuffix(path, ".s") { path := path[:len(path)-2] + ".ll" var r io.ReadCloser var err error r, err = os.Open(path) if err == nil { r = llgobuild.NewLLVMIRReader(r) } return r, err } } return os.Open(path) } pkg, err = buildctx.Import(pkgpath, "", 0) if err != nil { return nil, err } else { if overlaypkg == nil { overlaypkg = pkg } // TODO(axw) factor out the repeated code for i, filename := range pkg.GoFiles { pkgdir := pkg.Dir if overlayentries[filename] { pkgdir = overlaypkg.Dir } pkg.GoFiles[i] = path.Join(pkgdir, filename) } for i, filename := range pkg.CgoFiles { pkgdir := pkg.Dir if overlayentries[filename] { pkgdir = overlaypkg.Dir } pkg.CgoFiles[i] = path.Join(pkgdir, filename) } for i, filename := range pkg.TestGoFiles { pkgdir := pkg.Dir if overlayentries[filename] { pkgdir = overlaypkg.Dir } pkg.TestGoFiles[i] = path.Join(pkgdir, filename) } for i, filename := range pkg.XTestGoFiles { pkgdir := pkg.Dir if overlayentries[filename] { pkgdir = overlaypkg.Dir } pkg.XTestGoFiles[i] = path.Join(pkgdir, filename) } for i, filename := range pkg.CFiles { pkgdir := pkg.Dir if overlayentries[filename] { pkgdir = overlaypkg.Dir } pkg.CFiles[i] = path.Join(pkgdir, filename) } for i, filename := range pkg.SFiles { pkgdir := pkg.Dir if strings.HasSuffix(filename, ".S") { // .S files go straight to clang } else if overlayentries[filename] { pkgdir = overlaypkg.Dir filename = filename[:len(filename)-2] + ".ll" } else { err := fmt.Errorf("No matching .ll file for %q", filename) return nil, err } pkg.SFiles[i] = path.Join(pkgdir, filename) } } return pkg, nil }