D FFI
This is a "remake" of my "Oberon FFI" post. However, now I'm using D in a slightly different manner.
Build System Changes
D compilers generate machine code instead of transpiling to C, so instead of just including generated C code I have to compile and link a new object file. Compilation is taken care of by the following Makefile fragment:
The important part is the "-c" command-line option. This generates an ELF object file for later linking. Linking is something like the following:
Code Changes
Migration is best done one function at a time, running a test suite in between. For the first step, I copy/pasted one function to a file prefixed with *d*. I had to make the following changes:
- Import various functions from `core.stdc.*` instead of #include files
- Enclose the whole file in `extern (C):`
- Use normal functions rather than inlines
- Use `null` instead of `NULL`
I also had to add a new file, *prog.d*, which is the D declaration of all dependencies in the remaining C code. This starts out like:
The D syntax for enums and function declarations is similar enough to C that you might be able to copy-and-paste.
Note that I don't need annotations like `@system`, `nothrow` or `@nogc` because they're implied by the use of `core.stdc` functions or the *betterC* option.
Conclusion
It seems like D is a viable migration path for legacy C code. Perhaps also C++, but I haven't tested that. There is a path onwards too:
- Perform the above migration function-by-function for every file in the system
- Remove the `--betterC` compiler option and the `extern (C)` annotations
- Mark as many functions `@safe` as you can. This will probably require migrating some calls from `core.stdc.*` to Phobos.
- Use any other D features that make the code more readable, e.g. garbage collection, object-orientation
In contrast, Go is more fashionable (Rust is really for a different domain), but I totally failed to get c2go to work so incremental migration seems difficult.