Operating System - OpenVMS
1757004 Members
2349 Online
108858 Solutions
New Discussion юеВ

Undefined symbol linking C code with static library

 

Undefined symbol linking C code with static library

I have an undefined symbol warning in one of a set of C programs, each of which links to the same single object library. When linked with an equivalent shared image library, there is no such warning.

One difference I have noticed is that in all of the successful links, there was a selective search of SYS$COMMON:[SYSLIB]SYS$PUBLIC_VECTORS.EXE. The map of the link with the warning shows no reference to PUBLIC_VECTORS.EXE.

Is that difference likely significant in my undefined symbol problem? Can anyone suggest what may be going on?
16 REPLIES 16
Robert Brooks_1
Honored Contributor

Re: Undefined symbol linking C code with static library

What's the symbol that is not resolved?

Re: Undefined symbol linking C code with static library

I should have stated that the object library is not a system library.

The undefined symbol is a variable named _libGlobal__, which is declared extern in a header file included in many of the modules in the object library. It is an instance of a named typedef struct declared in the same header.

A member of the struct is used in a #define of a symbol IS_LOG_EXACT_TIME, which is referenced in a function called _LogTime. That function is defined in a module named derror.c which #includes the header.

The linker finds _LogTime, but it doesn't find _libGlobal__.
Steven Schweda
Honored Contributor

Re: Undefined symbol linking C code with static library

I got lost in that description, but in the
problem program, is _libGlobal__ ever
declared _other_ than as an extern (in the
header file)? (Perhaps in the main program?)
I'd guess that it _is_ in the non-problem
programs.

alp $ type a1.c

#include

extern int ext; /* Pretend that this is in a header file. */

extern int a2( void);

main()
{
ext = 1;
printf( " ext = %d. A2 says %d.\n", ext, a2());

}


alp $ type a2.c

extern int ext; /* Pretend that this is in a header file. */

int a2()
{
return ext;
}


alp $ cc a1
alp $ cc a2
alp $ link a1, a2
%LINK-W-NUDFSYMS, 1 undefined symbol:
%LINK-I-UDFSYM, EXT
%LINK-W-USEUNDEF, undefined symbol EXT referenced
in psect $LINK$ offset %X00000028
in module A1 file ALP$DKA0:[SMS]A1.OBJ;3
%LINK-W-USEUNDEF, undefined symbol EXT referenced
in psect $LINK$ offset %X00000010
in module A2 file ALP$DKA0:[SMS]A2.OBJ;2


alp $ type a3.c

int ext; /* Note: NOT extern. */

alp $ cc a3
alp $ link a1, a2, a3

alp $ r a1
ext = 1. A2 says 1.


It's not enough to say "extern int ext;"
everywhere. _Someone_ needs to declare
"ext" simply, to get some storage allocated
for it. In real life, no one would be likely
to declare "ext" in its own module this way,
but it does need to be declared _somewhere_.

In other words, "extern" tells the linker
that it exists elsewhere, but someone,
somewhere, needs to take responsibility and
actually make the thing.

Or else I misunderstand this whole thing.

Re: Undefined symbol linking C code with static library

Yes, it's easy to get lost in...

The variable itself is declared in BASE, a module in the object library, but not in the module DERROR which contains the function in which the linker reports the undefined symbol. It is never declared in the programs I'm compiling and linking with the library.

I have been scanning maps and listings, and noticed that there is nothing in the offending program which calls any function within BASE. There *is* a call to one or more functions in BASE in all the other programs.

The header makes the variable extern, and is included wherever there is any reference to the variable (either explicitly or via #defined symbols), including BASE.

There is no problem when I link to a shared image version of the library rather than the object library. The symbol_vector list for the shared image library link contains only functions.

I don't see why a function reference within BASE should be required in order to access an extern variable declared with file scope in BASE. But that seems to be so. If I insert such a reference into the problem program, the problem goes away.

What am I missing? (Besides my mind ;-)
Steven Schweda
Honored Contributor

Re: Undefined symbol linking C code with static library

> I don't see why a function reference
> within BASE should be required in order to
> access an extern variable declared with
> file scope in BASE.

Something has to get that module into the
executable, or else the storage for the
extern thing will not make it in.

I assume that you could link using something
like:

link [...] -
lib_with_base.olb /library /include = base -
[...]

which should pull in the module without
requiring some dummy function reference.

I don't do much with shared images, but I
assume that they're loaded all-or-nothing,
while, with an object library, the linker
pulls out only the pieces which it (thinks
that it) needs.

Re: Undefined symbol linking C code with static library

That's probably pretty convoluted, too. Let me try again.

GLOBAL.h contains
typedef struct _libGlobal
{ ... } _libGlobalRec, *_libGlobal;
extern _libGlobalRec _libGlobal__;
#define IS_LOG_EXACT_TIME (__libGlobal__.debug & (2 << 0)

MYLIB.olb contains
BASE.obj
#include "global.h"
_libGlobalRec _libGlobal__; /* file scope */


DERROR.obj
#include "global.h"
void _LogTime(FILE *fd, char *buf)
{ if (IS_LOG_EXACT_TIME) ... }

A program which does not call any function within BASE.obj in the library, but which does call stuff which calls stuff which calls _LogTime in DERROR.obj, gets an undefined symbol warning on _libGlobal__.

Add a call to any (I'm guessing -- I've tried three) function from BASE.obj and the problem goes away.

Why?

Re: Undefined symbol linking C code with static library

Hi Steven,

My attempt to clarify crossed with your last reply.

> Something has to get that module into the
> executable, or else the storage for the
> extern thing will not make it in.

> I assume that you could link using something
> like:

> link [...] -
> lib_with_base.olb /library /include = base -
> [...]

> which should pull in the module without
> requiring some dummy function reference.

I assumed (apparently incorrectly) that the compiler would generate a list (so to speak) of anything declared extern and created within a module, and the linker would use that (either from the .obj or from the module in the library) and thus be able to resolve any function or any external thing.

This code exists on various platforms. The problem is not observed on the other operating systems. It's mine alone, so to speak.

Thanks for your help!

Sue
Steven Schweda
Honored Contributor

Re: Undefined symbol linking C code with static library

Because the only real storage for
_libGlobal__ is declared/allocated in
BASE.obj. If the linker does not get
BASE.obj out of MYLIB.olb (and into your
executable), then your executable will not
get that storage. Hence, UDFSYM.

Refering to _libGlobal__ one more time (as
in IS_LOG_EXACT_TIME) does not get BASE.obj
into the executable.

> Add a call [...] and the problem goes away.

Yes, because that _will_ get BASE.obj into
the executable. (As will "/include = base"
in the LINK command.)


This says that it exists somewhere:
extern _libGlobalRec _libGlobal__;

So everyone believes (at compile time) that
it exists somewhere.


This makes it exist:
_libGlobalRec _libGlobal__; /* file scope */

but that's in BASE.obj, so if BASE.obj is not
linked in, then the storage for _libGlobal__
does not exist in your executable.


Now, if you want the storage to exist without
bringing in BASE.obj, you'll need to declare
_libGlobal__ somewhere else. (But if you
link together two modules which declare the
thing, then get ready for a MULDEF.)
Steven Schweda
Honored Contributor

Re: Undefined symbol linking C code with static library

This may be related to something like "weak"
versus "strong" references, or some other
topic about which I never read in the linker
manual. I would not be surprised if there
were some clever way to persuade the linker
to create this stuff the way you expected it
to happen, but I always do it the way I've
suggested (which also seems to work on UNIX
systems).

Everything's complicated, I always say.