cgo: Add LDFlags support
Этот коммит содержится в:
родитель
b9fd6cee6f
коммит
726d735ad3
8 изменённых файлов: 46 добавлений и 18 удалений
|
@ -32,7 +32,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
mod, extraFiles, errs := compiler.Compile(pkgName, machine, config)
|
mod, extraFiles, extraLDFlags, errs := compiler.Compile(pkgName, machine, config)
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
return newMultiError(errs)
|
return newMultiError(errs)
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
||||||
ldflags = append(ldflags, outpath)
|
ldflags = append(ldflags, outpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(extraLDFlags) > 0 {
|
||||||
|
ldflags = append(ldflags, extraLDFlags...)
|
||||||
|
}
|
||||||
|
|
||||||
// Link the object files together.
|
// Link the object files together.
|
||||||
err = link(config.Target.Linker, ldflags...)
|
err = link(config.Target.Linker, ldflags...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
20
cgo/cgo.go
20
cgo/cgo.go
|
@ -41,6 +41,7 @@ type cgoPackage struct {
|
||||||
elaboratedTypes map[string]*elaboratedTypeInfo
|
elaboratedTypes map[string]*elaboratedTypeInfo
|
||||||
enums map[string]enumInfo
|
enums map[string]enumInfo
|
||||||
anonStructNum int
|
anonStructNum int
|
||||||
|
ldflags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// constantInfo stores some information about a CGo constant found by libclang
|
// 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
|
// 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
|
// files. If there is one or more error, it returns these in the []error slice
|
||||||
// but still modifies the AST.
|
// 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{
|
p := &cgoPackage{
|
||||||
dir: dir,
|
dir: dir,
|
||||||
fset: fset,
|
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.
|
// Find the absolute path for this package.
|
||||||
packagePath, err := filepath.Abs(fset.File(files[0].Pos()).Name())
|
packagePath, err := filepath.Abs(fset.File(files[0].Pos()).Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, []error{
|
return nil, nil, []error{
|
||||||
scanner.Error{
|
scanner.Error{
|
||||||
Pos: fset.Position(files[0].Pos()),
|
Pos: fset.Position(files[0].Pos()),
|
||||||
Msg: "cgo: cannot find absolute path: " + err.Error(), // TODO: wrap this error
|
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)
|
makePathsAbsolute(flags, packagePath)
|
||||||
cflags = append(cflags, flags...)
|
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:
|
default:
|
||||||
startPos := strings.LastIndex(line[4:colon], name) + 4
|
startPos := strings.LastIndex(line[4:colon], name) + 4
|
||||||
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+startPos], "invalid #cgo line: "+name)
|
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.
|
// Print the newly generated in-memory AST, for debugging.
|
||||||
//ast.Print(fset, p.generated)
|
//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
|
// makePathsAbsolute converts some common path compiler flags (-I, -L) from
|
||||||
|
|
|
@ -50,7 +50,7 @@ func TestCGo(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the AST with CGo.
|
// 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.
|
// Check the AST for type errors.
|
||||||
var typecheckErrors []error
|
var typecheckErrors []error
|
||||||
|
|
7
cgo/testdata/flags.go
предоставленный
7
cgo/testdata/flags.go
предоставленный
|
@ -21,6 +21,13 @@ package main
|
||||||
#if defined(NOTDEFINED)
|
#if defined(NOTDEFINED)
|
||||||
#warning flag must not be defined
|
#warning flag must not be defined
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Check Compiler flags
|
||||||
|
#cgo LDFLAGS: -lc
|
||||||
|
|
||||||
|
// This flag is not valid ldflags
|
||||||
|
#cgo LDFLAGS: -does-not-exists
|
||||||
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
|
|
1
cgo/testdata/flags.out.go
предоставленный
1
cgo/testdata/flags.out.go
предоставленный
|
@ -1,6 +1,7 @@
|
||||||
// CGo errors:
|
// CGo errors:
|
||||||
// testdata/flags.go:5:7: invalid #cgo line: NOFLAGS
|
// testdata/flags.go:5:7: invalid #cgo line: NOFLAGS
|
||||||
// testdata/flags.go:8:13: invalid flag: -fdoes-not-exist
|
// testdata/flags.go:8:13: invalid flag: -fdoes-not-exist
|
||||||
|
// testdata/flags.go:29:14: invalid flag: -does-not-exists
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ func NewTargetMachine(config *compileopts.Config) (llvm.TargetMachine, error) {
|
||||||
// violation. Eventually, this Compile function should only compile a single
|
// violation. Eventually, this Compile function should only compile a single
|
||||||
// package and not the whole program, and loading of the program (including CGo
|
// package and not the whole program, and loading of the program (including CGo
|
||||||
// processing) should be moved outside the compiler package.
|
// 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{
|
c := &compilerContext{
|
||||||
Config: config,
|
Config: config,
|
||||||
difiles: make(map[string]llvm.Metadata),
|
difiles: make(map[string]llvm.Metadata),
|
||||||
|
@ -148,7 +148,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.mod, nil, []error{err}
|
return c.mod, nil, nil, []error{err}
|
||||||
}
|
}
|
||||||
lprogram := &loader.Program{
|
lprogram := &loader.Program{
|
||||||
Build: &build.Context{
|
Build: &build.Context{
|
||||||
|
@ -211,14 +211,14 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
|
||||||
if strings.HasSuffix(pkgName, ".go") {
|
if strings.HasSuffix(pkgName, ".go") {
|
||||||
_, err = lprogram.ImportFile(pkgName)
|
_, err = lprogram.ImportFile(pkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.mod, nil, []error{err}
|
return c.mod, nil, nil, []error{err}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_, err = lprogram.Import(pkgName, wd, token.Position{
|
_, err = lprogram.Import(pkgName, wd, token.Position{
|
||||||
Filename: "build command-line-arguments",
|
Filename: "build command-line-arguments",
|
||||||
})
|
})
|
||||||
if err != nil {
|
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",
|
Filename: "build default import",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.mod, nil, []error{err}
|
return c.mod, nil, nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = lprogram.Parse(c.TestConfig.CompileTestBinary)
|
err = lprogram.Parse(c.TestConfig.CompileTestBinary)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.mod, nil, []error{err}
|
return c.mod, nil, nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ir = ir.NewProgram(lprogram, pkgName)
|
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.
|
// Run a simple dead code elimination pass.
|
||||||
err = c.ir.SimpleDCE()
|
err = c.ir.SimpleDCE()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.mod, nil, []error{err}
|
return c.mod, nil, nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize debug information.
|
// 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
|
// getLLVMRuntimeType obtains a named type from the runtime package and returns
|
||||||
|
|
|
@ -31,6 +31,7 @@ type Program struct {
|
||||||
Dir string // current working directory (for error reporting)
|
Dir string // current working directory (for error reporting)
|
||||||
TINYGOROOT string // root of the TinyGo installation or root of the source code
|
TINYGOROOT string // root of the TinyGo installation or root of the source code
|
||||||
CFlags []string
|
CFlags []string
|
||||||
|
LDFlags []string
|
||||||
ClangHeaders string
|
ClangHeaders string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,11 +426,12 @@ func (p *Package) parseFiles(includeTests bool) ([]*ast.File, error) {
|
||||||
if p.ClangHeaders != "" {
|
if p.ClangHeaders != "" {
|
||||||
cflags = append(cflags, "-Xclang", "-internal-isystem", "-Xclang", 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 {
|
if errs != nil {
|
||||||
fileErrs = append(fileErrs, errs...)
|
fileErrs = append(fileErrs, errs...)
|
||||||
}
|
}
|
||||||
files = append(files, generated)
|
files = append(files, generated)
|
||||||
|
p.LDFlags = append(p.LDFlags, ldflags...)
|
||||||
}
|
}
|
||||||
if len(fileErrs) != 0 {
|
if len(fileErrs) != 0 {
|
||||||
return nil, Errors{p, fileErrs}
|
return nil, Errors{p, fileErrs}
|
||||||
|
|
|
@ -20,10 +20,10 @@ import (
|
||||||
type common struct {
|
type common struct {
|
||||||
output io.Writer
|
output io.Writer
|
||||||
|
|
||||||
failed bool // Test or benchmark has failed.
|
failed bool // Test or benchmark has failed.
|
||||||
skipped bool // Test of benchmark has been skipped.
|
skipped bool // Test of benchmark has been skipped.
|
||||||
finished bool // Test function has completed.
|
finished bool // Test function has completed.
|
||||||
name string // Name of test or benchmark.
|
name string // Name of test or benchmark.
|
||||||
}
|
}
|
||||||
|
|
||||||
// TB is the interface common to T and B.
|
// TB is the interface common to T and B.
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче