0

I am making a small, library, and I want to give the user the option to disable the parts they do not require.

lib.h

#ifndef ONLY_BASICS
    void complexFunction(void);
#endif

lib.c

#ifndef ONLY_BASICS
    void complexFunction(void) {
        printf("damn, this is complex alright!\n");
    }
#endif

main.c

#define ONLY_BASICS
#include "lib.h"

I have seen this being done in other libraries, what am I missing?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Jimmay
  • 959
  • 3
  • 13
  • 27
  • 4
    "what am I missing?" A question related to a problem you're having? – WhozCraig Aug 28 '13 at 18:30
  • Yes, I am still able to call the function even will the ONLY_BASICS set. – Jimmay Aug 28 '13 at 18:32
  • The problem is that `ONLY_BASICS` is only defined in `main.c`. `lib.c` will, therefore, define `complexFunction`. I don't think you can achieve what you're attempting with the `define` mechanism and still keep `lib.h` generic. However, when you compile, it should at least warn you that you're trying to call `complexFunction` without a function prototype. What other library have you seen use this technique? – lurker Aug 28 '13 at 18:36
  • OK, now I understand the problem. But is there a solution? – Jimmay Aug 28 '13 at 18:39
  • Can you put `#define ONLY_BASICS` in `lib.h`? Then it would work as long as other parts of the code don't need the complex items in `lib.c`. If `lib.c` is serving some modules that need `complexFunction` and some that don't, then what you're attempting to do is not achievable as a compile-time option. Either `complexFunction` exists in your build, or it doesn't it can't be both. – lurker Aug 28 '13 at 18:42
  • Yes, but you see. Different projects may, or may not need the define. I don't want the user to have to modify the internals of the library each time they want to change the settings. – Jimmay Aug 28 '13 at 18:45
  • Unless I put the code in the header file. – Jimmay Aug 28 '13 at 18:46
  • Jimmay, Your problem is really a two part problem. One is visibility, as @mbratch has explained. The tags you have used on this post suggest the answer to this problem - use a precompiler define. The second problem is that it is bad form to edit a library file within a project. So you will not be (should not be) surrounding code (lib.c/.h) with the exclusion ONLY_BASICS. – ryyker Aug 28 '13 at 19:01
  • It sounds like you need to versions of the library: `lib_simple` and `lib_complex` if you want to physically remove the ability to call `complexFunction` when only the simple case is desired. As I mentioned before, using your current scheme, you should at least be able to generate a compiler message if the function isn't defined (prototyped) in the `ONLY_BASICS` case. But you can't prevent it from being built into the lib if you need it sometimes and it will exist as a public symbol. – lurker Aug 28 '13 at 19:10
  • If by "I want to give the user the option to disable the parts they do not require" you mean you want them to be able to disable the parts *while they're compiling the library*, then you can just set the relevant `#define` using a compiler option, then they don't have to mess with the actual files. With gcc, for instance, you'd include `-DONLY_BASICS` as an option when compiling. If you want them to be able to do it after the library has already compiled, then the other answers are correct. – Crowman Aug 28 '13 at 19:29

2 Answers2

1

You can make users control the build using the prepossessing macros from the compiler without editing the code. If you use GCC use the switch -D followed by the macro name. On Microsoft compiler use the /D option.

For example using GCC, I have:

#include <stdio.h>

int main(int argc, char **argv) {

#ifdef SAYHI
    #ifdef CAPITAL
    printf("HI\n");
    #else
    printf("hi\n");
    #endif
#elif SAYHELLO
    #ifdef CAPITAL
    printf("HELLO\n");
    #else
    printf("hello\n");
    #endif
#else
    #ifdef CAPITAL
    printf("SAY SOMETHING\n");
    #else
    printf("say something\n");
    #endif
#endif

    return 0;
}

The user can enable and disable what he want via -DMACRO without editing the code, example:

$ gcc main.c
$ a.exe
say something
$ 
$ gcc main.c -DCAPITAL
$ a.exe
SAY SOMETHING
$ 
$ gcc main.c -DSAYHI -DCAPITAL
$ a.exe
HI
$ 
$ gcc main.c -DSAYHELLO
$ a.exe
hello
$ 
0

It seems you're misunderstanding what a library is and what it's used for. Most (all?) linkers already do what you're trying by not including unreferenced symbols from libraries - it's why with gcc, for instance, you need to put the libraries at the end of the command line after the list of source files that contain references to library functions.

What you're doing seems to be confusing this behaviour with compile-time options for the library itself. In that case, you can use the #ifndef blocks as you have in lib.h and lib.c, but you shouldn't need to do anything in main.c - the library will already have been built without complexFunction. You may want to have your library build process generate a header that describes which functionality is available.

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • Are you sure? [Does gnu ld link in whole object files or only the needed functions?](http://stackoverflow.com/a/13525970/1145760) – Vorac Aug 29 '13 at 14:02
  • 1
    That's why libraries are often compiled with `-ffunction-sections` or with a single function per translation unit. – Carl Norum Aug 29 '13 at 15:40