[Rd] multiple definitions in C code

Jan de Leeuw deleeuw@stat.ucla.edu
Wed, 2 Jan 2002 15:02:24 -0800


There is a problem in MacOS X with multiple definitions of the same
symbol in different files that will be put into the same bundle or
dynamic library by the dynamic linker. It occurs, for example, in
the rpart package, which includes rpart.h in all its source files,
and rpart.h has definitions of a structure rp and functions rp_init
and so on. I think the same problem occurs in the grid package --
all 150+ others seem to be fine. Just out of curiosity, I looked into
the problem a bit, in particular as it relates to dyld in OS X.

==========================================================================
====
According to the ANSI Standard

G.5 Common Extensions

The following extensions are widely used in many systems, but are not
portable to all implementations. The inclusion of any extension that may 
cause
a strictly conforming program to become invalid renders an implementation
non-conforming.

...

G.5.11 Multiple external definitions

There may be more than one external definition for the identifier of an 
object,
with or without the explicit use of the keyword extern. If the 
definitions
disagree, or more than one is initialized, the behavior is undefined.
==========================================================================
====
See also Summit, C Programming FAQ, section 1.7, or Koenig, C Traps and
Pitfalls, pages 54-56. Portability considerations makes them suggest 
that the
safe way to proceed is to have only a single definition, in a source 
file, with
or without initialization, and everywhere else (in header files) external
declarations.
==========================================================================
====
 From the MacOS X ld man page:

Different linking can occur only when there  is  more
than  one  definition  of a symbol and the library modules
that contain the definitions for that symbol do not define
and  reference  exactly  the  same symbols.  In this case,
even different executions of the same program can  produce
different  linking  because the dynamic linker binds unde-
fined functions as they are called, and this  affects  the
order  in  which  undefined symbols are bound.  Because it
can  produce  different  dynamic  linking,  using  dynamic
shared  libraries that define the same symbols in the same
program is strongly discouraged.
==========================================================================
====
 From Inside Mac OS X (page 134)

When you create a framework, you must ensure that each symbol
is defined only once in a library. In addition, "common" symbols
are not allowed in the library, you must use a single true definition
and precede all other definitions with the extern key word in C
code.
==========================================================================
====

Thus we see that the dynamic linker sets things up for "lazy
linking", where symbols are loaded at run time if they are actually
needed (and not at startup). It is different, I think, from Solaris
(see Solaris Porting Guide, p. 102-103), which also has "lazy
linking", but allows multiple definitions ("the first one wins").

The gcc compiler has a flag -fno-common (Stallman, p. 187), which 
allocates
space for each defined variable directly, and does not place it in
"common" space. The Next dynamic linker has a flag -m, which
makes multiple definitions into warnings instead of errors.
This if we have files galadriel.c with

==========================================================================
====
#include <stdio.h>

float bilbo;

int galadriel ()
{
bilbo = 1.0;
return printf("%1.0f\n", bilbo + bilbo);
}
==========================================================================
====

and elrond.c with

==========================================================================
====
#include <stdio.h>

int bilbo;

int elrond()
{
bilbo = 1;
return printf("%d\n", bilbo + bilbo);
}
==========================================================================
====

and we compile them with -fno-common, then we cannot link them
into either an executable (with a suitable main) or into a bundle.
If we leave out -fno-common, then we can. Linking into an
executable will lead to undefined but unambiguous behavior, linking 
into a
dynamic library could lead to different behaviors at different
occasions at run time. Thus

[localhost:~/Desktop/rings] deleeuw% gcc -c -fno-common elrond.c
[localhost:~/Desktop/rings] deleeuw% gcc -c -fno-common galadriel.c
[localhost:~/Desktop/rings] deleeuw% nm -pg elrond.o
000000a8 S _bilbo
00000000 T _elrond
          U _printf
          U dyld_stub_binding_helper
[localhost:~/Desktop/rings] deleeuw% nm -pg galadriel.o
000000c0 S _bilbo
00000000 T _galadriel
          U _printf
          U dyld_stub_binding_helper

and then

[localhost:~/Desktop/rings] deleeuw% gcc -bundle -o rings.so elrond.o 
galadriel.o
/usr/bin/ld: multiple definitions of symbol _bilbo
elrond.o definition of _bilbo in section (__DATA,__common)
galadriel.o definition of _bilbo in section (__DATA,__common)
[localhost:~/Desktop/rings] deleeuw% gcc -bundle -o rings.so -Xlinker -m 
elrond.o galadriel.o
/usr/bin/ld: warning multiple definitions of symbol _bilbo
elrond.o definition of _bilbo in section (__DATA,__common)
galadriel.o definition of _bilbo in section (__DATA,__common)
[localhost:~/Desktop/rings] deleeuw% nm -pg rings.so
00001018 S _bilbo
00000ecc T _elrond
00000f44 T _galadriel
          U _printf

  while

[localhost:~/Desktop/rings] deleeuw% gcc -c elrond.c
[localhost:~/Desktop/rings] deleeuw% gcc -c galadriel.c
[localhost:~/Desktop/rings] deleeuw% gcc -bundle -o rings.so elrond.o 
galadriel.o
[localhost:~/Desktop/rings] deleeuw% nm -pg elrond.o
00000000 T _elrond
00000004 C _bilbo
          U _printf
          U dyld_stub_binding_helper
[localhost:~/Desktop/rings] deleeuw% nm -pg galadriel.o
00000000 T _galadriel
00000004 C _bilbo
          U _printf
          U dyld_stub_binding_helper
[localhost:~/Desktop/rings] deleeuw% nm -pg rings.so
00001020 S _bilbo
00000ecc T _elrond
00000f44 T _galadriel
          U _printf

but now

[localhost:~/Desktop/rings] deleeuw% gcc -dynamiclib -o librings.dylib 
elrond.o galadriel.o
ld: common symbols not allowed with MH_DYLIB output format
elrond.o definition of common _bilbo (size 4)
/usr/bin/libtool: internal link edit command failed


Of course we can use ar to put the object files in an archive, but if a 
symbol
is defined (and initialized) more than once the table of contents cannot 
be
sorted by ranlib.


===
Jan de Leeuw; Professor and Chair, UCLA Department of Statistics;
US mail: 9432 Boelter Hall, Box 951554, Los Angeles, CA 90095-1554
phone (310)-825-9550;  fax (310)-206-5658;  email: deleeuw@stat.ucla.edu
homepage: http://www.stat.ucla.edu/~deleeuw
========================================================
           No matter where you go, there you are. --- Buckaroo Banzai
                    http://www.stat.ucla.edu/~deleeuw/sounds/nomatter.au
========================================================

-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !)  To: r-devel-request@stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._