1

I have a library that I want to use which only provides C++ header files and a static library. Go is unable to parse the namespaces that it is wrapped in.

I have looked at this: How to use C++ in Go? and it makes sense, but there are no namespaces involved there.

This is the C++ code in question that when imported causes issues (only the beginning shown):

#pragma once
#include <stdint.h>

namespace ctre {
namespace phoenix {

And here is the result of compiling:

./include/ctre/phoenix/ErrorCode.h:4:1: error: unknown type name 'namespace'
 namespace ctre {
 ^~~~~~~~~
./include/ctre/phoenix/ErrorCode.h:4:16: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
 namespace ctre {

Is there any way that I can provide a C wrapper which avoids this problem?

quintin
  • 161
  • 13
  • 1
    Since C++ compilers normally mangle names and add secret arguments and so on, and cgo is designed to call unmangled C functions without secret extra arguments and so on, you must provide the C wrapper or write your C++ functions as C functions. C wrappers don't have standard ways to access C++ namespaces. See https://stackoverflow.com/q/18945419/1256452 for more. – torek Oct 27 '19 at 06:43

1 Answers1

4

I figured it out by creating a C wrapper header file. Then I created a CPP file which bridges said C interface with the library CPP headers and library.

The C header understands my library object as a void pointer, and my CPP implementation has to cast it in order to access all of its functions.

The extern "C" part is very important and prevent Go from freaking out - It prevents the CPP compiler from mangling function names.

Of course, also link the binary with the proper LDFLAGS.

phoenix.h

typedef void CTalon;

#ifdef __cplusplus
extern "C" {
#endif

CTalon* CTRE_CreateTalon(int port);

void CTRE_Set(CTalon* talon, double output);

void CTRE_Follow(CTalon* slave, CTalon* master);

#ifdef __cplusplus
}
#endif

phoenix.cpp

#include "phoenix.h" // My C wrapper header

#include "ctre/phoenix/motorcontrol/can/TalonSRX.h" // Actual CPP header from library

#define TALON(ctalon) ((ctre::TalonSRX*) ctalon) // Helper macro to make converting to library object easier. Optional

namespace ctre { // Specific to my library which has a lot of long namespaces. Unrelated to problem
    using ctre::phoenix::motorcontrol::ControlMode;
    using ctre::phoenix::motorcontrol::can::TalonSRX;
}

extern "C" {
    CTalon* CTRE_CreateTalon(int port) {
        return (CTalon*) new ctre::TalonSRX(port);
    }

    void CTRE_Set(CTalon* talon, double output) {
        TALON(talon)->Set(ctre::ControlMode::PercentOutput, output);
    }

    void CTRE_Follow(CTalon* slave, CTalon* master) {
        TALON(slave)->Follow(*(TALON(master)));
    }
}
quintin
  • 161
  • 13