public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Multiple definition of static constexpr data member with C++11 and 17
@ 2021-08-16  9:36 wpty wpty
  2021-08-16  9:52 ` Jonathan Wakely
  0 siblings, 1 reply; 8+ messages in thread
From: wpty wpty @ 2021-08-16  9:36 UTC (permalink / raw)
  To: gcc-help

Hello,

I had a multiple definition error while trying to link a c++17 program
against a c++11-compiled library. The error doesn't happen if I use Clang
so I want to ask whether this is supported by GCC or something is wrong
with my code. I have a very small reproducer that I extracted from the real
code:

The library:

===============================
$ cat lib.h
#pragma once

struct A {
    static constexpr int x{ -1 };
};

void f(const int &x);
===============================

===============================
$ cat lib.cpp
#include "lib.h"

constexpr int A::x;

void f(const int& x) {}
===============================

And my program:

===============================
$ cat main.cpp
#include "lib.h"

int main() {
    f(A::x);
    return 0;
}
===============================


I use the following commands to compile the library and the main program:
===============================
$ g++ -std=c++11 -o lib.o -c lib.cpp
$ g++ -std=c++17 -o main.o -c main.cpp
$ g++ -o main lib.o main.o
/usr/bin/ld: main.o:(.rodata._ZN1A1xE[_ZN1A1xE]+0x0): multiple definition
of `A::x'; lib.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status
===============================

As shown, the last command fails with an error. If I replace "g++" with
"clang++", it works. Or if I use the same C++ standard (11 or 17) for both
object files, it works.

My questions are:
1. Is mixing C++11 and C++17-compiled object files like I do supported by
GCC?
2. If it is supported, then is something wrong with my code? The library is
compiled using C++11 and the C++11 standard requires that explicit
definition of constexpr static members are provided if they are odr-used
(which it is in my case), so lib.cpp has a definition of A::x. But if I try
to link the resulting object file with another object file that was
compiled using C++17, the linker gives a multiple definition error.

I have also compared symbol tables of main.o generated by GCC and Clang:
==================================================================
$ g++ -std=c++17 -o main.o -c main.cpp && readelf -s main.o | c++filt |
grep A::x
    11: 0000000000000000     4 OBJECT  UNIQUE DEFAULT    6 A::x
$ clang++ -std=c++17 -o main.o -c main.cpp && readelf -s main.o | c++filt |
grep A::x
     4: 0000000000000000     4 OBJECT  WEAK   DEFAULT    5 A::x
==================================================================
Clang generates a  WEAK symbol for A::x but GCC doesn't, maybe that's the
problem?

Relevant system and version info:
================================
$ g++ --version
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
$ clang++ --version
clang version 10.0.0-4ubuntu1
$ uname -a
Linux tp 5.10.0-1038-oem #40-Ubuntu SMP Fri Jul 16 15:08:30 UTC 2021 x86_64
x86_64 x86_64 GNU/Linux
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.2 LTS
Release: 20.04
Codename: focal
================================

Thanks in advance.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Multiple definition of static constexpr data member with C++11 and 17
  2021-08-16  9:36 Multiple definition of static constexpr data member with C++11 and 17 wpty wpty
@ 2021-08-16  9:52 ` Jonathan Wakely
  2021-08-16  9:59   ` Florian Weimer
  2021-08-16 10:02   ` wpty wpty
  0 siblings, 2 replies; 8+ messages in thread
From: Jonathan Wakely @ 2021-08-16  9:52 UTC (permalink / raw)
  To: wpty wpty; +Cc: gcc-help

On Mon, 16 Aug 2021 at 10:37, wpty wpty via Gcc-help
<gcc-help@gcc.gnu.org> wrote:
> My questions are:
> 1. Is mixing C++11 and C++17-compiled object files like I do supported by
> GCC?

Yes.

> 2. If it is supported, then is something wrong with my code? The library is
> compiled using C++11 and the C++11 standard requires that explicit
> definition of constexpr static members are provided if they are odr-used
> (which it is in my case), so lib.cpp has a definition of A::x. But if I try
> to link the resulting object file with another object file that was
> compiled using C++17, the linker gives a multiple definition error.

In C++17 the declaration in the class body is an inline variable, so
GCC emits a definition using the STB_GNU_UNIQUE binding, which means
that multiple definitions are allowed and the linker will only keep
one. However, that seems to only work if all definitions use that
binding. In this case, the C++11 lib.o object has a non-weak
non-STB_GNU_UNIQUE definition, which cannot be merged with the
STB_GNU_UNIQUE definition.

Clang's weak definition can be ignored by the linker in favour of the
non-weak definition from the C++11 object.

I'm not sure if GCC should change, or if the linker should be changed
to permit a single non-weak non-UNIQUE definition to be merged with
zero or more UNIQUE definitions. As a workaround you can compile the
C++17 code with -fno-gnu-unique so that GCC uses a weak symbol, but
that isn't a good solution in general (the unique binding exists for
good reasons).

Please report this to GCC's bugzilla, with the reproducer, thanks.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Multiple definition of static constexpr data member with C++11 and 17
  2021-08-16  9:52 ` Jonathan Wakely
