October 03, 2016 Re: Why using wrappers for D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chalix | On Monday, 3 October 2016 at 12:08:54 UTC, Chalix wrote: > Furthermore, if there is an not very popular C library, where no wrapper function exists, would it possible to include it into a D project? Probably I have to transform all the .h to .d files, so i can "import" them instead of "include" them. But then, could I link against the C-library? Yes, but here you're talking about a binding, not a wrapper. > > > I did not understand the concept of interaction between C and D, and I am a bit confused about wrapper functions and bindings for D now... > Would be great if someone could make it a bit more clear to me :) A binding is just the C function declared in D: // foo.h extern void my_func(const char *str); // foo.d extern(C) void my_func(const(char)* str) @nogc nothrow; Now with the declaration in D, you can link directly to the C library. But you also need foo.d to be linked into your program, either by compiling it alongside your own source files or linking it as a library (as you do with gtkd-3.lib). A wrapper takes a C interface and makes it more D like. // wrapfoo.d import foo; // import the foo module from above void myFunc(string s) { import std.string : toStringz; my_func(s.toStringz()); } |
October 03, 2016 Re: Why using wrappers for D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chalix | On Monday, 3 October 2016 at 12:47:48 UTC, Chalix wrote: > Also, I used the Qt library a lot with C++. But although it is a library, I have access to all the classes, like " QWidget w = new QWidget();". There is no factory method used. (This confuses me now a bit...) Qt bindings is a major undertaking, it was tried a couple of times. As an alternative you can try Calypso https://github.com/Syniurge/Calypso which has a C++ language plugin so can read headers directly. |
October 03, 2016 Re: Why using wrappers for D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chalix | On Monday, 3 October 2016 at 12:08:54 UTC, Chalix wrote: > Hi All! > > The documentation of D (https://dlang.org/overview.html#compatibility) says: > > "Direct Access to C API's > > Not only does D have data types that correspond to C types, it provides direct access to C functions. There is no need to write wrapper functions, parameter swizzlers, nor code to copy aggregate members one by one." D was inspired by Java, so wrappers meant here are probably JNI wrappers https://en.wikipedia.org/wiki/Java_Native_Interface |
October 03, 2016 Re: Why using wrappers for D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On Monday, 3 October 2016 at 13:51:28 UTC, Mike Parker wrote: > // wrapfoo.d > import foo; // import the foo module from above > > void myFunc(string s) > { > import std.string : toStringz; > my_func(s.toStringz()); > } Thank you for the example, Mike! And thanks to all others who support me with their answers! I didn't expect so much answers, the D community seems to be very helpful :) But there still is one thing, which I don't get: If I "import foo;" in my project, it will be compiled alongside. So there is no need for an extra library. Same should be for wrapfoo.d. If I "import wrapfoo;", I should just need the C-library "foo", and no D-library "food" right? To have a more practical example, I looked up the "header" of the GtkD gtk/Main.d file. There are functions exactly like you described: >public static void init(ref string[] argv) > { > int argc = cast(int)argv.length; > char** outargv = Str.toStringzArray(argv); > > gtk_init(&argc, &outargv); > > argv = Str.toStringArray(outargv, argc); > } This function wraps the C-like gtk_init function to a D init function. The gtk_init function is the function from the GTK+ library, which is loaded in the gtkc/gtk.d file: > Linker.link(gtk_init, "gtk_init", LIBRARY.GTK); Linker and link are defined in the gtkc/Loader.d So, why is it not enough just to "import gtk.Main"? What kind of code is inside the gtkd-3 library? |
October 03, 2016 Re: Why using wrappers for D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chalix | On Monday, October 03, 2016 17:19:47 Chalix via Digitalmars-d-learn wrote: > But there still is one thing, which I don't get: > > If I "import foo;" in my project, it will be compiled alongside. So there is no need for an extra library. Same should be for wrapfoo.d. If I "import wrapfoo;", I should just need the C-library "foo", and no D-library "food" right? The import statement just tells the D compiler to pull in declarations for the symbols that it needs from those modules. It doesn't actually compile those modules. You still have to give them to the compiler (either all together or separately to generate .o/.obj files) in order to actually compile them. And anything that's not D (like a C/C++ library) still needs to be linked in just like it would be in C/C++. In C/C++, #including is not enough to compile everything into your code unless everything is in the header files (which it rarely is). For the files in your project, you have to compile every .c/.cpp file to generate the .o or .obj files that the linker then links into your program, and for the 3rd party stuff that's in a library you need to link in the library. Simply #including doesn't actually bring something like curl or gtk into your program. You also have to link it when generating your executable. It's basically the same thing with D. Every .d file in your project needs to be compiled so that it gets linked into your executable, and if you want to use 3rd party stuff, you have to link in the libraries just like you would with C/C++. The separation is perhaps a bit less clear in D, because you usually just use .d files for everything, whereas C/C++ have .h and .c/.cpp as separate files. D does have .di files for the cases where you need to hide your code, but they don't get used often. But when you do use a .di file, that's what gets imported rather than the .d file which contains the actual definitions, so in that case, the separation is clearer. - Jonathan M Davis |
October 03, 2016 Re: Why using wrappers for D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chalix | On 10/03/2016 07:19 PM, Chalix wrote: > If I "import foo;" in my project, it will be compiled alongside. Not necessarily. dmd won't compile foo unless you tell it to by putting foo.d on the command line. If foo is only imported, dmd parses the file but it doesn't compile it. > So > there is no need for an extra library. You don't *need* the library. You can just compile the file together with the rest of your program, yes. When you do precompile to a library, you can skip the compilation later. That can save time. And you can shorten the distributed D source files to just the function signatures, like with header files in C. For this, the compiler recognizes the .di filename extension. This can be used to somewhat protect closed source code. And then there are shared libraries, which are loaded at run time. Their code is not included in the executable, so you get a smaller file. Makes sense with popular libraries that are used by many programs. > Same should be for wrapfoo.d. If > I "import wrapfoo;", I should just need the C-library "foo", and no > D-library "food" right? If wrapfoo is really just a binding, i.e. it provides only function signatures and no implementation, then there's no point in compiling it to a library. Otherwise, if wrapfoo actually implements something of its own, it can make sense to compile it to a library. Just like with every other piece of code. > To have a more practical example, I looked up the "header" of the GtkD > gtk/Main.d file. There are functions exactly like you described: > >> public static void init(ref string[] argv) >> { >> int argc = cast(int)argv.length; >> char** outargv = Str.toStringzArray(argv); >> >> gtk_init(&argc, &outargv); >> >> argv = Str.toStringArray(outargv, argc); >> } > > This function wraps the C-like gtk_init function to a D init function. > The gtk_init function is the function from the GTK+ library, which is > loaded in the gtkc/gtk.d file: >> Linker.link(gtk_init, "gtk_init", LIBRARY.GTK); > Linker and link are defined in the gtkc/Loader.d > > So, why is it not enough just to "import gtk.Main"? What kind of code is > inside the gtkd-3 library? If the GtkD files contain all the implementations (not just signatures), then you don't have to build/use the library. You can just compile the GtkD source files along with your program, and link with the C library. |
October 03, 2016 Re: Why using wrappers for D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Monday, 3 October 2016 at 17:45:55 UTC, Jonathan M Davis wrote:
> The import statement just tells the D compiler to pull in declarations for the symbols that it needs from those modules. It doesn't actually compile those modules. You still have to give them to the compiler (either all together or separately to generate .o/.obj files) in order to actually compile them. And anything that's not D (like a C/C++ library) still needs to be linked in just like it would be in C/C++.
>
> In C/C++, #including is not enough to compile everything into your code unless everything is in the header files (which it rarely is). For the files in your project, you have to compile every .c/.cpp file to generate the .o or .obj files that the linker then links into your program, and for the 3rd party stuff that's in a library you need to link in the library. Simply #including doesn't actually bring something like curl or gtk into your program. You also have to link it when generating your executable.
>
> It's basically the same thing with D. Every .d file in your project needs to be compiled so that it gets linked into your executable, and if you want to use 3rd party stuff, you have to link in the libraries just like you would with C/C++. The separation is perhaps a bit less clear in D, because you usually just use .d files for everything, whereas C/C++ have .h and .c/.cpp as separate files. D does have .di files for the cases where you need to hide your code, but they don't get used often. But when you do use a .di file, that's what gets imported rather than the .d file which contains the actual definitions, so in that case, the separation is clearer.
Ah great, now I understand it :)
I thought, import and include would work the same way (taking all the code in the .h or .d file and pasting it into the other file).
But if import extracts only the definitions, it is clear, that you have to link against the library, or to add all the .d files to your source code.
A big thank-you to all repliers for making things clear :D
|
October 03, 2016 Re: Why using wrappers for D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chalix | On 10/03/2016 05:47 AM, Chalix wrote: > what do you mean > by "turn C functions into classes"? Many C APIs are object-oriented in that, they pass the most interesting object as the first parameter: // C struct struct Foo { // ... }; // Factory method (or, "constructor") Foo* make_foo(int i, double d); void free_foo(Foo** foo); int use_foo(Foo* foo, const char *str); Instead of living with C's limitations, one can define a D struct Foo and turn such function into member functions: // D struct struct FooD { // ... Foo* c_foo; // other things that go with // Factory method (or, "constructor") this(int i, double d) { c_foo = make_foo(i, d); // dispatch to C library } ~this() { free_foo(&c_foo); // dispatch to C library } void use(BarD bar) { enforce(use_foo(c_foo, "hello"); } } That's how a D wrapper of a C library may look like, which should be almost identical to how it could be done in C++. > Also, I used the Qt library a lot with C++. But although it is a > library, I have access to all the classes, like " QWidget w = new > QWidget();". There is no factory method used. (This confuses me now a > bit...) 'new QWidget()' does call the constructor automatically, which D cannot do. (Although, with the recent changes in C++ interoperability, perhaps even that's doable today.) If D cannot create C++ object with the 'new' keyword, then they can use a layer of a factory method to do it: // A C++ layer extern "C" QWidget* make_QWidget() { return new QWidget(); } extern "C" void free_QWidget(QWidget* p) { delete p; } Since that function (i.e. not the "new expression" itself) is callable from D, the D code can now use the library: extern (C) { // ... QWidget* make_QWidget(); void free_QWidget(QWidget* p); } // D class class QWidgetD { QWidget* cpp_widget; this() { cpp_widget = make_QWidget(); } ~this() { free_QWidget(cpp_widget); } // ... } That's how I understand it anyway... :) Again though, this may be much easier today with the recent and ongoing improvements to C++ interoperability. Ali |
October 03, 2016 Re: Why using wrappers for D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | On Monday, 3 October 2016 at 17:56:46 UTC, ag0aep6g wrote:
> When you do precompile to a library, you can skip the compilation later. That can save time.
True, linking with this library instead of compiling it every time I changed my code will save me a lot of time :)
|
October 03, 2016 Re: Why using wrappers for D? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chalix | On Monday, 3 October 2016 at 17:19:47 UTC, Chalix wrote: > > If I "import foo;" in my project, it will be compiled alongside. So there is no need for an extra library. Same should be for wrapfoo.d. If I "import wrapfoo;", I should just need the C-library "foo", and no D-library "food" right? You do have some confusion here, which Jonathan's answer should clear up (that is, importing a module does not cause it to be compiled, only makes its symbols to the module in which the declaration is made), however, there is one point I'd like to make below. > > This function wraps the C-like gtk_init function to a D init function. > The gtk_init function is the function from the GTK+ library, which is loaded in the gtkc/gtk.d file: >> Linker.link(gtk_init, "gtk_init", LIBRARY.GTK); > Linker and link are defined in the gtkc/Loader.d > > So, why is it not enough just to "import gtk.Main"? What kind of code is inside the gtkd-3 library? I don't know the details of the gtkd-3 library, but consider this example: ``` // csay.c #include <stdio.h> void sayHi() { puts("Hi\n"); } // dsay.d module dsay; extern(C) void sayHi(); // hi.d import dsay; void main() { sayHi(); } ``` Assuming you have both dmd and dmc installed, you can easily do a bit of experimentation like so: First, use dmd to generate csay.obj. dmc -c csay.c Next, with dsay.d, hi.d and csay.obj all in the same directory, build an executable. dmd hi.d csay.obj This should result in both a successful compile and a successful link. But understand that dsay.d was *never* compiled in this process. Importing dsay made the source symbol 'sayHi' available to hi.d. The compiler emitted a call to sayHi in the generated binary (hi.obj). Finally, the linker was able to match that call to the C sayHi function and could perform the link to generate the executable. Because the binary symbol for sayHi was already present in csay.obj, you did not need to compile and link dsay.d. Now, let's change it up a bit: ``` // csay.h extern void sayHi(); #define sayHiTwice \ sayHi(); \ sayHi(); ``` This is a horrible macro, but it serves its purpose as an example. In order to provide sayHiTwice in D, it will have to be implemented and not just declared: ``` // dsay.d extern(C) void sayHi(); void sayHiTwice() { sayHi(); sayHi(); } ``` Since the C version of sayHiTwice is a macro and not a function, it need not be extern(C). However, no we have an implementation and not simply a declaration. So this: ``` // hi.d import dsay; void main() { sayHiTwice(); } ``` dmd hi.d csay.obj Is now going to generate a *linker* error. It will *compile* just fine, since the import of dsay makes sayHiTwice visible during compilation. However, since csay.obj does not contain a binary symbol for sayHiTwice (as it's a macro and not a function), the the linker will be unable to match the call to any existing symbol and will produce an error. So you would have to do this: dmd hi.d dsay.d csay.obj Now, the binary symbol for sayHiTwice will be generated because dsay.d is being compiled and linked into the program. So, when you have a declarations-only module, with no function implementations or template instantiations, then it need not actually be compiled and linked into the program. In that you are correct. But, no, importing a module does not automatically compile it. And any function declarations still need an implementation somewhere if they are used in the modules you do compile. |
Copyright © 1999-2021 by the D Language Foundation