This shows you the differences between two versions of the page.
dss:laboratoare:07 [2019/07/03 15:15] razvan.nitu1305 |
dss:laboratoare:07 [2021/07/19 10:08] (current) razvan.nitu1305 [Vibe.d] |
||
---|---|---|---|
Line 88: | Line 88: | ||
Both sides need to define the struct in order to know the layout in memory of the fields. | Both sides need to define the struct in order to know the layout in memory of the fields. | ||
+ | |||
+ | === Using existing C libraries === | ||
+ | |||
+ | 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 [[https://github.com/D-Programming-Deimos/|Deimos Project]]. If it isn't there already, and you write one, please contribute it to the Deimos Project. | ||
+ | |||
+ | === Accessing C globals === | ||
+ | |||
+ | 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. | ||
+ | |||
+ | <code D> | ||
+ | extern (C) __gshared int x; | ||
+ | </code> | ||
+ | |||
+ | ==== Interfacing to C++ ==== | ||
+ | |||
+ | Calling D functions from C++ and viceversa are achieved exactly the same as in the case of C, by using **extern(C++)**. | ||
+ | |||
+ | === C++ namespaces === | ||
+ | |||
+ | C++ symbols that reside in namespaces can be accessed from D. A namespace can be added to the **extern (C++)** linkage attribute: | ||
+ | |||
+ | <code D> | ||
+ | extern (C++, N) int foo(int i, int j, int k); | ||
+ | |||
+ | void main() | ||
+ | { | ||
+ | N.foo(1, 2, 3); // foo is in C++ namespace 'N' | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | === Classes === | ||
+ | |||
+ | 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**. | ||
+ | |||
+ | === Structs === | ||
+ | |||
+ | C++ allows a struct to inherit from a base struct. This is done in D using alias this. | ||
+ | |||
+ | === C++ Templates === | ||
+ | |||
+ | 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. | ||
+ | |||
+ | ==== BetterC ==== | ||
+ | |||
+ | 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: | ||
+ | |||
+ | - The D runtime library to be linked in, because many features of the core language require runtime library support. | ||
+ | - The **main()** function to be written in D, to ensure that the required runtime library support is properly initialized. | ||
+ | |||
+ | 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: | ||
+ | |||
+ | * Garbage Collection | ||
+ | * TypeInfo and ModuleInfo | ||
+ | * Classes | ||
+ | * Built-in threading (e.g. core.thread) | ||
+ | * Dynamic arrays (though slices of static arrays work) and associative arrays | ||
+ | * Exceptions | ||
+ | * synchronized and core.sync | ||
+ | * Static module constructors or destructors | ||
+ | * Vector Extensions | ||
+ | |||
+ | ==== Dub ==== | ||
+ | |||
+ | Dub is a package and build manager for D applications and libraries. | ||
+ | |||
+ | For a dub tutorial, visit this [[https://dub.pm/|page]]. | ||
+ | |||
+ | ==== DPP ==== | ||
+ | |||
+ | 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: | ||
+ | |||
+ | <code D> | ||
+ | // 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); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | |||
+ | |||
+ | ===== Exercises ==== | ||
+ | |||
+ | ==== 1. C function interface ==== | ||
+ | |||
+ | - Write a D function that computes the average of an array of ints. | ||
+ | - Write a main function in C that calls the function previously defined. | ||
+ | - Compile the code. Does it work? Why? | ||
+ | |||
+ | <note hint> | ||
+ | How are arrays represented in D? But in C? | ||
+ | </note> | ||
+ | |||
+ | ==== 2. C struct interface ==== | ||
+ | |||
+ | - Write a C function, called **sumMembers** that receives a parameter of type **struct List3** that packs 3 integer values and computes the sum of the 3 members. Define struct Node and a main function that calls **sumMembers**. | ||
+ | - Reimplement **sumMembers** in D by cut-pasting the original code. When linking the objects try using both **gcc** and **dmd**. What happens? | ||
+ | - Redesign **sumMembers** by initializing a builtin array from the members and calling the library function [[https://dlang.org/phobos/std_algorithm_iteration.html#sum|sum]] on it. Before calling sum, manually add 5 and 6 to the array by using the concatenation equals operator "~=". When linking, try using both **gcc** and **dmd**. What happens? Why? | ||
+ | - Compile the D code with betterC. What happens? Why? | ||
+ | |||
+ | ==== 3. Dub ==== | ||
+ | |||
+ | Clone [[https://github.com/libmir/mir|this repo]]. That is a competing library of phobos. Build, run and test the program using dub. | ||
+ | |||
+ | ==== 4. DPP ==== | ||
+ | |||
+ | Install dpp by using dub: | ||
+ | |||
+ | <code bash> | ||
+ | sudo apt-get install libclang1-3.9 libclang-3.9-dev | ||
+ | dub fetch libclang | ||
+ | dub build libclang | ||
+ | dub fetch dpp | ||
+ | dub build dpp | ||
+ | </code> | ||
+ | |||
+ | 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. |