@ 2021-08-16  9:59   ` Florian Weimer
  2021-08-16 11:31     ` Jonathan Wakely
  2021-08-16 10:02   ` wpty wpty
  1 sibling, 1 reply; 8+ messages in thread
From: Florian Weimer @ 2021-08-16  9:59 UTC (permalink / raw)
  To: Jonathan Wakely via Gcc-help

* Jonathan Wakely via Gcc-help:

> I'm not sure if GCC should change, or if the linker should be changed
> to permit a single non-weak non-UNIQUE definition to be merged with
> zero or more UNIQUE definitions. As a workaround you can compile the
> C++17 code with -fno-gnu-unique so that GCC uses a weak symbol, but
> that isn't a good solution in general (the unique binding exists for
> good reasons).

What are those reasons, exactly?

I've been trying to find a rationale and specification of
STB_GNU_UNIQUE, but have not been successful.

The glibc implementation does not handle symbol versions, it ignores
them.  It's not entirely clear to me if this is a bug.

Furthermore, I haven't seen a case yet which would require
STB_GNU_UNIQUE and could not have been handled equally well via symbol
interposition.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Multiple definition of static constexpr data member with C++11 and 17
  2021-08-16  9:52 ` Jonathan Wakely
  2021-08-16  9:59   ` Florian Weimer
@ 2021-08-16 10:02   ` wpty wpty
  1 sibling, 0 replies; 8+ messages in thread
From: wpty wpty @ 2021-08-16 10:02 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-help

Thank you for such a quick response. I will file a ticket on Bugzilla.

I have another question regarding your suggestion:

> As a workaround you can compile the
> C++17 code with -fno-gnu-unique so that GCC uses a weak symbol, but
> that isn't a good solution in general (the unique binding exists for
> good reasons).

Is there a workaround you can think of that can be done on the library
side? I am the maintainer of the library and can't control users' compile
options.

Thank you very much.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Multiple definition of static constexpr data member with C++11 and 17
  2021-08-16  9:59   ` Florian Weimer
@ 2021-08-16 11:31     ` Jonathan Wakely
  2021-08-16 12:47       ` Florian Weimer
  0 siblings, 1 reply; 8+ messages in thread
From: Jonathan Wakely @ 2021-08-16 11:31 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Jonathan Wakely via Gcc-help, wpty wpty

On Mon, 16 Aug 2021 at 10:59, Florian Weimer wrote:
>
> * Jonathan Wakely via Gcc-help:
>
> > I'm not sure if GCC should change, or if the linker should be changed
> > to permit a single non-weak non-UNIQUE definition to be merged with
> > zero or more UNIQUE definitions. As a workaround you can compile the
> > C++17 code with -fno-gnu-unique so that GCC uses a weak symbol, but
> > that isn't a good solution in general (the unique binding exists for
> > good reasons).
>
> What are those reasons, exactly?

I think it was added to ensure uniqueness of static objects across
libraries opened with RTLD_LOCAL.

> I've been trying to find a rationale and specification of
> STB_GNU_UNIQUE, but have not been successful.
>
> The glibc implementation does not handle symbol versions, it ignores
> them.  It's not entirely clear to me if this is a bug.

Does anybody use it with more than one symbol version though?

Using symbol versioning on a STB_GNU_UNIQUE symbol would seem to
violate its uniqueness.

> Furthermore, I haven't seen a case yet which would require
> STB_GNU_UNIQUE and could not have been handled equally well via symbol
> interposition.

Does that work for RTLD_LOCAL though?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Multiple definition of static constexpr data member with C++11 and 17
  2021-08-16 11:31     ` Jonathan Wakely
@ 2021-08-16 12:47       ` Florian Weimer
  2021-08-16 14:20         ` Jonathan Wakely
  0 siblings, 1 reply; 8+ messages in thread
From: Florian Weimer @ 2021-08-16 12:47 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Jonathan Wakely via Gcc-help, wpty wpty

* Jonathan Wakely:

> On Mon, 16 Aug 2021 at 10:59, Florian Weimer wrote:
>>
>> * Jonathan Wakely via Gcc-help:
>>
>> > I'm not sure if GCC should change, or if the linker should be changed
>> > to permit a single non-weak non-UNIQUE definition to be merged with
>> > zero or more UNIQUE definitions. As a workaround you can compile the
>> > C++17 code with -fno-gnu-unique so that GCC uses a weak symbol, but
>> > that isn't a good solution in general (the unique binding exists for
>> > good reasons).
>>
>> What are those reasons, exactly?
>
> I think it was added to ensure uniqueness of static objects across
> libraries opened with RTLD_LOCAL.

Hmm, that makes some sense.  The glibc implementation is not really
structured in such a way that it is obvious that this is the goal.
(glibc knows what it has loaded, so it could search just that, and not
construct a separate hash table.)

>> I've been trying to find a rationale and specification of
>> STB_GNU_UNIQUE, but have not been successful.
>>
>> The glibc implementation does not handle symbol versions, it ignores
>> them.  It's not entirely clear to me if this is a bug.
>
> Does anybody use it with more than one symbol version though?

