diff --git a/Makefile b/Makefile index 3af2c52fcb..6a892a98dc 100644 --- a/Makefile +++ b/Makefile @@ -467,6 +467,7 @@ endif @$(MD5SUM) test.hex ifneq ($(OS),Windows_NT) $(TINYGO) build -o test.elf -gc=leaking -scheduler=none examples/serial + $(TINYGO) build -o test.elf examples/callcpp endif diff --git a/builder/build.go b/builder/build.go index 12ea76f196..0dca6f033d 100644 --- a/builder/build.go +++ b/builder/build.go @@ -538,6 +538,21 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil } linkerDependencies = append(linkerDependencies, job) } + for _, filename := range pkg.CXXFiles { + abspath := filepath.Join(pkg.Dir, filename) + flags := make([]string, len(pkg.CFlags)+len(pkg.CXXFlags)) + copy(flags, pkg.CFlags) + copy(flags[len(pkg.CFlags):], pkg.CXXFlags) + job := &compileJob{ + description: "compile CGo C++ file " + abspath, + run: func(job *compileJob) error { + result, err := compileAndCacheCFile(abspath, dir, flags, config.Options.PrintCommands) + job.result = result + return err + }, + } + linkerDependencies = append(linkerDependencies, job) + } } // Linker flags from CGo lines: diff --git a/compileopts/config.go b/compileopts/config.go index 7da0323df0..939b3dcec4 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -223,6 +223,14 @@ func (c *Config) CFlags() []string { return cflags } +func (c *Config) CXXFlags() []string { + var cxxflags []string + for _, flag := range c.Target.CXXFlags { + cxxflags = append(cxxflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT"))) + } + return cxxflags +} + // LDFlags returns the flags to pass to the linker. A few more flags are needed // (like the one for the compiler runtime), but this represents the majority of // the flags. diff --git a/compileopts/target.go b/compileopts/target.go index aaa5fadadf..33602d7cd5 100644 --- a/compileopts/target.go +++ b/compileopts/target.go @@ -38,6 +38,7 @@ type TargetSpec struct { AutoStackSize *bool `json:"automatic-stack-size"` // Determine stack size automatically at compile time. DefaultStackSize uint64 `json:"default-stack-size"` // Default stack size if the size couldn't be determined at compile time. CFlags []string `json:"cflags"` + CXXFlags []string `json:"cxxflags"` LDFlags []string `json:"ldflags"` LinkerScript string `json:"linkerscript"` ExtraFiles []string `json:"extra-files"` diff --git a/loader/loader.go b/loader/loader.go index 3991fdcf51..1c150108a0 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -51,6 +51,7 @@ type PackageJSON struct { GoFiles []string CgoFiles []string CFiles []string + CXXFiles []string // Dependency information Imports []string @@ -72,6 +73,7 @@ type Package struct { Files []*ast.File FileHashes map[string][]byte CFlags []string // CFlags used during CGo preprocessing (only set if CGo is used) + CXXFlags []string CGoHeaders []string // text above 'import "C"' lines Pkg *types.Package info types.Info @@ -400,6 +402,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) { } generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.program.fset, initialCFlags) p.CFlags = append(initialCFlags, cflags...) + p.CXXFlags = append(p.CXXFlags, p.program.config.CXXFlags()...) p.CGoHeaders = headerCode for path, hash := range accessedFiles { p.FileHashes[path] = hash diff --git a/src/examples/callcpp/add.cpp b/src/examples/callcpp/add.cpp new file mode 100644 index 0000000000..efad51d390 --- /dev/null +++ b/src/examples/callcpp/add.cpp @@ -0,0 +1,9 @@ +template +T add(T a, T b) { + return a + b; +} + +extern "C" int add(int a, int b) { + return add(a, b); +} + diff --git a/src/examples/callcpp/main.go b/src/examples/callcpp/main.go new file mode 100644 index 0000000000..16237d4621 --- /dev/null +++ b/src/examples/callcpp/main.go @@ -0,0 +1,12 @@ +package main + +/* +int add(int a, int b); +*/ +import "C" +import "fmt" + +func main() { + a := C.add(C.int(1), C.int(2)) + fmt.Println(a) +}