Skip to content

Commit 726d735

Browse files
racerxdlaykevl
authored andcommitted
cgo: Add LDFlags support
1 parent b9fd6ce commit 726d735

File tree

8 files changed

+46
-18
lines changed

8 files changed

+46
-18
lines changed

builder/build.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
3232
if err != nil {
3333
return err
3434
}
35-
mod, extraFiles, errs := compiler.Compile(pkgName, machine, config)
35+
mod, extraFiles, extraLDFlags, errs := compiler.Compile(pkgName, machine, config)
3636
if errs != nil {
3737
return newMultiError(errs)
3838
}
@@ -187,6 +187,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
187187
ldflags = append(ldflags, outpath)
188188
}
189189

190+
if len(extraLDFlags) > 0 {
191+
ldflags = append(ldflags, extraLDFlags...)
192+
}
193+
190194
// Link the object files together.
191195
err = link(config.Target.Linker, ldflags...)
192196
if err != nil {

cgo/cgo.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type cgoPackage struct {
4141
elaboratedTypes map[string]*elaboratedTypeInfo
4242
enums map[string]enumInfo
4343
anonStructNum int
44+
ldflags []string
4445
}
4546

4647
// constantInfo stores some information about a CGo constant found by libclang
@@ -156,7 +157,7 @@ typedef unsigned long long _Cgo_ulonglong;
156157
// newly created *ast.File that should be added to the list of to-be-parsed
157158
// files. If there is one or more error, it returns these in the []error slice
158159
// but still modifies the AST.
159-
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []error) {
160+
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []string, []error) {
160161
p := &cgoPackage{
161162
dir: dir,
162163
fset: fset,
@@ -183,7 +184,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
183184
// Find the absolute path for this package.
184185
packagePath, err := filepath.Abs(fset.File(files[0].Pos()).Name())
185186
if err != nil {
186-
return nil, []error{
187+
return nil, nil, []error{
187188
scanner.Error{
188189
Pos: fset.Position(files[0].Pos()),
189190
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
359360
}
360361
makePathsAbsolute(flags, packagePath)
361362
cflags = append(cflags, flags...)
363+
case "LDFLAGS":
364+
flags, err := shlex.Split(value)
365+
if err != nil {
366+
// TODO: find the exact location where the error happened.
367+
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+colon+1], "failed to parse flags in #cgo line: "+err.Error())
368+
continue
369+
}
370+
if err := checkLinkerFlags(name, flags); err != nil {
371+
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+colon+1], err.Error())
372+
continue
373+
}
374+
makePathsAbsolute(flags, packagePath)
375+
p.ldflags = append(p.ldflags, flags...)
362376
default:
363377
startPos := strings.LastIndex(line[4:colon], name) + 4
364378
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
412426
// Print the newly generated in-memory AST, for debugging.
413427
//ast.Print(fset, p.generated)
414428

415-
return p.generated, p.errors
429+
return p.generated, p.ldflags, p.errors
416430
}
417431

418432
// makePathsAbsolute converts some common path compiler flags (-I, -L) from

cgo/cgo_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func TestCGo(t *testing.T) {
5050
}
5151

5252
// Process the AST with CGo.
53-
cgoAST, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
53+
cgoAST, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
5454

5555
// Check the AST for type errors.
5656
var typecheckErrors []error

cgo/testdata/flags.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ package main
2121
#if defined(NOTDEFINED)
2222
#warning flag must not be defined
2323
#endif
24+
25+
// Check Compiler flags
26+
#cgo LDFLAGS: -lc
27+
28+
// This flag is not valid ldflags
29+
#cgo LDFLAGS: -does-not-exists
30+
2431
*/
2532
import "C"
2633

cgo/testdata/flags.out.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// CGo errors:
22
// testdata/flags.go:5:7: invalid #cgo line: NOFLAGS
33
// testdata/flags.go:8:13: invalid flag: -fdoes-not-exist
4+
// testdata/flags.go:29:14: invalid flag: -does-not-exists
45

56
package main
67

compiler/compiler.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func NewTargetMachine(config *compileopts.Config) (llvm.TargetMachine, error) {
103103
// violation. Eventually, this Compile function should only compile a single
104104
// package and not the whole program, and loading of the program (including CGo
105105
// processing) should be moved outside the compiler package.
106-
func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Config) (llvm.Module, []string, []error) {
106+
func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Config) (mod llvm.Module, extrafiles []string, extraldflags []string, errors []error) {
107107
c := &compilerContext{
108108
Config: config,
109109
difiles: make(map[string]llvm.Metadata),
@@ -148,7 +148,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
148148

149149
wd, err := os.Getwd()
150150
if err != nil {
151-
return c.mod, nil, []error{err}
151+
return c.mod, nil, nil, []error{err}
152152
}
153153
lprogram := &loader.Program{
154154
Build: &build.Context{
@@ -211,35 +211,35 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
211211
if strings.HasSuffix(pkgName, ".go") {
212212
_, err = lprogram.ImportFile(pkgName)
213213
if err != nil {
214-
return c.mod, nil, []error{err}
214+
return c.mod, nil, nil, []error{err}
215215
}
216216
} else {
217217
_, err = lprogram.Import(pkgName, wd, token.Position{
218218
Filename: "build command-line-arguments",
219219
})
220220
if err != nil {
221-
return c.mod, nil, []error{err}
221+
return c.mod, nil, nil, []error{err}
222222
}
223223
}
224224

225225
_, err = lprogram.Import("runtime", "", token.Position{
226226
Filename: "build default import",
227227
})
228228
if err != nil {
229-
return c.mod, nil, []error{err}
229+
return c.mod, nil, nil, []error{err}
230230
}
231231

232232
err = lprogram.Parse(c.TestConfig.CompileTestBinary)
233233
if err != nil {
234-
return c.mod, nil, []error{err}
234+
return c.mod, nil, nil, []error{err}
235235
}
236236

237237
c.ir = ir.NewProgram(lprogram, pkgName)
238238

239239
// Run a simple dead code elimination pass.
240240
err = c.ir.SimpleDCE()
241241
if err != nil {
242-
return c.mod, nil, []error{err}
242+
return c.mod, nil, nil, []error{err}
243243
}
244244

245245
// Initialize debug information.
@@ -383,7 +383,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
383383
}
384384
}
385385

386-
return c.mod, extraFiles, c.diagnostics
386+
return c.mod, extraFiles, lprogram.LDFlags, c.diagnostics
387387
}
388388

389389
// getLLVMRuntimeType obtains a named type from the runtime package and returns

loader/loader.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type Program struct {
3131
Dir string // current working directory (for error reporting)
3232
TINYGOROOT string // root of the TinyGo installation or root of the source code
3333
CFlags []string
34+
LDFlags []string
3435
ClangHeaders string
3536
}
3637

@@ -425,11 +426,12 @@ func (p *Package) parseFiles(includeTests bool) ([]*ast.File, error) {
425426
if p.ClangHeaders != "" {
426427
cflags = append(cflags, "-Xclang", "-internal-isystem", "-Xclang", p.ClangHeaders)
427428
}
428-
generated, errs := cgo.Process(files, p.Program.Dir, p.fset, cflags)
429+
generated, ldflags, errs := cgo.Process(files, p.Program.Dir, p.fset, cflags)
429430
if errs != nil {
430431
fileErrs = append(fileErrs, errs...)
431432
}
432433
files = append(files, generated)
434+
p.LDFlags = append(p.LDFlags, ldflags...)
433435
}
434436
if len(fileErrs) != 0 {
435437
return nil, Errors{p, fileErrs}

src/testing/testing.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ import (
2020
type common struct {
2121
output io.Writer
2222

23-
failed bool // Test or benchmark has failed.
24-
skipped bool // Test of benchmark has been skipped.
25-
finished bool // Test function has completed.
26-
name string // Name of test or benchmark.
23+
failed bool // Test or benchmark has failed.
24+
skipped bool // Test of benchmark has been skipped.
25+
finished bool // Test function has completed.
26+
name string // Name of test or benchmark.
2727
}
2828

2929
// TB is the interface common to T and B.

0 commit comments

Comments
 (0)