There is an error like this for each inline function:
bare-metal-arm/accel.c:80: undefined reference to `i2c_start'
though, the function is defined in the same file where it is reported as an unknown symbol, like this:
inline void i2c_start(I2C_MemMapPtr p)
{
i2c_set_master(p);
i2c_set_tx(p);
}
The full project is a bare metal demo for the FRDM-KL25Z devboard, for Linux and without using the proprietary Freescale CodeWarrior tollchain/IDE, by payne92:
https://github.com/payne92/bare-metal-arm
Searching online, the error seems to be related with how different C/C++ standards define the "inline", "static inline" and "external inline" behaviour, according to https://gcc.gnu.org/onlinedocs/gcc/Inline.html#Inline
So far I've tried adding either "-std=gnu11" or "-finline-functions" to the Makefile, but that didn't fix the undefined symbols errors for the inline function names.
However, making the inline functions "static", fixes the error. My understanding so far is that adding "static" will also keep the entire function body out of any code optimization.
Is there any better way to avoid the missing symbols errors, while allowing the compiler to do whatever code optimization it might be able to do inside the body of the inline functions?
bare-metal-arm/accel.c:80: undefined reference to `i2c_start'
though, the function is defined in the same file where it is reported as an unknown symbol, like this:
inline void i2c_start(I2C_MemMapPtr p)
{
i2c_set_master(p);
i2c_set_tx(p);
}
If the compiler decides to perform a regular (non-inline) call to your function, it will require a regular (non-inline) definition for your function. This is your responsibility to provide that definition. As opposed to C++, in C the non-inline definition will NOT be generated automatically.
It is your responsibility to choose one (and only one) translation unit and make an `extern inline` declaration of your function in that translation unit. The compiler will then emit a non-inline definition in that translation unit. The linker will pick it up and use it to dispatch all non-inline calls.
Apparently, you forgot to do that, which is why the linker is complaining.
However, making the inline functions "static", fixes the error. My understanding so far is that adding "static" will also keep the entire function body out of any code optimization.
Um.. Not sure what you mean here. Making a functinon `static` is fully equivalent to making it `inline`, as far as optimizations are concerned. Every time the compiler can see the full definition of your function (the whole body), you get full optimizations.
This actually raises an obvious question: do you want your function to have external linkage? Is it important to you? `inline` is intended for functions with external linkage. If you don't need external linkage, just make it `static` and forget about `inline`. From `static` you will get everything that `inline` would give you.
I see that in your code the `inline` function is defined in a `.c` file (not in a header file), which most likely means that you don't need external linkage for this function. In that case just make it `static`. You can also make it `static inline` if you want, but it will not make any difference over simple `static`.
Unless I am missing something here the understanding of `inline` is wrong. An `inline` function is one that the compiler can chose to inline into another block of code omitting the overheads of a function call & return.
ie:
inline void myFunc(void)
{
doStuff();
doMoreStuff();
}
int main(int argc, char * argv[])
{
myFunc();
}
If the compiler decides it's optimal to inline (unless `always_inline` is used) the above would have the following effect:
int main(int argc, char * argv[])
{
doStuff();
doMoreStuff();
}
The function `myFunc` has been `inlined` improving performance as it avoids the need to CALL/RET, however if the function is called from many places it will bloat the application size. Because the compiler may inline the function, after the object has been compiled the function may not exist at all making it impossible to be linked against, as such inline functions that need to be shared across units are normally defined in the headers.
As for the definition of `static` above, it's absolutely correct. Making a function `static` does not inline it (but the compiler may opt to if it makes sense to), it simply prevents the compiler from generating a symbol for the function that can be linked against, allowing it to make decisions such as auto-inlining at compile time.
so far I used to use "volatile" (for variables) to preserve them against being silently removed during optimization,
This is not what volatile does and the compiler can still opt to remove them during optimization.
A good usage of inline in projects (espesially mcu projects) is when you have some code that pokes a register, ie:
inline void gpio_set(int pin, int on)
{
SOME_REGISTER |= 1 << pin;
}
This would inline very nicely and makes the code easy to debug unlike macros that can make this a nightmare as they get more and more complex/deep.
Some more usage examples from one of my FOSS projects:
https://github.com/gnif/LookingGlass/blob/master/common/include/common/time.h#L39