Browse Source

cgo: Add LDFlags support

pull/1126/head
Lucas Teske 5 years ago
committed by Ayke
parent
commit
726d735ad3
  1. 6
      builder/build.go
  2. 20
      cgo/cgo.go
  3. 2
      cgo/cgo_test.go
  4. 7
      cgo/testdata/flags.go
  5. 1
      cgo/testdata/flags.out.go
  6. 16
      compiler/compiler.go
  7. 4
      loader/loader.go
  8. 8
      src/testing/testing.go

6
builder/build.go

@ -32,7 +32,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
if err != nil {
return err
}
mod, extraFiles, errs := compiler.Compile(pkgName, machine, config)
mod, extraFiles, extraLDFlags, errs := compiler.Compile(pkgName, machine, config)
if errs != nil {
return newMultiError(errs)
}
@ -187,6 +187,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
ldflags = append(ldflags, outpath)
}
if len(extraLDFlags) > 0 {
ldflags = append(ldflags, extraLDFlags...)
}
// Link the object files together.
err = link(config.Target.Linker, ldflags...)
if err != nil {

20
cgo/cgo.go

@ -41,6 +41,7 @@ type cgoPackage struct {
elaboratedTypes map[string]*elaboratedTypeInfo
enums map[string]enumInfo
anonStructNum int
ldflags []string
}
// constantInfo stores some information about a CGo constant found by libclang
@ -156,7 +157,7 @@ typedef unsigned long long _Cgo_ulonglong;
// newly created *ast.File that should be added to the list of to-be-parsed
// files. If there is one or more error, it returns these in the []error slice
// but still modifies the AST.
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []error) {
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []string, []error) {
p := &cgoPackage{
dir: dir,
fset: fset,
@ -183,7 +184,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
// Find the absolute path for this package.
packagePath, err := filepath.Abs(fset.File(files[0].Pos()).Name())
if err != nil {
return nil, []error{
return nil, nil, []error{
scanner.Error{
Pos: fset.Position(files[0].Pos()),
Msg: "cgo: cannot find absolute path: " + err.Error(), // TODO: wrap this error
@ -359,6 +360,19 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
}
makePathsAbsolute(flags, packagePath)
cflags = append(cflags, flags...)
case "LDFLAGS":
flags, err := shlex.Split(value)
if err != nil {
// TODO: find the exact location where the error happened.
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+colon+1], "failed to parse flags in #cgo line: "+err.Error())
continue
}
if err := checkLinkerFlags(name, flags); err != nil {
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+colon+1], err.Error())
continue
}
makePathsAbsolute(flags, packagePath)
p.ldflags = append(p.ldflags, flags...)
default:
startPos := strings.LastIndex(line[4:colon], name) + 4
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+startPos], "invalid #cgo line: "+name)
@ -412,7 +426,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
// Print the newly generated in-memory AST, for debugging.
//ast.Print(fset, p.generated)
return p.generated, p.errors
return p.generated, p.ldflags, p.errors
}
// makePathsAbsolute converts some common path compiler flags (-I, -L) from

2
cgo/cgo_test.go

@ -50,7 +50,7 @@ func TestCGo(t *testing.T) {
}
// Process the AST with CGo.
cgoAST, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
cgoAST, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
// Check the AST for type errors.
var typecheckErrors []error

7
cgo/testdata/flags.go

@ -21,6 +21,13 @@ package main
#if defined(NOTDEFINED)
#warning flag must not be defined
#endif
// Check Compiler flags
#cgo LDFLAGS: -lc
// This flag is not valid ldflags
#cgo LDFLAGS: -does-not-exists
*/
import "C"

1
cgo/testdata/flags.out.go

@ -1,6 +1,7 @@
// CGo errors:
// testdata/flags.go:5:7: invalid #cgo line: NOFLAGS
// testdata/flags.go:8:13: invalid flag: -fdoes-not-exist
// testdata/flags.go:29:14: invalid flag: -does-not-exists
package main

16
compiler/compiler.go

@ -103,7 +103,7 @@ func NewTargetMachine(config *compileopts.Config) (llvm.TargetMachine, error) {
// violation. Eventually, this Compile function should only compile a single
// package and not the whole program, and loading of the program (including CGo
// processing) should be moved outside the compiler package.
func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Config) (llvm.Module, []string, []error) {
func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Config) (mod llvm.Module, extrafiles []string, extraldflags []string, errors []error) {
c := &compilerContext{
Config: config,
difiles: make(map[string]llvm.Metadata),
@ -148,7 +148,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
wd, err := os.Getwd()
if err != nil {
return c.mod, nil, []error{err}
return c.mod, nil, nil, []error{err}
}
lprogram := &loader.Program{
Build: &build.Context{
@ -211,14 +211,14 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
if strings.HasSuffix(pkgName, ".go") {
_, err = lprogram.ImportFile(pkgName)
if err != nil {
return c.mod, nil, []error{err}
return c.mod, nil, nil, []error{err}
}
} else {
_, err = lprogram.Import(pkgName, wd, token.Position{
Filename: "build command-line-arguments",
})
if err != nil {
return c.mod, nil, []error{err}
return c.mod, nil, nil, []error{err}
}
}
@ -226,12 +226,12 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
Filename: "build default import",
})
if err != nil {
return c.mod, nil, []error{err}
return c.mod, nil, nil, []error{err}
}
err = lprogram.Parse(c.TestConfig.CompileTestBinary)
if err != nil {
return c.mod, nil, []error{err}
return c.mod, nil, nil, []error{err}
}
c.ir = ir.NewProgram(lprogram, pkgName)
@ -239,7 +239,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
// Run a simple dead code elimination pass.
err = c.ir.SimpleDCE()
if err != nil {
return c.mod, nil, []error{err}
return c.mod, nil, nil, []error{err}
}
// Initialize debug information.
@ -383,7 +383,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
}
}
return c.mod, extraFiles, c.diagnostics
return c.mod, extraFiles, lprogram.LDFlags, c.diagnostics
}
// getLLVMRuntimeType obtains a named type from the runtime package and returns

4
loader/loader.go

@ -31,6 +31,7 @@ type Program struct {
Dir string // current working directory (for error reporting)
TINYGOROOT string // root of the TinyGo installation or root of the source code
CFlags []string
LDFlags []string
ClangHeaders string
}
@ -425,11 +426,12 @@ func (p *Package) parseFiles(includeTests bool) ([]*ast.File, error) {
if p.ClangHeaders != "" {
cflags = append(cflags, "-Xclang", "-internal-isystem", "-Xclang", p.ClangHeaders)
}
generated, errs := cgo.Process(files, p.Program.Dir, p.fset, cflags)
generated, ldflags, errs := cgo.Process(files, p.Program.Dir, p.fset, cflags)
if errs != nil {
fileErrs = append(fileErrs, errs...)
}
files = append(files, generated)
p.LDFlags = append(p.LDFlags, ldflags...)
}
if len(fileErrs) != 0 {
return nil, Errors{p, fileErrs}

8
src/testing/testing.go

@ -20,10 +20,10 @@ import (
type common struct {
output io.Writer
failed bool // Test or benchmark has failed.
skipped bool // Test of benchmark has been skipped.
finished bool // Test function has completed.
name string // Name of test or benchmark.
failed bool // Test or benchmark has failed.
skipped bool // Test of benchmark has been skipped.
finished bool // Test function has completed.
name string // Name of test or benchmark.
}
// TB is the interface common to T and B.

Loading…
Cancel
Save