5

Functions in a header-only library should be declared as inline to prevent multiple definitions in the different translation units. That is, for example, I wrote a header-only library mylib.hpp:

void do_something(int) {} 

And I used this header in two different cpp file:

// a.cpp # include "mylib.hpp" void func1() {do_something(1);} 
// b.cpp # include "mylib.hpp" void func2() {do_something(2);} 

Build them with g++ -o main a.cpp b.cpp, GCC will complain with "multiple definition of do_something(int)". To prevent this, define the function like static void do_something(int) {} to make it have a copy in each translation unit (that is, have two copies in the last output), or define the function like inline void do_something(int) {} to have exactly a single copy in the last output, which is what we want.

However, if I want to force do_something not to be inlined by the compiler (for example, I want to use backtrace library to dynamically find out which function called do_something), I should write it like:

[[gnu::noinline]] inline void do_something(int) {} 

However, GCC complains:

Warning: inline declaration of ‘do_something(int)’ follows declaration with attribute ‘noinline’ [-Wattributes] 

So, what is the proper way to do such things?

4
  • 1
    The proper way is to have the function definition a cpp file. But since your way is not proper, why you don't just ignore (disable) the warning? Commented May 20, 2022 at 16:10
  • @ixSci But if do_something is a function template, it may be not convenient to put it into a cpp file. Commented May 20, 2022 at 16:18
  • 1
    If it was a function template you would not have the inline keyword in the first place. Commented May 20, 2022 at 16:19
  • Please post full code needed to reproduce the problem. Please post the exact full verbatim error messages from your compiler. Warning: inline declaration of is there no file:line: first declared here ----> and then file:line: second time declared here --->? You have two declarations of do_something() in your code, which is the reason of the error. Commented May 20, 2022 at 18:14

3 Answers 3

1

The inline keyword does not mean the code must be inlined or that it even will. inline says that there may be multiple (identical) versions of this functions and the linker will pick at most one representative.

The compiler can inline the function if it thinks it's worth it and inline can make it more likely to be inline. But why not let the compiler decide? It doesn't inline functions without reason.

But if you must have you tried static? A static function will not be exported to the outside of the translation unit. Every translation unit can have a static version of the same function without conflict. But be aware that that will be many copies of the same function and each has a unique address.

Sign up to request clarification or add additional context in comments.

Comments

0

The 'proper' way to get rid of the warning is to split your code into a header (.h) and source (.cpp) file.

// mylib.h [[gnu::noinline]] void do_something(int); 
// mylib.cpp void do_something(int) { // Implementation } 
// a.cpp #include "mylib.h" void func1() { do_something(1); } 
// b.cpp #include "mylib.h" void func2() { do_something(2); } 

Frankly, a library being 'header-only' is an overrated property. Splitting code into header and source files can improve compile times because the function body is parsed and compiled just once instead of being parsed and examined multiple times. (If you define a function in a header, the compiler may need to examine it multiple times to check that it hasn't changed between translation units.)

If being 'header-only' is really that important to you the other options are:

  • Using static. This will silence the warning, but runs the risk of producing multiple copies of the same function - one per translation unit. A link-time optimiser might be able to eliminate the duplicates, but it might not be a good idea to assume that will be the case.
  • Making the function a template makes the function implicitly inline whilst still respecting the [[gnu::noinline]], but then you end up with a dummy template parameter and force people to specify that parameter when calling the function.
  • You could make the function a static class member, which will make it implicitly inline without upsetting the attribute, and only requiring a bit of extra typing from the user (Class::do_something(1)).

Another way that would work, but is really bad and should be avoided is:

#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wattributes" [[gnu::noinline]] inline void do_something(int) { // Implementation } #pragma GCC diagnostic pop 

But this is a very hacky solution. Naturally it'll only work if GCC is the compiler and will break many other compilers. (Clang might be able to deal with it, but VC++ will choke on it.)


Of course, you may not actually need to force the compiler to avoid inlining your function. Usually the compiler will make the right decision on its own.

Personally the only times I've needed to use [[gnu::noinline]] are when a function used inline assembly that broke when the compiler inlined it and when measuring the overhead of a function call. (The latter is probably the intended use of the attribute.)

Comments

-1

if I want to force do_something not to be inlined by the compiler

There is no portable way to do that.

inline has a confusing name, it's not about inlining. You want just:

[[gnu::noinline]] static void do_something(int) {} 

I want to use backtrace library to dynamically find out which function called do_something

There is artificial funciton attribute https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes .

what is the proper way to do such things?

The proper way of defining a function in a header is with a static keyword.

If you mean by not-inlining a function, you don't - compilers optimize code, functions get inlined. If you want a fuction to be available for debugging, you configure compiler not to inline the code (-fno-inline, if you want to force it).

2 Comments

As was mentioned in the question, static would cause duplicates of the symbol in each translation unit by marking them as having internal linkage. Although this works, this doesn't actually solve the problem practically for if the function is large, or used many times.
I do not understand. this doesn't actually solve the problem what problem is not solved?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.