digitalmars.D.learn - gdc and gcc object linking issues
- Andrej Mitrovic <andrej.mitrovich gmail.com> Jun 06 2012
- Dmitry Olshansky <dmitry.olsh gmail.com> Jun 06 2012
- Dmitry Olshansky <dmitry.olsh gmail.com> Jun 06 2012
- Dmitry Olshansky <dmitry.olsh gmail.com> Jun 07 2012
- Andrej Mitrovic <andrej.mitrovich gmail.com> Jun 06 2012
- "Kagamin" <spam here.lot> Jun 07 2012
- Andrej Mitrovic <andrej.mitrovich gmail.com> Jun 07 2012
- "Regan Heath" <regan netmail.co.nz> Jun 07 2012
- "Kagamin" <spam here.lot> Jun 07 2012
- "Kagamin" <spam here.lot> Jun 07 2012
- Andrej Mitrovic <andrej.mitrovich gmail.com> Jun 07 2012
- "Kagamin" <spam here.lot> Jun 08 2012
- Andrej Mitrovic <andrej.mitrovich gmail.com> Jun 08 2012
This is a bit more related to C++ than D, it has to do with wrapping.
I've got 4 files:
test.h:
class Class
{
public:
static int statField;
};
test.cpp:
#include "test.h"
extern "C" __attribute__((dllexport))
int getStatField()
{
return Class::statField;
}
test.d:
extern(C) int getStatField();
class Class
{
static int statField()
{
return getStatField();
}
}
main.d:
import test;
void main()
{
int x = Class.statField();
}
This is how I compile it (XP32):
g++ -m32 -g -I. -c test.cpp -o test_cpp.o
gdc -m32 -g -I. -c test.d -o test_d.o
gdc -m32 -g -I. -o main.exe test_cpp.o test_d.o main.d -lstdc++
But I get a linker error:
test_cpp.o: In function `getStatField':
D:\dev\code\d_code\testcpplink/test.cpp:5: undefined reference to
`Class::statField'
collect2: ld returned 1 exit status
If I change the static int field to a static function (and add
parenthesis for the function call) the linking works fine, e.g.:
test.h:
class Class
{
public:
// was: static int statField;
static int statField() { return 1; }
};
test.cpp:
#include "test.h"
extern "C" __attribute__((dllexport))
int getStatField()
{
// was: return Class::statField;
return Class::statField();
}
But for variables it doesn't link. What am I doing wrong?
Jun 06 2012
On 06.06.2012 22:20, Andrej Mitrovic wrote:This is a bit more related to C++ than D, it has to do with wrapping. I've got 4 files: test.h: class Class { public: static int statField; };
Old boring C++ :) Once you have this definition due to moronic linkage model (and probably some other reasonable things) you have to have: int Class:statField; declared somewhere in you cpp files that you link together so that compiler knows where to put it (in terms of obj files).But for variables it doesn't link. What am I doing wrong?
Nothing, C++ is pile of dirt. :) -- Dmitry Olshansky
Jun 06 2012
On 06.06.2012 22:39, Dmitry Olshansky wrote:On 06.06.2012 22:20, Andrej Mitrovic wrote:This is a bit more related to C++ than D, it has to do with wrapping. I've got 4 files: test.h: class Class { public: static int statField; };
Old boring C++ :) Once you have this definition due to moronic linkage model (and probably some other reasonable things) you have to have: int Class:statField;
int Class::statField; obviously -- Dmitry Olshansky
Jun 06 2012
On 07.06.2012 23:04, Kagamin wrote:On Thursday, 7 June 2012 at 14:29:24 UTC, Regan Heath wrote:In the quoted passage above I suspect he was referring to a static/global variable defined in a C header, not a C++ class member static or otherwise.
I'm pretty sure you can define (with storage) global variable in header file both in C and C++.
Indeed you can. Kind of anti-pattern.But don't qualify it static in C: this will make it hidden symbol so you will have several instances of the variable but no symbol collision.
Some libraries actually count on something like this, but I can't remember offhand. Logging probably? -- Dmitry Olshansky
Jun 07 2012
On 6/6/12, Dmitry Olshansky <dmitry.olsh gmail.com> wrote:Old boring C++ :) Once you have this definition due to moronic linkage model (and probably some other reasonable things) you have to have: int Class:statField;
int Class::statField; obviously
Thanks, that fixed it! :) Yeah C++ is a weirdo.
Jun 06 2012
A class declaration is simply a declaration, it doesn't allocate storage, so members end up being implicitly extern (or static inline for methods with bodies) except for instance fields, whose storage is allocated with the new operator. As static inlining a field has no sense, it becomes extern. You can declare extern variables in C too (try it). Extern declarations are included into each including module, but you can't do it with the variable's storage itself, so you should *define* the variable in a module where it will actually keep its value. If you define a variable in the header, it will be included in each including module and you'll get several instances of the variable and symbol collision at link time. You can think of a class as an interface declaration which happens to expose some implementation details to you.
Jun 07 2012
On 6/7/12, Kagamin <spam here.lot> wrote:If you define a variable in the header, it will be included in each including module and you'll get several instances of the variable and symbol collision at link time.
This wasn't a collision error, it was a missing symbol error. The variable is static, so it should be in the data or bss segment. You seem to be talking about instance variables but that wasn't the issue here.
Jun 07 2012
On Thu, 07 Jun 2012 15:12:46 +0100, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:On 6/7/12, Kagamin <spam here.lot> wrote:If you define a variable in the header, it will be included in each including module and you'll get several instances of the variable and symbol collision at link time.
This wasn't a collision error, it was a missing symbol error. The variable is static, so it should be in the data or bss segment. You seem to be talking about instance variables but that wasn't the issue here.
I don't think he was posting a solution to the OP, he was just describing some background :) In the quoted passage above I suspect he was referring to a static/global variable defined in a C header, not a C++ class member static or otherwise. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Jun 07 2012
On Thursday, 7 June 2012 at 14:29:24 UTC, Regan Heath wrote:In the quoted passage above I suspect he was referring to a static/global variable defined in a C header, not a C++ class member static or otherwise.
I'm pretty sure you can define (with storage) global variable in header file both in C and C++. But don't qualify it static in C: this will make it hidden symbol so you will have several instances of the variable but no symbol collision.
Jun 07 2012
On Thursday, 7 June 2012 at 14:12:56 UTC, Andrej Mitrovic wrote:This wasn't a collision error, it was a missing symbol error. The variable is static, so it should be in the data or bss segment. You seem to be talking about instance variables but that wasn't the issue here.
You didn't define the variable. It doesn't matter in which section a variable is placed, but which module it's defined in. In D you have declarations in .di files, but .di files alone won't work as you won't have the declared variables' storage - you'll have to link to an object compiled from the corresponding .d file because .d has definitions and that's how actual D members *definitions* are compiled and their storage allocated in sections.
Jun 07 2012
On 6/7/12, Kagamin <spam here.lot> wrote:You didn't define the variable.
Aah, I see what's going on. See, I was using this in the context of wrapping existing C++ libs. Since I was writing a small test-case for wrapping a static field I made a header file with a static field declaration but no .cpp implementation files (except the wrapper). I didn't know I had to either have an initializer in the header or have a .cpp file with the definition. For actual C++ libs the definition of a static field is somewhere in an existing cpp file, so I don't have to re-define the static field when wrapping (otherwise I'd probably get collisions or multiple independent variables).
Jun 07 2012
On Thursday, 7 June 2012 at 23:58:21 UTC, Andrej Mitrovic wrote:I didn't know I had to either have an initializer in the header or have a .cpp file with the definition.
Well, I'm not a C++ pro, but I won't recommend to place initializer in the header. That sounds odd. What would it mean? I guess, it will mean definition, so chances are it's not what you want. Initializers belong to definitions, and definitions belong to .cpp, that's how it usually works unless you know for sure you want something else. Bindings are just fine with declarations alone + support code.
Jun 08 2012
On 6/8/12, Kagamin <spam here.lot> wrote:Well, I'm not a C++ pro, but I won't recommend to place initializer in the header. That sounds odd. What would it mean? I guess, it will mean definition, so chances are it's not what you want. Initializers belong to definitions, and definitions belong to .cpp, that's how it usually works unless you know for sure you want something else. Bindings are just fine with declarations alone + support code.
Yeah I thought they might appear in an existing library in a header file but it seems they're in the definition file. Thanks for your help.
Jun 08 2012









Dmitry Olshansky <dmitry.olsh gmail.com> 