This is a "remake" of my "Oberon FFI" post. However, now I'm using D in a slightly different manner.
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:
DC := ldc2 DFLAGS := --O3 --release %.o: %.d dprog.d $(DC) $(DFLAGS) -c -<
The important part is the "-c" command-line option. This generates an ELF object file for later linking. Linking is something like the following:
SRC_D := dextension.d dprog.d OBJ_D := $(SRC_D:.d=.o) prog: ... $(OBJ_D) ...
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:
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:
module prog; // enums, etc. here extern (C): // function declarations here
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.
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:
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.