Skip to content

Commit

Permalink
cmd/llgo-build: record and use CGO_LDFLAGS
Browse files Browse the repository at this point in the history
We now write out <package>.ldflags for each
cgo-using package built with llgo-build. When
building a command, llgo-build will check to
see if there is an .ldflags file and add the
flags within to the final link flags.

With these changes, it is now possible to
build llgo with llgo: the actual resulting
binary does not work correctly, though.
  • Loading branch information
axw committed Mar 9, 2014
1 parent 6107485 commit 6b911ce
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 12 deletions.
23 changes: 19 additions & 4 deletions cmd/llgo-build/build.go
Expand Up @@ -255,7 +255,6 @@ func runCgo(pkgpath string, cgofiles, cppflags, cflags []string) (gofiles, cfile
return nil, nil, fmt.Errorf("failed to translate gccgo extern comments for %q: %v", gofile, err)
}
}

return gofiles, cfiles, nil
}

Expand All @@ -280,14 +279,24 @@ func buildPackage(pkg *build.Package, output string) error {
args = append(args, "-importpath", pkg.ImportPath)
}

var cgoCFLAGS, cgoCPPFLAGS []string
var cgoCFLAGS, cgoCPPFLAGS, cgoLDFLAGS []string
if len(pkg.CFiles) > 0 || len(pkg.CgoFiles) > 0 {
// TODO(axw) process pkg-config
cgoCFLAGS = append(envFields("CGO_CFLAGS"), pkg.CgoCFLAGS...)
cgoCPPFLAGS = append(envFields("CGO_CPPFLAGS"), pkg.CgoCPPFLAGS...)
//cgoCXXFLAGS = append(envFields("CGO_CXXFLAGS"), pkg.CgoCXXFLAGS...)
//cgoLDFLAGS = append(envFields("CGO_LDFLAGS"), pkg.CgoLDFLAGS...)
// TODO(axw) process pkg-config
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", workdir, "-I", pkg.Dir)
cgoLDFLAGS = append(envFields("CGO_LDFLAGS"), pkg.CgoLDFLAGS...)
// Get the library dir in which to find libgcc, libstdc++, etc.
// We need to do this because we rely on clang to link; in Ubuntu 14.04
// beta 1, there is no g++-4.9, but there is gccgo-4.9. Clang sees the
// partial 4.9 lib directory and uses it instead of 4.8, which is what
// should be used.
if gcclib, err := findGcclib(); err != nil {
return fmt.Errorf("failed to locate gcc lib dir: %v", err)
} else if gcclib != "." {
cgoLDFLAGS = append(cgoLDFLAGS, "-L", gcclib)
}
}
var gofiles, cfiles []string
if len(pkg.CgoFiles) > 0 {
Expand Down Expand Up @@ -382,6 +391,12 @@ func buildPackage(pkg *build.Package, output string) error {
if err := linktest(pkg, tempfile); err != nil {
return err
}
} else {
if output != "-" && len(cgoLDFLAGS) > 0 {
if err := writeLdflags(pkg.ImportPath, cgoLDFLAGS); err != nil {
return err
}
}
}
return moveFile(tempfile, output)
}
44 changes: 36 additions & 8 deletions cmd/llgo-build/link.go
Expand Up @@ -6,6 +6,7 @@ package main

import (
"go/build"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
Expand All @@ -23,10 +24,13 @@ func linkdeps(pkg *build.Package, output string) error {
pkg.Imports = append(pkg.Imports, "syscall")
}

var mkdeps func(pkg *build.Package, imports []string) error
mkdeps = func(pkg *build.Package, imports []string) error {
var mkdeps func(imports ...string) error
mkdeps = func(imports ...string) error {
for _, path := range imports {
if path == "C" {
if err := mkdeps("runtime/cgo", "syscall"); err != nil {
return err
}
continue
}
if !deps[path] {
Expand All @@ -35,7 +39,7 @@ func linkdeps(pkg *build.Package, output string) error {
if err != nil {
return err
}
if err = mkdeps(pkg, pkg.Imports); err != nil {
if err = mkdeps(pkg.Imports...); err != nil {
return err
}
depslist = append(depslist, path)
Expand All @@ -44,15 +48,15 @@ func linkdeps(pkg *build.Package, output string) error {
return nil
}

err := mkdeps(pkg, pkg.Imports)
err := mkdeps(pkg.Imports...)
if err != nil {
return err
}
if test {
if err = mkdeps(pkg, pkg.TestImports); err != nil {
if err = mkdeps(pkg.TestImports...); err != nil {
return err
}
if err = mkdeps(pkg, pkg.XTestImports); err != nil {
if err = mkdeps(pkg.XTestImports...); err != nil {
return err
}
}
Expand All @@ -64,6 +68,7 @@ func linkdeps(pkg *build.Package, output string) error {

llvmlink := filepath.Join(llvmbindir, "llvm-link")
args := []string{"-o", output, output}
var ldflags []string
for _, path := range depslist {
if path == pkg.ImportPath {
continue
Expand All @@ -77,6 +82,11 @@ func linkdeps(pkg *build.Package, output string) error {
}
}
args = append(args, bcfile)
if pkgldflags, err := readLdflags(path); err != nil {
return err
} else {
ldflags = append(ldflags, pkgldflags...)
}
}
cmd := exec.Command(llvmlink, args...)
cmd.Stdout = os.Stdout
Expand All @@ -101,11 +111,12 @@ func linkdeps(pkg *build.Package, output string) error {
}
}

args := []string{"-pthread", "-g", "-o", output, input}
args := []string{"-pthread", "-v", "-g", "-o", output, input}
if triple == "pnacl" {
args = append(args, "-l", "ppapi")
}
cmd := exec.Command(clang, args...)
args = append(args, ldflags...)
cmd := exec.Command(clang+"++", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err = runCmd(cmd); err != nil {
Expand All @@ -115,3 +126,20 @@ func linkdeps(pkg *build.Package, output string) error {

return nil
}

// writeLdflags writes CGO_LDFLAGS flags to a file, one argument per line.
func writeLdflags(pkgpath string, flags []string) error {
file := filepath.Join(pkgroot, pkgpath+".ldflags")
return ioutil.WriteFile(file, []byte(strings.Join(flags, "\n")), 0644)
}

// readLdflags reads CGO_LDFLAGS written to a file by writeLdflags.
func readLdflags(pkgpath string) ([]string, error) {
data, err := ioutil.ReadFile(filepath.Join(pkgroot, pkgpath+".ldflags"))
if err == nil {
return strings.Split(string(data), "\n"), nil
} else if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
19 changes: 19 additions & 0 deletions cmd/llgo-build/utils.go
Expand Up @@ -9,12 +9,14 @@
package main

import (
"bytes"
"fmt"
"go/build"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
Expand Down Expand Up @@ -129,6 +131,23 @@ func translateGccgoExterns(filename string) error {
return ioutil.WriteFile(filename, data, 0644)
}

// find the library directory for the version
// of gcc found in $PATH.
func findGcclib() (string, error) {
// TODO(axw) allow the use of $CC in place of cc. If we do this,
// we'll need to work around partial installations of gcc, e.g.
// ones without g++ (thus lacking libstdc++).
var buf bytes.Buffer
cmd := exec.Command("gcc", "--print-libgcc-file-name")
cmd.Stderr = os.Stderr
cmd.Stdout = &buf
if err := runCmd(cmd); err != nil {
return "", err
}
libfile := buf.String()
return filepath.Dir(libfile), nil
}

// envFields gets the environment variable with the
// specified name and splits it into fields separated
// by whitespace.
Expand Down

0 comments on commit 6b911ce

Please sign in to comment.