Solved

Static library with static variable gives unresolved external!

Posted on 2013-01-10
14
553 Views
Last Modified: 2013-01-21
Ah hello.

I am using VS 2005, and have the following code in my static library:

Functions.h:

#pragma once

#include <vector>

int FunctionInStaticLibrary();

class CMyClass
{
public:

	typedef std::vector<std::pair<int, std::string> > ERRORS;

	static const ERRORS& GetErrors() { 
		return m_vecErrors; }

	static const int& GetInt() {
		return s_n;}

private:

	static ERRORS m_vecErrors;
	static int s_n;
};

Open in new window


Functions.cpp:

#include "Functions.h"

int FunctionInStaticLibrary()
{
	return 42;
}

/*static*/ CMyClass::ERRORS m_vecErrors;
/*static*/ int CMyClass::s_n = 101;

Open in new window


I now have the following exe, which depends on my static library:

#include "..\StaticLibrary\Functions.h"

int main()
{
	const CMyClass::ERRORS vec = CMyClass::GetErrors();
	const int& n = CMyClass::GetInt();
}

Open in new window


The first line fails with an unresolved external in the object file of the exe source file, but the second does not.

1) Why does only the first line fail?  Is it because it is a complex type?
2) If other dependencies of my executable also link to this static library, will there be multiple instances of the variable in the executable?  If so, how is it determined which one gets used?  

TIA
0
Comment
Question by:mrwad99
  • 7
  • 4
  • 2
  • +1
14 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 38763836
Quick Q - do you get the error also when using

	const CMyClass::ERRORS& vec = CMyClass::GetErrors(); // note '&'

Open in new window


?
0
 
LVL 19

Author Comment

by:mrwad99
ID: 38763848
Hi jkr!

Yes, I do.  I also get the error when I simply create a CMyClass object:

CMyClass cc;

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
ID: 38763908
Have you tried using 'extern', e.g.

#pragma once

#include <vector>

#infdef BUILDING_MY_STATIC_LIB

extern {

int FunctionInStaticLibrary();

class CMyClass
{
public:

	typedef std::vector<std::pair<int, std::string> > ERRORS;

	static const ERRORS& GetErrors() { 
		return m_vecErrors; }

	static const int& GetInt() {
		return s_n;}

private:

	static ERRORS m_vecErrors;
	static int s_n;
};
 
}                                 

Open in new window


?
0
 
LVL 32

Accepted Solution

by:
phoffric earned 400 total points
ID: 38765666
CMyClass::ERRORS    m_vecErrors;
should be:
CMyClass::ERRORS    CMyClass::m_vecErrors;

>> int CMyClass::s_n = 101;
No problem here since the number 101 is not part of the class.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 38766454
Oh dear, what a silly mistake that was.  I guess the qualifier on the type is responsible for me missing this...

Thanks phoffric.

Can either of you comment on the second question above, i.e.

"If other dependencies of my executable also link to this static library, will there be multiple instances of the variable in the executable?  If so, how is it determined which one gets used?"

please?
0
 
LVL 32

Expert Comment

by:phoffric
ID: 38766815
It wasn't that silly of a mistake or we would have picked it up more quickly. :)
It might be helpful in the future to copy and paste the exact error message.

The two class variables are defined in Functions.cpp. There will be only one instance of these two class variables when this static library is linked into the executable.

If there wasn't a static library involved, and multiple modules referenced these two class variables, then you know that only one memory allocation will be made. Same thing applies for using the static library.

Maybe you have heard of some issues on multiple instances when working with dynamic libraries (and, of course, multiple inheritance).
0
 
LVL 19

Author Comment

by:mrwad99
ID: 38767263
Thanks phoffric.

I am still not sure about this though.

Lets refer to the library containing CMyClass::m_vecErrors as MyClass_Lib from now on.

Say I have another static library "A".  This uses CMyClass::m_vecErrors, so has to link with MyClass_Lib.

My executable uses library "A", but does not know that library "A" uses MyClass_Lib.  However, the application also needs to use CMyClass::m_vecErrors, so it too links to MyClass_Lib.

My concern is that we now have two occurences of m_vecErrors in the application: the one linked into library "A" (which itself is linked into the application), and the other linked into the application directly.

If this is the case, when my application wants to use CMyClass::m_vecErrors, how can I know which one it is using?  It kind of makes the whole "static" bit redundant...

If this is not the case, why is it not the case?  Does the linker perform some magic?

Thanks.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 32

Expert Comment

