After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 136898 - Build fails when compiling with the option -fdata-sections for gcc
Build fails when compiling with the option -fdata-sections for gcc
Status: RESOLVED FIXED
Product: gnome-games-superseded
Classification: Deprecated
Component: general
2.5.x
Other other
: Normal normal
: ---
Assigned To: Rosanna Yuen
GNOME Games maintainers
Depends on:
Blocks:
 
 
Reported: 2004-03-11 15:38 UTC by Heikki Tauriainen
Modified: 2012-01-31 23:25 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Heikki Tauriainen 2004-03-11 15:38:18 UTC
Distribution: Debian testing/unstable
Package: gnome-games
Severity: minor
Version: GNOME2.5.91 2.5.x
Gnome-Distributor: GARNOME
Synopsis: Build fails when compiling with the option -fdata-sections for gcc
Bugzilla-Product: gnome-games
Bugzilla-Component: aisleriot
Bugzilla-Version: 2.5.x
Description:
aisleriot (gnome-games-2.5.8) does not build successfully on gcc 3.3.3
(Debian GNU/Linux testing/i686) when compiling with the option
-fdata-sections. Using this option causes a linker error due to
multiply defined symbols.

Steps to reproduce the problem:
1. Run the gnome-games-2.5.8 configure script with the argument
`CFLAGS=-fdata-sections'.
2. Run make first in the `libgames-support', then in the
`gdk-card-image', and finally in the `aisleriot' subdirectory.

Actual Results:
The compilation of aisleriot fails with the following output:

gcc -fdata-sections -o .libs/sol sol.o slot.o dialog.o cscmi.o events.o
press_data.o draw.o menu.o card.o statistics.o -Wl,--export-dynamic 
-pthread -L/opt/garnome/lib -L/usr/X11R6/lib
../gdk-card-image/.libs/libgdkcardimage.so
/opt/garnome/lib/libglade-2.0.so /opt/garnome/lib/libgnomeui-2.so
/opt/garnome/lib/libgnome-keyring.so /usr/lib/libjpeg.so
/opt/garnome/lib/libbonoboui-2.so /opt/garnome/lib/libXcursor.so
/opt/garnome/lib/libXrender.so -lSM -lICE -lX11
/opt/garnome/lib/libgnomecanvas-2.so /opt/garnome/lib/libgnome-2.so
/opt/garnome/lib/libesd.so /opt/garnome/lib/libaudiofile.so
/opt/garnome/lib/libart_lgpl_2.so /opt/garnome/lib/libpangoft2-1.0.so
/opt/garnome/lib/libgnomevfs-2.so /opt/garnome/lib/libgconf-2.so
/opt/garnome/lib/libbonobo-2.so /opt/garnome/lib/libxml2.so -lz -lssl
-lcrypto -lrt /opt/garnome/lib/libbonobo-activation.so
/opt/garnome/lib/libORBitCosNaming-2.so /opt/garnome/lib/libORBit-2.so
/usr/lib/libpopt.so /opt/garnome/lib/libgthread-2.0.so
/opt/garnome/lib/libgtk-x11-2.0.so /opt/garnome/lib/libgdk-x11-2.0.so
/opt/garnome/lib/libatk-1.0.so /opt/garnome/lib/libgdk_pixbuf-2.0.so
/opt/garnome/lib/libpangoxft-1.0.so /opt/garnome/lib/libpangox-1.0.so
/opt/garnome/lib/libpango-1.0.so /opt/garnome/lib/libgobject-2.0.so
/opt/garnome/lib/libgmodule-2.0.so /opt/garnome/lib/libglib-2.0.so
../libgames-support/.libs/libgames-support.a -L/usr/lib
/usr/lib/libguile.so /usr/lib/libltdl.so -ldl /usr/lib/libqthreads.so
-lpthread -lm -Wl,--rpath -Wl,/usr/local/lib -Wl,--rpath
-Wl,/opt/garnome/lib
press_data.o(.bss.press_data+0x0): multiple definition of `press_data'
sol.o(.bss.press_data+0x0): first defined here
collect2: ld returned 1 exit status
make[1]: *** [sol] Error 1
make[1]: Leaving directory `/tmp/gnome-games-2.5.8/aisleriot'
make: *** [all-recursive] Error 1


Additional information:
`press_data' is defined in the source files `aisleriot/sol.c' and
`aisleriot/press_data.c'. Changing either of these definitions to an
extern declaration allows aisleriot to build successfully.




------- Bug moved to this database by unknown@bugzilla.gnome.org 2004-03-11 10:38 -------

The original reporter (heikki.tauriainen@hut.fi) of this bug does not have an account here.
Reassigning to the exporter, unknown@bugzilla.gnome.org.
Reassigning to the default owner of the component, zana@webwynk.net.

Comment 1 Callum McKenzie 2004-03-11 20:43:51 UTC
This looks like gcc's problem, not mine. Variables declared outside of
any function should have external linkage by default so the extern
modifier is optional (albeit good practice). gcc appears to be
generating the section names directly from the variable names and
getting a conflict. With the extern modifier it appears to be able to
resolve this. We are in code freeze for 2.6 so nothing is going to
change before then. For now don't use -fdata-sections. 

The code that is triggering this is definitely less than optimal and I
will leave this bug open so that I go back and fix it.

These comments apply to this and your previous two bugs, but this is
the only one I've looked at properly.

Comment 2 Heikki Tauriainen 2004-03-12 17:33:30 UTC
Yes, identifiers defined outside of functions have external linkage by
default. However, the extern modifier doesn't simply restate here that
an identifier should have external linkage; instead, it works as a
storage-class specifier (i.e., it effectively prevents the compiler to
reserve storage for the variable in two separate object files).

What I believe happens here is that declaring `press_data' in two
separate translation units without a storage-class specifier
effectively causes the variable to have two external definitions in
the entire program, which isn't allowed in strict C. (Because the
declarations have no initializers, leaving out the extern modifier
makes both declarations tentative definitions in two separate
translation units. This causes the compiler to reserve storage for the
variable in two separate object files.)

Actually, the reason why the compilation succeeds when not using
-fdata-sections seems to be that in this case `press_data' will be a
"common" symbol in both of the object files, and the (GNU) linker is
able to combine these symbols into one when linking. Apparently
-fdata-sections has the side effect of disabling common symbols (when
compiling with this option, `press_data' ends up in the uninitialized
data section in both object files, and this may be what then causes
the linker error). Indeed, the same error occurs when compiling with
the option -fno-common instead of -fdata-sections.

Anyway, the reason why I decided to report this bug (together with
bugs #136897 and #136896) in the first place was simply to point out a
(theoretical) possibility of a similar build problem on platforms with
less permissive compilers and linkers (on Linux, there is the trivial
"don't do that" workaround, of course). Sorry for not being clear
enough in my bug report.
Comment 3 Callum McKenzie 2004-03-15 09:43:42 UTC
I admit that the only reference I have for the C language at hand is
O'Reilly's C Pocket Reference which hardly goes into any detail but
seemed to imply that this would be OK. Since at least the press_data
example has been present for some time with no complaints from people
on "exotic" systems I'm not too worried. I've heard of recent
successes on Linux, FreeBSD and Solaris so I'm reasonably happy. I am
going to fix this in 2.7 (i.e. CVS HEAD) though since it is bad C
(regardless of whether it is legal C), but not 2.6 since we are only a
week away from release and I can't afford to accidentally break
anything (I've already caused at least one bug with a single-digit
change!). 
Comment 4 Heikki Tauriainen 2004-03-15 10:16:15 UTC
That's ok. Thanks for the information.
Comment 5 Callum McKenzie 2004-03-15 10:18:36 UTC
It is now fixed in my local copy. press_data is pretty evil anyway,
but now the evil is only spread across two files. I'll upload it to
CVS soonish, but I've only just branched and I have to let people
realise this before I start making gratuitous changes.
Comment 6 Callum McKenzie 2004-03-16 04:59:36 UTC
Since I needed to know the real answer.

From the C standard
(http://std.dkuug.dk/JTC1/SC22/WG14/www/docs/n843.htm, actually it is
the final draft):

Section 6.2.2#5:

If the declaration of an identifier for an object has file scope and
no storage-class specifier, its linkage is external.

Section 6.2.2#2:

In  the  set  of  translation units and libraries that constitutes an
entire  program,  each  declaration  of a particular identifier with
external linkage denotes the same object or  function.

I think that answers the question. This is of course the same
behaviour we expect with function names.

Comment 7 Heikki Tauriainen 2004-03-16 08:09:43 UTC
I understand that your conclusion is that the code _is_
standard-conforming even without storage-class specifiers?  (If I
misunderstood this, just forget about the rest of this comment.)

It's funny that I came to the opposite conclusion by looking at the
same draft of the standard (sorry to continue this debate, but the
question whether the code without the storage-class specifiers is
actually correct C got really interesting :-) ):

External definitions are discussed in Section 6.9 of the draft.

Section 6.9.2 (External object definitions):

    [#1]  If  the declaration of an identifier for an object has
    file  scope  and  an  initializer,  the  declaration  is  an
    external definition for the identifier.

    [#2]  A  declaration of an identifier for an object that has
    file scope without an initializer, and  without  a  storage-
    class  specifier or with the storage-class specifier static,
    constitutes a tentative definition. If  a  translation  unit
    contains   one   or   more   tentative  definitions  for  an
    identifier, and the translation unit  contains  no  external
    definition for that identifier, then the behavior is exactly
    as if the translation unit contains a file scope declaration
    of that identifier, with the composite type as of the end of
    the translation unit, with an initializer equal to 0.

In this particular case, it follows from #2 that the declaration
`press_data_type* press_data;' in `sol.c' and `press_data.c' is a
tentative definition for the variable in both files.  Because there
are no explicit external definitions (in the sense of #1) for the
variable in the files, the tentative definitions are then implicitly
treated as if they'd both been written in the form
`press_data_type* press_data = 0;' (by #2).  Therefore both
declarations are effectively external definitions by #1 (and have
external linkage).  The fact that `sol.c' and `press_data.c' don't
belong to the same translation unit is now what I believe what makes
the original code violate the C standard, since in Section 6.9
(External definitions) it's stated that a program may contain at most
one external definition for each object with external linkage:

    [#5]  An external definition is an external declaration that
    is also a definition of a function  or  an  object.   If  an
    identifier  declared  with  external  linkage  is used in an
    expression (other than as part of the operand  of  a  sizeof
    operator),  somewhere  in  the entire program there shall be
    exactly  one  external  definition   for   the   identifier;
    otherwise, there shall be no more than one.

BTW, I noticed that `sol.h' already contains a declaration for
`press_data' (with the `extern' storage-class specifier), so maybe the
definition in `sol.c' isn't even needed.
Comment 8 Callum McKenzie 2004-03-17 02:31:35 UTC
I agree with the first points, but I think you are misinterpreting
6.9#5. There is indeed only one *definition* of an external
*declaration*, but there can be multiple declarations that must have
identical definitions (up to the fuzziness about initialisation and
int[] vs. int[10]). If you interpreted things your way then you could
never have "extern int a" in one file (an explicit external
declaration) and "int a" in another file (an implicit external
declaration) since this would be two external declarations. However
they are the same external definition (i.e. both int). Having "extern
int a" in one file and "double a" in another is what I think 6.9 si
trying to avoid.

Also note that 6.9#5 does not distinguish functions and objects.
Declaring functions without extern and then declaring it with a
prototype (also without extern) in another file is a very widly
accepted practice and is exactly what was done in aisleriot, just with
an object instead.

Damn, we need a language lawyer.

On the last point about where press_data is defined: you are
absolutely correct, that is how I fixed it.
Comment 9 Heikki Tauriainen 2004-03-17 07:37:29 UTC
I absolutely agree about the need for a language lawyer here :-)

I think we may be having different views about the exact meaning of
declarations and definitions; I use the semantics defined in Section
6.7#5 of the standard draft:

    [#5]   A   declaration   specifies  the  interpretation  and
    attributes of a set of  identifiers.   A  definition  of  an
    identifier is a declaration for that identifier that:

         -- for  an  object, causes storage to be reserved for that
            object;
         -- for a function, includes the function body;
         -- for  an  enumeration  constant  or typedef name, is the
            (only) declaration of the identifier.

It's still perfectly ok to have `extern int a' in one file and `int a'
in another even if my interpretation is correct.  Here, `int a' is a
declaration that's also a (tentative) definition for the variable (by
6.9.2#2), whereas `extern int a' is a declaration that reserves no
storage (by 6.9.2#2, the `extern' specifier prevents the compiler from
treating the declaration as another tentative definition; removing it
would make `a' have two definitions in the entire program, which is
forbidden by 6.9#5).

It's confusing that the `extern' specifier is indeed redundant with
function declarations (by 6.7#5, a function declaration is a
definition only if it contains also the function body).  However, the
same doesn't hold for objects that are not functions.

(For another description about the difference, see Example 4.9 at
<http://publications.gbdirect.co.uk/c_book/chapter4/linkage.html>.
Although the book there isn't based on the latest C standard, I think
the explanation is still valid.)
Comment 10 Miloslav Trmac 2004-03-17 11:33:11 UTC
Heiki is correct here.
See http://std.dkuug.dk/JTC1/SC22/WG14/www/C99RationaleV5.10.pdf,
section 6.2.2.
Comment 11 Callum McKenzie 2004-03-17 21:57:56 UTC
OK, the rational explains things. I don't want to adjust 2.6 at this
late stage, although I'll probably back-port the changes to 2.6.1 once
HEAD has had a chance to show up problems.

I have to say that the standard isn't exactly clear and the rational
isn't much better. 

Now I get to add -fdata-sections to my list of useful error-finding
techniques !
Comment 12 Robert Ancell 2012-01-31 23:25:06 UTC
This bug is being reassigned to the "general" component so we can close the aisleriot bugzilla component.  Apologies for the mass email!