C functions can be called directly from D. There is no need for wrapper functions, argument swizzling, and the C functions do not need to be put into a separate DLL. The C function must be declared and given a calling convention, most likely the “C” calling convention, for example:
extern (C) int strcmp(const char* string1, const char* string2);
and then it can be called within D code in the obvious way:
import std.string; int myDfunction(char[] s) { return strcmp(std.string.toStringz(s), "foo"); }
For D functions to be able to be called from a C context, they should be annotated with the extern(C) attribute:
// test.d extern (C) int average(int a, int b) { return (a+b)/2; }
On the C side, the function signature must be provided:
// main.c int average(int a, int b); void main() { int a = average(5, 9); printf("%d\n", a); // prints 7; }
Compilation of the sources is done in the following manner:
dmd -c test.d gcc -o main.o -c main.c gcc test.o main.o
Compiling the D and C code to object modules and then linking them into an executable is all that needs to be done. For this to work it is imperative that the label (the function name) is exactly the same on both D and C sides; also both sides need to respect the same calling convention. extern (C) instructs the compiler to mangle the name of the function according to the rules of the C languages; the D calling convention is the same as the C one.
D structs and unions are analogous to C's. C code often adjusts the alignment and packing of struct members with a command line switch or with various implementation specific #pragmas. D supports explicit alignment attributes that correspond to the C compiler's rules. Check what alignment the C code is using, and explicitly set it for the D struct declaration. Example:
// test.d struct A { int a; } extern(C) int fun(A a) { return a.a + 7; }
// main.c #include <stdio.h> struct A { int a; } a; int fun(struct A a); void main() { a.a = 6; printf("Called fun, response: %d\n", fun(a)); }
Both sides need to define the struct in order to know the layout in memory of the fields.
Since D can call C code directly, it can also call any C library functions, giving D access to the smorgasbord of existing C libraries. To do so, however, one needs to write a D interface (.di) file, which is a translation of the C .h header file for the C library into D.
For popular C libraries, the first place to look for the corresponding D interface file is the Deimos Project. If it isn't there already, and you write one, please contribute it to the Deimos Project.
C globals can be accessed directly from D. C globals have the C naming convention, and so must be in an extern (C) block. Use the extern storage class to indicate that the global is allocated in the C code, not the D code. C globals default to being in global, not thread local, storage. To reference global storage from D, use the gshared storage class.
extern (C) __gshared int x;
Calling D functions from C++ and viceversa are achieved exactly the same as in the case of C, by using extern(C++).
C++ symbols that reside in namespaces can be accessed from D. A namespace can be added to the extern (C++) linkage attribute:
extern (C++, N) int foo(int i, int j, int k); void main() { N.foo(1, 2, 3); // foo is in C++ namespace 'N' }
C++ classes can be declared in D by using the extern (C++) attribute on class, struct and interface declarations. extern (C++) interfaces have the same restrictions as D interfaces, which means that Multiple Inheritance is supported to the extent that only one base class can have member fields.
extern (C++) structs do not support virtual functions but can be used to map C++ value types.
Unlike classes and interfaces with D linkage, extern (C++) classes and interfaces are not rooted in Object and cannot be used with typeid.
C++ allows a struct to inherit from a base struct. This is done in D using alias this.
C++ function and type templates can be bound by using the extern (C++) attribute on a function or type template declaration.
Note that all instantiations used in D code must be provided by linking to C++ object code or shared libraries containing the instantiations.
It is straightforward to link C functions and libraries into D programs. But linking D functions and libraries into C programs is not straightforward.
D programs generally require:
To link D functions and libraries into C programs, it's necessary to only require the C runtime library to be linked in. This is accomplished by defining a subset of D that fits this requirement, called BetterC. BetterC is typically enabled by setting the -betterC command line flag for the implementation.
D features not available with BetterC:
Dub is a package and build manager for D applications and libraries.
For a dub tutorial, visit this page.
D was designed from the beginning to be ABI compatible with C. Translate the declarations from a C header file into a D module and you can link directly with the corresponding C library or object files. The same is true in the other direction as long as the functions in the D code are annotated with the appropriate linkage attribute. These days, it’s possible to bind with C++ and even Objective-C.
dpp is a compiler wrapper that will parse a D source file with the .dpp extension and expand in place any #include directives it encounters, translating all of the C or C++ symbols to D, and then pass the result to a D compiler (DMD by default). Example:
// stdlib.dpp #include <stdio.h> #include <stdlib.h> void main() { printf("Hello world\n".ptr); enum numInts = 4; auto ints = cast(int*) malloc(int.sizeof * numInts); scope(exit) free(ints); foreach(int i; 0 .. numInts) { ints[i] = i; printf("ints[%d]: %d ".ptr, i, ints[i]); } printf("\n".ptr); }
Clone this repo. That is a competing library of phobos. Build, run and test the program using dub.
Install dpp by using dub:
sudo apt-get install libclang1-3.9 libclang-3.9-dev dub fetch libclang dub build libclang dub fetch dpp dub build dpp
dpp will be installed in ~/.dub/packages/dpp-some-version. You should probably create an alias with the executable.
Write a D program of your choosing in which you use C-style include directives. Compile and run the program with dpp.