aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLucas Teske <[email protected]>2020-05-20 13:05:25 -0300
committerAyke <[email protected]>2020-05-21 00:57:19 +0200
commit726d735ad35f1c1ea0ffc59a25a44e2d167a8ccf (patch)
treebd609c09ef2bc58f72b21ff9d2f6f2b5132edcfc
parentb9fd6cee6f0e427d1f2317734f49411e190cec75 (diff)
downloadtinygo-726d735ad35f1c1ea0ffc59a25a44e2d167a8ccf.tar.gz
tinygo-726d735ad35f1c1ea0ffc59a25a44e2d167a8ccf.zip
cgo: Add LDFlags support
-rw-r--r--builder/build.go6
-rw-r--r--cgo/cgo.go20
-rw-r--r--cgo/cgo_test.go2
-rw-r--r--cgo/testdata/flags.go7
-rw-r--r--cgo/testdata/flags.out.go1
-rw-r--r--compiler/compiler.go16
-rw-r--r--loader/loader.go4
-rw-r--r--src/testing/testing.go8
8 files changed, 46 insertions, 18 deletions
diff --git a/builder/build.go b/builder/build.go
index e67cb2bff..f8247f8b5 100644
--- a/builder/build.go
+++ b/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 {
diff --git a/cgo/cgo.go b/cgo/cgo.go
index d6470a522..7cc61b9ce 100644
--- a/cgo/cgo.go
+++ b/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
diff --git a/cgo/cgo_test.go b/cgo/cgo_test.go
index 5673ebad8..745824154 100644
--- a/cgo/cgo_test.go
+++ b/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
diff --git a/cgo/testdata/flags.go b/cgo/testdata/flags.go
index d52bbc5b9..012fad78d 100644
--- a/cgo/testdata/flags.go
+++ b/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"
diff --git a/cgo/testdata/flags.out.go b/cgo/testdata/flags.out.go
index 0bcad0d5a..4eb70112a 100644
--- a/cgo/testdata/flags.out.go
+++ b/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
diff --git a/compiler/compiler.go b/compiler/compiler.go
index e21f4a4e6..5ed85c053 100644
--- a/compiler/compiler.go
+++ b/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
diff --git a/loader/loader.go b/loader/loader.go
index 5682bfa4a..28ade8d2e 100644
--- a/loader/loader.go
+++ b/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}
diff --git a/src/testing/testing.go b/src/testing/testing.go
index f476514f6..ca353c608 100644
--- a/src/testing/testing.go
+++ b/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.