mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/cgo: avoid exporting all symbols on windows buildmode=c-shared
Disable default symbol auto-export behaviour by marking exported function with the __declspec(dllexport) attribute. Old behaviour can still be used by setting -extldflags=-Wl,--export-all-symbols. See https://sourceware.org/binutils/docs/ld/WIN32.html for more info. This change cuts 50kb of a "hello world" dll. Updates #6853 Fixes #30674 Change-Id: I9c7fb09c677cc760f24d0f7d199740ae73981413 Reviewed-on: https://go-review.googlesource.com/c/go/+/262797 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Trust: Alex Brainman <alex.brainman@gmail.com>
This commit is contained in:
parent
4ce9ea52c9
commit
6f7b553c82
2 changed files with 101 additions and 1 deletions
|
|
@ -7,6 +7,8 @@ package cshared_test
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
|
"debug/pe"
|
||||||
|
"encoding/binary"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
@ -355,6 +357,100 @@ func TestExportedSymbols(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkNumberOfExportedFunctionsWindows(t *testing.T, exportAllSymbols bool) {
|
||||||
|
const prog = `
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
//export GoFunc
|
||||||
|
func GoFunc() {
|
||||||
|
println(42)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export GoFunc2
|
||||||
|
func GoFunc2() {
|
||||||
|
println(24)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
tmpdir := t.TempDir()
|
||||||
|
|
||||||
|
srcfile := filepath.Join(tmpdir, "test.go")
|
||||||
|
objfile := filepath.Join(tmpdir, "test.dll")
|
||||||
|
if err := ioutil.WriteFile(srcfile, []byte(prog), 0666); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
argv := []string{"build", "-buildmode=c-shared"}
|
||||||
|
if exportAllSymbols {
|
||||||
|
argv = append(argv, "-ldflags", "-extldflags=-Wl,--export-all-symbols")
|
||||||
|
}
|
||||||
|
argv = append(argv, "-o", objfile, srcfile)
|
||||||
|
out, err := exec.Command("go", argv...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("build failure: %s\n%s\n", err, string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := pe.Open(objfile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("pe.Open failed: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
section := f.Section(".edata")
|
||||||
|
if section == nil {
|
||||||
|
t.Error(".edata section is not present")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: deduplicate this struct from cmd/link/internal/ld/pe.go
|
||||||
|
type IMAGE_EXPORT_DIRECTORY struct {
|
||||||
|
_ [2]uint32
|
||||||
|
_ [2]uint16
|
||||||
|
_ [2]uint32
|
||||||
|
NumberOfFunctions uint32
|
||||||
|
NumberOfNames uint32
|
||||||
|
_ [3]uint32
|
||||||
|
}
|
||||||
|
var e IMAGE_EXPORT_DIRECTORY
|
||||||
|
if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil {
|
||||||
|
t.Fatalf("binary.Read failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedNumber := uint32(2)
|
||||||
|
|
||||||
|
if exportAllSymbols {
|
||||||
|
if e.NumberOfFunctions <= expectedNumber {
|
||||||
|
t.Fatalf("missing exported functions: %v", e.NumberOfFunctions)
|
||||||
|
}
|
||||||
|
if e.NumberOfNames <= expectedNumber {
|
||||||
|
t.Fatalf("missing exported names: %v", e.NumberOfNames)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if e.NumberOfFunctions != expectedNumber {
|
||||||
|
t.Fatalf("too many exported functions: %v", e.NumberOfFunctions)
|
||||||
|
}
|
||||||
|
if e.NumberOfNames != expectedNumber {
|
||||||
|
t.Fatalf("too many exported names: %v", e.NumberOfNames)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNumberOfExportedFunctions(t *testing.T) {
|
||||||
|
if GOOS != "windows" {
|
||||||
|
t.Skip("skipping windows only test")
|
||||||
|
}
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("OnlyExported", func(t *testing.T) {
|
||||||
|
checkNumberOfExportedFunctionsWindows(t, false)
|
||||||
|
})
|
||||||
|
t.Run("All", func(t *testing.T) {
|
||||||
|
checkNumberOfExportedFunctionsWindows(t, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// test1: shared library can be dynamically loaded and exported symbols are accessible.
|
// test1: shared library can be dynamically loaded and exported symbols are accessible.
|
||||||
func TestExportedSymbolsWithDynamicLoad(t *testing.T) {
|
func TestExportedSymbolsWithDynamicLoad(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
|
||||||
|
|
@ -939,7 +939,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the wrapper function compiled by gcc.
|
// Build the wrapper function compiled by gcc.
|
||||||
s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
|
gccExport := ""
|
||||||
|
if goos == "windows" {
|
||||||
|
gccExport = "__declspec(dllexport)"
|
||||||
|
}
|
||||||
|
s := fmt.Sprintf("%s %s %s(", gccExport, gccResult, exp.ExpName)
|
||||||
if fn.Recv != nil {
|
if fn.Recv != nil {
|
||||||
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
||||||
s += " recv"
|
s += " recv"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue