Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Suggestion]: Ask users to post repos of successful translations using OMG, keep list of successes on readme #16

Open
GavinRay97 opened this issue May 17, 2021 · 4 comments

Comments

@GavinRay97
Copy link
Contributor

I think this would be a really cool way to share translations of useful libs with others, and also to show examples of what Ohmygentool is capable of, and the quality + accuracy of code it can produce 😃

I would be willing to start, I would just need to create repos for:

Also I believe Imperatorn had some degree of success translation both header types & function body code for this repo, which includes PDCurses in-tree:

I think it would also probably be helpful to see other people's gentool-config.json and notes on manual changes (if any) to the source to get it to compile, or changes to generated code. This way people could pick up on helpful tricks and common approaches.

Where the repo readme is something like this maybe:

Z3 C API translated to D

Generated: (gist here in lieu of actual source)
https://gist.github.com/GavinRay97/66f301b5a905de6b1739688553699253

How to generate

  • Clone Z3, open the folder z3/src/api
  • Compile or download a pre-compiled binary of Ohmygentool
  • Set up the gentool-config.json configuration we need (see below)
  • Create a new header which will hold some macros, a slight alteration, and forward declarations
  • Include the header under #pragma once in every file in input.paths in the JSON below
  • Run gentool ./gentool-config.json
// gentool-config.json
{
  "$schema": "./gentool-config.schema.json",
  "version": 1,
  "input": {
    "std": "c++20",
    "system": [],
    "defines": ["_WIN32=1", "_WIN64=1", "Z3_API="],
    "cflags": ["-Wno-pragma-once-outside-header" "-Wno-return-type-c-linkage"],
    "includes": ["../", "./"],
    "paths": [
      "./z3_algebraic.h",
      "./z3_api.h",
      "./z3_ast_containers.h",
      "./z3_fixedpoint.h",
      "./z3_fpa.h",
      "./z3_optimization.h",
      "./z3_polynomial.h",
      "./z3_private.h",
      "./z3_rcf.h",
      "./z3_replayer.h",
      "./z3_spacer.h"
    ]
  },
  "output": {
    "path": "./z3.d",
    "target": "dlang",
    "attr-nogc": false,
    "skip-bodies": true
  }
}
/**
 * THIS FILE IS USED AS A PRELUDE HEADER FOR THE C API HEADERS
 * SO THAT "Ohmygentool" CAN SUCCESSFULLY PARSE THE DEFINITIONS
 */
#pragma once
#include <stdint.h>

// The original version of this breaks Ohmygentool:
//    #define DEFINE_TYPE(T) typedef struct _ ## T *T
// Gives: "addType() error: empty path for entry <T>"
#define DEFINE_TYPE(T) struct T;

#ifndef Z3_bool_opt
#define Z3_bool_opt Z3_bool
#endif

#ifndef Z3_API
#ifdef __GNUC__
#define Z3_API __attribute__((visibility("default")))
#else
#define Z3_API
#endif
#endif

typedef bool Z3_bool;
typedef const char *Z3_string;
typedef char const *Z3_char_ptr;
typedef Z3_string *Z3_string_ptr;

#define Z3_TRUE true
#define Z3_FALSE false

DEFINE_TYPE(Z3_symbol);
// ... omitted for brevity
@Superbelko
Copy link
Owner

Maybe it generates them, but does it links? ( ͡° ͜ʖ ͡°)

Yep, addType is macro expanded to typedef, that's second annoyance after templates.
Though it's not technically broken, it just expands out of context.

As for generated stuff, be careful with these, it is generated for your host platform, if you build with it on another OS it might introduce subtle bugs because of ABI difference, so for now always (re)generate on target platform.

There is also subtle detail about __gshared static globals when you link against libraries, it will introduce second symbol and result is unpredictable, so it also needs to be marked export depending on link target.

P.S. $schema field is for VS Code JSON intellisense, maybe it'll work if you point to schema file on github, it does works locally though

@GavinRay97
Copy link
Contributor Author

GavinRay97 commented May 20, 2021

There is also subtle detail about __gshared static globals when you link against libraries, it will introduce second symbol and result is unpredictable, so it also needs to be marked export depending on link target.

Ahh I did not know this, thanks for telling me

P.S. $schema field is for VS Code JSON intellisense, maybe it'll work if you point to schema file on github, it does works locally though

I use VS Code but I also didn't know you could use an URL for the schema. I have been copying it to every project folder manually 😂 I will link to Github raw URL instead

Maybe it generates them, but does it links? ( ͡° ͜ʖ ͡°)

Ha, I should try to link the z3 one. It's a C API so I'd imagine it would -- that's maybe not the most impressive demo 😅

The REAPER one worked fantastic though, I have built stuff with it, it did a full working translation.

(Though for that one, it was actually not linked, but instead the entrypoint is called by a third-party binary, with a function used to get the fn-ptrs to the methods in the header)

// ./reaper/generated.d
module reaper.generated;
extern (C++) @cppclasssize(32) align(8) struct reaper_plugin_info_t
{

    @cppsize(4) public int caller_version;
    @cppsize(8) public HWND hwnd_main;
    @cppsize(8) public int function(const(char)*, void*) Register;
    @cppsize(8) public void* function(const(char)*) GetFunc;
}
// Struct just used for __traits reflection
// to load the function pointers into the generated definitions at runtime
__gshared struct Reaper
{
static:
    bool function(const(char)*, const(char)*, const(char)*, bool) AddCustomizableMenu;
    bool function() AddExtensionsMainMenu;
    MediaItem* function(MediaTrack*) AddMediaItemToTrack;
      // etc...
    void function(const(char)*) ShowConsoleMsg;
}

// app.d
import reaper = reaper.generated;

void load_reaper_api(reaper.reaper_plugin_info_t* rec)
{
    foreach (name; __traits(allMembers, reaper.Reaper))
    {
    // reaper.Reaper.ShowConsoleMsg = cast(typeof(reaper.Reaper.ShowConsoleMsg) rec.GetFunc("ShowConsoleMsg");
    mixin(`alias tmp = reaper.Reaper.`, name);
    mixin(q{
        tmp = cast(typeof(tmp)) rec.GetFunc(name);
        if (tmp is null) throw new Exception("Failed to load REAPER function: " ~ name);
    });
    }
}

extern (C) export int ReaperPluginEntry(HINSTANCE hInstance, reaper.reaper_plugin_info_t* rec)
{
	load_reaper_api(rec);
	reaper.Reaper.ShowConsoleMsg("Hello from Dlang!");
    return 1;
}

In fact, I saw this trick recently from your .NET host repo, and I have been saving it to clean that up:

// https://github.com/Superbelko/dotnethost-d/blob/7bee104c844b2753bfcd326371a6ac2dea8e438a/source/dotnet/host.d#L154-L162
mixin template InjectFunctionPointers(T)
{
    static foreach (fptr; __traits(allMembers, T))
    {
        static if (isFunctionPointer!(__traits(getMember, T, fptr)))
        {
            mixin(typeof(__traits(getMember, T, fptr)).stringof, " ", fptr, ";");
        }
    }
}

// Modify it to take a function for loading the function pointer, then:
InjectFunctionPointers!(reaper.Reaper)

@LorenDB
Copy link
Contributor

LorenDB commented Dec 13, 2021

+1 for this idea. I'd love to use this to generate bindings to Wt, but I am struggling to do so.

@Superbelko
Copy link
Owner

Open up a new issue with help request, I'll try to help sort it out.
Though as I see Wt relies heavily on STL and Boost, this is serious problem for the current generator, without lots of manual tweaking of the produced code there is no way it will work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants