LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 09-20-2013, 07:19 AM   #1
Pap
Member
 
Registered: May 2011
Distribution: Salix 14.1 GNU/Linux, 64-bit
Posts: 70

Rep: Reputation: 29
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:
Code:
.DELETE_ON_ERROR:

CC = g++
CCFLAGS = -g -std=c++11 -Wall
#CCFLAGS = -O2 -std=c++11 -Wall
PACKAGES = clanCore-3.0 clanDisplay-3.0 clanApp-3.0 clanGL-3.0 clanSWRender-3.0
LIBS = `pkg-config --cflags --libs $(PACKAGES)`

EXE = ../Fibonacci_Shapes
# ------------------------------------------------------------------------------
OBJ_DIR=..

OBJS = \
	$(OBJ_DIR)/Fibonacci_Data.o\
	$(OBJ_DIR)/Fibonacci_Shapes.o\
	$(OBJ_DIR)/Fading_Sprite.o\
	$(OBJ_DIR)/Help_Facilities.o\
	$(OBJ_DIR)/Application.o\
	$(OBJ_DIR)/Main.o

all: $(OBJS)
	$(CC) $(CCFLAGS) -pthread $(OBJS) $(LIBS) -o $(EXE)
# ------------------------------------------------------------------------------
$(OBJ_DIR)/Fibonacci_Data.o: Fibonacci_Data.hpp Fibonacci_Data.cpp
	$(CC) -c $(CCFLAGS) $(LIBS) Fibonacci_Data.cpp -o $@
$(OBJ_DIR)/Fibonacci_Shapes.o: Fibonacci_Data.hpp Fibonacci_Shapes.hpp\
                               Fibonacci_Shapes.cpp
	$(CC) -c $(CCFLAGS) $(LIBS) Fibonacci_Shapes.cpp -o $@
$(OBJ_DIR)/Fading_Sprite.o: Fading_Sprite.hpp Fading_Sprite.cpp
	$(CC) -c $(CCFLAGS) $(LIBS) Fading_Sprite.cpp -o $@
$(OBJ_DIR)/Help_Facilities.o: Help_Facilities.hpp Help_Facilities.cpp
	$(CC) -c $(CCFLAGS) $(LIBS) Help_Facilities.cpp -o $@
$(OBJ_DIR)/Application.o: Fibonacci_Shapes.hpp Help_Facilities.hpp\
                          Application.hpp Application.cpp
	$(CC) -c $(CCFLAGS) $(LIBS) Application.cpp -o $@
$(OBJ_DIR)/Main.o: Application.hpp Main.hpp Main.cpp
	$(CC) -c $(CCFLAGS) $(LIBS) Main.cpp -o $@
# ------------------------------------------------------------------------------
strip:
	-rm -f $(OBJ_DIR)/*.o
	-rm -f *~
# ------------------------------------------------------------------------------
clean: strip
	-rm -f $(EXE)
# ------------------------------------------------------------------------------
cleanall: clean all
# ------------------------------------------------------------------------------
 
Old 09-20-2013, 08:45 AM   #2
psionl0
Member
 
Registered: Jan 2011
Distribution: slackware_64 14.1
Posts: 722
Blog Entries: 2

Rep: Reputation: 124Reputation: 124
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.
 
Old 09-20-2013, 09:16 AM   #3
Pap
Member
 
Registered: May 2011
Distribution: Salix 14.1 GNU/Linux, 64-bit
Posts: 70

Original Poster
Rep: Reputation: 29
Quote:
Originally Posted by psionl0 View Post
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.)
 
Old 09-20-2013, 09:53 AM   #4
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by psionl0 View Post
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.
Because they're not using automatic dependency generation.

Quote:
Originally Posted by Pap
The only way to get rid of it is to use optimization, which makes debugging impossible.
This suggests it's getting inlined; is it a const and/or static variable? Maybe post the declaration and definition.
 
1 members found this post helpful.
Old 09-20-2013, 10:14 AM   #5
Pap
Member
 
Registered: May 2011
Distribution: Salix 14.1 GNU/Linux, 64-bit
Posts: 70

Original Poster
Rep: Reputation: 29
Quote:
Originally Posted by ntubski View Post
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.
 
Old 09-20-2013, 11:07 AM   #6
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by Pap
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...
 
Old 09-20-2013, 11:48 AM   #7
Pap
Member
 
Registered: May 2011
Distribution: Salix 14.1 GNU/Linux, 64-bit
Posts: 70

Original Poster
Rep: Reputation: 29
Quote:
Originally Posted by ntubski View Post
So is it declared within "class Shapes { ... }"?
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 View Post
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.)
 
Old 09-20-2013, 12:05 PM   #8
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
I think the old C trick can work here:
Code:
enum { maxShapes=20, maxFontSize=30 };
 
1 members found this post helpful.
Old 09-20-2013, 12:20 PM   #9
Pap
Member
 
Registered: May 2011
Distribution: Salix 14.1 GNU/Linux, 64-bit
Posts: 70

Original Poster
Rep: Reputation: 29
Quote:
Originally Posted by ntubski View Post
I think the old C trick can work here:
Code:
enum { maxShapes=20, maxFontSize=30 };
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

Last edited by Pap; 09-20-2013 at 12:31 PM.
 
Old 09-20-2013, 12:29 PM   #10
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by Pap View Post
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.
 
Old 09-20-2013, 12:58 PM   #11
Pap
Member
 
Registered: May 2011
Distribution: Salix 14.1 GNU/Linux, 64-bit
Posts: 70

Original Poster
Rep: Reputation: 29
Quote:
Originally Posted by ntubski View Post
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 ...
 
Old 09-20-2013, 06:41 PM   #12
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
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
 
Old 09-20-2013, 07:18 PM   #13
Pap
Member
 
Registered: May 2011
Distribution: Salix 14.1 GNU/Linux, 64-bit
Posts: 70

Original Poster
Rep: Reputation: 29
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:
Code:
labelFontIndex=std::min((uint)scaling,maxFontSize)-1u;
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
Code:
labelFontIndex=std::min((uint)scaling,(uint)maxFontSize)-1u;
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
Code:
labelFontIndex=std::min((uint)scaling,maxFontSize)-1u;
BUT it will link perfectly with
Code:
labelFontIndex=std::min((uint)scaling,0+maxFontSize)-1u;
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 .

Last edited by Pap; 09-20-2013 at 07:48 PM.
 
Old 09-20-2013, 08:08 PM   #14
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
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.
 
Old 09-20-2013, 10:51 PM   #15
turtleli
Member
 
Registered: Aug 2012
Location: UK
Posts: 206

Rep: Reputation: Disabled
Bjarne Stroustrup's C++ faq - How do I define an in-class constant? states
Quote:
You can take the address of a static member if (and only if) it has an out-of-class definition
So to make ntubski's test code work you would need to add
Code:
const int TheClass::max1;
I've tested this in clang and gcc.
 
2 members found this post helpful.
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] compiling error in sl-current "undefined reference to symbol"? marbangens Slackware 2 04-07-2013 09:51 AM
"undefined reference" error when trying to use GTL in a simple C++ application m4h Programming 6 03-29-2012 12:45 PM
Error when "make" the source of CosmoMC: undefined reference to `dpotrf_' limh Linux - Software 1 09-30-2009 02:27 PM
Error: Make on kismet-2005-08-R1 "undefined reference" zeevolking Linux - Software 1 12-23-2005 08:40 PM
G++ Linking Error "undefined reference" djjumper9 Programming 2 04-13-2004 09:36 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:02 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration