How to compile C header with inline functions using g++11?

211 Views Asked by At

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
1

There are 1 best solutions below

0
user3840170 On

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.