1

For simplicity, let's say I have the following C project structure:

src/
  utils/
    logger.c
    logger.h
   main.c
   secondary_component.c

main.c starts with:

#include "utils/logger.h"

I would like to keep the code and its structure as-is, but stub out logger.c, logger.h and avoid compiling secondary_component.c (i.e. only use the subset of main and logger). For instance, instead of the regular logger.c writing to a file, the stubbed version would include a simple printf.

My attempted solution: create an extra folder stubbed_src/utils and place my new logger.c, logger.h inside that folder. Then, I perform:

clang -iquote stubbed_src -iquote src -o main_proj main.c stubbed_src/utils/logger.c

The goal is that when clang sees the #include logger.h in main.c, it will first look at the stubbed_src folder and find it (and thereby ignore the original src/utils/logger.h). Unfortunately, clang always looks at the current folder first (i.e. it looks for utils/logger.h starting at src, where main.c is located) and only if it doesn't find it will it then looks at the iquote folders. In which case, it will always stop when it finds the implementation in src/utils.

There used to be a clang command line workaround which disabled this current working directory behavior, but it has since been deprecated.

If I were willing to change main.c's #include to be an angle bracketed #include, then using -I would also solve the problem since -I has no such restriction regarding the current directory. But this would be an improper usage of angle brackets, and also I'm unable to change main.c in this case.

Ideally, my stubbed versions of logger.c, logger.h would be much reduced in size and only implement functions used in main.c. For instance, I would like to discard any logger functions called by secondary_component.c since I only want to compile main.c. In addition, those extraneous functions called by secondary_component.c introduce their own #include requirements into the original logger files and I'm trying to avoid compiling those extra #includes. I would like to be able to simply compile main.c and have it work with stubbed logger functions and be able to avoid compiling any extra files.

Any other suggestions on how to use an alternative/stubbed out implementation of logger.c, logger.h?

ChaimKut
  • 123
  • 4
  • Change the current folder to `stubbed_src` before invoking Clang? – Robert Harvey May 21 '19 at 19:04
  • 2
    Is the stubbed-out version of `logger.h` different from the original? In what way? Usually header files only contain function prototypes, forward declarations, and other "parts of the API contract," so you would not normally want to stub out a header. What part of the header are you trying to stub out, and why? – Kevin May 21 '19 at 19:38
  • Good point. In other words, the header file is not likely to change. Your implementation (.c file) will, however. – Robert Harvey May 21 '19 at 20:08
  • @Kevin For instance, `logger.h` has a function not used by `main.c` (but used by some other file). That extra function results in extra `#include`'s in the header file (for instance, if the function prototype includes named structs specified elsewhere). One of my primary goals is to avoid compiling a long chain of `#include`'s if they're not at all needed for simply compiling `main.c`. – ChaimKut May 21 '19 at 20:09
  • @RobertHarvey The idea of 'current working directory' for purposes of clang compilation is relative the *file currently being compiled* (and *not* relative to where clang is being executed on the command line). So no matter where clang is invoked, as long as `main.c` is inside of `src`, then `src` will always be the current working directory for `main.c` compilation. – ChaimKut May 21 '19 at 20:11
  • But if `main.c` doesn't call your logging function, then you don't need to include `logger.h`, right? Conversely, if one of your other C files calls your logging function, you'll have to always include `logger.h` *even if you're using a different implementation of your logging function.* – Robert Harvey May 21 '19 at 20:32
  • This seems especially relevant: https://cgreen-devs.github.io/index.html#_what_is_cgreen – Robert Harvey May 21 '19 at 20:35
  • @RobertHarvey `main.c` *does* call some functions in `logger`, but not all of the `logger` functions. – ChaimKut May 21 '19 at 20:43
  • Does that matter? You don't use all of the functions in `stdio.h` either. – Robert Harvey May 21 '19 at 21:04
  • To be clear, what I'm saying is that, when you stub or mock your logger implementation, you're not replacing `logger.h`, you're replacing `logger.c`. – Robert Harvey May 21 '19 at 21:39

1 Answers1

4

The normal practice when mocking functions in C (or otherwise using different implementations) is to use different .c source files in your build process. Normally, header files are not replaced.

If header files really must be replaced, then the #include "header.h" include directive must not refer to a file that can be found directly from the current source's directory. The C standard specifies that the #include "..." form must always first look in the current directory before starting to look into other paths.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Bart van Ingen Schenau
  • 71,712
  • 20
  • 110
  • 179