[SOLVED] Strange "undefined reference" error while linking.
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Strange "undefined reference" error while linking.
Hi there,
this is actually a C++ programming question; maybe there are more "specialized" forums to post this, but I personally don't know any other forum as good as LQ, so here we go:
I recently came up against a very strange compiler (actually linker) error, which I never had before, in more than 20 years of programming experience, mostly in Fortran 90/95. Specifically, I am developing a project in C++, and everything goes well if and only if I use any kind of speed optimization, like g++ -O1, or g++ -O2 etc. If, however, I don't use optimization flags, either by g++ -g or g++ -O0, I get this error while linking the project:
Code:
undefined reference to `Fibonacci::Shapes::maxFontSize'
where maxFontSize is just a private integer variable, defined in the "Shapes" class, which is withing the namespace "Fibonacci". There is actually nothing wrong with the code; this variable is just one of the many other private variables defined there, and there is nothing special with it.
The only reason I could think is that sometimes linking sequence matters in C++. However, in my project, the object files are linked in logical order, that is, object files that correspond to classes without #include statements to other classes are linked first. Nevertheless, I get the above linker error. I even tried to change the linking sequence in many ways, clean the project, and recompile; I still get the same error, no matter what I do. The only way to get rid of it is to use optimization, which makes debugging impossible.
If someone had such a strange situation, any advices will be greatly appreciated. Thank you in advance.
Some additional details, although I doubt they really matter:
C++ compiler: g++ 4.7.3
OS: Debian Linux 8.0 ("jessie")
Project compilation/linking is maintained via a Makefile, which I include here, in case it helps:
I presume that the first line in Fibonacci_Shapes.hpp is #include "Fibonacci_Data.hpp" and that the respective .cpp files #include the respective .hpp files so I don't know why you need to mention the .hpp files in your makefile.
I presume that the first line in Fibonacci_Shapes.hpp is #include "Fibonacci_Data.hpp" and that the respective .cpp files #include the respective .hpp files so I don't know why you need to mention the .hpp files in your makefile.
Maybe some .hpp files are not needed in the Makefile, but even if I remove them all, the strange "undefined reference" error while linking persists, so apparently that's not the reason of the trouble here (it could not be the reason anyway.)
I presume that the first line in Fibonacci_Shapes.hpp is #include "Fibonacci_Data.hpp" and that the respective .cpp files #include the respective .hpp files so I don't know why you need to mention the .hpp files in your makefile.
This suggests it's getting inlined; is it a const and/or static variable? Maybe post the declaration and definition.
That gives me a hint. It is indeed a static const:
Code:
static const unsigned int maxShapes=20,maxFontSize=30;
and it needs to be a static const, as several arrays are declared using it, and if I turn it to a normal variable, I would need to use std::vector instead of normal C++ arrays, which I want to avoid, for several reasons.
Note that maxFontSize is not the only static const private variable in the class. As you can see in the above declaration, maxShapes is also such a variable, but for some reason linker doesn't complain about it. This makes the situation even more strange.
where maxFontSize is just a private integer variable, defined in the "Shapes" class, which is withing the namespace "Fibonacci".
Code:
static const unsigned int maxShapes=20,maxFontSize=30;
So is it declared within "class Shapes { ... }"?
Quote:
it needs to be a static const, as several arrays are declared using it, and if I turn it to a normal variable, I would need to use std::vector instead of normal C++ arrays, which I want to avoid, for several reasons.
Might constexpr be useful here? I'm not up to date with the latest C++11 stuff, but since you have -std=c++11...
Yes, it is declared in the private section within class Shapes{...}, which is declared within the Fibonacci namespace; all that in the header file Fibonacci_Shapes.hpp.
Quote:
Originally Posted by ntubski
Might constexpr be useful here? I'm not up to date with the latest C++11 stuff, but since you have -std=c++11...
Good idea... I'm not up-to-date with C+11 stuff either; I use -std=c++11 because the underlying multimedia library, ClanLib, requires it. It seems, however, that constexpr doesn't help here; changing declaration to
Code:
constexpr static unsigned int maxShapes=20,maxFontSize=30;
still produces the exact same error ("static" is still required, otherwise I cannot give a value to those constants in the header file, which is exactly what I need to do.)
Worked! Stupid me, I didn't think to try enum: Sometimes, being stuck to C++, I forget old-good C features, like enum, which indeed did the job here. I actually wanted those constants to be unsigned int, and using enum {maxShapes=20u,maxFontSize=30u} didn't worked, so I had to convert the constants to (uint) where needed.
I consider problem solved, although I am still wondering why g++ complained about maxFontSize and not about maxShapes. Both were defined in the exact same way, what makes maxFontSize so special?
Thank you ntubski
I am still wondering why g++ complained about maxFontSize and not about maxShapes. Both were defined in the exact same way, what makes maxFontSize so special?
Yes, I am curious about that too. If you have time, maybe you can cut the down the code to a minimal example that still shows the problem and post it.
Yes, I am curious about that too. If you have time, maybe you can cut the down the code to a minimal example that still shows the problem and post it.
I tried to strip the code to the minimum (just a main() and a simple class declaring those constants; the problem disappeared. Tried to make it a little more complex (ClanLib requires a class named Main which is transformed to a main() function via a ClanLib library; problem disappeared too. I think I'll quit trying here. Go figure ...
So I tried some things and I think I have a plausible explanation. But I noticed that I get line numbers in my linker errors, don't you? That would probably make it a lot easier to pin down the problem for certain.
First I tried taking the address, but that doesn't compile with the enum version so it can't be that. Then I tried using a const ref instead, that which does compile successfully with enums and fails to link with static const:
Code:
class TheClass {
private:
static const int max1 = 30, max2 = 40;
//enum { max1 = 30, max2 = 40 };
int array[max2];
public:
void func(const int& x = max1);
};
void TheClass::func(const int&) {}
int main() {
TheClass obj;
obj.func();
}
Code:
make -k -f Makefile main
g++ -Wall -Wextra -Wformat=2 -g -pedantic -std=c++11 -c -o main.o main.cc
g++ main.o -o main
main.o: In function `main':
/home/npostavs/tmp/link-fail/main.cc:14: undefined reference to `TheClass::max1'
collect2: error: ld returned 1 exit status
make: *** [main] Error 1
Yes, I did get a line number, and didn't pay much attention on that as the "erroneous" line had nothing wrong. However, I tried to switch to the "buggy" version of my code, removing the enum you suggested, and discovered this: The line number where g++ complains is in Fibonacci_Shapes.cpp, and reads:
Now, with maxFontSize defined as static const unsigned int, this line of code is where g++ reports that "undefined reference" linker error. If however, I change the line to
it links just fine .
Note that what I added was just a conversion of maxFontSize to uint, which is theoretically something not needed, as maxFontSize is already defined as uint anyway. uint is just typedef'd as a shorthand to unsigned int.
Well, this is really crazy now...
Edit: it gets even more frustrating; Linker will complain with
If you can't see the difference, I don't blame you. I just added a zero to maxFontSize and the linker error was magically gone.
The more I am looking on it, the more I feel the need to .
What I think what happens: when you pass a plain variable to a const ref, the compiler sees an lvalue so it passes by address. If you pass an expression, it passes by value.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.