Skip to content

Commit 48be3ed

Browse files
committed
cmd/go: support cgo files in overlays
This requires rewriting the paths of the files passed to the cgo tool toolchain to use the overlaid paths instead of the disk paths of files. Because the directories of the overlaid paths don't exist in general, the cgo tool have been updated to run in base.Cwd instead of the package directory. For #39958 Change-Id: I8986de889f56ecc2e64fa69f5f6f29fa907408f9 Reviewed-on: https://go-review.googlesource.com/c/go/+/262618 Trust: Michael Matloob <[email protected]> Run-TryBot: Michael Matloob <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Jay Conrod <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
1 parent 79fb187 commit 48be3ed

File tree

4 files changed

+156
-12
lines changed

4 files changed

+156
-12
lines changed

src/cmd/go/internal/work/exec.go

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package work
88

99
import (
1010
"bytes"
11+
"cmd/go/internal/fsys"
1112
"context"
1213
"encoding/json"
1314
"errors"
@@ -2242,8 +2243,6 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
22422243
// when -trimpath is enabled.
22432244
if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
22442245
if cfg.BuildTrimpath {
2245-
// TODO(#39958): handle overlays
2246-
22472246
// Keep in sync with Action.trimpath.
22482247
// The trimmed paths are a little different, but we need to trim in the
22492248
// same situations.
@@ -2313,7 +2312,8 @@ func (b *Builder) gccld(a *Action, p *load.Package, objdir, outfile string, flag
23132312

23142313
cmdargs := []interface{}{cmd, "-o", outfile, objs, flags}
23152314
dir := p.Dir
2316-
out, err := b.runOut(a, dir, b.cCompilerEnv(), cmdargs...)
2315+
out, err := b.runOut(a, base.Cwd, b.cCompilerEnv(), cmdargs...)
2316+
23172317
if len(out) > 0 {
23182318
// Filter out useless linker warnings caused by bugs outside Go.
23192319
// See also cmd/link/internal/ld's hostlink method.
@@ -2641,7 +2641,8 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
26412641
cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
26422642
}
26432643

2644-
// Allows including _cgo_export.h from .[ch] files in the package.
2644+
// Allows including _cgo_export.h, as well as the user's .h files,
2645+
// from .[ch] files in the package.
26452646
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", objdir)
26462647

26472648
// cgo
@@ -2654,6 +2655,8 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
26542655
cfiles = append(cfiles, f+".cgo2.c")
26552656
}
26562657

2658+
hfiles := append([]string{}, p.HFiles...)
2659+
26572660
// TODO: make cgo not depend on $GOARCH?
26582661

26592662
cgoflags := []string{}
@@ -2698,7 +2701,38 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
26982701
cgoflags = append(cgoflags, "-exportheader="+objdir+"_cgo_install.h")
26992702
}
27002703

2701-
if err := b.run(a, p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
2704+
execdir := p.Dir
2705+
2706+
// If any of the Cgo, C, or H files are overlaid, copy them all to
2707+
// objdir to ensure that they refer to the right header files.
2708+
// TODO(#39958): Ideally, we'd always do this, but this could
2709+
// subtly break some cgo files that include .h files across directory
2710+
// boundaries, even though they shouldn't.
2711+
hasOverlay := false
2712+
cgoFileLists := [][]string{cgofiles, gccfiles, gxxfiles, mfiles, ffiles, hfiles}
2713+
OverlayLoop:
2714+
for _, fs := range cgoFileLists {
2715+
for _, f := range fs {
2716+
if _, ok := fsys.OverlayPath(mkAbs(p.Dir, f)); ok {
2717+
hasOverlay = true
2718+
break OverlayLoop
2719+
}
2720+
}
2721+
}
2722+
if hasOverlay {
2723+
execdir = objdir
2724+
for _, fs := range cgoFileLists {
2725+
for i := range fs {
2726+
opath, _ := fsys.OverlayPath(mkAbs(p.Dir, fs[i]))
2727+
fs[i] = objdir + filepath.Base(fs[i])
2728+
if err := b.copyFile(fs[i], opath, 0666, false); err != nil {
2729+
return nil, nil, err
2730+
}
2731+
}
2732+
}
2733+
}
2734+
2735+
if err := b.run(a, execdir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
27022736
return nil, nil, err
27032737
}
27042738
outGo = append(outGo, gofiles...)
@@ -2792,7 +2826,7 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe
27922826
return err
27932827
}
27942828

2795-
linkobj := str.StringList(ofile, outObj, p.SysoFiles)
2829+
linkobj := str.StringList(ofile, outObj, mkAbsFiles(p.Dir, p.SysoFiles))
27962830
dynobj := objdir + "_cgo_.o"
27972831

27982832
// we need to use -pie for Linux/ARM to get accurate imported sym
@@ -2817,7 +2851,7 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe
28172851
if p.Standard && p.ImportPath == "runtime/cgo" {
28182852
cgoflags = []string{"-dynlinker"} // record path to dynamic linker
28192853
}
2820-
return b.run(a, p.Dir, p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
2854+
return b.run(a, base.Cwd, p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
28212855
}
28222856

28232857
// Run SWIG on all SWIG input files.

src/cmd/go/internal/work/gc.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ func (a *Action) trimpath() string {
262262
if len(objdir) > 1 && objdir[len(objdir)-1] == filepath.Separator {
263263
objdir = objdir[:len(objdir)-1]
264264
}
265-
rewrite := objdir + "=>"
265+
rewrite := ""
266266

267267
rewriteDir := a.Package.Dir
268268
if cfg.BuildTrimpath {
@@ -271,7 +271,7 @@ func (a *Action) trimpath() string {
271271
} else {
272272
rewriteDir = a.Package.ImportPath
273273
}
274-
rewrite += ";" + a.Package.Dir + "=>" + rewriteDir
274+
rewrite += a.Package.Dir + "=>" + rewriteDir + ";"
275275
}
276276

277277
// Add rewrites for overlays. The 'from' and 'to' paths in overlays don't need to have
@@ -280,11 +280,14 @@ func (a *Action) trimpath() string {
280280
if fsys.OverlayFile != "" {
281281
for _, filename := range a.Package.AllFiles() {
282282
overlayPath, ok := fsys.OverlayPath(filepath.Join(a.Package.Dir, filename))
283+
rewrite += filepath.Join(objdir, filename) + "=>" + filepath.Join(rewriteDir, filename) + ";"
283284
if !ok {
284285
continue
285286
}
286-
rewrite += ";" + overlayPath + "=>" + filepath.Join(rewriteDir, filename)
287+
rewrite += overlayPath + "=>" + filepath.Join(rewriteDir, filename) + ";"
287288
}
289+
} else {
290+
rewrite += objdir + "=>"
288291
}
289292

290293
return rewrite

src/cmd/go/testdata/script/build_overlay.txt

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
[short] skip
22

33
# Test building in overlays.
4-
# TODO(matloob): add a test case where the destination file in the replace map
4+
# TODO(#39958): add a test case where the destination file in the replace map
55
# isn't a go file. Either completely exclude that case in fs.IsDirWithGoFiles
66
# if the compiler doesn't allow it, or test that it works all the way.
7+
# TODO(#39958): add a test that both gc and gccgo assembly files can include .h
8+
# files.
79

810
# The main package (m) is contained in an overlay. It imports m/dir2 which has one
911
# file in an overlay and one file outside the overlay, which in turn imports m/dir,
@@ -29,6 +31,18 @@ exec ./print_trimpath_two_files$GOEXE
2931
stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go
3032
stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]other.go
3133

34+
go build -overlay overlay.json -o main_cgo_replace$GOEXE ./cgo_hello_replace
35+
exec ./main_cgo_replace$GOEXE
36+
stdout '^hello cgo$'
37+
38+
go build -overlay overlay.json -o main_cgo_quote$GOEXE ./cgo_hello_quote
39+
exec ./main_cgo_quote$GOEXE
40+
stdout '^hello cgo$'
41+
42+
go build -overlay overlay.json -o main_cgo_angle$GOEXE ./cgo_hello_angle
43+
exec ./main_cgo_angle$GOEXE
44+
stdout '^hello cgo$'
45+
3246
# Run same tests but with gccgo.
3347
env GO111MODULE=off
3448
[!exec:gccgo] stop
@@ -46,6 +60,19 @@ go build -compiler=gccgo -overlay overlay.json -o print_trimpath_gccgo$GOEXE -tr
4660
exec ./print_trimpath_gccgo$GOEXE
4761
stdout ^\.[/\\]printpath[/\\]main.go
4862

63+
64+
go build -compiler=gccgo -overlay overlay.json -o main_cgo_replace_gccgo$GOEXE ./cgo_hello_replace
65+
exec ./main_cgo_replace_gccgo$GOEXE
66+
stdout '^hello cgo$'
67+
68+
go build -compiler=gccgo -overlay overlay.json -o main_cgo_quote_gccgo$GOEXE ./cgo_hello_quote
69+
exec ./main_cgo_quote_gccgo$GOEXE
70+
stdout '^hello cgo$'
71+
72+
go build -compiler=gccgo -overlay overlay.json -o main_cgo_angle_gccgo$GOEXE ./cgo_hello_angle
73+
exec ./main_cgo_angle_gccgo$GOEXE
74+
stdout '^hello cgo$'
75+
4976
-- m/go.mod --
5077
// TODO(matloob): how do overlays work with go.mod (especially if mod=readonly)
5178
module m
@@ -71,9 +98,32 @@ the actual code is in the overlay
7198
"dir/g.go": "overlay/dir_g.go",
7299
"dir2/i.go": "overlay/dir2_i.go",
73100
"printpath/main.go": "overlay/printpath.go",
74-
"printpath/other.go": "overlay2/printpath2.go"
101+
"printpath/other.go": "overlay2/printpath2.go",
102+
"cgo_hello_replace/cgo_header.h": "overlay/cgo_head.h",
103+
"cgo_hello_quote/cgo_hello.go": "overlay/cgo_hello_quote.go",
104+
"cgo_hello_quote/cgo_header.h": "overlay/cgo_head.h",
105+
"cgo_hello_angle/cgo_hello.go": "overlay/cgo_hello_angle.go",
106+
"cgo_hello_angle/cgo_header.h": "overlay/cgo_head.h"
75107
}
76108
}
109+
-- m/cgo_hello_replace/cgo_hello_replace.go --
110+
package main
111+
112+
// #include "cgo_header.h"
113+
import "C"
114+
115+
func main() {
116+
C.say_hello()
117+
}
118+
-- m/cgo_hello_replace/cgo_header.h --
119+
// Test that this header is replaced with one that has the proper declaration.
120+
void say_goodbye();
121+
122+
-- m/cgo_hello_replace/goodbye.c --
123+
#include <stdio.h>
124+
125+
void say_hello() { puts("hello cgo\n"); }
126+
77127
-- m/overlay/f.go --
78128
package main
79129

@@ -128,3 +178,32 @@ import "m/dir"
128178
func printMessage() {
129179
dir.PrintMessage()
130180
}
181+
-- m/overlay/cgo_hello_quote.go --
182+
package main
183+
184+
// #include "cgo_header.h"
185+
import "C"
186+
187+
func main() {
188+
C.say_hello()
189+
}
190+
-- m/overlay/cgo_hello_angle.go --
191+
package main
192+
193+
// #include <cgo_header.h>
194+
import "C"
195+
196+
func main() {
197+
C.say_hello()
198+
}
199+
-- m/overlay/cgo_head.h --
200+
void say_hello();
201+
-- m/cgo_hello_quote/hello.c --
202+
#include <stdio.h>
203+
204+
void say_hello() { puts("hello cgo\n"); }
205+
-- m/cgo_hello_angle/hello.c --
206+
#include <stdio.h>
207+
208+
void say_hello() { puts("hello cgo\n"); }
209+

src/cmd/go/testdata/script/build_trimpath_cgo.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,38 @@ go build -trimpath -o hello.exe .
2020
go run ./list-dwarf hello.exe
2121
! stdout gopath/src
2222

23+
24+
# Do the above, with the cgo (but not .c) sources in an overlay
25+
# Check that the source path appears when -trimpath is not used.
26+
mkdir $WORK/overlay
27+
cp hello.go $WORK/overlay/hello.go
28+
mkdir hello_overlay
29+
cp hello.c hello_overlay/hello.c
30+
go build -overlay overlay.json -o hello_overlay.exe ./hello_overlay
31+
grep -q gopath[/\\]src hello_overlay.exe
32+
! grep -q $WORK[/\\]overlay hello_overlay.exe
33+
go run ./list-dwarf hello_overlay.exe
34+
stdout gopath[/\\]src
35+
! stdout $WORK[/\\]overlay
36+
37+
# Check that the source path does not appear when -trimpath is used.
38+
go build -overlay overlay.json -trimpath -o hello_overlay.exe ./hello_overlay
39+
! grep -q gopath[/\\]src hello_overlay.exe
40+
! grep -q $WORK[/\\]overlay hello_overlay.exe
41+
go run ./list-dwarf hello_overlay.exe
42+
! stdout gopath/src
43+
! stdout $WORK[/\\]overlay
44+
2345
-- go.mod --
2446
module m
2547

2648
go 1.14
49+
-- overlay.json --
50+
{
51+
"Replace": {
52+
"hello_overlay/hello.go": "../../overlay/hello.go"
53+
}
54+
}
2755
-- hello.c --
2856
#include <stdio.h>
2957

0 commit comments

Comments
 (0)