set -e
-ccargs=""
+ccargs=
if [ "$(go env GOOS)" == "darwin" ]; then
ccargs="-Wl,-no_pie"
# For darwin/arm.
# TODO(crawshaw): Can we do better?
ccargs="$ccargs -framework CoreFoundation -framework Foundation"
fi
+ccargs="$ccargs -I pkg/$(go env GOOS)_$(go env GOARCH)"
# TODO(crawshaw): Consider a go env for exec script name.
bin=./testp
bin="$exec_script ./testp"
fi
+rm -rf libgo.a libgo.h testp pkg
+
+# Installing first will create the header files we want.
+
+GOPATH=$(pwd) go install -buildmode=c-archive libgo
+$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c pkg/$(go env GOOS)_$(go env GOARCH)/libgo.a
+$bin arg1 arg2
+rm -f libgo.a libgo.h testp
+
+# Test building libgo other than installing it.
+# Header files are now present.
+
GOPATH=$(pwd) go build -buildmode=c-archive src/libgo/libgo.go
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a
$bin arg1 arg2
-rm libgo.a testp
+rm -f libgo.a libgo.h testp
GOPATH=$(pwd) go build -buildmode=c-archive -o libgo.a libgo
$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a
$bin arg1 arg2
-rm libgo.a testp
+rm -rf libgo.a libgo.h testp pkg
androidpath=/data/local/tmp/testcshared-$$
function cleanup() {
- rm -f libgo.so libgo2.so testp testp2 testp3
+ rm -rf libgo.so libgo2.so libgo.h testp testp2 testp3 pkg
+
+ rm -rf $(go env GOROOT)/pkg/$(go env GOOS)_$(go env GOARCH)_testcshared_shared
if [ "$(go env GOOS)" == "android" ]; then
adb shell rm -rf $androidpath
fi
}
-GOPATH=$(pwd) go build -buildmode=c-shared -o libgo.so src/libgo/libgo.go
+rm -rf pkg
+
+suffix="-installsuffix testcshared"
+
+# Create the header files.
+GOPATH=$(pwd) go install -buildmode=c-shared $suffix libgo
+
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo.so src/libgo/libgo.go
binpush libgo.so
# test0: exported symbols in shared lib are accessible.
-$(go env CC) $(go env GOGCCFLAGS) -o testp main0.c libgo.so
+# TODO(iant): using _shared here shouldn't really be necessary.
+$(go env CC) $(go env GOGCCFLAGS) -I pkg/$(go env GOOS)_$(go env GOARCH)_testcshared_shared -o testp main0.c libgo.so
binpush testp
output=$(run LD_LIBRARY_PATH=. ./testp)
if [ "$output" != "PASS" ]; then
fi
# test2: tests libgo2.so which does not export any functions.
-GOPATH=$(pwd) go build -buildmode=c-shared -o libgo2.so src/libgo2/libgo2.go
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.so src/libgo2/libgo2.go
binpush libgo2.so
$(go env CC) $(go env GOGCCFLAGS) -o testp2 main2.c -Wl,--no-as-needed libgo2.so
binpush testp2
p.target = "" // must build - not up to date
a := b.action(modeInstall, depMode, p)
a.target = *buildO
+ if p.local {
+ // If p.local, then b.action did not really install,
+ // so install the header file now if necessary.
+ a = b.maybeAddHeaderAction(a, false)
+ }
b.do(a)
return
}
a.f = (*builder).install
a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared)}
a.target = a.p.target
+ a = b.maybeAddHeaderAction(a, true)
+
case modeBuild:
a.f = (*builder).build
a.target = a.objpkg
return a
}
+// In c-archive/c-shared mode, if the package for the action uses cgo,
+// add a dependency to install the generated export header file, if
+// there is one.
+// The isInstall parameter is whether a is an install action.
+func (b *builder) maybeAddHeaderAction(a *action, isInstall bool) *action {
+ switch buildBuildmode {
+ case "c-archive", "c-shared":
+ default:
+ return a
+ }
+ if !a.p.usesCgo() {
+ return a
+ }
+
+ if isInstall {
+ // For an install action, change the action function.
+ // We can't add an action after the install action,
+ // because it deletes the working directory.
+ // Adding an action before the install action is painful,
+ // because it uses deps[0] to find the source.
+ a.f = (*builder).installWithHeader
+ return a
+ }
+
+ return &action{
+ p: a.p,
+ deps: []*action{a},
+ f: (*builder).installHeader,
+ pkgdir: a.pkgdir,
+ objdir: a.objdir,
+ target: a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h",
+ }
+}
+
+// Install the library and the cgo export header if there is one.
+func (b *builder) installWithHeader(a *action) error {
+ target := a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h"
+ if err := b.doInstallHeader(a, a.objdir, target); err != nil {
+ return err
+ }
+ return b.install(a)
+}
+
// actionList returns the list of actions in the dag rooted at root
// as visited in a depth-first post-order traversal.
func actionList(root *action) []*action {
a1 := a.deps[0]
perm := os.FileMode(0644)
if a1.link {
- perm = 0755
+ switch buildBuildmode {
+ case "c-archive", "c-shared":
+ default:
+ perm = 0755
+ }
}
// make target directory
return nil
}
+// Install the cgo export header file, if there is one.
+func (b *builder) installHeader(a *action) error {
+ return b.doInstallHeader(a, a.objdir, a.target)
+}
+
+func (b *builder) doInstallHeader(a *action, objdir, target string) error {
+ src := objdir + "_cgo_install.h"
+ if _, err := os.Stat(src); os.IsNotExist(err) {
+ // If the file does not exist, there are no exported
+ // functions, and we do not install anything.
+ return nil
+ }
+
+ dir, _ := filepath.Split(target)
+ if dir != "" {
+ if err := b.mkdir(dir); err != nil {
+ return err
+ }
+ }
+
+ return b.moveOrCopyFile(a, target, src, 0644)
+}
+
// cover runs, in effect,
// go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go
func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName string) error {
cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
}
}
- if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil {
+
+ switch buildBuildmode {
+ case "c-archive", "c-shared":
+ // Tell cgo that if there are any exported functions
+ // it should generate a header file that C code can
+ // #include.
+ cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h")
+ }
+
+ if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil {
return nil, nil, err
}
outGo = append(outGo, gofiles...)