diff --git a/CHANGES.current b/CHANGES.current index 21f75ecf8..93e5fb943 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -5,6 +5,10 @@ See the RELEASENOTES file for a summary of changes in each release. Version 3.0.6 (in progress) =========================== +2015-03-02: ianlancetaylor + [Go] Add -cgo option, required for Go versions 1.5 and + later. + 2015-02-26: olly Fix segmentation fault when top==NULL, introduced by nested class handling (reported in issue#346 by Paweł Tomulik). diff --git a/Doc/Manual/Go.html b/Doc/Manual/Go.html index 895e6c581..175f22f26 100644 --- a/Doc/Manual/Go.html +++ b/Doc/Manual/Go.html @@ -111,6 +111,14 @@ swig -go -help
When generating Go code, SWIG will generate the following - files:
+There are two different approaches to generating output files, + controlled by SWIG's -cgo option. The -cgo option + works with Go version 1.2 or later. It is required when using Go + version 1.5 or later.
+ +With or without the -cgo option, SWIG will generate the + following files when generating Go code:
When neither the -cgo nor the -gccgo option is + used, SWIG will also generate an additional file:
+ +@@ -203,14 +225,33 @@ support for SWIG. To use it, put your SWIG interface into a file with the extension .swig, or, if you are wrapping C++ code, .swigcxx. Put that file in a GOPATH/src directory as usual for Go sources. Put other interface code in the same directory with extensions of .c and -.cxx. The go build command and go install commands will automatically -run SWIG for you and will build the interface code. +.cxx. The go build and go install commands will +automatically run SWIG for you and will build the interface code.
-You can also use SWIG directly yourself. When using the gc compiler -version 1.2 or later, or when using gccgo, the code generated by SWIG -can be linked directly into the Go program. A typical command +You can also use SWIG directly yourself. When using +the -cgo option, SWIG will generate files that can be used +directly by go build. Put your SWIG input file in a +directory under GOPATH/src, and give it a name that does not end in +.swig or .swigcxx. +
+ ++% swig -go -cgo example.i +% go install +
+You will now have a Go package that you can import from other Go +packages as usual. +
+ ++To use SWIG without the -cgo option, more steps are required. +Recall that this only works with Go versions before 1.5. When using +Go version 1.2 or later, or when using gccgo, the code generated by +SWIG can be linked directly into the Go program. A typical command sequence when using the gc compiler would look like this:
@@ -227,9 +268,8 @@ sequence when using the gc compiler would look like this:You can also put the wrapped code into a shared library, and when -using the gc compiler before version 1.2 this is the only supported -option. A typical command sequence for this approach would look like -this: +using the Go versions before 1.2 this is the only supported option. A +typical command sequence for this approach would look like this:
diff --git a/Examples/Makefile.in b/Examples/Makefile.in index 8aa1ecedf..47e2d7ca7 100644 --- a/Examples/Makefile.in +++ b/Examples/Makefile.in @@ -1752,15 +1752,18 @@ scilab_clean: GO = @GO@ GOGCC = @GOGCC@ +GCCGO = @GCCGO@ GO1 = @GO1@ GO12 = @GO12@ GO13 = @GO13@ +GO15 = @GO15@ GOC = @GOC@ GOOPT = @GOOPT@ +GCCGOOPT = @GCCGOOPT@ GOVERSIONOPTION = @GOVERSIONOPTION@ GOSWIGARG = `if $(GOGCC) ; then echo -gccgo; fi` -GOCOMPILEARG = `if $(GOGCC) ; then echo -c -g; elif $(GO1) ; then echo tool $(GOC:c=g) ; fi` `if $(GO13) && ! $(GOGCC); then echo -pack ; fi` +GOCOMPILEARG = `if $(GO1) ; then echo tool $(GOC:c=g) ; fi` `if $(GO13) || $(GO15); then echo -pack ; fi` GOSRCS = $(INTERFACE:.i=.go) GOCSRCS = $(INTERFACE:.i=_gc.c) @@ -1769,7 +1772,9 @@ GOLD = $(GOC:c=l) GOTOOL = `if $(GO1) ; then echo go tool; fi` GOPACK = `if $(GO1) ; then echo go tool pack; else echo gopack; fi` -GOPACKAGE = $(INTERFACE:.i=.a) +GOPACKAGE = $(notdir $(INTERFACE:.i=.a)) + +GOPATHDIR = gopath/src/$(INTERFACE:.i=) GOOBJEXT = $(GOC:c=) GOGCOBJS = $(GOSRCS:.go=.$(GOOBJEXT)) @@ -1779,19 +1784,21 @@ GOGCCOBJS = $(GOSRCS:.go=.@OBJEXT@) # Build a Go module (C) # ---------------------------------------------------------------- -go: $(SRCDIR_SRCS) +go_nocgo: $(SRCDIR_SRCS) $(SWIG) -go $(GOOPT) $(GOSWIGARG) $(SWIGOPT) -o $(ISRCS) $(INTERFACEPATH) - if $(GO12) || $(GO13) || $(GOGCC); then \ + if $(GO12) || $(GO13) || $(GO15) || $(GOGCC); then \ $(CC) -g -c $(CPPFLAGS) $(CFLAGS) $(SRCDIR_SRCS) $(ISRCS) $(INCLUDES); \ else \ $(CC) -g -c $(CCSHARED) $(CPPFLAGS) $(CFLAGS) $(SRCDIR_SRCS) $(ISRCS) $(INCLUDES); \ $(LDSHARED) $(CFLAGS) $(LDFLAGS) $(OBJS) $(IOBJS) $(LIBS) -o $(LIBPREFIX)$(TARGET)$(SO); \ fi - $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(GOSRCS) - if ! $(GOGCC) ; then \ + if $(GOGCC) ; then \ + $(COMPILETOOL) $(GCCGO) -g -c -I . $(GOSRCS); \ + else \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(GOSRCS); \ $(COMPILETOOL) $(GOTOOL) $(GOC) -I $${GOROOT:-`go env GOROOT`}/pkg/$${GOOS:-`go env GOOS`}_$${GOARCH:-`go env GOARCH`} $(GOCSRCS); \ rm -f $(GOPACKAGE); \ - if $(GO13); then \ + if $(GO13) || $(GO15); then \ cp $(GOGCOBJS) $(GOPACKAGE); \ $(COMPILETOOL) $(GOPACK) r $(GOPACKAGE) $(GOCSRCS:.c=.$(GOOBJEXT)) $(OBJS) $(IOBJS); \ elif $(GO12); then \ @@ -1801,12 +1808,54 @@ go: $(SRCDIR_SRCS) fi; \ fi if test -f $(SRCDIR)$(RUNME).go; then \ - $(GO) $(GOCOMPILEARG) $(SRCDIR)$(RUNME).go; \ if $(GOGCC) ; then \ - $(COMPILETOOL) $(GO) -o $(RUNME) $(RUNME).@OBJEXT@ $(GOGCCOBJS) $(OBJS) $(IOBJS); \ - elif $(GO12) || $(GO13); then \ + $(COMPILETOOL) $(GCCGO) -g -c $(SRCDIR)$(RUNME).go; \ + $(COMPILETOOL) $(GCCGO) -o $(RUNME) $(RUNME).@OBJEXT@ $(GOGCCOBJS) $(OBJS) $(IOBJS); \ + elif $(GO12) || $(GO13) || $(GO15); then \ + $(GO) $(GOCOMPILEARG) $(SRCDIR)$(RUNME).go; \ $(COMPILETOOL) $(GOTOOL) $(GOLD) -linkmode external -extld "$(CC)" -extldflags "$(CFLAGS) $(LDFLAGS)" -o $(RUNME) $(RUNME).$(GOOBJEXT); \ else \ + $(GO) $(GOCOMPILEARG) $(SRCDIR)$(RUNME).go; \ + $(COMPILETOOL) $(GOTOOL) $(GOLD) -r $${GOROOT:-`go env GOROOT`}/pkg/$${GOOS:-`go env GOOS`}_$${GOARCH:-`go env GOARCH`}:. -o $(RUNME) $(RUNME).$(GOOBJEXT); \ + fi; \ + fi + +go: $(SRCDIR_SRCS) + $(SWIG) -go -cgo $(GOOPT) $(GOSWIGARG) $(SWIGOPT) -o $(ISRCS) $(INTERFACEPATH) + @mkdir gopath 2>/dev/null || true + @mkdir gopath/src 2>/dev/null || true + @mkdir gopath/src/$(INTERFACE:.i=) 2>/dev/null || true + rm -f $(GOPATHDIR)/* + cp $(ISRCS) $(GOPATHDIR)/ + if test -f $(IWRAP:.i=.h); then \ + cp $(IWRAP:.i=.h) $(GOPATHDIR)/; \ + fi + if test -n "$(SRCDIR_SRCS)"; then \ + cp $(SRCDIR_SRCS) $(GOPATHDIR)/; \ + fi + cp $(GOSRCS) $(GOPATHDIR)/ + GOPATH=`pwd`/gopath; \ + export GOPATH; \ + CGO_CPPFLAGS="$(CPPFLAGS) $(INCLUDES) -I `pwd`"; \ + export CGO_CPPFLAGS; \ + CGO_CFLAGS="$(CFLAGS)"; \ + export CGO_CFLAGS; \ + CGO_LDFLAGS="$(LDFLAGS) -lm"; \ + export CGO_LDFLAGS; \ + (cd $(GOPATHDIR)/ && $(COMPILETOOL) $(GO) build `if $(GOGCC); then echo -compiler=gccgo; fi` -o $(GOPACKAGE)) + cp $(GOPATHDIR)/$(GOPACKAGE) $(dir $(INTERFACE))/$(GOPACKAGE) + if $(GOGCC); then \ + cp $(dir $(INTERFACE))/$(GOPACKAGE) $(dir $(INTERFACE))/$(GOPACKAGE:.a=.gox); \ + fi + if test -f $(SRCDIR)$(RUNME).go; then \ + if $(GOGCC) ; then \ + $(COMPILETOOL) $(GCCGO) -c -g $(SRCDIR)$(RUNME).go; \ + $(COMPILETOOL) $(GCCGO) -o $(RUNME) $(RUNME).@OBJEXT@ $(dir $(INTERFACE))/$(GOPACKAGE); \ + elif $(GO12) || $(GO13) || $(GO15); then \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) $(SRCDIR)$(RUNME).go; \ + $(COMPILETOOL) $(GOTOOL) $(GOLD) -linkmode external -extld "$(CC)" -extldflags "$(CFLAGS) $(LDFLAGS)" -o $(RUNME) $(RUNME).$(GOOBJEXT); \ + else \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) $(SRCDIR)$(RUNME).go; \ $(COMPILETOOL) $(GOTOOL) $(GOLD) -r $${GOROOT:-`go env GOROOT`}/pkg/$${GOOS:-`go env GOOS`}_$${GOARCH:-`go env GOARCH`}:. -o $(RUNME) $(RUNME).$(GOOBJEXT); \ fi; \ fi @@ -1815,9 +1864,9 @@ go: $(SRCDIR_SRCS) # Build a Go module (C++) # ---------------------------------------------------------------- -go_cpp: $(SRCDIR_SRCS) +go_cpp_nocgo: $(SRCDIR_SRCS) $(SWIG) -go -c++ $(GOOPT) $(GOSWIGARG) $(SWIGOPT) -o $(ICXXSRCS) $(INTERFACEPATH) - if $(GO12) || $(GO13) || $(GOGCC); then \ + if $(GO12) || $(GO13) || $(GO15) || $(GOGCC); then \ if test -n "$(SRCDIR_CXXSRCS)$(SRCDIR_SRCS)"; then \ $(CXX) -g -c $(CPPFLAGS) $(CXXFLAGS) $(SRCDIR_CXXSRCS) $(SRCDIR_SRCS) $(INCLUDES); \ fi; \ @@ -1837,7 +1886,7 @@ go_cpp: $(SRCDIR_SRCS) -o $(addsuffix .$(GOOBJEXT),$(basename $f)) $f; \ ) \ rm -f $(GOPACKAGE); \ - if $(GO13); then \ + if $(GO13) || $(GO15); then \ cp $(GOGCOBJS) $(GOPACKAGE); \ $(COMPILETOOL) $(GOPACK) r $(GOPACKAGE) $(GOCSRCS:.c=.$(GOOBJEXT)) $(OBJS) $(IOBJS); \ elif $(GO12); then \ @@ -1847,16 +1896,63 @@ go_cpp: $(SRCDIR_SRCS) fi; \ else \ $(foreach f,$(GOSRCS), \ - $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . -o $(addsuffix .@OBJEXT@,$(basename $f)) $f \ + $(COMPILETOOL) $(GCCGO) -g -c -I . -o $(addsuffix .@OBJEXT@,$(basename $f)) $f \ ); \ fi if test -f $(SRCDIR)$(RUNME).go; then \ - $(GO) $(GOCOMPILEARG) $(SRCDIR)$(RUNME).go; \ if $(GOGCC) ; then \ - $(COMPILETOOL) $(GO) -o $(RUNME) $(RUNME).@OBJEXT@ $(GOGCCOBJS) $(OBJS) $(IOBJS) -lstdc++; \ - elif $(GO12) || $(GO13); then \ + $(COMPILETOOL) $(GCCGO) -g -c $(SRCDIR)$(RUNME).go; \ + $(COMPILETOOL) $(GCCGO) -o $(RUNME) $(RUNME).@OBJEXT@ $(GOGCCOBJS) $(OBJS) $(IOBJS) -lstdc++; \ + elif $(GO12) || $(GO13) || $(GO15); then \ + $(GO) $(GOCOMPILEARG) $(SRCDIR)$(RUNME).go; \ $(COMPILETOOL) $(GOTOOL) $(GOLD) -linkmode external -extld "$(CXX)" -extldflags "$(CXXFLAGS) $(LDFLAGS)" -o $(RUNME) $(RUNME).$(GOOBJEXT); \ else \ + $(GO) $(GOCOMPILEARG) $(SRCDIR)$(RUNME).go; \ + $(COMPILETOOL) $(GOTOOL) $(GOLD) -r $${GOROOT:-`go env GOROOT`}/pkg/$${GOOS:-`go env GOOS`}_$${GOARCH:-`go env GOARCH`}:. -o $(RUNME) $(RUNME).$(GOOBJEXT); \ + fi; \ + fi + +go_cpp: $(SRCDIR_SRCS) + $(SWIG) -go -c++ -cgo $(GOOPT) $(GOSWIGARG) $(SWIGOPT) -o $(ICXXSRCS) $(INTERFACEPATH) + @mkdir gopath 2>/dev/null || true + @mkdir gopath/src 2>/dev/null || true + @mkdir gopath/src/$(INTERFACE:.i=) 2>/dev/null || true + rm -f $(GOPATHDIR)/* + cp $(ICXXSRCS) $(GOPATHDIR)/ + if test -f $(IWRAP:.i=.h); then \ + cp $(IWRAP:.i=.h) $(GOPATHDIR)/; \ + fi + if test -n "$(SRCDIR_CXXSRCS)"; then \ + cp $(SRCDIR_CXXSRCS) $(GOPATHDIR)/; \ + fi + if test -n "$(SRCDIR_SRCS)"; then \ + cp $(SRCDIR_SRCS) $(GOPATHDIR)/; \ + fi + cp $(GOSRCS) $(GOPATHDIR)/ + GOPATH=`pwd`/gopath; \ + export GOPATH; \ + CGO_CPPFLAGS="$(CPPFLAGS) $(INCLUDES) -I `pwd`"; \ + export CGO_CPPFLAGS; \ + CGO_CFLAGS="$(CFLAGS)"; \ + export CGO_CFLAGS; \ + CGO_CXXFLAGS="$(CXXFLAGS)"; \ + export CGO_CXXFLAGS; \ + CGO_LDFLAGS="$(LDFLAGS) -lm"; \ + export CGO_LDFLAGS; \ + (cd $(GOPATHDIR) && $(COMPILETOOL) $(GO) build `if $(GOGCC); then echo -compiler=gccgo; fi` -o $(GOPACKAGE)) + cp $(GOPATHDIR)/$(GOPACKAGE) $(dir $(INTERFACE))/$(GOPACKAGE) + if $(GOGCC); then \ + cp $(dir $(INTERFACE))/$(GOPACKAGE) $(dir $(INTERFACE))/$(GOPACKAGE:.a=.gox); \ + fi + if test -f $(SRCDIR)$(RUNME).go; then \ + if $(GOGCC) ; then \ + $(COMPILETOOL) $(GCCGO) -g -c $(SRCDIR)$(RUNME).go; \ + $(COMPILETOOL) $(GCCGO) -o $(RUNME) $(RUNME).@OBJEXT@ $(dir $(INTERFACE))/$(GOPACKAGE) -lstdc++; \ + elif $(GO12) || $(GO13) || $(GO15); then \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) $(SRCDIR)$(RUNME).go; \ + $(COMPILETOOL) $(GOTOOL) $(GOLD) -linkmode external -extld "$(CXX)" -extldflags "$(CXXFLAGS) $(LDFLAGS)" -o $(RUNME) $(RUNME).$(GOOBJEXT); \ + else \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) $(SRCDIR)$(RUNME).go; \ $(COMPILETOOL) $(GOTOOL) $(GOLD) -r $${GOROOT:-`go env GOROOT`}/pkg/$${GOOS:-`go env GOOS`}_$${GOARCH:-`go env GOARCH`}:. -o $(RUNME) $(RUNME).$(GOOBJEXT); \ fi; \ fi @@ -1880,7 +1976,8 @@ go_version: # ----------------------------------------------------------------- go_clean: - rm -f *_wrap* *_gc* .~* $(RUNME) $(GOSRCS) + rm -f *_wrap* *_gc* *.gox .~* $(RUNME) $(GOSRCS) + rm -rf gopath rm -f core @EXTRA_CLEAN@ rm -f *.@OBJEXT@ *.[568] *.a *@SO@ diff --git a/Examples/test-suite/go/Makefile.in b/Examples/test-suite/go/Makefile.in index b4747601c..3c99a0879 100644 --- a/Examples/test-suite/go/Makefile.in +++ b/Examples/test-suite/go/Makefile.in @@ -5,13 +5,15 @@ LANGUAGE = go GO = @GO@ GOGCC = @GOGCC@ +GCCGO = @GCCGO@ GO1 = @GO1@ GO12 = @GO12@ GO13 = @GO13@ +GO15 = @GO15@ GOC = @GOC@ SCRIPTSUFFIX = _runme.go -GOCOMPILEARG = `if $(GOGCC) ; then echo -c -g; elif $(GO1) ; then echo tool $(GOC:c=g) ; fi` +GOCOMPILEARG = `if $(GO1) ; then echo tool $(GOC:c=g) ; fi` GOLD = $(GOC:c=l) GOTOOL = `if $(GO1) ; then echo go tool; fi` GOPACK = `if $(GO1) ; then echo go tool pack; else echo gopack; fi` @@ -20,9 +22,10 @@ GOOBJEXT = $(GOC:c=) SO = @SO@ -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -top_builddir = @top_builddir@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ CPP_TEST_CASES = \ go_inout \ @@ -33,6 +36,8 @@ MULTI_CPP_TEST_CASES = \ include $(srcdir)/../common.mk +INCLUDES = -I$(abs_top_srcdir)/$(EXAMPLES)/$(TEST_SUITE) + .SUFFIXES: .cpptest .ctest .multicpptest # Rules for the different types of tests @@ -40,17 +45,37 @@ include $(srcdir)/../common.mk $(setup) +$(swig_and_compile_cpp) $(run_testcase_cpp) + if ! $(GO15); then \ + $(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile SRCDIR="$(SRCDIR)" CXXSRCS="$(CXXSRCS)" \ + SWIG_LIB="$(SWIG_LIB)" SWIG="$(SWIG)" \ + INCLUDES="$(INCLUDES)" SWIGOPT="$(SWIGOPT)" NOLINK=true \ + TARGET="$(TARGETPREFIX)$*$(TARGETSUFFIX)" INTERFACEDIR="$(INTERFACEDIR)" INTERFACE="$*.i" \ + $(LANGUAGE)$(VARIANT)_cpp_nocgo; \ + $(run_testcase_cpp); \ + fi %.ctest: $(setup) +$(swig_and_compile_c) $(run_testcase) + if ! $(GO15); then \ + $(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile SRCDIR="$(SRCDIR)" CSRCS="$(CSRCS)" \ + SWIG_LIB="$(SWIG_LIB)" SWIG="$(SWIG)" \ + INCLUDES="$(INCLUDES)" SWIGOPT="$(SWIGOPT)" NOLINK=true \ + TARGET="$(TARGETPREFIX)$*$(TARGETSUFFIX)" INTERFACEDIR="$(INTERFACEDIR)" INTERFACE="$*.i" \ + $(LANGUAGE)$(VARIANT)_nocgo; \ + $(run_testcase); \ + fi %.multicpptest: $(setup) +$(swig_and_compile_multi_cpp) $(run_multi_testcase) +li_windows.cpptest: + # Does not work because go build won't build li_windows.go, + # because file names with "windows" are only built on Windows. + multi_import.multicpptest: $(setup) for f in multi_import_b multi_import_a; do \ @@ -65,6 +90,7 @@ multi_import.multicpptest: go_subdir_import.multicpptest: $(setup) mkdir -p testdir/go_subdir_import/ + mkdir -p gopath/src/testdir/go_subdir_import/ $(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile SRCDIR="$(SRCDIR)" CXXSRCS="$(CXXSRCS)" \ SWIG_LIB="$(SWIG_LIB)" SWIG="$(SWIG)" LIBS='$(LIBS)' \ INTERFACEPATH="$(SRCDIR)$(INTERFACEDIR)go_subdir_import_b.i" \ @@ -80,19 +106,24 @@ go_subdir_import.multicpptest: $(LANGUAGE)$(VARIANT)_cpp; \ done if $(GOGCC); then \ - cp testdir/go_subdir_import/*.@OBJEXT@ .; \ + cp gopath/src/testdir/go_subdir_import/go_subdir_import_b/go_subdir_import_b.a gopath/src/testdir/go_subdir_import/go_subdir_import_b.gox; \ + cp gopath/src/testdir/go_subdir_import/go_subdir_import_b/go_subdir_import_b.a .; \ + cp gopath/src/testdir/go_subdir_import/go_subdir_import_c/go_subdir_import_c.a gopath/src/testdir/go_subdir_import/go_subdir_import_c.gox; \ + cp gopath/src/testdir/go_subdir_import/go_subdir_import_c/go_subdir_import_c.a testdir/go_subdir_import/; \ fi $(run_multi_testcase) # Runs the testcase. run_testcase = \ if test -f $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX); then \ - $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ if $(GOGCC) ; then \ - $(COMPILETOOL) $(GO) -o $*_runme $(SCRIPTPREFIX)$*_runme.@OBJEXT@ $*.@OBJEXT@ $*_wrap.@OBJEXT@; \ - elif $(GO12) || $(GO13); then \ + $(COMPILETOOL) $(GCCGO) -c -g -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ + $(COMPILETOOL) $(GCCGO) -o $*_runme $(SCRIPTPREFIX)$*_runme.@OBJEXT@ $*.a; \ + elif $(GO12) || $(GO13) || $(GO15); then \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ $(COMPILETOOL) $(GOTOOL) $(GOLD) -linkmode external -extld $(CC) -extldflags "$(CFLAGS)" -o $*_runme $(SCRIPTPREFIX)$*_runme.$(GOOBJEXT); \ else \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ $(COMPILETOOL) $(GOTOOL) $(GOLD) -L . -r $${GOROOT:-`go env GOROOT`}/pkg/$${GOOS:-`go env GOOS`}_$${GOARCH:-`go env GOARCH`}:. -o $*_runme $(SCRIPTPREFIX)$*_runme.$(GOOBJEXT); \ fi && \ env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH $(RUNTOOL) ./$*_runme; \ @@ -100,12 +131,14 @@ run_testcase = \ run_testcase_cpp = \ if test -f $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX); then \ - $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ if $(GOGCC) ; then \ - $(COMPILETOOL) $(GO) -o $*_runme $(SCRIPTPREFIX)$*_runme.@OBJEXT@ $*.@OBJEXT@ $*_wrap.@OBJEXT@ -lstdc++; \ - elif $(GO12) || $(GO13); then \ + $(COMPILETOOL) $(GCCGO) -c -g -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ + $(COMPILETOOL) $(GCCGO) -o $*_runme $(SCRIPTPREFIX)$*_runme.@OBJEXT@ $*.a -lstdc++; \ + elif $(GO12) || $(GO13) || $(GO15); then \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ $(COMPILETOOL) $(GOTOOL) $(GOLD) -linkmode external -extld $(CXX) -extldflags "$(CXXFLAGS)" -o $*_runme $(SCRIPTPREFIX)$*_runme.$(GOOBJEXT); \ else \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ $(COMPILETOOL) $(GOTOOL) $(GOLD) -L . -r $${GOROOT:-`go env GOROOT`}/pkg/$${GOOS:-`go env GOOS`}_$${GOARCH:-`go env GOARCH`}:. -o $*_runme $(SCRIPTPREFIX)$*_runme.$(GOOBJEXT); \ fi && \ env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH $(RUNTOOL) ./$*_runme; \ @@ -113,29 +146,38 @@ run_testcase_cpp = \ run_multi_testcase = \ if test -f $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX); then \ - $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ if $(GOGCC) ; then \ + $(COMPILETOOL) $(GCCGO) -c -g -I . -I gopath/src $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ files=`cat $(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$*.list`; \ - $(COMPILETOOL) $(GO) -o $*_runme $(SCRIPTPREFIX)$*_runme.@OBJEXT@ `for f in $$files; do echo $$f.@OBJEXT@ $${f}_wrap.@OBJEXT@; done` -lstdc++; \ - elif $(GO12) || $(GO13); then \ + $(COMPILETOOL) $(GCCGO) -o $*_runme $(SCRIPTPREFIX)$*_runme.@OBJEXT@ `for f in $$files; do echo $$f.a; done` -lstdc++; \ + elif $(GO12) || $(GO13) || $(GO15); then \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ $(COMPILETOOL) $(GOTOOL) $(GOLD) -L . -linkmode external -extld $(CXX) -extldflags "$(CXXFLAGS)" -o $*_runme $(SCRIPTPREFIX)$*_runme.$(GOOBJEXT); \ else \ + $(COMPILETOOL) $(GO) $(GOCOMPILEARG) -I . $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) && \ $(COMPILETOOL) $(GOTOOL) $(GOLD) -L . -r $${GOROOT:-`go env GOROOT`}/pkg/$${GOOS:-`go env GOOS`}_$${GOARCH:-`go env GOARCH`}:. -o $*_runme $(SCRIPTPREFIX)$*_runme.$(GOOBJEXT); \ fi && \ env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH $(RUNTOOL) ./$*_runme; \ fi %.clean: - @rm -f $*.go $*_gc.c $*_wrap.* $*_runme + @rm -rf $*.go $*_gc.c $*_wrap.* $*_runme $*.gox $*.a clean: $(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile SRCDIR="$(SRCDIR)" go_clean - rm -f mod_a.go mod_b.go imports_a.go imports_b.go - rm -f clientdata_prop_a.go clientdata_prop_b.go - rm -f multi_import_a.go multi_import_b.go - rm -rf go_subdir_import_a.go testdir - rm -f packageoption_a.go packageoption_b.go packageoption_c.go - rm -f import_stl_a.go import_stl_b.go + rm -f mod_a.go mod_a.gox mod_b.go mod_b.gox + rm -f imports_a.go imports_a.gox imports_b.go imports_b.gox + rm -f clientdata_prop_a.go clientdata_prop_a.gox + rm -f clientdata_prop_b.go clientdata_prop_b.gox + rm -f multi_import_a.go multi_import_a.gox + rm -f multi_import_b.go multi_import_b.gox + rm -rf go_subdir_import_a.go go_subdir_import_a.gox testdir + rm -f packageoption_a.go packageoption_a.gox + rm -f packageoption_b.go packageoption_b.gox + rm -f packageoption_c.go packageoption_c.gox + rm -f import_stl_a.go import_stl_a.gox + rm -f import_stl_b.go import_stl_b.gox + rm -rf gopath cvsignore: @echo '*_gc.c *_wrap.* *.so *.dll *.exp *.lib' diff --git a/Examples/test-suite/go_subdir_import_a.i b/Examples/test-suite/go_subdir_import_a.i index 72b28786e..3fc36e6f9 100644 --- a/Examples/test-suite/go_subdir_import_a.i +++ b/Examples/test-suite/go_subdir_import_a.i @@ -20,12 +20,12 @@ %{ class ObjC { public: - int getInt() const; + virtual int getInt() const; }; class ObjB { public: - int getInt() const; + virtual int getInt() const; }; %} diff --git a/Examples/test-suite/go_subdir_import_b.i b/Examples/test-suite/go_subdir_import_b.i index b87f7cf3c..42544822e 100644 --- a/Examples/test-suite/go_subdir_import_b.i +++ b/Examples/test-suite/go_subdir_import_b.i @@ -4,7 +4,7 @@ %inline %{ class ObjB { public: - int getInt() const { + virtual int getInt() const { return 27; } }; diff --git a/Examples/test-suite/testdir/go_subdir_import/go_subdir_import_c.i b/Examples/test-suite/testdir/go_subdir_import/go_subdir_import_c.i index 2c2c2e1fe..dff269c3f 100644 --- a/Examples/test-suite/testdir/go_subdir_import/go_subdir_import_c.i +++ b/Examples/test-suite/testdir/go_subdir_import/go_subdir_import_c.i @@ -4,7 +4,7 @@ %inline %{ class ObjC { public: - int getInt() const { + virtual int getInt() const { return 18; } }; diff --git a/Lib/go/go.swg b/Lib/go/go.swg index d38623b4a..35f914c5b 100644 --- a/Lib/go/go.swg +++ b/Lib/go/go.swg @@ -533,7 +533,7 @@ %typemap(directorin) enum SWIGTYPE & (intgo e) %{ e = (intgo)$1; - $input = &e; + $input = ($1_ltype)&e; %} %typemap(godirectorin) enum SWIGTYPE & "" diff --git a/Lib/go/goruntime.swg b/Lib/go/goruntime.swg index f76da9c78..d776e414a 100644 --- a/Lib/go/goruntime.swg +++ b/Lib/go/goruntime.swg @@ -19,21 +19,45 @@ static void Swig_free(void* p) { %} +#if SWIGGO_CGO +%insert(cgo_comment_typedefs) %{ +#include+%} +#endif + #if SWIGGO_INTGO_SIZE == 32 %insert(runtime) %{ typedef int intgo; typedef unsigned int uintgo; %} +#if SWIGGO_CGO +%insert(cgo_comment_typedefs) %{ +typedef int intgo; +typedef unsigned int uintgo; +%} +#endif #elif SWIGGO_INTGO_SIZE == 64 %insert(runtime) %{ typedef long long intgo; typedef unsigned long long uintgo; %} +#if SWIGGO_CGO +%insert(cgo_comment_typedefs) %{ +typedef long long intgo; +typedef unsigned long long uintgo; +%} +#endif #else %insert(runtime) %{ typedef ptrdiff_t intgo; typedef size_t uintgo; %} +#if SWIGGO_CGO +%insert(cgo_comment_typedefs) %{ +typedef ptrdiff_t intgo; +typedef size_t uintgo; +%} +#endif #endif %insert(runtime) %{ @@ -43,6 +67,17 @@ typedef struct { void* array; intgo len; intgo cap; } _goslice_; %} +#ifdef SWIGGO_CGO + +%insert(cgo_comment_typedefs) %{ + +typedef struct { char *p; intgo n; } _gostring_; +typedef struct { void* array; intgo len; intgo cap; } _goslice_; + +%} + +#endif + #ifndef SWIGGO_GCCGO /* Boilerplate for C/C++ code when using 6g/8g. This code is compiled with gcc. */ @@ -98,6 +133,8 @@ static void _swig_gopanic(const char *p) { %} +#if !SWIGGO_CGO + /* Boilerplate for C code when using 6g/8g. This code is compiled with 6c/8c. */ %insert(gc_header) %{ @@ -111,6 +148,8 @@ void *·_cgo_runtime_cgocall = &cgocall; %} +#endif + #else /* Boilerplate for C/C++ code when using gccgo. */ @@ -122,6 +161,17 @@ extern "C" { #endif extern void *_cgo_allocate(size_t); extern void _cgo_panic(const char *); +#ifdef __cplusplus +} +#endif + +#define _swig_goallocate _cgo_allocate +#define _swig_gopanic _cgo_panic +%} + +#if !SWIGGO_CGO + +%insert(runtime) %{ /* Implementations of SwigCgocall and friends for different versions of gccgo. The Go code will call these functions using C names with @@ -130,6 +180,10 @@ extern void _cgo_panic(const char *); version. We assume that the version of gcc used to compile this file is the same as the version of gccgo. */ +#ifdef __cplusplus +extern "C" { +#endif + #define SWIG_GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) @@ -184,13 +238,12 @@ void SwigCgocallBackDone() { } #endif -#define _swig_goallocate _cgo_allocate -#define _swig_gopanic _cgo_panic - %} #endif +#endif + %insert(runtime) %{ static _gostring_ _swig_makegostring(const char *p, size_t l) { @@ -209,9 +262,11 @@ static _gostring_ _swig_makegostring(const char *p, size_t l) { %go_import("unsafe", _ "runtime/cgo") +#if !SWIGGO_CGO %insert(go_header) %{ var _cgo_runtime_cgocall func(unsafe.Pointer, uintptr) %} +#endif #else @@ -231,6 +286,8 @@ type _ unsafe.Pointer %} +#if !SWIGGO_CGO + /* Swig_always_false is used to conditionally assign parameters to Swig_escape_val so that the compiler thinks that they escape. We only assign them if Swig_always_false is true, which it never is. @@ -241,6 +298,8 @@ var Swig_escape_always_false bool var Swig_escape_val interface{} %} +#endif + /* Function pointers are translated by the code in go.cxx into _swig_fnptr. Member pointers are translated to _swig_memberptr. */ diff --git a/Source/Modules/go.cxx b/Source/Modules/go.cxx index 92d857c56..0d349bd22 100644 --- a/Source/Modules/go.cxx +++ b/Source/Modules/go.cxx @@ -115,6 +115,8 @@ class GO:public Language { String *package; // SWIG module name. String *module; + // Flag for generating cgo input files. + bool cgo_flag; // Flag for generating gccgo output. bool gccgo_flag; // Prefix to use with gccgo. @@ -150,6 +152,8 @@ class GO:public Language { File *f_gc_runtime; File *f_gc_header; File *f_gc_wrappers; + File *f_cgo_comment; + File *f_cgo_comment_typedefs; // True if we imported a module. bool saw_import; @@ -195,6 +199,7 @@ class GO:public Language { public: GO():package(NULL), module(NULL), + cgo_flag(false), gccgo_flag(false), go_prefix(NULL), prefix_option(NULL), @@ -219,6 +224,8 @@ public: f_gc_runtime(NULL), f_gc_header(NULL), f_gc_wrappers(NULL), + f_cgo_comment(NULL), + f_cgo_comment_typedefs(NULL), saw_import(false), imported_package(NULL), interfaces(NULL), @@ -231,7 +238,8 @@ public: undefined_enum_types(NULL), undefined_types(NULL), defined_types(NULL), - go_imports(NULL) { + go_imports(NULL), + unique_id(NULL) { director_multiple_inheritance = 1; director_language = 1; director_prot_ctor_code = NewString("_swig_gopanic(\"accessing abstract class or protected constructor\");"); @@ -258,6 +266,9 @@ private: } else { Swig_arg_error(); } + } else if (strcmp(argv[i], "-cgo") == 0) { + Swig_mark_arg(i); + cgo_flag = true; } else if (strcmp(argv[i], "-gccgo") == 0) { Swig_mark_arg(i); gccgo_flag = true; @@ -327,6 +338,10 @@ private: // Add preprocessor symbol to parser. Preprocessor_define("SWIGGO 1", 0); + if (cgo_flag) { + Preprocessor_define("SWIGGO_CGO 1", 0); + } + if (gccgo_flag) { Preprocessor_define("SWIGGO_GCCGO 1", 0); } @@ -474,7 +489,7 @@ private: SWIG_exit(EXIT_FAILURE); } - if (!gccgo_flag) { + if (!gccgo_flag && !cgo_flag) { f_gc_begin = NewFile(gc_filename, "w", SWIG_output_files()); if (!f_gc_begin) { FileErrorDisplay(gc_filename); @@ -492,11 +507,15 @@ private: f_go_header = NewString(""); f_go_wrappers = NewString(""); f_go_directors = NewString(""); - if (!gccgo_flag) { + if (!gccgo_flag && !cgo_flag) { f_gc_runtime = NewString(""); f_gc_header = NewString(""); f_gc_wrappers = NewString(""); } + if (cgo_flag) { + f_cgo_comment = NewString(""); + f_cgo_comment_typedefs = NewString(""); + } Swig_register_filebyname("begin", f_c_begin); Swig_register_filebyname("runtime", f_c_runtime); @@ -511,12 +530,16 @@ private: Swig_register_filebyname("go_header", f_go_header); Swig_register_filebyname("go_wrapper", f_go_wrappers); Swig_register_filebyname("go_director", f_go_directors); - if (!gccgo_flag) { + if (!gccgo_flag && !cgo_flag) { Swig_register_filebyname("gc_begin", f_gc_begin); Swig_register_filebyname("gc_runtime", f_gc_runtime); Swig_register_filebyname("gc_header", f_gc_header); Swig_register_filebyname("gc_wrapper", f_gc_wrappers); } + if (cgo_flag) { + Swig_register_filebyname("cgo_comment", f_cgo_comment); + Swig_register_filebyname("cgo_comment_typedefs", f_cgo_comment_typedefs); + } Swig_banner(f_c_begin); if (CPlusPlus) { @@ -549,18 +572,28 @@ private: Swig_banner(f_go_begin); Printf(f_go_begin, "\n// source: %s\n", swig_filename); - if (!gccgo_flag && soname) { + if (!gccgo_flag && !cgo_flag && soname) { Swig_banner(f_gc_begin); Printf(f_gc_begin, "\n/* source: %s */\n\n", swig_filename); Printf(f_gc_begin, "\n/* This file should be compiled with 6c/8c. */\n"); Printf(f_gc_begin, "#pragma dynimport _ _ \"%s\"\n", soname); } + if (cgo_flag) { + Printv(f_cgo_comment_typedefs, "/*\n", NULL); + + // The cgo program defines the intgo type after our function + // definitions, but we want those definitions to be able to use + // intgo also. + Printv(f_cgo_comment_typedefs, "#define intgo swig_intgo\n", NULL); + Printv(f_cgo_comment_typedefs, "typedef void *swig_voidp;\n", NULL); + } + // Output module initialization code. Printf(f_go_begin, "\npackage %s\n\n", getModuleName(package)); - if (gccgo_flag) { + if (gccgo_flag && !cgo_flag) { Printf(f_go_runtime, "func SwigCgocall()\n"); Printf(f_go_runtime, "func SwigCgocallDone()\n"); Printf(f_go_runtime, "func SwigCgocallBack()\n"); @@ -632,9 +665,21 @@ private: // End the extern "C". Printv(f_c_wrappers, "#ifdef __cplusplus\n", "}\n", "#endif\n\n", NULL); + if (cgo_flag) { + // End the cgo comment. + Printv(f_cgo_comment, "#undef intgo\n", NULL); + Printv(f_cgo_comment, "*/\n", NULL); + Printv(f_cgo_comment, "import \"C\"\n", NULL); + Printv(f_cgo_comment, "\n", NULL); + } + Dump(f_c_runtime, f_c_begin); Dump(f_c_wrappers, f_c_begin); Dump(f_c_init, f_c_begin); + if (cgo_flag) { + Dump(f_cgo_comment_typedefs, f_go_begin); + Dump(f_cgo_comment, f_go_begin); + } Dump(f_go_imports, f_go_begin); Dump(f_go_header, f_go_begin); Dump(f_go_runtime, f_go_begin); @@ -642,7 +687,7 @@ private: if (directorsEnabled()) { Dump(f_go_directors, f_go_begin); } - if (!gccgo_flag) { + if (!gccgo_flag && !cgo_flag) { Dump(f_gc_header, f_gc_begin); Dump(f_gc_runtime, f_gc_begin); Dump(f_gc_wrappers, f_gc_begin); @@ -657,15 +702,19 @@ private: Delete(f_go_header); Delete(f_go_wrappers); Delete(f_go_directors); - if (!gccgo_flag) { + if (!gccgo_flag && !cgo_flag) { Delete(f_gc_runtime); Delete(f_gc_header); Delete(f_gc_wrappers); } + if (cgo_flag) { + Delete(f_cgo_comment); + Delete(f_cgo_comment_typedefs); + } Delete(f_c_begin); Delete(f_go_begin); - if (!gccgo_flag) { + if (!gccgo_flag && !cgo_flag) { Delete(f_gc_begin); } @@ -945,24 +994,33 @@ private: assert(result); - int r = goFunctionWrapper(n, name, go_name, overname, wname, base, parms, result, is_static); - if (r != SWIG_OK) { - return r; - } + int ret = SWIG_OK; - if (!gccgo_flag) { - r = gcFunctionWrapper(wname); + if (cgo_flag) { + int r = makeCgoWrappers(n, go_name, overname, wname, base, parms, result, is_static); if (r != SWIG_OK) { - return r; - } - r = gccFunctionWrapper(n, base, wname, parms, result); - if (r != SWIG_OK) { - return r; + ret = r; } } else { - r = gccgoFunctionWrapper(n, base, wname, parms, result); + int r = goFunctionWrapper(n, name, go_name, overname, wname, base, parms, result, is_static); if (r != SWIG_OK) { - return r; + ret = r; + } + + if (!gccgo_flag) { + r = gcFunctionWrapper(wname); + if (r != SWIG_OK) { + ret = r; + } + r = gccFunctionWrapper(n, base, wname, parms, result); + if (r != SWIG_OK) { + ret = r; + } + } else { + r = gccgoFunctionWrapper(n, base, wname, parms, result); + if (r != SWIG_OK) { + ret = r; + } } } @@ -970,6 +1028,556 @@ private: Setattr(class_methods, Getattr(n, "name"), NewString("")); } + return ret; + } + + /* ---------------------------------------------------------------------- + * struct cgoWrapperInfo + * + * Information needed by the CGO wrapper functions. + * ---------------------------------------------------------------------- */ + + struct cgoWrapperInfo { + // The function we are generating code for. + Node *n; + // The name of the Go function. + String *go_name; + // The overload string for an overloaded function. + String *overname; + // The name of the C wrapper function. + String *wname; + // The base classes. + List *base; + // The parameters. + ParmList *parms; + // The result type. + SwigType *result; + // Whether this is a static function, not a class method. + bool is_static; + // The Go receiver type. + String *receiver; + // Whether this is a class constructor. + bool is_constructor; + // Whether this is a class destructor. + bool is_destructor; + }; + + /* ---------------------------------------------------------------------- + * makeCgoWrappers() + * + * Write out the wrappers for a function when producing cgo input + * files. + * ---------------------------------------------------------------------- */ + + int makeCgoWrappers(Node *n, String *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static) { + Swig_save("makeCgoWrappers", n, "emit:cgotype", "emit:cgotypestruct", NULL); + + cgoWrapperInfo info; + + info.n = n; + info.go_name = go_name; + info.overname = overname; + info.wname = wname; + info.base = base; + info.parms = parms; + info.result = result; + info.is_static = is_static; + + info.receiver = class_receiver; + if (is_static) { + info.receiver = NULL; + } + + String *nodetype = Getattr(n, "nodeType"); + info.is_constructor = Cmp(nodetype, "constructor") == 0; + info.is_destructor = Cmp(nodetype, "destructor") == 0; + if (info.is_constructor || info.is_destructor) { + assert(class_receiver); + assert(!base); + info.receiver = NULL; + } + + int ret = SWIG_OK; + + int r = cgoGoWrapper(&info); + if (r != SWIG_OK) { + ret = r; + } + + r = cgoCommentWrapper(&info); + if (r != SWIG_OK) { + ret = r; + } + + r = cgoGccWrapper(&info); + if (r != SWIG_OK) { + ret = r; + } + + Swig_restore(n); + + return ret; + } + + /* ---------------------------------------------------------------------- + * cgoGoWrapper() + * + * Write out Go code to call a cgo function. This code will go into + * the generated Go output file. + * ---------------------------------------------------------------------- */ + int cgoGoWrapper(const cgoWrapperInfo *info) { + + Wrapper *dummy = initGoTypemaps(info->parms); + + bool add_to_interface = interfaces && !info->is_constructor && !info->is_destructor && !info->is_static && !info->overname && checkFunctionVisibility(info->n, NULL); + + Printv(f_go_wrappers, "func ", NULL); + + Parm *p = info->parms; + int pi = 0; + + // Add the receiver first if this is a method. + if (info->receiver) { + Printv(f_go_wrappers, "(", NULL); + if (info->base && info->receiver) { + Printv(f_go_wrappers, "_swig_base", NULL); + } else { + Printv(f_go_wrappers, Getattr(p, "lname"), NULL); + p = nextParm(p); + ++pi; + } + Printv(f_go_wrappers, " ", info->receiver, ") ", NULL); + } + + Printv(f_go_wrappers, info->go_name, NULL); + if (info->overname) { + Printv(f_go_wrappers, info->overname, NULL); + } + Printv(f_go_wrappers, "(", NULL); + + // If we are doing methods, add this method to the interface. + if (add_to_interface) { + Printv(interfaces, "\t", info->go_name, "(", NULL); + } + + // Write out the parameters to both the function definition and + // the interface. + + String *parm_print = NewString(""); + + int parm_count = emit_num_arguments(info->parms); + int required_count = emit_num_required(info->parms); + int args = 0; + + for (; pi < parm_count; ++pi) { + p = getParm(p); + if (pi == 0 && info->is_destructor) { + String *cl = exportedName(class_name); + Printv(parm_print, Getattr(p, "lname"), " ", cl, NULL); + Delete(cl); + ++args; + } else { + if (args > 0) { + Printv(parm_print, ", ", NULL); + } + ++args; + if (pi >= required_count) { + Printv(parm_print, "_swig_args ...interface{}", NULL); + break; + } + Printv(parm_print, Getattr(p, "lname"), " ", NULL); + String *tm = goType(p, Getattr(p, "type")); + Printv(parm_print, tm, NULL); + Delete(tm); + } + p = nextParm(p); + } + + Printv(parm_print, ")", NULL); + + // Write out the result type. + if (info->is_constructor) { + String *cl = exportedName(class_name); + Printv(parm_print, " (_swig_ret ", cl, ")", NULL); + Delete(cl); + } else { + if (SwigType_type(info->result) != T_VOID) { + String *tm = goType(info->n, info->result); + Printv(parm_print, " (_swig_ret ", tm, ")", NULL); + Delete(tm); + } + } + + Printv(f_go_wrappers, parm_print, NULL); + if (add_to_interface) { + Printv(interfaces, parm_print, "\n", NULL); + } + + // Write out the function body. + + Printv(f_go_wrappers, " {\n", NULL); + + if (parm_count > required_count) { + Parm *p = info->parms; + int i; + for (i = 0; i < required_count; ++i) { + p = getParm(p); + p = nextParm(p); + } + for (; i < parm_count; ++i) { + p = getParm(p); + String *tm = goType(p, Getattr(p, "type")); + Printv(f_go_wrappers, "\tvar ", Getattr(p, "lname"), " ", tm, "\n", NULL); + Printf(f_go_wrappers, "\tif len(_swig_args) > %d {\n", i - required_count); + Printf(f_go_wrappers, "\t\t%s = _swig_args[%d].(%s)\n", Getattr(p, "lname"), i - required_count, tm); + Printv(f_go_wrappers, "\t}\n", NULL); + Delete(tm); + p = nextParm(p); + } + } + + String *call = NewString("\t"); + + String *ret_type = NULL; + bool memcpy_ret = false; + String *wt = NULL; + if (SwigType_type(info->result) != T_VOID) { + if (info->is_constructor) { + ret_type = exportedName(class_name); + } else { + ret_type = goImType(info->n, info->result); + } + Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); + + bool c_struct_type; + Delete(cgoTypeForGoValue(info->n, info->result, &c_struct_type)); + if (c_struct_type) { + memcpy_ret = true; + } + + if (memcpy_ret) { + Printv(call, "swig_r_p := ", NULL); + } else { + Printv(call, "swig_r = (", ret_type, ")(", NULL); + } + + if (info->is_constructor || goTypeIsInterface(info->n, info->result)) { + if (info->is_constructor) { + wt = Copy(class_receiver); + } else { + wt = goWrapperType(info->n, info->result, true); + } + Printv(call, wt, "(", NULL); + } + } + + Printv(call, "C.", info->wname, "(", NULL); + + args = 0; + + if (parm_count > required_count) { + Printv(call, "C.swig_intgo(len(_swig_args))", NULL); + ++args; + } + + if (info->base && info->receiver) { + if (args > 0) { + Printv(call, ", ", NULL); + } + ++args; + Printv(call, "C.uintptr_t(_swig_base)", NULL); + } + + p = info->parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (args > 0) { + Printv(call, ", ", NULL); + } + ++args; + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + String *ivar = NewStringf("_swig_i_%d", i); + + String *goin = goGetattr(p, "tmap:goin"); + if (goin == NULL) { + Printv(f_go_wrappers, "\t", ivar, " := ", ln, NULL); + if ((i == 0 && info->is_destructor) || ((i > 0 || !info->receiver || info->base || info->is_constructor) && goTypeIsInterface(p, pt))) { + Printv(f_go_wrappers, ".Swigcptr()", NULL); + } + Printv(f_go_wrappers, "\n", NULL); + Setattr(p, "emit:goinput", ln); + } else { + String *itm = goImType(p, pt); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); + goin = Copy(goin); + Replaceall(goin, "$input", ln); + Replaceall(goin, "$result", ivar); + Printv(f_go_wrappers, goin, "\n", NULL); + Delete(goin); + Setattr(p, "emit:goinput", ivar); + } + + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + if (c_struct_type) { + Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); + } else { + Printv(call, "C.", ct, "(", ivar, ")", NULL); + } + Delete(ct); + + p = nextParm(p); + } + + Printv(f_go_wrappers, call, ")", NULL); + Delete(call); + + if (wt) { + // Close the type conversion to the wrapper type. + Printv(f_go_wrappers, ")", NULL); + } + if (SwigType_type(info->result) != T_VOID && !memcpy_ret) { + // Close the type conversion of the return value. + Printv(f_go_wrappers, ")", NULL); + } + + Printv(f_go_wrappers, "\n", NULL); + + if (memcpy_ret) { + Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); + } + if (ret_type) { + Delete(ret_type); + } + + goargout(info->parms, parm_count); + + if (SwigType_type(info->result) != T_VOID) { + String *goout = goTypemapLookup("goout", info->n, "swig_r"); + if (goout == NULL) { + Printv(f_go_wrappers, "\treturn swig_r\n", NULL); + } else { + String *tm = goType(info->n, info->result); + Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); + goout = Copy(goout); + Replaceall(goout, "$input", "swig_r"); + Replaceall(goout, "$result", "swig_r_1"); + Printv(f_go_wrappers, goout, "\n", NULL); + Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); + } + } + + Printv(f_go_wrappers, "}\n\n", NULL); + + DelWrapper(dummy); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * cgoCommentWrapper() + * + * Write out a cgo function to call a C/C++ function. This code + * will go into the cgo comment in the generated Go output file. + * ---------------------------------------------------------------------- */ + int cgoCommentWrapper(const cgoWrapperInfo *info) { + String *ret_type; + if (SwigType_type(info->result) == T_VOID) { + ret_type = NewString("void"); + } else { + bool c_struct_type; + ret_type = cgoTypeForGoValue(info->n, info->result, &c_struct_type); + } + + Printv(f_cgo_comment, "extern ", ret_type, " ", info->wname, "(", NULL); + + Delete(ret_type); + + int parm_count = emit_num_arguments(info->parms); + int required_count = emit_num_required(info->parms); + int args = 0; + + if (parm_count > required_count) { + Printv(f_cgo_comment, "intgo _swig_args", NULL); + ++args; + } + + if (info->base && info->receiver) { + if (args > 0) { + Printv(f_cgo_comment, ", ", NULL); + } + ++args; + Printv(f_cgo_comment, "uintptr_t _swig_base", NULL); + } + + Parm *p = info->parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (args > 0) { + Printv(f_cgo_comment, ", ", NULL); + } + ++args; + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + Printv(f_cgo_comment, ct, " ", ln, NULL); + Delete(ct); + + p = nextParm(p); + } + + if (args == 0) { + Printv(f_cgo_comment, "void", NULL); + } + + Printv(f_cgo_comment, ");\n", NULL); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * cgoGccWrapper() + * + * Write out code to the C/C++ wrapper file. This code will be + * called by the code generated by cgoCommentWrapper. + * ---------------------------------------------------------------------- */ + int cgoGccWrapper(const cgoWrapperInfo *info) { + Wrapper *f = NewWrapper(); + + Swig_save("cgoGccWrapper", info->n, "parms", NULL); + + ParmList *parms = info->parms; + + Parm *base_parm = NULL; + if (info->base && !isStatic(info->n)) { + SwigType *base_type = Copy(getClassType()); + SwigType_add_pointer(base_type); + base_parm = NewParm(base_type, NewString("arg1"), info->n); + set_nextSibling(base_parm, parms); + parms = base_parm; + } + + emit_parameter_variables(parms, f); + emit_attach_parmmaps(parms, f); + int parm_count = emit_num_arguments(parms); + int required_count = emit_num_required(parms); + + emit_return_variable(info->n, info->result, f); + + // Start the function definition. + + String *fnname = NewString(""); + Printv(fnname, info->wname, "(", NULL); + + int args = 0; + + if (parm_count > required_count) { + Printv(fnname, "intgo _swig_optargc", NULL); + ++args; + } + + Parm *p = parms; + for (int i = 0; i < parm_count; ++i) { + if (args > 0) { + Printv(fnname, ", ", NULL); + } + ++args; + + p = getParm(p); + + SwigType *pt = Copy(Getattr(p, "type")); + if (SwigType_isarray(pt)) { + SwigType_del_array(pt); + SwigType_add_pointer(pt); + } + String *pn = NewStringf("_swig_go_%d", i); + String *ct = gcCTypeForGoValue(p, pt, pn); + Printv(fnname, ct, NULL); + Delete(ct); + Delete(pn); + Delete(pt); + + p = nextParm(p); + } + + Printv(fnname, ")", NULL); + + if (SwigType_type(info->result) == T_VOID) { + Printv(f->def, "void ", fnname, NULL); + } else { + String *ct = gcCTypeForGoValue(info->n, info->result, fnname); + Printv(f->def, ct, NULL); + Delete(ct); + + String *ln = NewString("_swig_go_result"); + ct = gcCTypeForGoValue(info->n, info->result, ln); + Wrapper_add_local(f, "_swig_go_result", ct); + Delete(ct); + Delete(ln); + } + + Delete(fnname); + + Printv(f->def, " {\n", NULL); + + // Apply the in typemaps. + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *tm = Getattr(p, "tmap:in"); + if (!tm) { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "unable to use type %s as a function argument\n", SwigType_str(Getattr(p, "type"), 0)); + } else { + tm = Copy(tm); + String *pn = NewStringf("_swig_go_%d", i); + Replaceall(tm, "$input", pn); + if (i < required_count) { + Printv(f->code, "\t", tm, "\n", NULL); + } else { + Printf(f->code, "\tif (_swig_optargc > %d) {\n", i - required_count); + Printv(f->code, "\t\t", tm, "\n", NULL); + Printv(f->code, "\t}\n", NULL); + } + Delete(tm); + Setattr(p, "emit:input", pn); + } + p = nextParm(p); + } + + Printv(f->code, "\n", NULL); + + // Do the real work of the function. + + checkConstraints(parms, f); + + emitGoAction(info->n, info->base, parms, info->result, f); + + argout(parms, f); + + cleanupFunction(info->n, f, parms); + + if (SwigType_type(info->result) != T_VOID) { + Printv(f->code, "\treturn _swig_go_result;\n", NULL); + } + + Printv(f->code, "}\n", NULL); + + Wrapper_print(f, f_c_wrappers); + + Swig_restore(info->n); + + DelWrapper(f); + if (base_parm) { + Delete(base_parm); + } + return SWIG_OK; } @@ -985,23 +1593,9 @@ private: * ---------------------------------------------------------------------- */ int goFunctionWrapper(Node *n, String *name, String *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static) { - Wrapper *dummy = NewWrapper(); - emit_attach_parmmaps(parms, dummy); + Wrapper *dummy = initGoTypemaps(parms); - Parm *p = parms; int parm_count = emit_num_arguments(parms); - for (int i = 0; i < parm_count; ++i) { - p = getParm(p); - Swig_cparm_name(p, i); - p = nextParm(p); - } - - Swig_typemap_attach_parms("default", parms, dummy); - Swig_typemap_attach_parms("gotype", parms, dummy); - Swig_typemap_attach_parms("goin", parms, dummy); - Swig_typemap_attach_parms("goargout", parms, dummy); - Swig_typemap_attach_parms("imtype", parms, dummy); - int required_count = emit_num_required(parms); String *receiver = class_receiver; @@ -1032,7 +1626,7 @@ private: // See whether any of the function parameters are represented by // interface values. When calling the C++ code, we need to convert // back to a uintptr. - p = parms; + Parm *p = parms; for (int i = 0; i < parm_count; ++i) { p = getParm(p); String *ty = Getattr(p, "type"); @@ -1322,11 +1916,11 @@ private: String *ivar = NewString(""); Printf(ivar, "_swig_i_%d", i); String *itm = goImType(p, pt); - Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, NULL); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); goin = Copy(goin); Replaceall(goin, "$input", ln); Replaceall(goin, "$result", ivar); - Printv(f_go_wrappers, goin, NULL); + Printv(f_go_wrappers, goin, "\n", NULL); Delete(goin); Printv(call, ivar, NULL); Setattr(p, "emit:goinput", ivar); @@ -1391,6 +1985,34 @@ private: return SWIG_OK; } + /* ---------------------------------------------------------------------- + * initGoTypemaps() + * + * Initialize the typenames for a Go wrapper, returning a dummy + * Wrapper*. Also set consistent names for the parameters. + * ---------------------------------------------------------------------- */ + + Wrapper* initGoTypemaps(ParmList *parms) { + Wrapper *dummy = NewWrapper(); + emit_attach_parmmaps(parms, dummy); + + Parm *p = parms; + int parm_count = emit_num_arguments(parms); + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + Swig_cparm_name(p, i); + p = nextParm(p); + } + + Swig_typemap_attach_parms("default", parms, dummy); + Swig_typemap_attach_parms("gotype", parms, dummy); + Swig_typemap_attach_parms("goin", parms, dummy); + Swig_typemap_attach_parms("goargout", parms, dummy); + Swig_typemap_attach_parms("imtype", parms, dummy); + + return dummy; + } + /* ---------------------------------------------------------------------- * argName() * @@ -1771,7 +2393,7 @@ private: * ----------------------------------------------------------------------- */ void emitGoAction(Node *n, List *base, ParmList *parms, SwigType *result, Wrapper *f) { - if (!gccgo_flag && SwigType_type(result) != T_VOID) { + if (!gccgo_flag && !cgo_flag && SwigType_type(result) != T_VOID) { Wrapper_add_local(f, "swig_stktop", "char *swig_stktop"); Printv(f->code, "\tswig_stktop = _swig_topofstack();\n", NULL); } @@ -1784,7 +2406,7 @@ private: actioncode = NewString(""); String *current = NewString(""); - if (!gccgo_flag) { + if (!gccgo_flag && !cgo_flag) { Printv(current, "swig_a->", NULL); } Printv(current, Getattr(parms, "lname"), NULL); @@ -1821,7 +2443,7 @@ private: Delete(tm); } - if (!gccgo_flag && SwigType_type(result) != T_VOID) { + if (!gccgo_flag && !cgo_flag && SwigType_type(result) != T_VOID) { // If the function called back into the Go code, the stack might // have been copied. We need to adjust swig_a accordingly here. // This is what cgo does. @@ -2896,6 +3518,11 @@ private: } } + String *fn_with_over_name = Copy(fn_name); + if (overname) { + Append(fn_with_over_name, overname); + } + String *wname = Swig_name_wrapper(fn_name); if (overname) { @@ -2935,47 +3562,58 @@ private: } if (!is_ignored) { - // Declare the C++ wrapper. + if (cgo_flag) { + Printv(f_cgo_comment, "extern uintptr_t ", wname, "(int", NULL); - if (!gccgo_flag) { - Printv(f_go_wrappers, "var ", wname, " unsafe.Pointer\n\n", NULL); + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type); + Printv(f_cgo_comment, ", ", ct, " ", Getattr(p, "lname"), NULL); + p = nextParm(p); + } + Printv(f_cgo_comment, ");\n", NULL); } else { - Printv(f_go_wrappers, "//extern ", go_prefix, "_", wname, "\n", NULL); + // Declare the C++ wrapper. + + if (!gccgo_flag) { + Printv(f_go_wrappers, "var ", wname, " unsafe.Pointer\n\n", NULL); + } else { + Printv(f_go_wrappers, "//extern ", go_prefix, "_", wname, "\n", NULL); + } + + Printv(f_go_wrappers, "func ", fn_with_over_name, "(_swig_director int", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *tm = goWrapperType(p, Getattr(p, "type"), false); + Printv(f_go_wrappers, ", _ ", tm, NULL); + Delete(tm); + p = nextParm(p); + } + + Printv(f_go_wrappers, ") (_swig_ret ", go_type_name, ")", NULL); + + if (!gccgo_flag) { + Printv(f_go_wrappers, " {\n", NULL); + Printv(f_go_wrappers, "\t_swig_p := uintptr(unsafe.Pointer(&_swig_director))\n", NULL); + Printv(f_go_wrappers, "\t_cgo_runtime_cgocall(", wname, ", _swig_p)\n", NULL); + Printv(f_go_wrappers, "\treturn\n", NULL); + Printv(f_go_wrappers, "}", NULL); + } + + Printv(f_go_wrappers, "\n\n", NULL); } - Printv(f_go_wrappers, "func ", fn_name, NULL); - if (overname) { - Printv(f_go_wrappers, overname, NULL); - } - Printv(f_go_wrappers, "(_swig_director int", NULL); - - p = parms; - for (int i = 0; i < parm_count; ++i) { - p = getParm(p); - String *tm = goType(p, Getattr(p, "type")); - Printv(f_go_wrappers, ", _ ", tm, NULL); - Delete(tm); - p = nextParm(p); - } - - Printv(f_go_wrappers, ") (_swig_ret ", go_type_name, ")", NULL); - - if (!gccgo_flag) { - Printv(f_go_wrappers, " {\n", NULL); - Printv(f_go_wrappers, "\t_swig_p := uintptr(unsafe.Pointer(&_swig_director))\n", NULL); - Printv(f_go_wrappers, "\t_cgo_runtime_cgocall(", wname, ", _swig_p)\n", NULL); - Printv(f_go_wrappers, "\treturn\n", NULL); - Printv(f_go_wrappers, "}", NULL); - } - - Printv(f_go_wrappers, "\n\n", NULL); + // Write out the Go function that calls the wrapper. Printv(f_go_wrappers, "func ", func_with_over_name, "(v interface{}", NULL); p = parms; for (int i = 0; i < parm_count; ++i) { p = getParm(p); - // Set the lname parameter. Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", NULL); String *tm = goType(p, Getattr(p, "type")); Printv(f_go_wrappers, tm, NULL); @@ -2987,25 +3625,71 @@ private: Printv(f_go_wrappers, "\tp := &", director_struct_name, "{0, v}\n", NULL); - if (gccgo_flag) { + if (gccgo_flag && !cgo_flag) { Printv(f_go_wrappers, "\tdefer SwigCgocallDone()\n", NULL); Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL); } - Printv(f_go_wrappers, "\tp.", class_receiver, " = ", fn_name, NULL); - if (overname) { - Printv(f_go_wrappers, overname, NULL); + String *call = NewString(""); + + Printv(call, "\tp.", class_receiver, " = ", NULL); + if (cgo_flag) { + Printv(call, go_type_name, "(C.", wname, "(C.int(swigDirectorAdd(p))", NULL); + } else { + Printv(call, fn_with_over_name, "(swigDirectorAdd(p)", NULL); } - Printv(f_go_wrappers, "(swigDirectorAdd(p)", NULL); p = parms; for (int i = 0; i < parm_count; ++i) { + Printv(call, ", ", NULL); + p = getParm(p); - Printv(f_go_wrappers, ", ", Getattr(p, "lname"), NULL); + String *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + String *ivar = NewStringf("_swig_i_%d", i); + + String *goin = goGetattr(p, "tmap:goin"); + if (goin == NULL) { + Printv(f_go_wrappers, "\t", ivar, " := ", ln, NULL); + if (goTypeIsInterface(p, pt)) { + Printv(f_go_wrappers, ".Swigcptr()", NULL); + } + Printv(f_go_wrappers, "\n", NULL); + } else { + String *itm = goImType(p, pt); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); + goin = Copy(goin); + Replaceall(goin, "$input", ln); + Replaceall(goin, "$result", ivar); + Printv(f_go_wrappers, goin, "\n", NULL); + Delete(goin); + } + + Setattr(p, "emit:goinput", ivar); + + if (cgo_flag) { + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + if (c_struct_type) { + Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); + } else { + Printv(call, "C.", ct, "(", ivar, ")", NULL); + } + Delete(ct); + } else { + Printv(call, ivar, NULL); + } p = nextParm(p); } - Printv(f_go_wrappers, ")\n", NULL); + Printv(call, ")", NULL); + if (cgo_flag) { + Printv(call, ")", NULL); + } + + Printv(f_go_wrappers, call, "\n", NULL); + Printv(f_go_wrappers, "\treturn p\n", NULL); Printv(f_go_wrappers, "}\n\n", NULL); @@ -3038,7 +3722,26 @@ private: Printv(action, ");", NULL); Setattr(n, "wrap:action", action); - if (!gccgo_flag) { + if (cgo_flag) { + cgoWrapperInfo info; + + info.n = n; + info.go_name = func_name; + info.overname = overname; + info.wname = wname; + info.base = NULL; + info.parms = first_parm; + info.result = result; + info.is_static = false; + info.receiver = NULL; + info.is_constructor = true; + info.is_destructor = false; + + int r = cgoGccWrapper(&info); + if (r != SWIG_OK) { + return r; + } + } else if (!gccgo_flag) { int r = gcFunctionWrapper(wname); if (r != SWIG_OK) { return r; @@ -3101,6 +3804,7 @@ private: Delete(go_type_name); Delete(director_struct_name); Delete(fn_name); + Delete(fn_with_over_name); Delete(func_name); Delete(func_with_over_name); Delete(wname); @@ -3184,18 +3888,9 @@ private: Printv(director_sig, "{\n", NULL); if (!is_ignored) { - makeDirectorDestructorWrapper(go_name, director_sig); + makeDirectorDestructorWrapper(go_name, director_struct_name, director_sig); Printv(f_c_directors, " delete swig_mem;\n", NULL); - - Printv(f_go_wrappers, "func ", go_name, "(c int) {\n", NULL); - if (gccgo_flag) { - Printv(f_go_wrappers, "\tSwigCgocallBack()\n", NULL); - Printv(f_go_wrappers, "\tdefer SwigCgocallBackDone()\n", NULL); - } - Printv(f_go_wrappers, "\tswigDirectorLookup(c).(*", director_struct_name, ").", class_receiver, " = 0\n", NULL); - Printv(f_go_wrappers, "\tswigDirectorDelete(c)\n", NULL); - Printv(f_go_wrappers, "}\n\n", NULL); } Printv(f_c_directors, "}\n\n", NULL); @@ -3216,7 +3911,21 @@ private: * unfinished. * ------------------------------------------------------------ */ - void makeDirectorDestructorWrapper(String *go_name, String *director_sig) { + void makeDirectorDestructorWrapper(String *go_name, String *director_struct_name, String *director_sig) { + if (cgo_flag) { + makeCgoDirectorDestructorWrapper(go_name, director_struct_name, director_sig); + return; + } + + Printv(f_go_wrappers, "func ", go_name, "(c int) {\n", NULL); + if (gccgo_flag) { + Printv(f_go_wrappers, "\tSwigCgocallBack()\n", NULL); + Printv(f_go_wrappers, "\tdefer SwigCgocallBackDone()\n", NULL); + } + Printv(f_go_wrappers, "\tswigDirectorLookup(c).(*", director_struct_name, ").", class_receiver, " = 0\n", NULL); + Printv(f_go_wrappers, "\tswigDirectorDelete(c)\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + String *wname = NewString("_swiggo_wrap_DeleteDirector_"); Append(wname, class_name); @@ -3249,6 +3958,28 @@ private: Delete(wname); } + /* ------------------------------------------------------------ + * makeCgoDirectorDestructorWrapper + * + * When using cgo, emit the function wrapper for the destructor of a + * director class. + * ------------------------------------------------------------ */ + + void makeCgoDirectorDestructorWrapper(String *go_name, String *director_struct_name, String *director_sig) { + String *wname = Copy(go_name); + Append(wname, unique_id); + + Printv(f_go_wrappers, "//export ", wname, "\n", NULL); + Printv(f_go_wrappers, "func ", wname, "(c int) {\n", NULL); + Printv(f_go_wrappers, "\tswigDirectorLookup(c).(*", director_struct_name, ").", class_receiver, " = 0\n", NULL); + Printv(f_go_wrappers, "\tswigDirectorDelete(c)\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + Printv(f_c_directors, "extern \"C\" void ", wname, "(intgo);\n", NULL); + Printv(f_c_directors, director_sig, NULL); + Printv(f_c_directors, " ", wname, "(go_val);\n", NULL); + } + /* ------------------------------------------------------------ * classDirectorMethod * @@ -3404,6 +4135,9 @@ private: if (overname) { Append(callback_name, overname); } + if (cgo_flag) { + Append(callback_name, unique_id); + } String *upcall_name = Copy(director_struct_name); Append(upcall_name, "_upcall_"); @@ -3462,43 +4196,68 @@ private: Printv(f_go_wrappers, "}\n\n", NULL); if (!GetFlag(n, "abstract")) { - // Declare the upcall function, which calls the method on the - // parent class. + if (cgo_flag) { + Printv(f_cgo_comment, "extern ", NULL); - if (!gccgo_flag) { - Printv(f_go_wrappers, "var ", upcall_wname, " unsafe.Pointer\n\n", NULL); + if (SwigType_type(result) == T_VOID) { + Printv(f_cgo_comment, "void", NULL); + } else { + bool c_struct_type; + String *ret_type = cgoTypeForGoValue(n, result, &c_struct_type); + Printv(f_cgo_comment, ret_type, NULL); + Delete(ret_type); + } + + Printv(f_cgo_comment, " ", upcall_wname, "(uintptr_t", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type); + Printv(f_cgo_comment, ", ", ct, " ", Getattr(p, "lname"), NULL); + p = nextParm(p); + } + Printv(f_cgo_comment, ");\n", NULL); } else { - Printv(f_go_wrappers, "//extern ", go_prefix, "_", upcall_wname, "\n", NULL); + // Declare the upcall function, which calls the method on + // the parent class. + + if (!gccgo_flag) { + Printv(f_go_wrappers, "var ", upcall_wname, " unsafe.Pointer\n\n", NULL); + } else { + Printv(f_go_wrappers, "//extern ", go_prefix, "_", upcall_wname, "\n", NULL); + } + + Printv(f_go_wrappers, "func ", upcall_gc_name, "(_swig_ptr ", go_type_name, NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *tm = goWrapperType(p, Getattr(p, "type"), false); + Printv(f_go_wrappers, ", _ ", tm, NULL); + Delete(tm); + p = nextParm(p); + } + + Printv(f_go_wrappers, ")", NULL); + + if (SwigType_type(result) != T_VOID) { + String *tm = goWrapperType(n, result, true); + Printv(f_go_wrappers, " (_swig_ret ", tm, ")", NULL); + Delete(tm); + } + + if (!gccgo_flag) { + Printv(f_go_wrappers, " {\n", NULL); + Printv(f_go_wrappers, "\t_swig_p := uintptr(unsafe.Pointer(&_swig_ptr))\n", NULL); + Printv(f_go_wrappers, "\t_cgo_runtime_cgocall(", upcall_wname, ", _swig_p)\n", NULL); + Printv(f_go_wrappers, "\treturn\n", NULL); + Printv(f_go_wrappers, "}", NULL); + } + + Printv(f_go_wrappers, "\n\n", NULL); } - - Printv(f_go_wrappers, "func ", upcall_gc_name, "(_swig_ptr ", go_type_name, NULL); - - p = parms; - for (int i = 0; i < parm_count; ++i) { - p = getParm(p); - String *tm = goWrapperType(p, Getattr(p, "type"), false); - Printv(f_go_wrappers, ", _ ", tm, NULL); - Delete(tm); - p = nextParm(p); - } - - Printv(f_go_wrappers, ")", NULL); - - if (SwigType_type(result) != T_VOID) { - String *tm = goWrapperType(n, result, true); - Printv(f_go_wrappers, " (_swig_ret ", tm, ")", NULL); - Delete(tm); - } - - if (!gccgo_flag) { - Printv(f_go_wrappers, " {\n", NULL); - Printv(f_go_wrappers, "\t_swig_p := uintptr(unsafe.Pointer(&_swig_ptr))\n", NULL); - Printv(f_go_wrappers, "\t_cgo_runtime_cgocall(", upcall_wname, ", _swig_p)\n", NULL); - Printv(f_go_wrappers, "\treturn\n", NULL); - Printv(f_go_wrappers, "}", NULL); - } - - Printv(f_go_wrappers, "\n\n", NULL); } // Define the method on the director class in Go. @@ -3554,14 +4313,26 @@ private: if (GetFlag(n, "abstract")) { Printv(f_go_wrappers, "\tpanic(\"call to pure virtual method\")\n", NULL); } else { + String *ret_type = NULL; + bool memcpy_ret = false; + String *wt = NULL; bool has_goout = false; String *goout = NULL; if (SwigType_type(result) != T_VOID) { - Printv(f_go_wrappers, "\tvar swig_r ", goImType(n, result), "\n", NULL); + ret_type = goImType(n, result); + Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); goout = goTypemapLookup("goout", n, "swig_r"); if (goout) { has_goout = true; } + + if (cgo_flag) { + bool c_struct_type; + Delete(cgoTypeForGoValue(n, result, &c_struct_type)); + if (c_struct_type) { + memcpy_ret = true; + } + } } p = parms; @@ -3575,7 +4346,7 @@ private: String *call = NewString(""); - if (gccgo_flag) { + if (gccgo_flag && !cgo_flag) { if (has_goout) { Printv(call, "\tfunc() {\n", NULL); } @@ -3585,9 +4356,33 @@ private: Printv(call, "\t", NULL); if (SwigType_type(result) != T_VOID) { - Printv(call, "swig_r = ", NULL); + if (memcpy_ret) { + Printv(call, "swig_r_p := ", NULL); + } else { + Printv(call, "swig_r = ", NULL); + if (cgo_flag) { + Printv(call, "(", ret_type, ")(", NULL); + } + } + if (cgo_flag && goTypeIsInterface(n, result)) { + wt = goWrapperType(n, result, true); + Printv(call, "(", wt, ")(", NULL); + } + } + + if (cgo_flag) { + Printv(call, "C.", upcall_wname, NULL); + } else { + Printv(call, upcall_gc_name, NULL); + } + Printv(call, "(", NULL); + if (cgo_flag) { + Printv(call, "C.uintptr_t(", NULL); + } + Printv(call, "swig_p.", go_type_name, NULL); + if (cgo_flag) { + Printv(call, ")", NULL); } - Printv(call, upcall_gc_name, "(swig_p.", go_type_name, NULL); p = parms; for (int i = 0; i < parm_count; ++i) { @@ -3597,41 +4392,70 @@ private: String *ln = Getattr(p, "lname"); + String *ivar = NewStringf("_swig_i_%d", i); + // This is an ordinary call from Go to C++, so adjust using // the goin typemap. String *goin = goGetattr(p, "tmap:goin"); if (goin == NULL) { - Printv(call, ln, NULL); + Printv(f_go_wrappers, "\t", ivar, " := ", ln, NULL); if (goTypeIsInterface(p, pt)) { - Printv(call, ".Swigcptr()", NULL); + Printv(f_go_wrappers, ".Swigcptr()", NULL); } - Setattr(p, "emit:goinput", ln); + Printv(f_go_wrappers, "\n", NULL); } else { - String *ivar = NewString(""); - Printf(ivar, "_swig_i_%d", i); String *itm = goImType(p, pt); - Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, NULL); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); goin = Copy(goin); Replaceall(goin, "$input", ln); Replaceall(goin, "$result", ivar); Printv(f_go_wrappers, goin, NULL); Delete(goin); + } + + Setattr(p, "emit:goinput", ivar); + + if (cgo_flag) { + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + if (c_struct_type) { + Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); + } else { + Printv(call, "C.", ct, "(", ivar, ")", NULL); + } + } else { Printv(call, ivar, NULL); - Setattr(p, "emit:goinput", ivar); } p = nextParm(p); } - Printv(call, ")\n", NULL); + Printv(call, ")", NULL); - if (gccgo_flag && has_goout) { - Printv(call, "\t}()\n", NULL); + if (gccgo_flag && !cgo_flag && has_goout) { + Printv(call, "\n\t}()", NULL); } + if (cgo_flag) { + if (wt) { + // Close the type conversion to the wrapper type. + Printv(call, ")", NULL); + } + if (SwigType_type(result) != T_VOID && !memcpy_ret) { + // Close the type conversion of the return value. + Printv(call, ")", NULL); + } + } + + Printv(call, "\n", NULL); + Printv(f_go_wrappers, call, NULL); Delete(call); + if (memcpy_ret) { + Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); + } + goargout(parms, parm_count); if (SwigType_type(result) != T_VOID) { @@ -3646,6 +4470,13 @@ private: Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); } } + + if (ret_type) { + Delete(ret_type); + } + if (wt) { + Delete(wt); + } } Printv(f_go_wrappers, "}\n\n", NULL); @@ -3727,7 +4558,26 @@ private: Printv(action, ");", NULL); Setattr(n, "wrap:action", action); - if (!gccgo_flag) { + if (cgo_flag) { + cgoWrapperInfo info; + + info.n = n; + info.go_name = go_name; + info.overname = overname; + info.wname = upcall_wname; + info.base = NULL; + info.parms = first_parm; + info.result = result; + info.is_static = is_static; + info.receiver = NULL; + info.is_constructor = false; + info.is_destructor = false; + + int r = cgoGccWrapper(&info); + if (r != SWIG_OK) { + return r; + } + } else if (!gccgo_flag) { // Write the upcall wrapper function. This is compiled by gc // and calls the C++ function. int r = gcFunctionWrapper(upcall_wname); @@ -3778,15 +4628,27 @@ private: Printv(f_go_wrappers, " {\n", NULL); + String *ret_type = NULL; + bool memcpy_ret = false; + String *wt = NULL; String *goout = NULL; if (SwigType_type(result) != T_VOID) { - Printv(f_go_wrappers, "\tvar swig_r ", goImType(n, result), "\n", NULL); + ret_type = goImType(n, result); + Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); goout = goTypemapLookup("goout", n, "swig_r"); + + if (cgo_flag) { + bool c_struct_type; + Delete(cgoTypeForGoValue(n, result, &c_struct_type)); + if (c_struct_type) { + memcpy_ret = true; + } + } } String *call = NewString(""); - if (gccgo_flag) { + if (gccgo_flag && !cgo_flag) { if (goout != NULL) { Printv(call, "\tfunc() {\n", NULL); } @@ -3796,9 +4658,33 @@ private: Printv(call, "\t", NULL); if (SwigType_type(result) != T_VOID) { - Printv(call, "swig_r = ", NULL); + if (memcpy_ret) { + Printv(call, "swig_r_p := ", NULL); + } else { + Printv(call, "swig_r = ", NULL); + if (cgo_flag) { + Printv(call, "(", ret_type, ")(", NULL); + } + } + if (cgo_flag && goTypeIsInterface(n, result)) { + wt = goWrapperType(n, result, true); + Printv(call, "(", wt, ")(", NULL); + } + } + + if (cgo_flag) { + Printv(call, "C.", upcall_wname, NULL); + } else { + Printv(call, upcall_gc_name, NULL); + } + Printv(call, "(", NULL); + if (cgo_flag) { + Printv(call, "C.uintptr_t(", NULL); + } + Printv(call, "p.(*", director_struct_name, ").", go_type_name, NULL); + if (cgo_flag) { + Printv(call, ")", NULL); } - Printv(call, upcall_gc_name, "(p.(*", director_struct_name, ").", go_type_name, NULL); p = parms; for (int i = 0; i < parm_count; ++i) { @@ -3806,27 +4692,39 @@ private: p = getParm(p); SwigType *pt = Getattr(p, "type"); + String *ivar = NewStringf("_swig_i_%d", i); + String *ln = Copy(Getattr(p, "lname")); - if (goTypeIsInterface(p, pt)) { - Printv(ln, ".Swigcptr()", NULL); - } String *goin = goGetattr(p, "tmap:goin"); if (goin == NULL) { - Printv(call, ln, NULL); - Setattr(p, "emit:goinput", ln); + Printv(f_go_wrappers, "\t", ivar, " := ", ln, NULL); + if (goTypeIsInterface(p, pt)) { + Printv(f_go_wrappers, ".Swigcptr()", NULL); + } + Printv(f_go_wrappers, "\n", NULL); } else { - String *ivar = NewString(""); - Printf(ivar, "_swig_i_%d", i); String *itm = goImType(p, pt); - Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, NULL); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); goin = Copy(goin); Replaceall(goin, "$input", ln); Replaceall(goin, "$result", ivar); Printv(f_go_wrappers, goin, NULL); Delete(goin); + } + + Setattr(p, "emit:goinput", ivar); + + if (cgo_flag) { + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + if (c_struct_type) { + Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); + } else { + Printv(call, "C.", ct, "(", ivar, ")", NULL); + } + } else { Printv(call, ivar, NULL); - Setattr(p, "emit:goinput", ivar); } Delete(ln); @@ -3834,15 +4732,32 @@ private: p = nextParm(p); } - Printv(call, ")\n", NULL); + Printv(call, ")", NULL); - if (gccgo_flag && goout != NULL) { - Printv(call, "\t}()\n", NULL); + if (gccgo_flag && !cgo_flag && goout != NULL) { + Printv(call, "\n\t}()", NULL); } + if (cgo_flag) { + if (wt) { + // Close the type conversion to the wrapper type. + Printv(call, ")", NULL); + } + if (SwigType_type(result) != T_VOID && !memcpy_ret) { + // Close the type conversion of the return value. + Printv(call, ")", NULL); + } + } + + Printv(call, "\n", NULL); + Printv(f_go_wrappers, call, NULL); Delete(call); + if (memcpy_ret) { + Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); + } + goargout(parms, parm_count); if (SwigType_type(result) != T_VOID) { @@ -3859,11 +4774,22 @@ private: } Printv(f_go_wrappers, "}\n\n", NULL); + + if (ret_type) { + Delete(ret_type); + } + if (wt) { + Delete(wt); + } } // The Go function which invokes the method. This is called // from by the C++ method on the director class. + if (cgo_flag) { + Printv(f_go_wrappers, "//export ", callback_name, "\n", NULL); + } + Printv(f_go_wrappers, "func ", callback_name, "(swig_c int", NULL); p = parms; @@ -3970,7 +4896,7 @@ private: } Printv(call, "\n", NULL); - if (gccgo_flag) { + if (gccgo_flag && !cgo_flag) { if (goout != NULL) { Printv(f_go_wrappers, "\tfunc() {\n", NULL); } @@ -3983,7 +4909,7 @@ private: Printv(f_go_wrappers, call, NULL); Delete(call); - if (gccgo_flag && goout != NULL) { + if (gccgo_flag && !cgo_flag && goout != NULL) { Printv(f_go_wrappers, "\t}()\n", NULL); } @@ -4062,6 +4988,7 @@ private: Delete(go_type_name); Delete(director_struct_name); Delete(interface_name); + Delete(callback_name); Delete(upcall_name); Delete(go_name); DelWrapper(w); @@ -4075,6 +5002,11 @@ private: * Emit the function wrapper for a director method. * ------------------------------------------------------------ */ void makeDirectorMethodWrapper(Node *n, Wrapper *w, String *callback_name) { + if (cgo_flag) { + makeCgoDirectorMethodWrapper(n, w, callback_name); + return; + } + ParmList *parms = Getattr(n, "wrap:parms"); SwigType *result = Getattr(n, "type"); @@ -4298,6 +5230,129 @@ private: Delete(callback_wname); } + /* ------------------------------------------------------------ + * makeDirectorMethodWrapper + * + * Emit the function wrapper for a director method for cgo. + * ------------------------------------------------------------ */ + + void makeCgoDirectorMethodWrapper(Node *n, Wrapper *w, String *callback_name) { + ParmList *parms = Getattr(n, "wrap:parms"); + SwigType *result = Getattr(n, "type"); + + Printv(f_c_directors, "extern \"C\" ", NULL); + + String *fnname = Copy(callback_name); + Append(fnname, "(int"); + + Parm *p = parms; + while (p) { + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + String *cg = gcCTypeForGoValue(p, Getattr(p, "type"), Getattr(p, "lname")); + Printv(fnname, ", ", cg, NULL); + Delete(cg); + p = Getattr(p, "tmap:directorin:next"); + } + + Printv(fnname, ")", NULL); + + if (SwigType_type(result) == T_VOID) { + Printv(f_c_directors, "void ", fnname, NULL); + } else { + String *tm = gcCTypeForGoValue(n, result, fnname); + Printv(f_c_directors, tm, NULL); + Delete(tm); + } + + Delete(fnname); + + Printv(f_c_directors, ";\n", NULL); + + if (SwigType_type(result) != T_VOID) { + String *r = NewString(Swig_cresult_name()); + String *tm = gcCTypeForGoValue(n, result, r); + Wrapper_add_local(w, r, tm); + Delete(tm); + Delete(r); + } + + String *args = NewString(""); + + p = parms; + while (p) { + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + + String *pn = NewString("swig_"); + Append(pn, Getattr(p, "lname")); + Setattr(p, "emit:directorinput", pn); + + String *tm = gcCTypeForGoValue(p, Getattr(p, "type"), pn); + Wrapper_add_local(w, pn, tm); + Delete(tm); + + tm = Getattr(p, "tmap:directorin"); + if (!tm) { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, + line_number, "Unable to use type %s as director method argument\n", SwigType_str(Getattr(p, "type"), 0)); + } else { + tm = Copy(tm); + Replaceall(tm, "$input", pn); + Replaceall(tm, "$owner", 0); + Printv(w->code, " ", tm, "\n", NULL); + Delete(tm); + + Printv(args, ", ", pn, NULL); + } + + p = Getattr(p, "tmap:directorin:next"); + } + + Printv(w->code, " ", NULL); + if (SwigType_type(result) != T_VOID) { + Printv(w->code, Swig_cresult_name(), " = ", NULL); + } + Printv(w->code, callback_name, "(go_val", args, ");\n", NULL); + + /* Marshal outputs */ + for (p = parms; p; ) { + String *tm; + if ((tm = Getattr(p, "tmap:directorargout"))) { + tm = Copy(tm); + Replaceall(tm, "$result", "jresult"); + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NULL); + Delete(tm); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + if (SwigType_type(result) != T_VOID) { + String *result_str = NewString("c_result"); + String *tm = Swig_typemap_lookup("directorout", n, result_str, NULL); + if (!tm) { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use type %s as director method result\n", SwigType_str(result, 0)); + } else { + tm = Copy(tm); + Replaceall(tm, "$input", Swig_cresult_name()); + Replaceall(tm, "$result", "c_result"); + Printv(w->code, " ", tm, "\n", NULL); + String *retstr = SwigType_rcaststr(result, "c_result"); + Printv(w->code, " return ", retstr, ";\n", NULL); + Delete(retstr); + Delete(tm); + } + Delete(result_str); + } + } + + /* ------------------------------------------------------------ * classDirectorEnd * @@ -5218,6 +6273,106 @@ private: return ret; } + /* ---------------------------------------------------------------------- + * cgoTypeForGoValue() + * + * Given a SWIG type, return a string for the C type to use for the + * cgo wrapper code. This always returns a simple identifier, since + * it is used in Go code as C.name. + * + * This sets *c_struct_type if the C type uses a struct where the Go + * type uses a simple type. This is true for strings and slices. + * When this is true the Go code has to jump through unsafe hoops to + * pass the type checker. + * ---------------------------------------------------------------------- */ + + String *cgoTypeForGoValue(Node *n, SwigType *type, bool *c_struct_type) { + *c_struct_type = false; + + bool is_interface; + String *go_type = goTypeWithInfo(n, type, false, &is_interface); + if (is_interface) { + Delete(go_type); + return NewString("uintptr_t"); + } + if (Strcmp(go_type, "uintptr") == 0) { + Delete(go_type); + return NewString("uintptr_t"); + } + if (((char*)Char(go_type))[0] == '*') { + // Treat all pointers as void*. There is no meaningful type + // checking going on here anyhow, and that lets us avoid + // worrying about defining the base type of the pointer. + Delete(go_type); + return NewString("swig_voidp"); + } + Delete(go_type); + + String *ct = Getattr(n, "emit:cgotype"); + if (ct) { + *c_struct_type = (bool)Getattr(n, "emit:cgotypestruct"); + return Copy(ct); + } + + String *t = Copy(type); + if (SwigType_isarray(t)) { + SwigType_del_array(t); + SwigType_add_pointer(t); + } + + bool add_typedef = true; + + static int count; + ++count; + ct = NewStringf("swig_type_%d", count); + + String *gct = gcCTypeForGoValue(n, t, ct); + Delete(t); + + if (Strncmp(gct, "_gostring_", 10) == 0 || Strncmp(gct, "_goslice_", 9) == 0) { + *c_struct_type = true; + Setattr(n, "emit:cgotypestruct", type); + } else { + char *p = Strstr(gct, ct); + if (p != NULL && p > (char*)Char(gct) && p[-1] == '*' && p[Len(ct)] == '\0') { + // Treat all pointers as void*. See above. + Delete(ct); + --count; + ct = NewString("swig_voidp"); + add_typedef = false; + } + + if (Strncmp(gct, "bool ", 5) == 0) { + // Change the C++ type bool to the C type _Bool. + Replace(gct, "bool", "_Bool", DOH_REPLACE_FIRST); + } + if (Strncmp(gct, "intgo ", 6) == 0) { + // We #define intgo to swig_intgo for the cgo comment. + Replace(gct, "intgo", "swig_intgo", DOH_REPLACE_FIRST); + } + p = Strstr(gct, ct); + if (p != NULL && p > (char*)Char(gct) && p[-1] == ' ' && p[Len(ct)] == '\0') { + String *q = NewStringWithSize(gct, Len(gct) - Len(ct) - 1); + if (validIdentifier(q)) { + // This is a simple type name, and we can use it directly. + Delete(ct); + --count; + ct = q; + add_typedef = false; + } + } + } + if (add_typedef) { + Printv(f_cgo_comment_typedefs, "typedef ", gct, ";\n", NULL); + } + + Setattr(n, "emit:cgotype", ct); + + Delete(gct); + + return Copy(ct); + } + /* ---------------------------------------------------------------------- * goWrapperType() * @@ -5330,6 +6485,7 @@ private: bool is_member = Strcmp(gt, "_swig_memberptr") == 0; bool is_complex64 = Strcmp(gt, "complex64") == 0; bool is_complex128 = Strcmp(gt, "complex128") == 0; + bool is_bool = false; bool is_int8 = false; bool is_int16 = false; bool is_int = Strcmp(gt, "int") == 0 || Strcmp(gt, "uint") == 0; @@ -5337,7 +6493,10 @@ private: bool is_int64 = false; bool is_float32 = false; bool is_float64 = false; - if ((n != NULL && Getattr(n, "tmap:gotype") != NULL) || hasGoTypemap(n, type)) { + + bool has_typemap = (n != NULL && Getattr(n, "tmap:gotype") != NULL) || hasGoTypemap(n, type); + if (has_typemap) { + is_bool = Strcmp(gt, "bool") == 0; is_int8 = Strcmp(gt, "int8") == 0 || Strcmp(gt, "uint8") == 0 || Strcmp(gt, "byte") == 0; is_int16 = Strcmp(gt, "int16") == 0 || Strcmp(gt, "uint16") == 0; is_int32 = Strcmp(gt, "int32") == 0 || Strcmp(gt, "uint32") == 0; @@ -5386,7 +6545,7 @@ private: return ret; } else { SwigType *t = SwigType_typedef_resolve_all(type); - if (SwigType_isreference(t)) { + if (!has_typemap && SwigType_isreference(t)) { // A const reference to a known type, or to a pointer, is not // mapped to a pointer. SwigType_del_reference(t); @@ -5424,7 +6583,9 @@ private: } Delete(t); - if (is_int8) { + if (is_bool) { + ret = NewString("bool "); + } else if (is_int8) { ret = NewString("char "); } else if (is_int16) { ret = NewString("short "); @@ -5445,7 +6606,7 @@ private: } Append(ret, tail); - if (SwigType_isreference(type)) { + if (!has_typemap && SwigType_isreference(type)) { Append(ret, "* "); } Append(ret, name); @@ -5651,6 +6812,7 @@ extern "C" Language *swig_go(void) { // Usage message. const char * const GO::usage = "\ Go Options (available with -go)\n\ + -cgo - Generate cgo input files\n\ -gccgo - Generate code for gccgo rather than 6g/8g\n\ -go-pkgpath - Like gccgo -fgo-pkgpath option\n\ -go-prefix
- Like gccgo -fgo-prefix option\n\ diff --git a/configure.ac b/configure.ac index c2a36fc95..b595de08e 100644 --- a/configure.ac +++ b/configure.ac @@ -2319,109 +2319,102 @@ if test x"${GOBIN}" = xno -o x"${with_alllang}" = xno ; then GO1=false GO12=false GO13=false + GO15=false GOGCC=false + GCCGO= GOOPT= + GCCGOOPT= GOVERSIONOPTION= else if test "x$GOBIN" = xyes; then - AC_CHECK_PROGS(GO, go 6g 8g gccgo) + AC_CHECK_PROGS(GO, go) else GO="$GOBIN" fi + AC_CHECK_PROGS(GCCGO, gccgo) + GOGCC=false + GCCGO= GO1=false GO12=false GO13=false + GO15=false GOOPT= + GCCGOOPT= GOVERSIONOPTION= - if test -n "$GO" ; then - if $GO --help 2>/dev/null | grep gccgo >/dev/null 2>&1 ; then - GOGCC=true - GOVERSIONOPTION=--version - AC_MSG_CHECKING([whether gccgo version is too old]) - go_version=[`$GO $GOVERSIONOPTION | sed -n '1p' | sed -e 's/^.* \([0-9.]*\) *$/\1/' -e 's/[.]//g'`] - if test "x$go_version" = x; then - AC_MSG_RESULT([could not determine gccgo version - disabling Go]) - GO= - elif test "$go_version" -lt 470; then - AC_MSG_RESULT([yes - minimum version is 4.7.0]) - GO= - else - AC_MSG_RESULT([no]) - if test "$go_version" -lt 480; then - GOOPT="-intgosize 32" - else - AC_CHECK_SIZEOF([void *], [4]) - if test "$ac_cv_sizeof_void_p" = "8"; then - GOOPT="-intgosize 64" - else - GOOPT="-intgosize 32" - fi - fi - fi - elif test "`echo $GO | sed -e 's|.*/||'`" = "go"; then - GO1=true - GOVERSIONOPTION=version - GOC=$(sh -c "$(go env) && echo \$GOCHAR")c - go_version=$($GO $GOVERSIONOPTION | sed -e 's/go version //') - AC_MSG_CHECKING([whether go version is too old]) - case $go_version in - go1.0* | go1 ) - AC_MSG_RESULT([yes - minimum version is 1.1]) - GO= - GOOPT="-intgosize 32" - ;; - *) - AC_MSG_RESULT([no]) - if test "$GOC" = "6c"; then - GOOPT="-intgosize 64" - else - GOOPT="-intgosize 32" - fi - ;; - esac - case $go_version in - go1.0* | go1 | go1.1*) - GOOPT="$GOOPT -use-shlib" - ;; - go1.2*) - GO12=true - ;; - *) - GO13=true - ;; - esac + + GO1=true + GOVERSIONOPTION=version + GOC=$(sh -c "$(go env) && echo \$GOCHAR")c + go_version=$($GO $GOVERSIONOPTION | sed -e 's/go version //') + AC_MSG_CHECKING([whether go version is too old]) + case $go_version in + go1.0* | go1 ) + AC_MSG_RESULT([yes - minimum version is 1.1]) + GO= + GOOPT="-intgosize 32" + ;; + *) + AC_MSG_RESULT([no]) + if test "$GOC" = "6c"; then + GOOPT="-intgosize 64" else - GOC=`echo $GO | sed -e 's/g/c/'` - GOVERSIONOPTION=-V - AC_MSG_CHECKING([whether Go ($GO) version is too old]) - AC_MSG_RESULT([yes - minimum version is 1.1]) - GO= - dnl Old code retained for now in case we implement an option for it. - dnl go_version=`$GO $GOVERSIONOPTION 2>/dev/null | sed -e 's/.*version.* \([[0-9]]*\).*/\1/'` - dnl go_min_version=7077 - dnl if test "$go_version" != "" -a "$go_version" -lt $go_min_version; then - dnl AC_MSG_RESULT([yes - minimum version is $go_min_version]) - dnl GO= - dnl else - dnl AC_MSG_RESULT([no]) - dnl fi GOOPT="-intgosize 32" - GO12=false - GO13=false + fi + ;; + esac + case $go_version in + go1.0* | go1 | go1.1*) + GOOPT="$GOOPT -use-shlib" + ;; + go1.2*) + GO12=true + ;; + go1.3* | go1.4*) + GO13=true + ;; + *) + GO15=true + ;; + esac + + if $GCCGO --help 2>/dev/null | grep gccgo >/dev/null 2>&1 ; then + AC_MSG_CHECKING([whether gccgo version is too old]) + go_version=[`$GO $GOVERSIONOPTION | sed -n '1p' | sed -e 's/^.* \([0-9.]*\) *$/\1/' -e 's/[.]//g'`] + if test "x$go_version" = x; then + AC_MSG_RESULT([could not determine gccgo version]) + GCCGO= + elif test "$go_version" -lt 470; then + AC_MSG_RESULT([yes - minimum version is 4.7.0]) + GCCGO= + else + AC_MSG_RESULT([no]) + if test "$go_version" -lt 480; then + GCCGOOPT="-intgosize 32" + else + AC_CHECK_SIZEOF([void *], [4]) + if test "$ac_cv_sizeof_void_p" = "8"; then + GCCGOOPT="-intgosize 64" + else + GCCGOOPT="-intgosize 32" + fi + fi fi fi fi AC_SUBST(GOGCC) +AC_SUBST(GCCGO) AC_SUBST(GO) AC_SUBST(GOC) AC_SUBST(GO1) AC_SUBST(GO12) AC_SUBST(GO13) +AC_SUBST(GO15) AC_SUBST(GOOPT) +AC_SUBST(GCCGOOPT) AC_SUBST(GOVERSIONOPTION) #----------------------------------------------------------------