cpp

package module
v0.0.0-...-13fc70c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 1, 2024 License: MIT Imports: 7 Imported by: 0

README

cppgo

Build Status GoDoc MIT License

This library allows methods on C++ objects to be called directly from the Go runtime without requiring cgo compilation.

To set up a Go object that proxies method calls to a C++ object:

  1. Define a Go struct type with function pointer field declarations that match the C++ class declaration,
  2. Get the address of the C++ object in memory as a uintptr type,
  3. Call cpp.ConvertRef(addr, &o) to point this proxy struct object (o) at the C++ object by its addr.
  4. After this initial setup, the function pointers on the struct object will be ready to use like any Go method.

Example Usage

The following example will call into a C++ class Library with a GetString(char *name) object method prototype. See the "STEP X" comments for usage guides:

package main

import (
	"fmt"

	cpp "github.com/lsegal/cppgo"
	"github.com/lsegal/cppgo/dl"
)

var (
	dll    = dl.Open("mylib.dll")
	create = dll.Load("new_object")
)

// STEP 1. define our C++ proxy struct type with function pointers.
// The functions in this struct will be filled in by the `cpp.ConvertRef()`
// function, at which point this struct will proxy all method calls to the
// C++ object.
type Library struct {
	GetString func(name string) string
}

func main() {
	// STEP 2. get an address for the C++ object
	// NOTE: you may need to free this later depending on call semantics.
	o, _ := create.Call() // o is a uintptr

	// STEP 3. point our proxy structure at the functions located in the object
	// that we got from step 2.
	var lib Library
	if err := cpp.ConvertRef(o, &lib); err != nil {
		panic(err)
	}

	// STEP 4. call the function with arguments
	fmt.Println(lib.GetString("Loren"))

	// Clean up library
	dll.Close()
}

The C++ class for the above program could look something like:

#include <string>

#ifndef WIN32
#  define __declspec(x)
#endif

class Library {
  std::string str_;

public:
  virtual const char *GetString(char *name) {
    str_ = "Hello, " + std::string(name) + "!";
    return str_.c_str();
  }
};

extern "C" __declspec(dllexport) Library* new_object() {
  return new Library();
}

Getting a C++ Object Pointer

In some cases you may also need to figure out how to get access to the C++ object you want to call into. Although you may already have the object pointer in memory, sometimes this object will come from a library call. This library also abstracts the loading of dynamic libraries through the dl package:

dll := dl.Open("path/to/library")
fn := dll.Load("get_object")
result, err := fn.Call()

// result now olds a uintptr to your object

// call this when you are done with the C++ object.
// this may not be at the end of the load function.
dll.Close()

See documentation for dl for more information on advanced usage.

Using __stdcall & __cdecl Calling Convention on Windows

By default, this library will use the "default" calling convention for C++ methods on that platform. For POSIX systems, this is __cdecl, but on Windows, the default calling convention is __thiscall.

In short, if you are using the default calling convention for your C++ methods, you do not have to do anything differently from the above example. However, if you encounter methods tagged with __stdcall or __cdecl, you can support these conventions by adding a call:"std" or call:"cdecl" tag on the field declaration respectively:

type Library struct {
  GetID()   int    `call:"std"`   // "stdcall" is also valid here
  GetName() string `call:"cdecl"`
}

This will ensure that the function pointer is compatible with the library's calling convention.

Caveats & Gotchas

Limited Type Conversion

You can define arbitrary function arguments and return types, but the internal translation does not support a full range of types. Currently, only the following types are supported:

  • uint*, int*, string, uintptr

Any other type of pointer will be passed as a pointer directly, which may be what you want, but may not be. For any type that isn't well converted by the library, use uintptr to send its address. Note also that floating points are explicitly unsupported.

Note that slices are not well supported due to the extra information encoded in a Go slice.

Note also that string converts only to and from the char* C type, in other words, C strings. The std::cstring or wchar_t types are not yet supported.

Passing Objects as Arguments

When passing C++ objects to methods, you will want to use the cpp.Ptr or uintptr value representing the address of the object. You cannot use the pointer to the proxy struct, since this does not actually point to the object, and cppgo does not know how to translate between the two.

For example, to send objects to methods, define a function and call it using the bare address pointers:

// C++ class defined as:
//
// class MyClass {
//   virtual void DoWork(MyClass *other);
// }
type MyClass struct {
  DoWork(obj uintptr)
}

func main() {
  var m1 MyClass
  var m2 MyClass
  o1 := get_object_address() // uintptr
  o2 := get_object_address() // uintptr

  cpp.ConvertRef(o, &m1)
  cpp.ConvertRef(o, &m2)

  // we may have m2 here, but we call DoWork() with the uintptr address.
  m1.DoWork(o2)
}
Non-Virtual Functions Not Supported

This library does not yet support non-virtual functions. Only functions defined with the virtual keyword are callable.

Author & License

Written by Loren Segal in 2017, licensed under MIT License (see LICENSE).

Documentation

Overview

Package cpp allows methods on C++ objects to be called directly from the Go runtime without requiring cgo compilation.

For more information on how to use this library, see the project README: https://github.com/lsegal/cppgo/blob/master/README.md

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConvertRef

func ConvertRef(ref uintptr, obj interface{}) error

ConvertRef converts a C++ object ref into a wrapper obj that can call methods on the reference object. The obj interface type should be a struct containing function pointers matching the interface of the C++ class. For example, given the following class:

class Math {
public:
	int multiply(int value, int times);
}

You might create a struct type Math as follows:

type Math struct {
	Multiply func(value, times int) int
}

You would then call ConvertRef with a pointer to this structure.

Example
package main

import (
	"fmt"

	cpp "github.com/lsegal/cppgo"
	"github.com/lsegal/cppgo/dl"
)

var get_object *dl.Func

type lib struct {
	GetInt     func() int        `call:"cdecl"`
	GetBool    func(b bool) bool `call:"this"`
	FlipBool   func(b *bool)
	GetString  func() string
	GetSelf    func() *lib
	TestValues func(string, int, uintptr) bool
	Add        func(n, m int) int `call:"std"`
}

func objref() uintptr {
	o, _ := get_object.Call()
	return o
}

func main() {
	/*
		// with Go type `lib`:
		type lib struct {
			GetString func() string
		}

		// and C++ class Library:
		class Library {
		public:
			const char *get_string();
		}
	*/
	var l lib
	err := cpp.ConvertRef(objref(), &l)
	if err != nil {
		return
	}
	fmt.Println(l.GetString())
}
Output:

hello world

Types

This section is empty.

Directories

Path Synopsis
Package asmcall implements low-level ABI method calls for various C calling conventions without using cgo.
Package asmcall implements low-level ABI method calls for various C calling conventions without using cgo.
cdecl
Package cdecl implements method call ABI for the POSIX C/C++ calling convention.
Package cdecl implements method call ABI for the POSIX C/C++ calling convention.
stdcall
Package stdcall implements method call ABI for the __stdcall calling convention.
Package stdcall implements method call ABI for the __stdcall calling convention.
thiscall
Package thiscall implements method call ABI for the __thiscall calling convention.
Package thiscall implements method call ABI for the __thiscall calling convention.
Package dl implements support for loading dynamic libraries at runtime without cgo.
Package dl implements support for loading dynamic libraries at runtime without cgo.
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL