Benjamin
Benjamin

Reputation: 10393

How to inline a function for only release build

// common.h
// This is foo function. It has a body.
__inline void foo() { /* something */ }

// a.cpp
#include "common.h" // for foo function
// Call foo

// b.cpp
#include "common.h" // for foo function
// Call foo

I would like to inline the foo function only when I build for release. I don't want to inline functions for Debug build.

I tried it but linker errors annoyed me.
In this case, foo function's body is defined in common.h header file.
so if I just do

//common.h
#if !defined(_DEBUG)
__inline
#endif
void foo() { /* something */ }

It will be met a link error in DEBUG build. Because two modules try to include common.h.
I have no idea to solve it.
Is it possible?

Upvotes: 3

Views: 2088

Answers (6)

DeveloperChris
DeveloperChris

Reputation: 3448

#ifdef RELEASE
#define INLINE __inline
#else
#define INLINE
#endif

Then

// common.h
INLINE void foo() { /* something */ }

// a.cpp
#include "common.h" // for foo function
// Call foo

// b.cpp
#include "common.h" // for foo function
// Call foo

then define RELEASE for the release version. of course you can see from this there are lots of ways to do it.

Upvotes: 3

Moshe
Moshe

Reputation: 58087

Use compiler conditionals and define a compile time flag.

Example:

#ifdef RELEASE_BUILD_FLAG
  //Run inline function
#else
  //some alternative
#endif

Upvotes: 0

Michael Burr
Michael Burr

Reputation: 340218

The fundamental thing to realize is that the inline keyword (or Microsoft's __inline extension for C - since MSVC doesn't support C99) is essentially a pass to violate the one definition rule. If you think about it - that's all it really is, since the compiler is under no obligation to actually perform any inlining.

So, when you have an inline function you're allowed to have the function defined in more than one module. In fact, you're obligated to have it defined in any module that actually uses the function.

However, if you don't declare the function as inline, you have to ensure that you have no more than one definition (exactly one if it actually gets used). For non-member functions (all function in C), there are a few ways around this:

  • declare the function as static to change it's linkage to internal (note that you can have static inline functions to begin with).
  • in C++ you can place them in an anonymous namespace (which has an effect similar to declaring the static)
  • you can use preprocessor manipulation to handle this. It's kind of ugly, but it works, and I've seen the technique used successfully in the wild. Whether it's worth the effort is another thing altogether - you'll have to decide that yourself.

Basically, what you need to do is have an implementation of the function in a separate .c file, just like if you were following the tradition of a-single-function-per-module coding standard (actually you can do this just as well putting several inline functions in the .c module - but they should all be inline or not inline as a group to keep things from getting too out of hand). The implementation of the function needs to arrange to be able to be included in a header - so it needs include guards, just like any other header. Then you use the preprocessor to conditionally include the implementation as part of the header when you want inline functions (so the implementation will be available to all modules), but don't include it if you're not inlining (so you follow the one definition rule in that case):

The common.h header: // common.h #ifndef COMMON_H #define COMMON_H

#ifdef RELEASE
#define USE_INLINE
#define INLINE __inline
#else
#define INLINE
#endif

INLINE void foo(void);
#ifdef USE_INLINE
#include "foo.c"
#endif

#endif /* COMMON_H */

The implementation of foo():

// foo.c
#ifndef FOO_C
#define FOO_C

#include <stdio.h>
#include "common.h"


INLINE void foo()
{
    printf("foo\n");
}

#endif /* FOO_C */

And an example program:

// main.c
#include<stdio.h>
#include "common.h"

int main()
{
    foo();
    return 0;
}

Now if you compile for release:

cl /DRELEASE main.c foo.c

foo() will be inline (or __inline as the case may be).

If you compile for non-release:

cl  test.c foo.c

you have a non-inline foo().

And both the compiler and linker are happy in either case.

All that said, I kind of like the suggestion to maybe redefine INLINE to be static for debugging purposes.

However, ultimately I'm not sure I see the point to any of this really - modern debuggers are able to step through functions that are inline, and the debugger probably won't inline function calls if you disable optimizations. So you can set breakpoints inside the inline function as well and have it work fine in non-optimized builds.

I'm not sure exactly what you're end-goal in this really is. What's the drawback to leaving the functions as inline in debug/non-optimized builds?

Upvotes: 5

watson1180
watson1180

Reputation: 2045

You can't declare header only functions as non-inline. You could declare them as static (a.k.a. C-style static), but that will generate a copy of the function (including local static variables, if any) in each translation unit. A better solution is to leave it as inline. In debug mode when optimizations are disabled compilers usually don't inline any functions.

Upvotes: 3

greyfade
greyfade

Reputation: 25657

The "easy" solution would be this:

#if !defined(_DEBUG) || defined(NDEBUG)
#define INLINE inline
#else
#define INLINE static
#endif

static is necessary to silence linking errors and get around the One Definition Rule.

A better solution would be to simply disable inlining project wide for debugging. GCC supports the -wno-inline-functions and -fno-inline-small-functions options to counteract those optimizations, and it also does not enable inlining for -O1 or lower (and probably -Os as well). Most compilers have similar options.

I call the latter a better solution because it should instruct the compiler to ignore the inline hint, eliminating the need for pesky preprocessor directives.

Upvotes: 8

santiagoIT
santiagoIT

Reputation: 9431

In most cases release flags are not defined. Typically debug flags are defined. _DEBUG is defined by most compilers, so there is no need to define a release flag:

More practical:

#ifndef _DEBUG
    __inline void foo() { /* something */ }
#else 
     //some alternative
#endif

Upvotes: 1

Related Questions