by:phoffric
ID: 38769177
/*
MyClass_Lib has a module in it which defines CMyClass::m_vecErrors. By "defines", I mean that the module has reserved a memory location for CMyClass::m_vecErrors.

static library "A" uses CMyClass::m_vecErrors, but "A" does not reserve memory for CMyClass::m_vecErrors (think extern). Actually, a static library doesn't use a variable. A static library is just a set of modules. If a module needs to access CMyClass::m_vecErrors, whether the module is in a static library or not, then it does so by including the Functions.h header file, just as your main() module in your OP has done.

The linker identifies the modules it needs from a static library and includes those modules in the executable. If the module is not in a static library, but instead is included in the makefile linker line, then it is included in the executable even if it is not needed by the executable.

The modules that include Functions.h are not reserving any memory for the class variables in CMyClass. Those class variables are treated as extern variables. During the linker process, the addresses of these class variables as well as extern variables and extern functions get resolved in the executable.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 38774724
OK.  I think I need to take a step back here and question my understanding of static libraries.

I believed that when you link to a SL, the net effect is that you "include" all of the code from it into whatever is linking to it.  This is why whatever links it in grows substantially in size.

Is this correct?

"static library "A" uses CMyClass::m_vecErrors, but "A" does not reserve memory for CMyClass::m_vecErrors (think extern). Actually, a static library doesn't use a variable."

I don't understand the last part, about not using a variable.  Can you please clarify?

"The linker identifies the modules it needs from a static library and includes those modules in the executable. "

Does the module containing the definition of the vector exist in both "A" and "MyClass_Lib"?  If so, does the linker know this and only include the defintion from one of those static libraries?

Sorry to keep this going phoffric but I don't like not understanding.  If you can point me at any internet resources that explain how (in sufficient detail) static libraries work then please do point me at them.

Thanks.
0
 
LVL 32

Assisted Solution

by:phoffric
phoffric earned 400 total points
ID: 38775886
Hi mrwad99,

>> but I don't like not understanding
A very excellent trait!!

>> I believed that when you link to a SL, the net effect is that you "include" all of the code from it into whatever is linking to it.  This is why whatever links it in grows substantially in size. Is this correct?

From http://en.wikipedia.org/wiki/Static_library:
With static linking, it is enough to include those parts of the library that are directly and indirectly referenced by the target executable (or target library). With dynamic libraries, the entire library is loaded, as it is not known in advance which functions will be invoked by applications.
Apparently you are using every module in your static library. Try building a simple program that uses one module in a static library. Then add many more modules to the static library that are not used by the simple program and see that the executable does not increase in size even though the static library increased in size.

This good discussion of static libraries is getting a bit off track from the original question. It would make a good question for the EE PAQ.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 38777942
Yes, I had read that page before.  I understand that only what is actually used is linked in.  My concern was that if something gets thrown into the mix twice.  One library contains a function that another library uses, but also that the executable uses.  The executable also uses both libraries, so the function is in there twice.  Kind of like making a recipe:

1) Add 10g of salt to water
2) Add 100g of chicken to water
3) Boil

With the caveat that we must not exceed 10g of salt.

The problem is that the chicken might already have salt in it!  Is the chef smart enough to know that the chicken has already got salt in it, so knows not to throw any more in?  That is, does the linker know not to include my function twice in the executable, because it has already been included in the other library that it has already linked in to the executable?  And is this the same for my static variable?

I appreciate your comment about this going slightly off track.  This is my last comment, if you could clear the above up and I understand it I will close this off, otherwise I will open a new question.  Thanks.
0
 
LVL 22

Assisted Solution

by:ambience
ambience earned 100 total points
ID: 38778822
The answer to the chicken and salt parable is that salt only dissolves in water.

A linker works in multiple phases, in one phase it just puts references to referred functions and data. In another phase it puts together all referenced code and data in the executable data and code sections. This phase is only performed for an executable.

A static library is simply an archive or obj files that contain code and data identified by symbols. When you use a static lib inside another static lib it just puts there a reference to the same symbol (at this point these are just symbols, not even pointers). If there are multiple symbols with the same name a linker error is thrown as is thrown when no symbol matches that name. The important point to note is that the linker searches available library files.

In short, functions dont get added to libs when you link other libs, this is why you need all static libs to be included in the final executable linkage specifications.
0
 
LVL 19

Assisted Solution

by:mrwad99
mrwad99 earned 0 total points
ID: 38782155
Thanks for joining in ambience!

OK, I think I have got it.  I did some additional googling based on what you said here and learnt some more.

"In short, functions dont get added to libs when you link other libs"

I was confused about why I could have static lib A use code from static lib B, yet specify no dependencies, and have A build fine.  So I had a play and discovered what you said here: there is no linking involved in creating a static library, the .obj files are simply bundled together (I know, obvious now I think about it).  I found additional info at http://rdsrc.us/HMeopd.

I also found http://rdsrc.us/X6kgAf ("Beginner's Guide to Linkers") very useful too.

Overall, thanks greatly all for for continuing with me on this one and helping me understand it better :o)
0
 
LVL 19

Author Closing Comment

by:mrwad99
ID: 38800462
I have marked my comment above as an addtional solution since it provides a summary in noddy terms of the additional query about *how linking works*, so hopefully readers of this question can learn from it too.  The original question though was answered by phoffric early on.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now