January 22, 2016 Re: Linking C libraries with DMD | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Friday, 22 January 2016 at 02:39:33 UTC, jmh530 wrote: > I tried to create an example that more closely resembles what is in LearningD (see https://github.com/aldacron/LearningD/tree/master/Chapter09_Connecting%20D%20with%20C/clib). I created two files > > clib.c > ---------------- > #include <stdio.h> > > int some_c_function(int); > > int some_c_function(int a) { > printf("Hello, D! from C! %d\n", a); > return a + 20; > } > > and > > dclib.d > ----------------- > pragma(lib, `libclib.lib`); > > extern(C) @nogc nothrow { > int some_c_function(int); > } > > void main() > { > import std.stdio : writeln; > writeln(some_c_function(10)); > } > > ------------------ > I then ran > gcc -Wall -fPIC -c clib.c > gcc -shared -o libclib.dll clib.o > implib libclib.lib libclib.dll That should be implib /system libclib.lib libclib.dll. I'm pretty sure the /system option is required. (Also be sure you are not mixing 32-bit or 64-bit libraries. I don't think implib works with 64-bit.) > I'm getting an error on the implib command on my home computer. Maybe running it on a different computer would work. > > The LearningD book says that you should compile the libraries with DMC on Windows, but I can't figure out how to generate a shared library on DMC. I didn't get the implib error for what I was working on before. You won't need to use DMC if you're using implib. > I feel like getting stuff to work with Windows is always such a hassle, but that's the only way I'll be able to use this stuff at work. It definitely is more difficult. |
January 22, 2016 Re: Linking C libraries with DMD | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Friday, 22 January 2016 at 02:39:33 UTC, jmh530 wrote:
>
> The LearningD book says that you should compile the libraries with DMC on Windows, but I can't figure out how to generate a shared library on DMC. I didn't get the implib error for what I was working on before.
>
> I feel like getting stuff to work with Windows is always such a hassle, but that's the only way I'll be able to use this stuff at work.
Your confusion appears to be coming from a lack of understanding of what's going on under the hood. When working with a system language like D, it is imperative to understand what the compiler and linker are doing. The same issues you are having can arise when using C and C++, they are just less common as you tend to use the same compiler toolchain for both your executable and your libraries.
First of all, understand that DMD does not use just one linker on Windows. The default is OPTLINK, which only works with 32-bit object files (and by extension, library files, as they are just archives of objects) in the OMF format. When compiling with -m32mscoff or -m64, DMD uses the Microsoft linker, which deals with objects in the COFF format. This matters at *link time*, not at runtime. So it *generally* (see below) doesn't matter which format your DLL is in, as it is loaded at runtime no matter how you compile.
Second, understand that when you choose to link with an import library rather than loading the DLL manually, then it is the format of the import library that's important. It needs to be in the OMF format if you are compiling with vanilla DMD and in the COFF format if not. OMF import libraries can be generated from COFF DLLS with implib. Import libraries generated by the MinGW toolchain are actually in the COFF format, but they are not always compatible with the Microsoft toolchain. You are likely going to have issues even when compiling with -m32mscoff or -m64. Your implib difficulties may actually be arising because the DLL was compiled with MinGW, despite it being in COFF.
Third, understand that passing -L to DMD tells it that the succeeding flag should be passed to the linker. On Windows, -L-L has no meaning, as neither OPTLINK nor the MS linker accept the -L switch. -L is used with GCC to specify the library path, so in the command line -L-L/path/to/libs, the first -L tells DMD that the next part is for the linker and the second -L tells the linker where to find libraries. Again, this is only for the GCC toolchain. For DMD on Windows, how you specify the library path depends on whether you are linking with OPTLINK or the MS linker. As for the libraries themselves, you don't need to don't actually need the -L flag on Windows. In fact, you can save yourself some trouble and just pass the full path to any libraries you need with no flags at all:
dmd myapp.d C:\path\to\libs\mylib.lib
As long as the library is in the appropriate format, this command line will do the right thing.
I strongly recommend that you compile your DLL and generate the import library with the Microsoft tools. Then you should be able to use the 32-bit version with -m32mscoff and the 64-bit version with -m64. This should /just work/.
Development on Windows is not any more difficult than on Linux. It's annoying, sure, but not difficult. You just need to make sure that all of the tools you are using are compatible.
|
January 22, 2016 Re: Linking C libraries with DMD | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On Friday, 22 January 2016 at 04:03:27 UTC, Mike Parker wrote:
> [snip]
Thanks for the detailed reply.
|
January 22, 2016 Re: Linking C libraries with DMD | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | I've take your example, modified it slightly, compiled the DLL with Visual Studio, and got a working executable. Firs up, the C file. Here's your original: > clib.c > ---------------- > #include <stdio.h> > > int some_c_function(int); > > int some_c_function(int a) { > printf("Hello, D! from C! %d\n", a); > return a + 20; > } > First, the function prototype is not needed. You only need those in header files for other C modules to have access to them. Declaring them in the same source file as the function implementation serves no purpose. Second, the Microsoft linker needs to know which functions you intend to export from your DLL. In order to tell it, you either need to add a __declspec(dllexport) to the functions you plan to export, or provide a module definition file on the command line (see [1]). I opted for the former approach. With that, your C source file looks like this: ``` #include <stdio.h> __declspec(dllexport) int some_c_function(int a) { printf("Hello, D! from C! %d\n", a); return a + 20; } ``` In the D source file, I opted to remove the pragma in favor of passing the import library on the command line: > extern(C) @nogc nothrow { > int some_c_function(int); > } > > void main() > { > import std.stdio : writeln; > writeln(some_c_function(10)); > } > OK, now create the following file/folder heirarchy: -vctest --src ----c/clib.c ----d/dclib.d --lib --bin I have Visual Studio Community 2015 installed. Whichever version you have, you should find a folder for it in the Windows start menu that provides shortcuts to various command prompts. I opted for the one labeled VS2015 x64 Native Tools Command Prompt. You might select the 32-bit (x86) version instead. Open one of them, navigate to the vctest directory, and execute the following command line: cl /D_USRDLL /D_WINDLL src\c\clib.c /LD /Felib\clib.lib /link Note the backslashes in src\c\clib.c and lib\clib.lib. You'll likely see an error with forward slashes, unless you put the paths in quotes (see [2] for compiler options). This should create both clib.dll and the import library clib.lib in the lib directory. Next, copy the dll to the bin directory: copy lib\clib.dll bin Now, either in the same command prompt or a separate one where DMD is on the path (depending on your configuration), execute the following: dmd -m64 src/d/dclib.d lib/clib.lib -ofbin/dclib.exe Replace -m64 with -m32mscoff if you used the 32-bit toolchain instead of the 64-bit. Following these steps, I produced a working executable that output the following: Hello, D! from C! 10 30 [1] https://msdn.microsoft.com/en-us/library/34c30xs1.aspx [2] https://msdn.microsoft.com/en-us/library/19z1t1wy.aspx |
January 22, 2016 Re: Linking C libraries with DMD | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On Friday, 22 January 2016 at 04:43:52 UTC, Mike Parker wrote:
> [snip]
Thanks again! Will review.
|
February 02, 2016 Re: Linking C libraries with DMD | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Parker | On Friday, 22 January 2016 at 04:43:52 UTC, Mike Parker wrote:
> [snip]
Thanks again for your help. I've worked through some simple examples and started trying to write a binding to a C library.
I think I've got the .h file converted properly (the D file compiles), but I was getting a linking error. The enums were showing up, but not the functions. I tried creating a simple project that mimics what was happening in the C library and found no issues.
I think I narrowed it down to what is causing the linking error. I had not compiled the C dll myself. Looking in to the issue, I noticed it was compiled with MinGW. There were instructions for using it with Visual Studio (to make the .def and .dll files into a .lib) though and I assumed following those was sufficient. However, based on what you've said, I suspect that if I re-compile the dll using Visual Studio, then it will work with D.
I don't think I would have figured that out without your comments above.
|
February 02, 2016 Re: Linking C libraries with DMD | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Tuesday, 2 February 2016 at 20:06:05 UTC, jmh530 wrote:
> I suspect that if I re-compile the dll using Visual Studio, then it will work with D.
>
Yeah, this is what finally allowed me to progress.
Unfortunately, my sample example compiles, but throws an Access Violation error when I run it. I think I will start a new thread to address that.
|
Copyright © 1999-2021 by the D Language Foundation