Example #1
0
File: main.go Project: rvedam/llgo
func main() {
	flag.Parse()

	if triple == "" {
		log.Fatal("No default triple set")
	}

	if clang == "" {
		clang = "clang"
	}

	llgobuildctx, err := llgobuild.ContextFromTriple(triple)
	if err != nil {
		log.Fatal(err)
	}
	buildctx = &llgobuildctx.Context

	// pkgroot = $GOPATH/pkg/llgo/<triple>
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		gopath = runtime.GOROOT()
	} else {
		gopath = filepath.SplitList(gopath)[0]
	}
	pkgroot = filepath.Join(gopath, "pkg", "llgo", triple)

	// Create a temporary work dir.
	workdir, err = ioutil.TempDir("", "llgo")
	if err != nil {
		log.Fatal(err)
	}
	if work {
		log.Println("Working directory:", workdir)
	}
	args := flag.Args()
	if test {
		if len(args) > 1 {
			err = fmt.Errorf("Multiple files/packages can not be specified when building a test binary")
		} else {
			err = buildPackageTests(args[0])
		}
	} else {
		err = buildPackages(args)
	}
	if !work {
		os.RemoveAll(workdir)
	}
	if err != nil {
		log.Fatal(err)
	}
}
Example #2
0
func buildLlgo() error {
	log.Println("Building llgo")

	cmd := command("go", "get", "-d", llvmpkgpath)
	output, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", string(output))
		return err
	}
	pkg, err := gobuild.Import(llvmpkgpath, "", gobuild.FindOnly)
	if err != nil {
		return err
	}
	if alwaysbuild {
		if _, err := os.Stat(pkg.PkgObj); err == nil {
			log.Println("- Rebuilding go-llvm/llvm")
			os.Remove(pkg.PkgObj)
		}
	}

	cgoCflags := fmt.Sprintf("%s -I %s/../include", llvmcflags, pkg.Dir)
	cgoLdflags := fmt.Sprintf("-Wl,-L%s", llvmlibdir)
	ldflags := fmt.Sprintf("-r %q", llvmlibdir)

	if sharedllvm {
		cgoLdflags += fmt.Sprintf(" -lLLVM-%s ", llvmversion)
	} else {
		cgoLdflags += " " + llvmlibs + " -lstdc++ -lm "
	}
	cgoLdflags += " " + llvmldflags

	args := []string{"get", "-ldflags", ldflags}
	llvmtag := "llvm" + llvmversion
	if strings.HasSuffix(llvmversion, "svn") {
		llvmtag = "llvmsvn"
	}
	args = append(args, []string{"-tags", llvmtag}...)
	args = append(args, llgopkgpath)

	cmd = command("go", args...)
	cmd.Env = os.Environ()
	cmd.Env = append(cmd.Env, "CGO_CFLAGS="+cgoCflags)
	cmd.Env = append(cmd.Env, "CGO_LDFLAGS="+cgoLdflags)
	output, err = cmd.CombinedOutput()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", string(output))
		return err
	}

	if llgobin, err = findCommand(llgopkgpath); err != nil {
		return err
	}

	// If the user did not specify -triple on the command
	// line, ask llgo for it now.
	if triple == "" {
		output, err = command(llgobin, "-print-triple").CombinedOutput()
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", string(output))
			return err
		}
		triple = strings.TrimSpace(string(output))
	}
	llgobuildctx, err := build.ContextFromTriple(triple)
	if err != nil {
		return err
	}
	buildctx = &llgobuildctx.Context
	log.Printf("GOARCH = %s, GOOS = %s", buildctx.GOARCH, buildctx.GOOS)
	log.Printf("Built %s", llgobin)
	if install_name_tool && sharedllvm {
		// TODO: this was with the LLVM shipped with the pnacl sdk and might not be true of *all* libLLVM-xxx.dylibs.
		//       Is there a link time commandline option that has the same effect?
		cmd = command("install_name_tool", "-change", fmt.Sprintf("@executable_path/../lib/libLLVM-%s.dylib", llvmversion), fmt.Sprintf("%s/libLLVM-%s.dylib", llvmlibdir, llvmversion), llgobin)
		output, err = cmd.CombinedOutput()
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", string(output))
			return err
		}
		log.Printf("Successfully changed shared libLLVM path")
	}
	return nil
}
Example #3
0
func (compiler *compiler) compile(filenames []string, importpath string) (m *Module, err error) {
	buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple)
	if err != nil {
		return nil, err
	}

	initmap := make(map[*types.Package]gccgoimporter.InitData)
	var importer types.Importer
	if compiler.GccgoPath == "" {
		paths := append(append([]string{}, compiler.ImportPaths...), ".")
		importer = gccgoimporter.GetImporter(paths, initmap)
	} else {
		var inst gccgoimporter.GccgoInstallation
		err = inst.InitFromDriver(compiler.GccgoPath)
		if err != nil {
			return nil, err
		}
		importer = inst.GetImporter(compiler.ImportPaths, initmap)
	}

	impcfg := &loader.Config{
		Fset: token.NewFileSet(),
		TypeChecker: types.Config{
			Import: importer,
			Sizes:  compiler.llvmtypes,
		},
		Build: &buildctx.Context,
	}
	// Must use parseFiles, so we retain comments;
	// this is important for annotation processing.
	astFiles, err := parseFiles(impcfg.Fset, filenames)
	if err != nil {
		return nil, err
	}
	// If no import path is specified, then set the import
	// path to be the same as the package's name.
	if importpath == "" {
		importpath = astFiles[0].Name.String()
	}
	impcfg.CreateFromFiles(importpath, astFiles...)
	iprog, err := impcfg.Load()
	if err != nil {
		return nil, err
	}
	program := ssa.Create(iprog, ssa.BareInits)
	mainPkginfo := iprog.InitialPackages()[0]
	mainPkg := program.CreatePackage(mainPkginfo)

	// Create a Module, which contains the LLVM module.
	modulename := importpath
	compiler.module = &Module{Module: llvm.NewModule(modulename), Path: modulename}
	compiler.module.SetTarget(compiler.TargetTriple)
	compiler.module.SetDataLayout(compiler.dataLayout)

	// Create a new translation unit.
	unit := newUnit(compiler, mainPkg)

	// Create the runtime interface.
	compiler.runtime, err = newRuntimeInterface(compiler.module.Module, compiler.llvmtypes)
	if err != nil {
		return nil, err
	}

	mainPkg.Build()

	// Create a struct responsible for mapping static types to LLVM types,
	// and to runtime/dynamic type values.
	compiler.types = NewTypeMap(
		mainPkg,
		compiler.llvmtypes,
		compiler.module.Module,
		compiler.runtime,
		MethodResolver(unit),
	)

	if compiler.GenerateDebug {
		compiler.debug = debug.NewDIBuilder(
			types.Sizes(compiler.llvmtypes),
			compiler.module.Module,
			impcfg.Fset,
			compiler.DebugPrefixMaps,
		)
		defer compiler.debug.Destroy()
		defer compiler.debug.Finalize()
	}

	unit.translatePackage(mainPkg)
	compiler.processAnnotations(unit, mainPkginfo)

	if importpath == "main" {
		if err = compiler.createInitMainFunction(mainPkg, initmap); err != nil {
			return nil, fmt.Errorf("failed to create __go_init_main: %v", err)
		}
	} else {
		compiler.module.ExportData = compiler.buildExportData(mainPkg, initmap)
	}

	return compiler.module, nil
}
Example #4
0
func (compiler *compiler) compile(filenames []string, importpath string) (m *Module, err error) {
	buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple)
	if err != nil {
		return nil, err
	}
	impcfg := &loader.Config{
		Fset: token.NewFileSet(),
		TypeChecker: types.Config{
			Import: llgoimporter.NewImporter(buildctx).Import,
			Sizes:  compiler.llvmtypes,
		},
		Build: &buildctx.Context,
	}
	// Must use parseFiles, so we retain comments;
	// this is important for annotation processing.
	astFiles, err := parseFiles(impcfg.Fset, filenames)
	if err != nil {
		return nil, err
	}
	// If no import path is specified, or the package's
	// name (not path) is "main", then set the import
	// path to be the same as the package's name.
	if pkgname := astFiles[0].Name.String(); importpath == "" || pkgname == "main" {
		importpath = pkgname
	}
	impcfg.CreateFromFiles(importpath, astFiles...)
	// Create a "runtime" package too, so we can reference
	// its types and functions in the compiler and generated
	// code.
	if importpath != "runtime" {
		astFiles, err := parseRuntime(&buildctx.Context, impcfg.Fset)
		if err != nil {
			return nil, err
		}
		impcfg.CreateFromFiles("runtime", astFiles...)
	}
	iprog, err := impcfg.Load()
	if err != nil {
		return nil, err
	}
	program := ssa.Create(iprog, 0)
	var mainPkginfo, runtimePkginfo *loader.PackageInfo
	if pkgs := iprog.InitialPackages(); len(pkgs) == 1 {
		mainPkginfo, runtimePkginfo = pkgs[0], pkgs[0]
	} else {
		mainPkginfo, runtimePkginfo = pkgs[0], pkgs[1]
	}
	mainPkg := program.CreatePackage(mainPkginfo)

	// Create a Module, which contains the LLVM bitcode.
	modulename := importpath
	compiler.module = &Module{Module: llvm.NewModule(modulename), Name: modulename}
	compiler.module.SetTarget(compiler.TargetTriple)
	compiler.module.SetDataLayout(compiler.dataLayout)

	// Create a new translation unit.
	unit := newUnit(compiler, mainPkg)

	// Create the runtime interface.
	compiler.runtime, err = newRuntimeInterface(
		runtimePkginfo.Pkg,
		compiler.module.Module,
		compiler.llvmtypes,
		FuncResolver(unit),
	)
	if err != nil {
		return nil, err
	}

	// Create a struct responsible for mapping static types to LLVM types,
	// and to runtime/dynamic type values.
	compiler.types = NewTypeMap(
		importpath,
		compiler.llvmtypes,
		compiler.module.Module,
		compiler.runtime,
		MethodResolver(unit),
	)

	// Create a Builder, for building LLVM instructions.
	compiler.builder = llvm.GlobalContext().NewBuilder()
	defer compiler.builder.Dispose()

	// Initialise debugging.
	compiler.debug.module = compiler.module.Module
	compiler.debug.Fset = impcfg.Fset
	compiler.debug.Sizes = compiler.llvmtypes

	mainPkg.Build()
	unit.translatePackage(mainPkg)
	compiler.processAnnotations(unit, mainPkginfo)
	if runtimePkginfo != mainPkginfo {
		compiler.processAnnotations(unit, runtimePkginfo)
	}

	// Finalise debugging.
	for _, cu := range compiler.debug.cu {
		compiler.module.AddNamedMetadataOperand(
			"llvm.dbg.cu",
			compiler.debug.MDNode(cu),
		)
	}

	// Export runtime type information.
	var exportedTypes []types.Type
	for _, m := range mainPkg.Members {
		if t, ok := m.(*ssa.Type); ok && ast.IsExported(t.Name()) {
			exportedTypes = append(exportedTypes, t.Type())
		}
	}
	compiler.exportRuntimeTypes(exportedTypes, importpath == "runtime")

	if importpath == "main" {
		// Wrap "main.main" in a call to runtime.main.
		if err = compiler.createMainFunction(); err != nil {
			return nil, fmt.Errorf("failed to create main.main: %v", err)
		}
	} else {
		if err := llgoimporter.Export(buildctx, mainPkg.Object); err != nil {
			return nil, fmt.Errorf("failed to export package data: %v", err)
		}
	}

	return compiler.module, nil
}