gnustep / libobjc2

Objective-C runtime library intended for use with Clang.
http://www.gnustep.org/
MIT License
434 stars 118 forks source link

Duplicate symbol definition when including objc/objc.h in ObjC++ source #117

Closed iamleeg closed 5 years ago

iamleeg commented 5 years ago

Environment: tested on freebsd 12 with libobjc2 2.0 (from pkg, which looks identical to the released source). I used both clang 6.0 and 8.0 (again from FreeBSD packages), and got the same behavior.

Here's my file:

#include <objc/objc.h>

int main()
{
}

If I compile this as an ObjC file:

$ /usr/local/bin/clang80 -I/usr/local/include -c -x objective-c a.m
$ nm a.o
0000000000000000 T main
0000000000000008 C objc_method_cache_version

But if I compile it as an ObjC++ file:

$ /usr/local/bin/clang80 -I/usr/local/include -c -x objective-c++ a.m
$ nm a.o
0000000000000000 T main
0000000000000000 B objc_method_cache_version

It looks like in ObjC++, objc_method_cache_version is zero-initialized and gets written as a public symbol in BSS. But that means that I can't link two files that both included objc/objc.h and were both compiled as ObjC++ into the same executable:

$ /usr/local/bin/clang80 -L/usr/local/lib a.o b.o -lobjc
/usr/bin/ld: error: duplicate symbol: objc_method_cache_version
>>> defined at a.mm
>>>            a.o:(objc_method_cache_version)
>>> defined at b.mm
>>>            b.o:(.bss+0x0)
clang-8: error: linker command failed with exit code 1 (use -v to see invocation)

I would like to be able to do that.

davidchisnall commented 5 years ago

This is odd. I would expect it to show up as U in both cases, because it's an extern symbol. I believe that the bug is caused by a missing extern "C" in this file.

iamleeg commented 5 years ago

Thanks @davidchisnall, I've patched that change into slot.h locally and it doesn't change the result :(

davidchisnall commented 5 years ago

I think there's something weird in your config then. I can compile the C and C++ versions of the file and link them together (after renaming the main function in one to avoid that conflict). Please can you submit a complete test case that fails for you?

iamleeg commented 5 years ago

But you helped me track down the problem :). In the FreeBSD package, slot.h doesn't have the extern modifier (or the OBJC_PUBLIC modifier). I was wrong in thinking it was using the upstream sources.

iamleeg commented 5 years ago

Sorry, the FreeBSD port is based on 0db500a which does indeed exhibit this bug.