0

I'm having problem compiling cpp file with C inline functions using g++11. Following is an example:

c.h:

#ifndef C_H
#define C_H

#ifdef __cplusplus
extern "C" {
#endif

inline int add(int a,int b){return a+b;}

#ifdef __cplusplus
}
#endif

#endif

c.c

#include "c.h"
extern inline int add(int a,int b);

cpp.cpp:

#include "c.h"
int main(){
    return add(1,2);
}

Compile cmd

gcc -c c.c
g++ -c cpp.cpp
g++ c.o cpp.o

Problem: Link error. Multiple definitions of add.

The situation is using a C++ test framework to test a C code base. So I cannot modify the C code.

Platform is MSYS2/MinGW64, gcc 11.2.0. nm cpp.o gives the following:

0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 p .pdata
0000000000000000 p .pdata$add
0000000000000000 r .rdata$zzz
0000000000000000 t .text
0000000000000000 t .text$add
0000000000000000 r .xdata
0000000000000000 r .xdata$add
                 U __main
0000000000000000 T add
0000000000000000 T main
user3840170
  • 26,597
  • 4
  • 30
  • 62
Jackoo
  • 117
  • 1
  • 1
  • 12
  • 4
    Why are you declaring the inline function `extern` in `c.c`? – Barmar Mar 27 '22 at 09:38
  • 1
    @Barmar The extern inline is to provide a definition for C code. See the example part of https://en.cppreference.com/w/c/language/inline.html – Jackoo Mar 27 '22 at 09:42
  • `inline` works very differently in C and C++. I wouldn't use it for interop between the two languages. – HolyBlackCat Mar 27 '22 at 11:46
  • `extern "C"` does not mean compile this code as C. When c.h is included in a C++ compilation unit the code is compiled as C++. – Pete Becker Mar 27 '22 at 12:27

1 Answers1

0

I think your best option is to force the symbols to be emitted as weak in the C++ translation units by using file-level inline assembly:

__asm__(".weak add");
#include "c.h"

As far as I can tell, GCC makes non-static inline function symbols weak out of the box on ELF targets, where it causes no issues (which also makes your original example compile just fine on Linux). For some reason, GCC doesn’t do the same on MinGW, even though the object format does have some support for weak symbols.

You will need to obtain a complete list of non-static inline functions in the C header to make this work. You should be able to generate one using nm:

g++ -c -x c++ c.h -o /tmp/syms.o -Dinline='__attribute__((__used__)) inline' &&
nm -g -f just-symbols /tmp/syms.o |
    awk '{ print "X(" $0 ");" }' |
    gcc -E -P - -D'X(a)=__asm__(".weak " #a)' -o weaksyms.h

You will obtain a file weaksyms.h, which you can just include next to the C header. The order should not matter, nor should whether any of the symbols will actually end up in the C++ translation unit.

I tested the above answer with Debian’s GCC 10 and binutils 2.37 targetting x86_64-w64-mingw32. Attempting to do the above with #define inline __attribute__((__weak__)) inline for some reason does not work, and triggers a -Wattributes warning instead.

user3840170
  • 26,597
  • 4
  • 30
  • 62