digitalmars.D - C++ header generation: Mixin template to create C ABI from D class
- Gavin Ray (111/111) Nov 07 2021 Hello all.
- Adam D Ruppe (7/9) Nov 07 2021 That would create a function with the literal mangle
- rikki cattermole (34/46) Nov 07 2021 ```d
Hello all. Rikki Cattermole gave me this useful mixin, which can wrap a D class and create a "flattened" C ABI for it. The issue is, trying to use: ```d pragma(mangle, "create_" ~ __traits(identifier, Type)) void* creator(Parameters!(Type.__ctor) args) {} ``` Doesn't actually seem to apply the mangling =/ I've also tried: ```D enum ConstructorName(Type) = "create_" ~ __traits(identifier, Type); pragma(mangle, "create_" ~ ConstructorName!(Type)) void* creator(Parameters!(Type.__ctor) args) {} ``` To no success. The source code I am using is: ```d import std; // Try to use an enum to force comptime resolve enum ConstructorName(Type) = "create_" ~ __traits(identifier, Type); // Compile time mixin function that generates an "extern C" flattened ABI for a D class: mixin template CWrapper(Type) { import std.traits; export extern (C): pragma(mangle, "create_" ~ __traits(identifier, Type)) void* creator(Parameters!(Type.__ctor) args) { return cast(void*) new Type(args); } mixin(() { string ret; foreach (m; __traits(allMembers, Type)) { static if (m != "__ctor" && m != "__dtor" && isFunction!(__traits(getMember, Type, m))) { ret ~= `ReturnType!(__traits(getMember, Type, "` ~ m ~ `")) ` ~ __traits(identifier, Type) ~ `_` ~ m ~ `(void* obj, Parameters!(__traits(getMember, Type, "` ~ m ~ `")) args) { return (cast(Type)obj).` ~ m ~ `(args); }`; } } return ret; }()); } // Sample class to generate C ABI for: class Foo { int x; this(int x) { this.x = x; } int getX() { return x; } void setX(int x) { this.x = x; } } mixin CWrapper!(Foo); ``` Running the below: ```sh $ dmd -HC=verbose -HCf=main.h main.d $ ldc2 --HC=verbose --HCf=main_ldc.h main.d ``` Gives the same issue -- the constructor is not mangled, it is emitted as `creator()`: ```cpp // Automatically generated by LDC Compiler v2098 #pragma once #include <assert.h> #include <stddef.h> #include <stdint.h> #include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE #else /// Represents a D [] array template<typename T> struct _d_dynamicArray final { size_t length; T *ptr; _d_dynamicArray() : length(0), ptr(NULL) { } _d_dynamicArray(size_t length_in, T *ptr_in) : length(length_in), ptr(ptr_in) { } T& operator[](const size_t idx) { assert(idx < length); return ptr[idx]; } const T& operator[](const size_t idx) const { assert(idx < length); return ptr[idx]; } }; #endif class Object; // Ignored template main.ConstructorName(Type) because of linkage // Ignored template main.CWrapper(Type) because of linkage // Ignored class main.Foo because of linkage extern "C" void* creator(int32_t _param_0); extern "C" int32_t Foo_getX(void* obj); extern "C" void Foo_setX(void* obj, int32_t _param_1); extern "C" _d_dynamicArray< const char > Foo_toString(void* obj); extern "C" Foo_toHash(void* obj); extern "C" int32_t Foo_opCmp(void* obj, Object* _param_1); extern "C" bool Foo_opEquals(void* obj, Object* _param_1); extern "C" Object* Foo_factory(void* obj, _d_dynamicArray< const char > _param_1); ```
Nov 07 2021
On Sunday, 7 November 2021 at 19:25:43 UTC, Gavin Ray wrote:pragma(mangle, "create_" ~ __traits(identifier, Type)) void* creator(Parameters!(Type.__ctor) args) {}That would create a function with the literal mangle create_TYPENAMEHERE which isn't C++ compatible. If you had an `extern "C" whatever create_TYPENAMEHERE(whateveR);` then that mangle would tie in. You might just want to use an extern(C++) constructor here..
Nov 07 2021
On 08/11/2021 8:25 AM, Gavin Ray wrote:Hello all. Rikki Cattermole gave me this useful mixin, which can wrap a D class and create a "flattened" C ABI for it. The issue is, trying to use: ```d pragma(mangle, "create_" ~ __traits(identifier, Type)) void* creator(Parameters!(Type.__ctor) args) {} ``` Doesn't actually seem to apply the mangling =/```d class Type { this() {} } pragma(msg, creator.mangleof); // _D9onlineapp7creatorFZPv pragma(mangle, "create_" ~ __traits(identifier, Type)) void* creator(Parameters!(Type.__ctor) args) { pragma(msg, creator.mangleof); // create_Type return cast(void*)(new Type(args)); } pragma(msg, creator.mangleof); // create_Type ``` Order matters for this stuff unfortunately. Now with regards to -HC That is certainly a bug with the generator. ```asm .text.create_Type segment assume CS:.text.create_Type create_Type: push RBP mov RBP,RSP sub RSP,010h mov RDI,onlineapp.Type.__Class GOTPCREL[RIP] call _d_newclass PLT32 mov -8[RBP],RAX mov RDI,RAX call onlineapp.Type onlineapp.Type.__ctor() PLT32 leave ret add [RAX],AL .text.create_Type ends ``` https://issues.dlang.org/show_bug.cgi?id=22489
Nov 07 2021