digitalmars.D.learn - Dynamically calling external libraries.
- Setra (10/10) Feb 26 2014 Hello all! I am in the process of creating a programming
- Adam D. Ruppe (11/11) Feb 26 2014 You'd do it the same way you do in C. On Windows, call
- Mike James (7/18) Feb 26 2014 That's the way I do it but I was wondering. Is it better to load
- John Colvin (5/24) Feb 26 2014 Normally one loads it at the start. In the case of an optional
- Setra (40/40) Feb 27 2014 I have found the Dlang wiki article on how to do it.
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (19/23) Feb 27 2014 What do you mean by "returns"? You're not actually printing the
- Setra (13/13) Feb 27 2014 By returns I ment what it wrote to the screen. I realise now that
- Setra (2/2) Feb 28 2014 Marc would you be willing to post your compile script? Or did you
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (17/19) Feb 28 2014 I used exactly what I quoted in my post:
- Setra (1/1) Feb 28 2014 I am using dmd_2.065.0-0_i386.deb on a 32 bit machine.
- Tolga Cakiroglu (17/18) Feb 28 2014 Hi Setra,
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (19/20) Feb 28 2014 Ah, I can reproduce it with 32bit executables:
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (12/32) Feb 28 2014 No, it isn't. The problem is here:
- Setra (1/1) Feb 28 2014 Thanks! That was perfect!
Hello all! I am in the process of creating a programming language, and I have completed parsing for most of the actual language (it is interpreted). I do not however have a way to print to the screen yet. This is because I want to use external libraries. My question is how in D can I call a external library that is specified at runtime not compile time? I want the scripting language to be able to specifiy a library to load / call, and then do so while running. Any thoughts of how to do this? Thanks! -Setra
Feb 26 2014
You'd do it the same way you do in C. On Windows, call LoadLibrary, FreeLibrary, and GetProcAddress or the COM functions. On Linux, the family of functions is dlopen, dlsym, and dlclose. Knowing the types to pass the functions is gonna be tricky and this needs to be right to avoid crashes. On Windows with scripting language, this is often done through COM automation: the IDispatch interface. With regular C functions, you really just have to know the prototypes ahead of time... it won't be fully dynamic, you load the library at run time but know how to use it at compile time.
Feb 26 2014
On Wednesday, 26 February 2014 at 14:41:02 UTC, Adam D. Ruppe wrote:You'd do it the same way you do in C. On Windows, call LoadLibrary, FreeLibrary, and GetProcAddress or the COM functions. On Linux, the family of functions is dlopen, dlsym, and dlclose. Knowing the types to pass the functions is gonna be tricky and this needs to be right to avoid crashes. On Windows with scripting language, this is often done through COM automation: the IDispatch interface. With regular C functions, you really just have to know the prototypes ahead of time... it won't be fully dynamic, you load the library at run time but know how to use it at compile time.That's the way I do it but I was wondering. Is it better to load all the functions from the DLL at the start of the program or load them when required and keep having to check if they're loaded before each use? -<Mike>-
Feb 26 2014
On Wednesday, 26 February 2014 at 17:58:46 UTC, Mike James wrote:On Wednesday, 26 February 2014 at 14:41:02 UTC, Adam D. Ruppe wrote:Normally one loads it at the start. In the case of an optional feature depending on a shared library, you can always set a global flag (probably shared/__gshared) to say whether the load was successful and use that later on to check.You'd do it the same way you do in C. On Windows, call LoadLibrary, FreeLibrary, and GetProcAddress or the COM functions. On Linux, the family of functions is dlopen, dlsym, and dlclose. Knowing the types to pass the functions is gonna be tricky and this needs to be right to avoid crashes. On Windows with scripting language, this is often done through COM automation: the IDispatch interface. With regular C functions, you really just have to know the prototypes ahead of time... it won't be fully dynamic, you load the library at run time but know how to use it at compile time.That's the way I do it but I was wondering. Is it better to load all the functions from the DLL at the start of the program or load them when required and keep having to check if they're loaded before each use? -<Mike>-
Feb 26 2014
I have found the Dlang wiki article on how to do it. http://dlang.org/dll-linux.html I am using the following code. [code] import core.stdc.stdio; import core.stdc.stdlib; import core.sys.posix.dlfcn; extern (C) int dll(); int main() { printf("+main()\n"); void *lh = dlopen("libdll.so", RTLD_LAZY); if (!lh) { fprintf(stderr, "dlopen error: %s\n", dlerror()); exit(1); } printf("libdll.so is loaded\n"); int function(int x) fn = cast(int function(int x))dlsym(lh, "dll"); printf("dll() function is found\n"); fn(72); printf("unloading libdll.so\n"); dlclose(lh); printf("-main()\n"); return 0; } [\code] [code] import core.stdc.stdio; import std.stdio; extern (C) int dll(int x) { printf("dll()\n"); writeln(x); return 0; } [\code] I am compiling it the way to guide recomends it. It compiles however for some reason when it runs the value returned by the dll is incorrect? Does anyone know why? It always returns the same value even when I change the parameter. Thanks!
Feb 27 2014
On Thursday, 27 February 2014 at 14:38:11 UTC, Setra wrote:I am compiling it the way to guide recomends it. It compiles however for some reason when it runs the value returned by the dll is incorrect? Does anyone know why? It always returns the same value even when I change the parameter.What do you mean by "returns"? You're not actually printing the return value of fn(). Are you referring to the value printed in dll()? For me this works (openSUSE 13.1, DMD git master): +main() libdll.so is loaded dll() function is found dll() 72 unloading libdll.so -main() (I had to remove the "import std.stdio" and change the writeln() to printf("%d", x) to get it to link because of an undefined symbol.)
Feb 27 2014
By returns I ment what it wrote to the screen. I realise now that that was a bad word to use... Every time I run it I get the value 134515512. Here is my compile script (Note I edited my code to use the same method of printing that you did and got the same result): dmd -c dll.d -fPIC dmd -oflibdll.so dll.o -shared -defaultlib=libphobos2.so -L-rpath=/path/to/where/shared/library/is dmd -c main.d dmd main.o -L-ldl -defaultlib=libphobos2.so -L-rpath=.:/path/to/where/shared/library/is -map ./main Thanks!
Feb 27 2014
Marc would you be willing to post your compile script? Or did you just use what the wiki said to?
Feb 28 2014
On Friday, 28 February 2014 at 16:44:02 UTC, Setra wrote:Marc would you be willing to post your compile script? Or did you just use what the wiki said to?I used exactly what I quoted in my post: dmd main1.d -L-ldl dmd -c dll.d -fPIC dmd -oflibdll.so dll.o -shared -defaultlib= LD_LIBRARY_PATH=. ./main1 But what you just wrote works correctly, too. Are you sure you're actually using the correct object files? I.e. try deleting all output files first. Sometimes it's really trivialities like this :-) Or it's an architectural problem? I'm on x86_64, maybe you're compiling 32bit code (although of course that should work, but you can never know)? Which version of DMD are you using? Otherwise you could try disassembling things or single-step through the call with a debugger. But maybe someone else knows something better?
Feb 28 2014
I am using dmd_2.065.0-0_i386.deb on a 32 bit machine.
Feb 28 2014
On Friday, 28 February 2014 at 17:29:09 UTC, Setra wrote:I am using dmd_2.065.0-0_i386.deb on a 32 bit machine.Hi Setra, I am trying to make external libraries work as well, but having problems continuously. Could you test that following function in your library and call it from main programme. I am having "Segmentation Fault" with it, and wondering if other people has the same thing. class A{ public this(){ writeln("Created"); } } extern(C) void foo(){ Object obj = new Object(); A objA = new A(); char[] c = new char[ 1024 ]; }
Feb 28 2014
On Friday, 28 February 2014 at 17:29:09 UTC, Setra wrote:I am using dmd_2.065.0-0_i386.deb on a 32 bit machine.Ah, I can reproduce it with 32bit executables: +main() libdll.so is loaded dll() function is found dll() 134684056 unloading libdll.so -main() ./main1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, BuildID[sha1]=a0eb9b8af3a95d0c4fddd2daf7a476aabed4b53e, not stripped Might be a compiler bug...
Feb 28 2014
On Friday, 28 February 2014 at 18:05:13 UTC, Marc Schütz wrote:On Friday, 28 February 2014 at 17:29:09 UTC, Setra wrote:No, it isn't. The problem is here: int function(int x) fn = cast(int function(int x))dlsym(lh, "dll"); This should be: extern(C) int function(int x) fn = cast(int function(int x))dlsym(lh, "dll"); The calling conventions for C and D are different on x86, but happen to agree on x86_64 (at least the parts that are relevant here). Btw, the forward declaration on top "extern (C) int dll();" isn't used anywhere.I am using dmd_2.065.0-0_i386.deb on a 32 bit machine.Ah, I can reproduce it with 32bit executables: +main() libdll.so is loaded dll() function is found dll() 134684056 unloading libdll.so -main() ./main1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, BuildID[sha1]=a0eb9b8af3a95d0c4fddd2daf7a476aabed4b53e, not stripped Might be a compiler bug...
Feb 28 2014