10

My C library has some optional features, and using automake, the user can turn them on and off by providing flags to configure.

If a feature is turned off, that function will not be compiled.

However, my question is, should I also remove the function prototype from the public headers in that case?

It seems like not a good idea to have function prototypes for functions that are not compiled, but it also seems to me not a good idea to have different public headers installed depending on the library configuration. (Similar to how it's bad practice to install config.h in the public headers directory.)

What's the best approach for public headers when it comes to optional features? If a user tries to use a disabled feature, should the error come at compile time, or link time? There must be a standard practise for this situation. (I prefer to comply with GNU coding standards if there are multiple ideas, but I don't know of the GNU standard on this issue.)

Steve
  • 8,153
  • 9
  • 44
  • 91
  • 1
    I think it is a good idea to not include the prototype if the function isn't defined, so that the error is found at compile time instead of link time, but I'm not aware of any standard practice on this. I would use #if. – Vaughn Cato Mar 09 '12 at 18:39
  • @VaughnCato if the prototype is excluded by a preprocessor directive, you'll get a compiler error. – Luchian Grigore Mar 09 '12 at 18:40
  • @LuchianGrigore yes, exactly. – Vaughn Cato Mar 09 '12 at 18:43
  • 1
    @LuchianGrigore Yeah, that's precisely the point: If you make the preprocessor exclude the implementation, also strip the declaration so people get a compiler error rather than a linker error (possibly dynamic linking too!). –  Mar 09 '12 at 18:44
  • What do you mean by remove? Actually remove the text? I would use #if to effectively remove it while not actually removing the text. – Vaughn Cato Mar 09 '12 at 18:44
  • I don't think there is a standard practice. Zlib seems to install its config header (as `zconf.h`), other libraries always provide stub implementations that just return a "not implemented" error. – Fred Foo Mar 12 '12 at 10:43

3 Answers3

3

Definetely don't only exclude the implementation from the compilation, but the whole function.

//feature.h
#ifndef EXCLUDE_FEATURE
   void foo();
#endif

//feature.c
#include "feature.h"
#ifndef EXCLUDE_FEATURE
void foo()
{
}
#endif

This way, you'll get a compiler, not linker error, if you try to use foo with the feature excluded. You want to signal an error as soon as possible, linker errors in general transmit less about the intention of the developer.

Microsoft does this (conditionals in header files) for MFC and it works quite nicely. (of course that's C++, but the principle stands.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    Right, thanks. I thought about that, my only worry is that it seems very similar to me to including the config.h file for example -- I was under the impression that the specific library configuration shouldn't necessarily be reflected in the headers since e.g. multiple versions of the library could be installed. That's really my only concern with this approach. – Steve Mar 11 '12 at 03:13
1

I think there are 2 valid approaches to this problem

  • Have a single header file which uses #ifdef to remove functions which aren't supported in certain configurations
  • Have multiple header files with no #ifdef each of which is specific to a configuration

It seems like a really bad practice to leave functions which aren't present in the lib in the header file for a given configuration. It will take what should be a compile time error and move it to a linker one.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
1

I observed the following approach in some projects: Generate the header file from a template one.

The file generation is based on the configuration flags.

This approach seemed to me more clean than using never ending conditionals definitions in the header... to me it seems much more clean.

Disadvantage: It may be a support burden (for the script).

EdwardH
  • 1,523
  • 2
  • 12
  • 20