Skip to content

Notes on the translation process

dkorpel edited this page Aug 13, 2020 · 1 revision

The C sources for GLFW 3.3.2 were copied into a dub project, and the .c and .h files were translated one by one. The initial translation was done automatically using a program I made: ctod. (if that link 404's it's probably still private) That program was being developed in tandem with this translation.

I started with the x11 target, and also had to (partially) translate certain header files (X11.h, input.h) that GLFW uses.

The x11 target also depends on regex.h, but only for linux_joystick to detect file names of the form event[0-9]+. I implemented a function that manually checks that pattern, since that was easier than actually translating the regex header.

The automatic conversion converts a lot of C syntax to D, but there were still semantic differences to translate manually:

  • passing static arrays to function require a .ptr
  • taking function addresses require a &
  • switch statements need a default case
  • the result of calloc needs to be explicitly cast from void* to the wanted pointer type
  • aliases to dynamically loaded function pointers _glfw.x11.func are not allowed (need this for global variable _glfw)
  • many macros (GLFW_REQUIRE_INIT) need a string mixin at the usage site, and other macros were translated to a function

The translation was mostly uneventful, except for these things:

  • I assumed long in C is 4 bytes big and only long long is 8 bytes. This is true on Windows 32/64 bit, but on Linux 64-bit a long is 8 bytes. I had to manually change long into c_long from core.stdc.config.
  • Public GLFW functions have a GLFWAPI macro to make them exported in a DLL build. This macro placement was seen as a syntax error by the C parser, so some of the return types were 'eaten' and replaced by GLFWAPI, which I manually corrected.
  • there were some link errors because the headers were initially not mentioned as source files in dub.sdl, but that led to certain missing struct.init symbols. Even though I try to initialize every struct member with 0 to avoid these 'init' symbols, it seems older versions of dmd still emit the all-zero init symbol.
  • linux joystick used to not work because a memcpy had a wrongly translated length parameter. meaning the button mapping remained all zero.

After that the Windows target was translated.

  • I found out that while most WinAPI functions in GLFW use late-binding, AdjustWindowRectEx seems to be linked using import libraries. In win32_window.d it often appears right next to AdjustWindowRectExForDpi, which is manually loaded. Looks like an oversight in the original GLFW source, but I am not sure.
  • dinput.h uses Windows' Component Object Model (COM) to simulate OOP structures. The IDirectInputDevice8W and IDirectInput8W interfaces are declared using macros, so it took a little digging to find what structures were actually being declared. It turns out the first member of these structs is a pointer to the Vtable, which is a struct with the interfaces member functions in order of appearance in the header. I translated the Vtables correctly, but initially I put the Vtable structure itself as the first member, instead of a pointer to the Vtable.

Here's an overview of the newly introduced header files:

File Header it replaces
directinput8.d dinput.h
xinput.d xinput.h
x11_header.d X11.h
linuxinput.d input.h and input-event-codes.h
Clone this wiki locally