libstdc++?

> Using symbol versioning on a STB_GNU_UNIQUE symbol would seem to
> violate its uniqueness.
>
>> Furthermore, I haven't seen a case yet which would require
>> STB_GNU_UNIQUE and could not have been handled equally well via symbol
>> interposition.
>
> Does that work for RTLD_LOCAL though?

No, I don't think so.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Multiple definition of static constexpr data member with C++11 and 17
  2021-08-16 12:47       ` Florian Weimer
@ 2021-08-16 14:20         ` Jonathan Wakely
  2021-08-16 15:48           ` Florian Weimer
  0 siblings, 1 reply; 8+ messages in thread
From: Jonathan Wakely @ 2021-08-16 14:20 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Jonathan Wakely via Gcc-help, wpty wpty

On Mon, 16 Aug 2021 at 13:47, Florian Weimer <fweimer@redhat.com> wrote:
>
> * Jonathan Wakely:
>
> > On Mon, 16 Aug 2021 at 10:59, Florian Weimer wrote:
> >>
> >> * Jonathan Wakely via Gcc-help:
> >>
> >> > I'm not sure if GCC should change, or if the linker should be changed
> >> > to permit a single non-weak non-UNIQUE definition to be merged with
> >> > zero or more UNIQUE definitions. As a workaround you can compile the
> >> > C++17 code with -fno-gnu-unique so that GCC uses a weak symbol, but
> >> > that isn't a good solution in general (the unique binding exists for
> >> > good reasons).
> >>
> >> What are those reasons, exactly?
> >
> > I think it was added to ensure uniqueness of static objects across
> > libraries opened with RTLD_LOCAL.
>
> Hmm, that makes some sense.  The glibc implementation is not really
> structured in such a way that it is obvious that this is the goal.
> (glibc knows what it has loaded, so it could search just that, and not
> construct a separate hash table.)
>
> >> I've been trying to find a rationale and specification of
> >> STB_GNU_UNIQUE, but have not been successful.
> >>
> >> The glibc implementation does not handle symbol versions, it ignores
> >> them.  It's not entirely clear to me if this is a bug.
> >
> > Does anybody use it with more than one symbol version though?
>
> libstdc++?

There are no symbols in libstdc++ that exist with multiple versions.

That is, we have foo@GLIBCXX_3.4.x and bar@GLIBCXX_3.4.y but we never
have foo@GLIBCXX_3.4.y or bar@GLIBCXX_3.4.z

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Multiple definition of static constexpr data member with C++11 and 17
  2021-08-16 14:20         ` Jonathan Wakely
@ 2021-08-16 15:48           ` Florian Weimer
  0 siblings, 0 replies; 8+ messages in thread
From: Florian Weimer @ 2021-08-16 15:48 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Jonathan Wakely via Gcc-help, wpty wpty

* Jonathan Wakely:

> On Mon, 16 Aug 2021 at 13:47, Florian Weimer <fweimer@redhat.com> wrote:
>>
>> * Jonathan Wakely:
>>
>> > On Mon, 16 Aug 2021 at 10:59, Florian Weimer wrote:
>> >>
>> >> * Jonathan Wakely via Gcc-help:
>> >>
>> >> > I'm not sure if GCC should change, or if the linker should be changed
>> >> > to permit a single non-weak non-UNIQUE definition to be merged with
>> >> > zero or more UNIQUE definitions. As a workaround you can compile the
>> >> > C++17 code with -fno-gnu-unique so that GCC uses a weak symbol, but
>> >> > that isn't a good solution in general (the unique binding exists for
>> >> > good reasons).
>> >>
>> >> What are those reasons, exactly?
>> >
>> > I think it was added to ensure uniqueness of static objects across
>> > libraries opened with RTLD_LOCAL.
>>
>> Hmm, that makes some sense.  The glibc implementation is not really
>> structured in such a way that it is obvious that this is the goal.
>> (glibc knows what it has loaded, so it could search just that, and not
>> construct a separate hash table.)
>>
>> >> I've been trying to find a rationale and specification of
>> >> STB_GNU_UNIQUE, but have not been successful.
>> >>
>> >> The glibc implementation does not handle symbol versions, it ignores
>> >> them.  It's not entirely clear to me if this is a bug.
>> >
>> > Does anybody use it with more than one symbol version though?
>>
>> libstdc++?
>
> There are no symbols in libstdc++ that exist with multiple versions.

I think someone complained that a versioned libc++ had a symbol clash
with libstdc++ through STB_GNU_UNIQUE symbols.

I can't find that bug report right now though. 8-(

Thanks,
Florian


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-08-16 15:48 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-16  9:36 Multiple definition of static constexpr data member with C++11 and 17 wpty wpty
2021-08-16  9:52 ` Jonathan Wakely
2021-08-16  9:59   ` Florian Weimer
2021-08-16 11:31     ` Jonathan Wakely
2021-08-16 12:47       ` Florian Weimer
2021-08-16 14:20         ` Jonathan Wakely
2021-08-16 15:48           ` Florian Weimer
2021-08-16 10:02   ` wpty wpty

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).