Skip to content

02 Customizing Method Names

Anders Langlands edited this page Apr 17, 2021 · 3 revisions

A More Complex Example

Let's expand our simple Hello class to take arguments. And because it's C++ we'll implement different argument types as overloads

#pragma once

#include <iostream>

namespace hello {

class Hello {
public:
    void hello(const char* msg) const {
        std::cout << "Hello, " << msg << "!\n";
    }
    void hello(const int msg) const { std::cout << "Hello, " << msg << "!\n"; }
    void hello(const float msg) const {
        std::cout << "Hello, " << msg << "!\n";
    }
};

} // namespace hello

We'll create a new working directory and save this as 02_customizing_methods/include/hello.hpp.

Next we'll need to update our binding file to match the new method signiatures

#include "hello.hpp"

namespace cppmm_bind {

namespace hello {

struct Hello {
    using BoundType = ::hello::Hello;
    void hello(const char* msg) const;
    void hello(const int msg) const;
    void hello(const float msg) const;
};

} // namespace hello

} // namespace cppmm_bind

and we'll save this as 02_customizing_methods/bind/c-hello.cpp.

If we now generate the AST and the bindings:

./astgen/astgen 02_customizing_methods/bind/c-hello.cpp -v 1 -o 02_customizing_methods/ast -- -I../tutorial/02_customizing_methods/include
./asttoc/asttoc 02_customizing_methods/ast -o 02_customizing_methods -p customizing_methods

and inspect the resulting C header, 02_customizing_methods/customizing_methods-c/c-hello.h, we can see that asttoc has renamed the methods for us to avoid name collisions. The names aren't exactly helpful though:

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

typedef struct hello__Hello_t_s {
    char data[1];
} __attribute__((aligned(1))) hello__Hello_t;
typedef hello__Hello_t hello_Hello_t;

void hello__Hello_hello(
    hello_Hello_t const * this_
    , char const * msg);

#define hello_Hello_hello hello__Hello_hello

void hello__Hello_hello_1(
    hello_Hello_t const * this_
    , int const msg);

#define hello_Hello_hello_1 hello__Hello_hello_1

void hello__Hello_hello_2(
    hello_Hello_t const * this_
    , float const msg);

#define hello_Hello_hello_2 hello__Hello_hello_2

#ifdef __cplusplus
}
#endif

Customizing the Method Names

Fortunately, astgen lets us add attributes to the binding file to tweak the generated binding in a number of ways, including renaming methods. This is done with standard clang/gcc attributes, and they're wrapped up in macros to make them easier to use.

These macros are defined in a virtual file that's injected by astgen automatically, called cppmm_bind.hpp, so the first thing to do is to modify the binding file to include this virtual header, and then we can use the CPPMM_RENAME macro to specify what name we want for each overload. For example:

#include "hello.hpp"

#include <cppmm_bind.hpp>

namespace cppmm_bind {

namespace hello {

struct Hello {
    using BoundType = ::hello::Hello;
    void hello(const char* msg) const CPPMM_RENAME(hello_string);
    void hello(const int msg) const CPPMM_RENAME(hello_int);
    void hello(const float msg) const CPPMM_RENAME(hello_float);
};

} // namespace hello

} // namespace cppmm_bind

and re-running the ast and binding generation as above gives us

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

typedef struct hello__Hello_t_s {
    char data[1];
} __attribute__((aligned(1))) hello__Hello_t;
typedef hello__Hello_t hello_Hello_t;

void hello__Hello_hello_string(
    hello_Hello_t const * this_
    , char const * msg);

#define hello_Hello_hello_string hello__Hello_hello_string

void hello__Hello_hello_int(
    hello_Hello_t const * this_
    , int const msg);

#define hello_Hello_hello_int hello__Hello_hello_int

void hello__Hello_hello_float(
    hello_Hello_t const * this_
    , float const msg);

#define hello_Hello_hello_float hello__Hello_hello_float

#ifdef __cplusplus
}
#endif

Much better!

Clone this wiki locally