arrieta / golang-cpp-basic-example

A simple example demonstrating how to call C++ from Go
92 stars 21 forks source link

A question on cpp class headers #1

Open lonnietc opened 2 years ago

lonnietc commented 2 years ago

Hello,

I am looking to call some C++ code that I can build into a library and run in C++ but I am not clear on how the class header would be received by Golang.

In your examples, you do not actually define any C++ classes in your header files so I am not sure how to call the C++ methods from Golang.

Any thoughts would be greatly appreciated.

arrieta commented 2 years ago

The file library.hpp does define a class. Maybe I'm not understanding your question?

lonnietc commented 2 years ago

Hello and Thanks for getting back to me on this.

I was able to compile and run your code, so I know that it works, but I am using it to learn since I need to apply these ideas to a C++ library that I have and which I want to run from Go.

With that in mind, I was looking at the "fancy" code in the goroutines directory.

// fancy.hpp
#pragma once
#ifdef __cplusplus
extern "C" {
#endif

int cpu_intensive(int n);
int io_intensive();

#ifdef __cplusplus
}  // extern "C"
#endif

and

// fancy.cpp
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <mutex>
#include <thread>

#include "fancy.hpp"

// Print to STDOUT without interleaving messages
std::mutex gIO_MUTEX;
#define LOG(x)                                  \
  do {                                          \
    {                                           \
      std::lock_guard<std::mutex> _(gIO_MUTEX); \
      std::cout << x << std::endl;              \
    }                                           \
  } while (false)

// Sample "cpu-intensive" task
int fib(int n) {
  switch (n) {
    case 0:
      return 1;
    case 1:
      return 1;
    default:
      return fib(n - 1) + fib(n - 2);
  }
}

// Sample "io-intensive" task
static constexpr const char* const COMMAND =
    ""
    "curl -O "
    "https://photojournal.jpl.nasa.gov/tiff/PIA17218.tif "
    " 2>/dev/null";
int fetch_nasa_image() { return std::system(COMMAND); }

using namespace std::chrono;
int cpu_intensive(int n) {
  const auto tbeg = system_clock::now();
  const auto id = std::this_thread::get_id();
  LOG("[c++] starting fib(" << n << ") on thread " << id << ".");
  const auto res = n < 0 ? -1 : fib(n);
  const auto dur = nanoseconds(system_clock::now() - tbeg).count();
  LOG("[c++] fib(" << n << ") on thread " << id << " took " << (dur / 1.0E9)
                   << " seconds.");
  return res;
}

int io_intensive() {
  const auto tbeg = system_clock::now();
  const auto id = std::this_thread::get_id();
  LOG("[c++] starting to download NASA image on thread " << id << ".");
  const auto status = fetch_nasa_image();
  if (status == 0) {
    LOG("[c++] downloaded NASA image");
  } else {
    LOG("[c++] failed to download NASA image");
  }
  const auto dur = nanoseconds(system_clock::now() - tbeg).count();
  LOG("[c++] io_intensive on thread " << id << " took " << (dur / 1.0E9)
                                      << " seconds.");
  return status;
}

while the code does seem to use a few C++ features, it really does not show much about using C++ classes or inheritance.

I was hoping to try and figure out how to have defined C++ classes and then expose those methods to C which in-turn would expose them to Go.

My question is how you might be able to do that?

For example (from https://www.cplusplus.com/doc/tutorial/classes/)

// member initialization
#include <iostream>
using namespace std;

class Circle {
    double radius;
  public:
    Circle(double r) : radius(r) { }
    double area() {return radius*radius*3.14159265;}
};

class Cylinder {
    Circle base;
    double height;
  public:
    Cylinder(double r, double h) : base (r), height(h) {}
    double volume() {return base.area() * height;}
};

int main () {
  Cylinder foo (10,20);

  cout << "foo's volume: " << foo.volume() << '\n';
  return 0;
}

If this was a C++ library then we would want to expose the "Cylinder" and "Circle" class methods.

Hope that this clarifies my question. Thanks again

arrieta commented 2 years ago

I created the basic-class directory that shows how one could implement the example you mention.