Thread overview | |||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 07, 2010 'Undefined reference' linking errors | ||||
---|---|---|---|---|
| ||||
Hello everyone, A probably stupid but I-can't-find-the-solution-with-Google problem. I'm trying to compile a small project I'm working on to learn D, called 'dregs'. It's just 3 files for now (2 modules plus a little test program). Unfortunately every time I try and compile, I get 'undefined reference' errors for the classes/structs in the modules. Here are the files: // reputation.d module dregs.reputation; struct rating { uint u; // user ID uint o; // object ID double r; // rating value } class reputation { this() { } this(ref rating[] ratings, ref double[] reputation_user, ref double[] reputation_object) { } } // END // avg.d module dregs.avg; public import dregs.reputation; class avg_weighted : reputation { double[] weight_sum; this(){} this(ref rating[] ratings, ref double[] reputation_user, ref double[] reputation_object) { weight_sum.length = reputation_object.length; foreach(r; ratings) { reputation_object[r.o] += r.r; weight_sum[r.o] += reputation_user[r.u]; } foreach(o, r; reputation_object) r /= weight_sum[o]; } void opCall(ref rating[] ratings, ref double[] reputation_user, ref double[] reputation_object); } class avg_arithmetic : avg_weighted { this(ref rating[] ratings, ref double[] reputation_user, ref double[] reputation_object) { foreach(r; reputation_user) r = 1; super(ratings,reputation_user,reputation_object); } void something(ref dregs.reputation.rating[] ratings, ref double[] reputation_user, ref double[] reputation_object) { avg_weighted(ratings,reputation_user,reputation_object); } } // END // test.d import std.stdio; import dregs.reputation; import dregs.avg; void main() { rating[] r; double[] reputation_user; double[] reputation_object; reputation_user.length = 999; reputation_object.length = 1; foreach(u;0..reputation_user.length) { rating _r = {u,0,(u%3)}; r ~= _r; } } // END I'm running dmd 2.042 on Ubuntu 9.10. dmd -O -I../ test.d avg.d reputation.d ... produces the following errors: ------------------------------------ test.o:(.rodata+0x98): undefined reference to `_D5dregs3avg12avg_weighted6opCallMFKAS5dregs10reputation6ratingKAdKAdZv' test.o:(.rodata+0xf8): undefined reference to `_D5dregs3avg12avg_weighted6opCallMFKAS5dregs10reputation6ratingKAdKAdZv' test.o: In function `_D5dregs3avg14avg_arithmetic9somethingMFKAS5dregs10reputation6ratingKAdKAdZv': reputation.d:(.text._D5dregs3avg14avg_arithmetic9somethingMFKAS5dregs10reputation6ratingKAdKAdZv+0x1b): undefined reference to `_D5dregs3avg12avg_weighted6opCallMFKAS5dregs10reputation6ratingKAdKAdZv' collect2: ld returned 1 exit status --- errorlevel 1 ------------------------------------ This surely is something very basic, but I couldn't find a reason for it in my search of the archives ... :-( Can anyone advise what I'm doing wrong? Thanks & best wishes, -- Joe |
April 07, 2010 Re: 'Undefined reference' linking errors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joseph Wakeling | Joseph Wakeling wrote: > void opCall(ref rating[] ratings, > ref double[] reputation_user, > ref double[] reputation_object); The errors are for the missing definitions of that function. Either provide a definition, or just remove that declaration. (Remove the declaration if you just want to create an object below. > avg_weighted(ratings,reputation_user,reputation_object); If you want to create an object of avg_weighted: auto aw = new avg_weighted(ratings,reputation_user,reputation_object); > test.o:(.rodata+0x98): undefined reference to > `_D5dregs3avg12avg_weighted6opCallMFKAS5dregs10reputation6ratingKAdKAdZv' > test.o:(.rodata+0xf8): undefined reference to I wonder how you missed the "opCall" in there! :p Ali |
April 07, 2010 Re: 'Undefined reference' linking errors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joseph Wakeling | Few notes: - opCall() of AvgWeighted was abstract. - keep in mind that in D classes are CamelCase; - variable names are written like weightSum (but once in a while a underscore doesn't kill). - Be careful because ref arguments are tricky. - There is a line like foreach (r; reputationUser) r = 1; that can be a bug. - foreach (objectID, rating; reputationObject) rating /= weightSum[objectID]; can be another bug. - Use better attribute names in Rating struct, when you need to comment a variable name then it's often a wrong name. - To create structs you can most times use the syntax I've used in the main. - In methods/functions divide your code into paragraphs; - keep your indentations more coherent - I suggest to add contracts and unittests. Keeping the code tidy helps a lot avoid bugs. The following is surely not perfect, but it's better: struct Rating { uint userID, objectID; double rating; } class Reputation { this() {} this(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) {} } class AvgWeighted : Reputation { double[] weightSum; this(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) { weightSum.length = reputationObject.length; foreach (r; ratings) { reputationObject[r.objectID] += r.rating; weightSum[r.objectID] += reputationUser[r.userID]; } foreach (objectID, rating; reputationObject) rating /= weightSum[objectID]; // useless? } void opCall(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) {} } class AvgArithmetic : AvgWeighted { this(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) { // foreach (r; reputationUser) r = 1; // bug? reputationUser[] = 1; super(ratings, reputationUser, reputationObject); } void something(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) { AvgWeighted(ratings, reputationUser, reputationObject); } } void main() { double[] reputationUser; reputationUser.length = 999; double[] reputationObject; reputationObject.length = 1; Rating[] r; foreach (userID; 0 .. reputationUser.length) r ~= Rating(userID, 0, userID % 3); } Bye, bearophile |
April 07, 2010 Re: 'Undefined reference' linking errors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | Ali Çehreli:
> > avg_weighted(ratings,reputation_user,reputation_object);
And I have missed this is my cleaning of the code :-)
Bye,
bearophile
|
April 07, 2010 Re: 'Undefined reference' linking errors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | Ali Çehreli:
> > test.o:(.rodata+0x98): undefined reference to
> > `_D5dregs3avg12avg_weighted6opCallMFKAS5dregs10reputation6ratingKAdKAdZv'
> > test.o:(.rodata+0xf8): undefined reference to
>
> I wonder how you missed the "opCall" in there! :p
Those mangled ids are ugly. It's much better to show programmers more readable names in error messages. This can even become a bug report.
Bye,
bearophile
|
April 07, 2010 Re: 'Undefined reference' linking errors | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 07/04/10 22:19, bearophile wrote: > Those mangled ids are ugly. It's much better to show programmers more readable names in error messages. This can even become a bug report. These errors are being given by the linker, and the linker doesn't know how to demangle D symbols, so it doesn't. If you make a bug it should go to the linker's bugzilla as an enhancement request... In the mean time there's several scripts out there that will demangle an input from stdin, so you can pipe the output from the linker to it and get them automatically demangled :) > > Bye, > bearophile |
April 08, 2010 Re: 'Undefined reference' linking errors | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | Thanks to everyone for the responses. I'll respond to Bearophile's detailed comments: > Few notes: > - opCall() of AvgWeighted was abstract. > - keep in mind that in D classes are CamelCase; > - variable names are written like weightSum (but once in a while a underscore doesn't kill). I think it's obvious from my syntax that my background is with C; I'm not experienced with Java, C# etc. This may explain some of the problems I'm having. Regarding opCall I was following the syntax described here: http://www.digitalmars.com/d/2.0/operatoroverloading.html#FunctionCall ... but clearly without understanding it properly. What I was aiming for was a bit smartarse -- to have a class which could in some cases be treated as a function. Each of these classes (later ones will be more sophisticated) is meant to be a data analysis tool which takes a dataset of user-object ratings and user and object reputation values and helps aggregate the ratings and in the process update the reputation values. The aim was that if you just wanted a once-off analysis you could use the class in a throwaway fashion -- hence the use of, avg_weighted(......); rather than avg_weighted aw(.....); The aim is that you would use the second if you were interested in employing the analysis multiple times, and that the class will have other functions that can be used for different or secondary analyses from the main one. It's maybe not the best way to approach what I want to do, but since D is a new language for me, I thought I would be playful with it and try and bend it around in some interesting ways. > - Be careful because ref arguments are tricky. The choice is deliberate here, because the arrays passed to the constructor (or opCall) are meant to be modified. > - There is a line like foreach (r; reputationUser) r = 1; that can be a bug. I guess that I should put a 'double' in front of the r, no? In any case, I guess there is a better way of setting all elements of an array equal to 1.0. > - foreach (objectID, rating; reputationObject) rating /= weightSum[objectID]; can be another bug. ... so should be uint objectID, double rating ... ? I think it's obvious that I want each the value of each element of reputationObject to be divided by the value of the corresponding element of weightSum -- is there a more intelligent way of doing this? Reading Andrei Alexandrescu's article on Dr Dobb's gave me the impression something could be done using chain(), but I couldn't work out how (and probably misunderstood). > - Use better attribute names in Rating struct, when you need to comment a variable name then it's often a wrong name. > - To create structs you can most times use the syntax I've used in the main. > - In methods/functions divide your code into paragraphs; > - keep your indentations more coherent It's nice to see the stress in D on well-written code. Thanks for taking the time to clean up mine. :-) > - I suggest to add contracts and unittests. As you might have guessed, I'm not a developer -- can you provide more info? Thanks & best wishes, -- Joe |
April 08, 2010 Re: 'Undefined reference' linking errors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joseph Wakeling | Joseph Wakeling wrote: >> - opCall() of AvgWeighted was abstract. >> - keep in mind that in D classes are CamelCase; >> - variable names are written like weightSum (but once in a while a underscore > doesn't kill). > > I think it's obvious from my syntax that my background is with C; I'm not > experienced with Java, C# etc. This may explain some of the problems I'm having. > > Regarding opCall I was following the syntax described here: > http://www.digitalmars.com/d/2.0/operatoroverloading.html#FunctionCall > > ... but clearly without understanding it properly. I have experience with C++ and still don't understand why opCall exists. :) I think I heard that opCall was needed to create struct objects before structs had constructors in D. Now structs do have constructors, which sometimes conflict with opCall. :) > What I was aiming for was a bit smartarse -- to have a class which could in some > cases be treated as a function. I consider myself a function-happy programmer. To me, not everything is a class. :) > Each of these classes (later ones will be more > sophisticated) is meant to be a data analysis tool which takes a dataset of > user-object ratings and user and object reputation values and helps aggregate the > ratings and in the process update the reputation values. > > The aim was that if you just wanted a once-off analysis you could use the class in > a throwaway fashion -- hence the use of, > > avg_weighted(......); It could be a function that instantiates on object, that would be thrown away. > It's maybe not the best way to approach what I want to do, but since D is a new > language for me, I thought I would be playful with it and try and bend it around > in some interesting ways. No harm in that. :) >> - Be careful because ref arguments are tricky. > > The choice is deliberate here, because the arrays passed to the constructor (or > opCall) are meant to be modified. D has "reference types". When you pass a class object to a function "by-value", it is actually passed-by-reference. I think this is the same in Java. You can imagine the function parameter being a pointer behind the scenes. ClassType variable = new ClassType; ClassType variable2 = variable; You have a single "object" created with new, and two "variables" that refer to that object. >> - There is a line like foreach (r; reputationUser) r = 1; that can be a bug. > > I guess that I should put a 'double' in front of the r, no? In any case, I guess > there is a better way of setting all elements of an array equal to 1.0. You would put 'ref' in front of the foreach variables. Otherwise they are copies in the foreach loop. >> - foreach (objectID, rating; reputationObject) rating /= weightSum[objectID]; > can be another bug. > > ... so should be uint objectID, double rating ... ? Same: Should probably be 'ref rating' if you want to modify reputationObject. > I think it's obvious that I want each the value of each element of > reputationObject to be divided by the value of the corresponding element of > weightSum -- is there a more intelligent way of doing this? >> - I suggest to add contracts and unittests. > > As you might have guessed, I'm not a developer -- can you provide more info? They are of the greater features of D. :) You can define function pre- and post-conditions and struct and class invariants. You can have unittest blocks... Great stuff! :) http://digitalmars.com/d/2.0/unittest.html http://digitalmars.com/d/2.0/dbc.html http://digitalmars.com/d/2.0/class.html#Invariant Ali |
April 08, 2010 Re: 'Undefined reference' linking errors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | Ali Çehreli wrote: > D has "reference types". When you pass a class object to a function > "by-value", it is actually passed-by-reference. Didn't mean to leave out the others. These are the "reference"s in D: - foreach ref parameters - ref function parameters - dynamic arrays - associative arrays - pointers I am not sure about function and delegate, and I don't know whether there is more that I am missing. Ali |
April 09, 2010 Class-related queries [was: Re: 'Undefined reference' linking errors] | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | Ali Çehreli wrote: > I have experience with C++ and still don't understand why opCall exists. :) I think I heard that opCall was needed to create struct objects before structs had constructors in D. > > Now structs do have constructors, which sometimes conflict with opCall. :) I also have some C++ experience, but it seems to be confusing as much as complementary with respect to D ... :-) Current source of confusion relates to declaring objects of a class whose constructor takes input -- confusion because I can write, class Foo { int x; uint y; this() { x = -1; y = 2; } } void main() { Foo f; } and have no problem, but if instead the constructor is, this(int z) { x = z; y = 2; } ... it seems like I have to write instead, auto f = new Foo(-1); ... and if I write as per C++, Foo f(-1); ... I get back a compiler error: "found 'f' when expecting ';' following 'statement'". Am I right in thinking that the 'new' syntax is necessary when the class has a constructor which takes input? This creates confusion also because in C++ one associates 'new' with dynamic allocation of memory, and it requires a consequent 'delete' statement. I know that D has GC, and I know that it also has 'delete' statements, but ... this one is 'ouch' for me :-P In my own code (cleaned up, attached following this email, and now working), I note the line, auto aw = new AvgWeighted(ratings,reputationUser,reputationObject); where if I write instead, AvgWeighted aw(ratings,reputationUser,reputationObject); ... I get the error: Error: ratings is used as a type Error: cannot have parameter of type void Error: reputationUser is used as a type Error: cannot have parameter of type void Error: reputationObject is used as a type Error: cannot have parameter of type void ... which is difficult to understand, but I presume it relates to the fact that an array is a class and not a value. Apologies if these are relatively trivial questions -- I am sure they will all become clearer once Andrei Alexandrescu's book is out ... :-) Thanks & best wishes, -- Joe ///////// My code .... struct Rating { uint u; // user ID uint o; // object ID double r; // rating value } class Reputation { this() {} this(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) {} } class AvgWeighted : Reputation { double[] weightSum; this(){} this(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) { opCall(ratings,reputationUser,reputationObject); } void opCall(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) { weightSum.length = reputationObject.length; weightSum[] = 0; reputationObject[] = 0; foreach(ref Rating r; ratings) { reputationObject[r.o] += reputationUser[r.u]*r.r; weightSum[r.o] += reputationUser[r.u]; } foreach(uint o, ref double r; reputationObject) r /= weightSum[o]; } } class AvgArithmetic : AvgWeighted { this(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) { opCall(ratings,reputationUser,reputationObject); } void opCall(ref Rating[] ratings, ref double[] reputationUser, ref double[] reputationObject) { reputationUser[] = 1; super.opCall(ratings,reputationUser,reputationObject); } } void main() { Rating[] ratings; double[] reputationUser; double[] reputationObject; foreach(uint u; 0..999) reputationUser ~= 0.1*(u%3); reputationObject.length = 1; reputationObject[] = 0; foreach(uint u;0..reputationUser.length) { Rating _r = {u,0,(u%3)}; writefln("%u %g",_r.u,_r.r); ratings ~= _r; } auto aw = new AvgWeighted(ratings,reputationUser,reputationObject); aw(ratings,reputationUser,reputationObject); foreach(double o; reputationObject) writefln("%g",o); } |
Copyright © 1999-2021 by the D Language Foundation