Thread overview
export keyword messes up static linking
Jan 24, 2007
torhu
Jan 24, 2007
Carlos Santander
Jan 26, 2007
torhu
Jan 26, 2007
Frits van Bommel
Jan 26, 2007
torhu
Jan 26, 2007
torhu
January 24, 2007
I'm porting headers for a C lib do D.  There are a bunch of globals in the C lib.  To get those correctly linked with the D code, I have to declare them 'export extern extern (C)'.

That works fine for dynamically linking with the C lib, at least with dmd on windows.  The problem is that it won't work if you try to link statically.  The linker accepts it, but at least some of the globals are not linked with the C definitions, they don't contain the correct values.

And for linking statically using dmd on linux, it just doesn't work. The export symbols get mangled like '_imp__foo', so it won't link.

Is there any way around this?  I've tried using a .def file, but it doesn't do anything.  This is what I tried:

EXETYPE NT
SUBSYSTEM CONSOLE

IMPORTS
    cglobals.var
    cglobals.array


If that had worked, I wouldn't have had to declare global C variables 'export' in my import modules, so I would have been able to link the same code both statically and dynamically.

Littering the code with version statements for this seems a bit over the top.  And using the C preprocessor on D code wasn't supposed to be necessary.
January 24, 2007
torhu escribió:
> I'm porting headers for a C lib do D.  There are a bunch of globals in the C lib.  To get those correctly linked with the D code, I have to declare them 'export extern extern (C)'.
> 
> That works fine for dynamically linking with the C lib, at least with dmd on windows.  The problem is that it won't work if you try to link statically.  The linker accepts it, but at least some of the globals are not linked with the C definitions, they don't contain the correct values.
> 
> And for linking statically using dmd on linux, it just doesn't work. The export symbols get mangled like '_imp__foo', so it won't link.
> 
> Is there any way around this?  I've tried using a .def file, but it doesn't do anything.  This is what I tried:
> 
> EXETYPE NT
> SUBSYSTEM CONSOLE
> 
> IMPORTS
>     cglobals.var
>     cglobals.array
> 
> 
> If that had worked, I wouldn't have had to declare global C variables 'export' in my import modules, so I would have been able to link the same code both statically and dynamically.
> 
> Littering the code with version statements for this seems a bit over the top.  And using the C preprocessor on D code wasn't supposed to be necessary.

Start with something simple. Maybe this will give you some ideas:

$ cat cmod.c
#include <stdio.h>

void foo()
{
        printf("hi from c\n");
}

$ cat dmod.d
extern (C) void foo();

void main()
{
        foo();
}

$ gcc -c cmod.c

$ gdmd dmod cmod.o

$ ./dmod
hi from c

That was using GDC. On Windows (using DMD) you would replace "gcc" with "dmc" and "gdmd dmod cmod.o" with "dmd dmod cmod.obj".

If you have a library, put all your declarations in a single .d (or .di) file, and use the .lib instead of the .obj. You can check the Bindings project at DSource to see how it's done.

-- 
Carlos Santander Bernal
January 26, 2007
I think I'll try to restate the problem in a simpler way.

I have a C lib, that I want to link with D apps.  So I write a D 'header', like so:

module clib;

export extern extern (C) {
    int foo;
    char* bar;
}


This works just fine, if I link dynamically with the C lib.  But if I want to link statically, it doesn't work.  This is because 'export' can't be there when you link statically.  foo and bar ptr get random values in the D app.

In this example 'export' works like msvc's __declspec(dllimport).  So in C code, you could use a macro to turn it off for static linking.


Does Optlink have a switch for this, or can someone tell me how to write a .def file so I don't have to declare the variables 'export'?

This C lib is cross-platform, so I'd also like to know if gcc (for dmd use), or at least gdc has a solution for this.  Currently we use a script that just does 's/export//g'.
January 26, 2007
torhu wrote:
> I think I'll try to restate the problem in a simpler way.
> 
> I have a C lib, that I want to link with D apps.  So I write a D 'header', like so:
> 
> module clib;
> 
> export extern extern (C) {
>     int foo;
>     char* bar;
> }
> 
> 
> This works just fine, if I link dynamically with the C lib.  But if I want to link statically, it doesn't work.  This is because 'export' can't be there when you link statically.  foo and bar ptr get random values in the D app.
> 
> In this example 'export' works like msvc's __declspec(dllimport).  So in C code, you could use a macro to turn it off for static linking.
> 
> 
> Does Optlink have a switch for this, or can someone tell me how to write a .def file so I don't have to declare the variables 'export'?
> 
> This C lib is cross-platform, so I'd also like to know if gcc (for dmd use), or at least gdc has a solution for this.  Currently we use a script that just does 's/export//g'.

Put "version(C_Lib_Dll) export:" before your declarations.
If you then pass "-version=C_Lib_Dll" (no quotes) to DMD (or something like "-fversion=C_Lib_Dll" to GDC) when compiling, or put "version = C_Lib_Dll" in the source above that line, 'export' will be applied to all declarations after that. If you don't do any of those things, it won't. This means you have to put all non-exported symbols (if any) above this line, though.
Of course, the "C_Lib_Dll" should be changed to something unique to your C library (and preferably indicate it is to be loaded as a DLL).
Normally, the scope of such a statement can be limited by putting it in a {} block, but those aren't allowed at module scope.
January 26, 2007
Frits van Bommel wrote:
> torhu wrote:
>> I think I'll try to restate the problem in a simpler way.
>> 
>> I have a C lib, that I want to link with D apps.  So I write a D 'header', like so:
>> 
>> module clib;
>> 
>> export extern extern (C) {
>>     int foo;
>>     char* bar;
>> }
>> 
>> 
>> This works just fine, if I link dynamically with the C lib.  But if I want to link statically, it doesn't work.  This is because 'export' can't be there when you link statically.  foo and bar ptr get random values in the D app.
>> 
>> In this example 'export' works like msvc's __declspec(dllimport).  So in C code, you could use a macro to turn it off for static linking.
>> 
>> 
>> Does Optlink have a switch for this, or can someone tell me how to write a .def file so I don't have to declare the variables 'export'?
>> 
>> This C lib is cross-platform, so I'd also like to know if gcc (for dmd use), or at least gdc has a solution for this.  Currently we use a script that just does 's/export//g'.
> 
> Put "version(C_Lib_Dll) export:" before your declarations.
> If you then pass "-version=C_Lib_Dll" (no quotes) to DMD (or something like "-fversion=C_Lib_Dll" to GDC) when compiling, or put "version = C_Lib_Dll" in the source above that line, 'export' will be applied to all declarations after that. If you don't do any of those things, it won't. This means you have to put all non-exported symbols (if any) above this line, though.
> Of course, the "C_Lib_Dll" should be changed to something unique to your C library (and preferably indicate it is to be loaded as a DLL).
> Normally, the scope of such a statement can be limited by putting it in a {} block, but those aren't allowed at module scope.

Part of the problem is that I want to keep the .d files as close the .h files as possible, so it's easier to find where things are when updating them for new versions etc.

from http://www.digitalmars.com/d/attribute.html :
"Export means that any code outside the executable can access the member. Export is analogous to exporting definitions from a DLL."

This is all that's written about export, apart from some examples on the pages about DLL's and '.h to .d'.  They mostly show  that export is also used for importing definitions from a DLL, not just exporting.

Just putting this on top of the file seems to work with dmd on windows, at least after some preliminary testing:

version (STATICLINK) {}
else export:

I didn't think of using export with a colon, but it seems the best alternative to search and replace.  Can I safely assume that if I have a definition in the D code that is declared export (but not extern), it will still be a definition?  That seems to be the idea, but I don't feel entirely safe.

The other way, leaving out 'export' for symbols that are imported from the DLL when doing dynamic linking actually works for some symbols but not others, which is a bit scary.  It's not needed for functions, just for variables.
January 26, 2007
torhu wrote:

> from http://www.digitalmars.com/d/attribute.html :
> "Export means that any code outside the executable can access the member. Export is analogous to exporting definitions from a DLL."
> 
> This is all that's written about export, apart from some examples on the pages about DLL's and '.h to .d'.  They mostly show  that export is also used for importing definitions from a DLL, not just exporting.
> 
> Just putting this on top of the file seems to work with dmd on windows, at least after some preliminary testing:
> 
> version (STATICLINK) {}
> else export:
> 
> I didn't think of using export with a colon, but it seems the best alternative to search and replace.  Can I safely assume that if I have a definition in the D code that is declared export (but not extern), it will still be a definition?  That seems to be the idea, but I don't feel entirely safe.
> 
> The other way, leaving out 'export' for symbols that are imported from the DLL when doing dynamic linking actually works for some symbols but not others, which is a bit scary.  It's not needed for functions, just for variables.

'export:' at the top of the files seems to work.  Except for one thing.  Imported functions that are declared like this only partially work:

export extern (C) int f(float x);

The export makes them it impossible to use their address in static initialization.  This doesn't compile:

extern (C) int (*proc)(float) = &f;


So I still think a suitable .def file might be a cleaner solution.