www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Step by step tutorials for using bindings in D

reply eXodiquas <exodiquas gmail.com> writes:
Hello everyone,

once again, I am here for your help. My last questions were 
answered really competently so I try again. :P

So, maybe this is a stupid question, but I have read a lot about 
Bindings to C and C++ libraries for D. For example the Derelict 
project (or now [BindBC](https://github.com/BindBC/bindbc-sfml)) 
is full of them. Now I wanted to use the SMFL2 dynamic bindings.

In my head this works like this:
1. I create a project called sfmltest
2. I have to get the original SFML2 from somewhere
3. I have to place some already compiled SFML2 files somewhere in 
the sfmltest project
4. I have to add the BindBC-SFML dependencies to the sfmltest 
project
5. I have to load the compiled SFML2 files from within my D code
6. I can use the bindings.

But as you see, my idea about the whole workflow is pretty vague.
- What files do I really need from SFML2?
- Where do I have to store the files from SFML2?
- How can I tell the D compiler where to find those SFML2 files?
- Is the overall idea I have about those bindings correct at all?
- How do dynamic bindings and static bindings differ from each 
other?

Is there a good resource to learn about those bindings? I 
currently skim through the books "Web Development in D" and "D 
Cookbook" and there are also mentions of bindings in them, but 
they assume I know what I am doing, what I am not. :D

I hope this question or the array of questions to be real is not 
too stupid.

Thanks in advance and have a nice weekend!

eXodiquas
Mar 24 2023
parent reply Inkrementator <invalid email.com> writes:
On Friday, 24 March 2023 at 23:45:15 UTC, eXodiquas wrote:
 Hello everyone,

 once again, I am here for your help. My last questions were 
 answered really competently so I try again. :P

 So, maybe this is a stupid question, but I have read a lot 
 about Bindings to C and C++ libraries for D. For example the 
 Derelict project (or now 
 [BindBC](https://github.com/BindBC/bindbc-sfml)) is full of 
 them. Now I wanted to use the SMFL2 dynamic bindings.

 In my head this works like this:
 1. I create a project called sfmltest
 2. I have to get the original SFML2 from somewhere
 3. I have to place some already compiled SFML2 files somewhere 
 in the sfmltest project
 4. I have to add the BindBC-SFML dependencies to the sfmltest 
 project
 5. I have to load the compiled SFML2 files from within my D code
 6. I can use the bindings.

 But as you see, my idea about the whole workflow is pretty 
 vague.
 - What files do I really need from SFML2?
 - Where do I have to store the files from SFML2?
 - How can I tell the D compiler where to find those SFML2 files?
 - Is the overall idea I have about those bindings correct at 
 all?
 - How do dynamic bindings and static bindings differ from each 
 other?

 Is there a good resource to learn about those bindings? I 
 currently skim through the books "Web Development in D" and "D 
 Cookbook" and there are also mentions of bindings in them, but 
 they assume I know what I am doing, what I am not. :D

 I hope this question or the array of questions to be real is 
 not too stupid.

 Thanks in advance and have a nice weekend!

 eXodiquas
Hi, there are two things going on here that we need to pick apart, unfortunately they are confusingly named. On the one hand, we have static and dynamic linking, on the other we have static /dynamic bindings. _This in written from the linux perspective. For windows, most of it will still apply, but details like executable names or file endings will change_ To understand this, we first need to understand a bit more about compilation. Again, we have some unpedagogical nomenclature, so I'll refer to compilation from Source to Executable/ Library as Translation from now on, while the *compilation phase* gets to keep its name. Translation can roughly be divided into two phases: The compilation phase and the linking phase. The compilation phase converts every source file into an object file with the ending ".o". They already contain binary code, with the exception of symbols (function name, global vars), which are still in text form. These symbols can be undefined and point to functions from other object files or libraries, but you need the types to be able to generate binary code, this is why we need binding (more on them later). The linker will combine all the object files into one file. It will resolve the undefined (and defined) symbols and insert actual addresses. How it handles external libraries depends on whether you choose a static or dynamic library. A static library (ending ".a" on linux) is basically just a file containing many different object files. If you link against it, the library gets bundled into your final executable like the rest of your object files. This has the advantage of making your executable independent of the environment where you deploy it, it won't crash when your user updates his libraries. But it leads to space waste when many programs use the same library and also forces you to distribute a recompiled version when you just want to update a library. This is especially problematic when one of your libraries has a security issue as it lengthens the update cycle. Dynamic Libraries (ending ".so" on Linux, ".dll" on windows) get loaded dynamically when the program starts. The environment needs to provide them. Execute `ldconfig -p` to list all shared libraries on the system. `ldd MyExecutable` will list all dynamic libraries required by your executable. Dynamic Bindings only work when using the dynamic library. bindbc-sfml allows you to instead of using the system dynamic library loader ld.so to instead manually load the dynamic library. https://github.com/BindBC/bindbc-loader/blob/master/source/bindbc/loader/sharedlib.d#L320 Afaict, this is only used so you don't need the original SFML library on your dev system, it will still be needed on the client or if you want to test. I don't understand why you'd want to do this, maybe someone else here can illuminate this issue. Normally, dynamic binding is useful when you want to lazily load shared libraries which in some extreme cases can be benefitial, or want to be able to hotload plugins. Now you might wonder: Why does the dynamic linker need the shared library present on the dev system and doesn't just internally do the same thing as bindbc_loaders? I'm actually not quite sure, I think it has to do with when compiling you can specify many different libraries, and so it would have to search for each symbol (functionname) in all specified shared libraries at runtime. Two ways to go about this: 1. Get SFML dynamic library somewhere 2. Create a project called sfmltest 3. Add BindBC-SFML dependency via dub 4. Put SFML dynamic library files into the directory where you will execute your file. Here we see that the dynamic bindings looks for the lib in the current directory: https://github.com/BindBC/bindbc-sfml/blob/a1bc81da5c41ec49257228a29dc0f30ec7e5c788/source/bindbc/sfml/system.d#L215 You can also use static bindings, but that will involve telling your linker about the library. I won't go into detail but it basically boils down to installing SFML to system directory or LD_LIBRARY_PATH and compiling your test project with -lSFML flag, or whatever the option is for dub. If you can install it via your package-manager, static bindings might be less of a hassle. And learning the process is worth it, you'll need it in the future, since dynamic binding are the exception.
Mar 26 2023
parent reply eXodiquas <exodiquas gmail.com> writes:
On Sunday, 26 March 2023 at 14:09:19 UTC, Inkrementator wrote:

 Two ways to go about this:
 1. Get SFML dynamic library somewhere
 2. Create a project called sfmltest
 3. Add BindBC-SFML dependency via dub
 4. Put SFML dynamic library files into the directory where you 
 will execute your file.
 Here we see that the dynamic bindings looks for the lib in the 
 current directory: 
 https://github.com/BindBC/bindbc-sfml/blob/a1bc81da5c41ec49257228a29dc0f30ec7e5c788/source/bindbc/sfml/system.d#L215

 You can also use static bindings, but that will involve telling 
 your linker about the library. I won't go into detail but it 
 basically boils down to installing SFML to system directory or 
 LD_LIBRARY_PATH and compiling your test project with -lSFML 
 flag, or whatever the option is for dub.
 If you can install it via your package-manager, static bindings 
 might be less of a hassle. And learning the process is worth 
 it, you'll need it in the future, since dynamic binding are the 
 exception.
Thank you very much for your detailed answer. I got dynamic bindings running now. But you said static bindings are the main portion of bindings we use. So I tried to get static Lua bindings going. I got the static library `liblua.a` and I told my linker in the dub.json file where to find it: ```json [...] "versions": ["LUA_52"], "lflags": ["-L/usr/local/lib/liblua.a"], [...] ``` This works perfectly fine. I can also use `"libs": ["lua"]` so I don't have to specify the complete path. But now I wonder, do I have to specify all static bindings via linker commands or is there a mechanism which allows me to specify a path where all the libraries can be found? And my other question is, if I have to specify all static libraries by name, how do I know the name of the library? Giving the system path as `lflag` is easy, but where does Lua get the `lua` name from which works in the `"libs": ["lua"]` string? Thanks for answering my noob questions. I've never dealt with bindings and compiler flags in the languages I come from. :P
Mar 26 2023
parent reply Inkrementator <invalid email.com> writes:
On Sunday, 26 March 2023 at 18:49:57 UTC, eXodiquas wrote:
 On Sunday, 26 March 2023 at 14:09:19 UTC, Inkrementator wrote:
 But you said static bindings are the main portion of bindings 
 we use. So I tried to get static Lua bindings going.
Static Binding != Static Linking. Like I said, the terminology is not noob friendly and funnily enough, you might have taken away from the sentence the opposite of what is true. To statically bind, you have to do nothing in 99.9% of cases I have never encountered a library before that handles it like the one you posted and does offers dynamic binding. But for static/ dynamic *linking*, it's the opposite. If you don't type in a full path, but just `"libs": ["lua"]`, the compiler will by default pick the shared library if both static and shared are available. In general I would say it doesn't really matter until you want to distribute your app, then you have to think about it. So **TL;DR**: Don't bother with static linking. Just say `"libs": ["lua"]` and don't worry about it. In the following I try to explain what actually happens in the background, but understanding it is not important in the beginning. The following is only for your interest.
`"lflags": ["-L/usr/local/lib/liblua.a"]`
I'm surprised this worked, according to `man ld`, the -L flag takes a dir as input, not a full filepath. Can you please post your full dub config? I'm intrigued.
 This works perfectly fine. I can also use `"libs": ["lua"]` so 
 I don't have to specify the complete path. But now I wonder, do 
 I have to specify all static bindings via linker commands or is 
 there a mechanism which allows me to specify a path where all 
 the libraries can be found? And my other question is, if I have 
 to specify all static libraries by name, how do I know the name 
 of the library? Giving the system path as `lflag` is easy, but 
 where does Lua get the `lua` name from which works in the 
 `"libs": ["lua"]` string?
These questions are related. `"libs": ["lua"]` will get translated to the compiler option `\<compiler> -llua`, who will search the library search path for files named liblua.so.\<Version>, and if it doesn't exist, liblua.a . This is why we have to give full file path of static libraries. You can check the path here: `ld --verbose|grep SEARCH` and can add custom paths via the environment variable LD_LIBRARY_PATH If you want to give (temporary) priority to static library, you can do so via `ld -Bstatic lib1 -Bdynamic lib2 file.o` or if you use a compiler, you have to pass the linkflag, so it's `gdc -Wl,-Bstatic -llib1 file.d`. See: https://stackoverflow.com/questions/6578484/telling-gcc-directly-to-link- -library-statically (gcc is a C compiler, but many concepts will map to D compilers, and almost all to [gdc](https://wiki.dlang.org/GDC) ) Sidenote: If you use this, you have to always make sure you have an `-Bdynamic` or `-Wl,-Bdynamic` at the end, as libc should always be linked dynamically. Problem is, I don't think dub officially supports this. You could try: `"lflags": ["-Bstatic", "-llua", "-Bdynamic"]` But this would be kind of a hack, since now lua shouldn't be listed in the `"libs":"` section anymore. This is an artifact of the fact that not many people bother with static linking. As you see, it's kind of a mess. To make matters worse, depending on the compiler and linker, these options might look different. gcc, ldc and dmd all use some kind of different options, though some stay the same: `-llua` will work for every compiler. But I suppose this is one of the reasons why not inserting hacks into dub like above makes sense, since then it can abstract over different compilers for you.
 Thanks for answering my noob questions. I've never dealt with 
 bindings and compiler flags in the languages I come from. :P
My pleasure. Answering these has been (un)surprisingly helpful in strengthening my own understanding. ____ PS: To really understand what is happening, you might want to try manually compiling a hello world program that depends on a library instead of using dub. Some pointers: `dub build -v` will print out the compiler and linkflags used. `pkg-config --libs --cflags lua` would generate compiler options for you. Use it like `dmd $(pkg-config --libs --cflags lua) program.d` If you decide to try this, I can walk you through it. But remember that it's not that important this is probably all a bit much.
Mar 26 2023
next sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Monday, 27 March 2023 at 00:06:36 UTC, Inkrementator wrote:
 PS: To really understand what is happening, you might want to 
 try manually compiling a hello world program that depends on a 
 library instead of using dub. Some pointers:
 `dub build -v` will print out the compiler and linkflags used.

 `pkg-config --libs --cflags lua` would generate compiler 
 options for you. Use it like
 `dmd $(pkg-config --libs --cflags lua) program.d`

 If you decide to try this, I can walk you through it. But 
 remember that it's not that important this is probably all a 
 bit much.
Even if I wrote similar articles ([for example](https://forum.dlang.org/post/qnzmxceqesmcsmfmzxyr forum.dlang.org), in my own language), it would not be enough! Even writing is not enough... What era are we living in? There is something called YouTube: [How to set up D and GLFW/OpenGL project on MacOS, Linux and Windows](https://www.youtube.com/watch?v=wG6OG6uWyDw&feature=youtu.be) by Ki Rill Likes **17** Views **265** Released on March **8, 2023** I have to ask... How many of you have made such how-to videos? This is a question I have to answer too! Use DUB, recommend, bird in the hand is worth two in the bush 😀 SDB 79
Mar 26 2023
parent Inkrementator <invalid email.com> writes:
On Monday, 27 March 2023 at 00:45:28 UTC, Salih Dincer wrote:
 Likes **17**
 Views **265**
 Released on March **8, 2023**
I'm surprised that you can get 300 views in a month on a primarily D video, but it's nice to see
Mar 30 2023
prev sibling parent eXodiquas <exodiquas gmail.com> writes:
On Monday, 27 March 2023 at 00:06:36 UTC, Inkrementator wrote:
 I'm surprised this worked, according to `man ld`, the -L flag 
 takes a dir as input, not a full filepath. Can you please post 
 your full dub config? I'm intrigued.
Hello again and thank you very much. I got it now, I got OpenGL, ncurses, Lua and Imgui running. This is amazing. My dub.json file looked like this: ```json { "authors": [ "eXodiquas" ], "copyright": "Copyright © 2023, eXodiquas", "dependencies": { "bindbc-lua": "~>1.0.0" }, "lflags": ["-L/usr/local/lib/liblua.a"], "versions": ["LUA_53"], "description": "A minimal D application.", "license": "proprietary", "name": "test" } ``` And I don't know what I did last time but this does not work, like you said. Maybe I forgot to save and was a bit stupid. ```json { "authors": [ "eXodiquas" ], "copyright": "Copyright © 2023, eXodiquas", "dependencies": { "bindbc-lua": "~>0.5.1" }, "description": "A minimal D application.", "libs": ["lua"], "license": "proprietary", "name": "test", "versions": [ "LUA_53" ] } ``` This is working as it is supposed to do. Thanks again for your time!
Mar 28 2023