First you need to understand the built-in C99 model - maybe something is wrong with your headers. There are two types of definitions for built-in functions with external (non-static) binding
External definition
This definition of a function can appear only once in the entire program in the designated TU. It provides an exported function that can be used from other TUs.
Inline definition
They appear in each TU, which is declared as a separate definition. Definitions do not have to be identical to each other or to an external definition. If they are used inside the library, they can omit the verification of function arguments that would otherwise be executed in the external definition.
Each function definition has its own local static variables, because their local declarations have no relationship (they are not shared, as in C ++). A definition of a non-static built-in function will be a built-in definition if
- Each function declaration in TU includes an
inline specifier and - A function declaration in TU does not include an
extern specifier.
Otherwise, the definition that should appear in this TU (since the built-in functions must be defined in the same TU where it is declared) is an external definition. When calling the built-in function, it did not indicate whether an external or built-in definition was used. However, since the function defined in all cases still remains unchanged (since it has an external connection), its address is compared in all cases the same way, regardless of how many built-in definitions appear. Therefore, if you take the address of the function, the compiler will probably allow an external definition (especially if optimization is disabled).
An example that demonstrates the misuse of inline because it includes an external function definition twice in two TUs, resulting in a multiple definition error
// included into two TUs void f(void); // no inline specifier inline void f(void) { }
The following program is dangerous because the compiler has the right to use an external definition, but the program does not provide one
// main.c, only TU of the program inline void g(void) { printf("inline definition\n"); } int main(void) { g(); // could use external definition! }
I did some test cases using GCC, which further demonstrate the mechanism:
main.c
main1.c
#include <stdio.h> inline void f(void); // inline definition of 'f' inline void f(void) { printf("inline def main1.c\n"); } void g(void) { f(); }
main2.c
#include <stdio.h> // external definition! extern inline void f(void); inline void f(void) { printf("external def\n"); } void h(void) { f(); // calls external def }
Now the program displays what we expected!
$ gcc -std=c99 -O2 main.c main1.c main2.c inline def main.c inline def main1.c external def external def
Looking at the symbol table, we see that the symbol of the built-in definition is not exported (from main1.o ), but the external definition is exported (from main2.o ).
Now, if your static libraries have an external definition of their built-in functions (as it should be), they naturally conflict with each other. The solution is to make the built-in functions static or just rename them. They will always provide external definitions (therefore they are full definitions), but they are not exported because they have an internal relationship, therefore they do not conflict
static inline void f(void) { printf("i'm unique in every TU\n"); }