Reputation: 483
In my project we are heavily using a C header which provides an API to comunicate to an external software. Long story short, in our project's bugs show up more often on the calling of the functions defined in those headers (it is an old and ugly legacy code).
I would like to implement an indirection on the calling of those functions, so I could include some profiling before calling the actual implementation.
Because I'm not the only person working on this project, I would like to make those wrappers in a such way that if someone uses the original implementations directly it should cause a compile error.
If those headers were C++ sources, I would be able to simply make a namespace
, wrap the included files in it, and implement my functions using it (the other developers would be able to use the original implementation using the ::
operator, but just not being able to call it directly is enough encapsulation to me). However the headers are C sources (which I have to include with extern "C"
directive to include), so namespaces won't help me AFAIK.
I tried to play around with define
s, but with no luck, like this:
#define my_func api_func
#define api_func NULL
What I wanted with the above code is to make my_func
to be translated to api_func
during the preprocessing, while making a direct call to api_func
give a compile error, but that won't work because it will actually make my_func
to be translated to NULL
too.
So, basically, I would like to make a wrapper, and make sure the only way to access the API is through this wrapper (unless the other developers make some workaround, but this is inevitable). Please note that I need to wrap hundreds of functions, which show up spread in the whole code several times.
My wrapper necessarily will have to include those C headers, but I would like to make them leave scope outside the file of my wrapper, and make them to be unavailable to every other file who includes my wrapper, but I guess this is not possible in C/C++.
Upvotes: 0
Views: 210
Reputation: 16530
There are two ways to wrap or override C functions in Linux:
Using LD_PRELOAD:
There is a shell environment variable in Linux called LD_PRELOAD,
which can be set to a path of a shared library,
and that library will be loaded before any other library (including glibc).
Using ‘ld --wrap=symbol‘:
This can be used to use a wrapper function for symbol.
Any further reference to symbol will be resolved to the wrapper function.
a complete writeup can be found at:
http://samanbarghi.com/blog/2014/09/05/how-to-wrap-a-system-call-libc-function-in-linux/
Upvotes: 1
Reputation: 6073
You can do something like
[your wrapper's include file]
int origFunc1 (int x);
int origFunc2 (int x, int y);
#ifndef WRAPPER_IMPL
#define origFunc1 wrappedFunc1
#define origFunc2 wrappedFunc2
#else
int wrappedFunc1(int x);
int wrappedFunc2(int x, int y);
#endif
[your wrapper implementation]
#define WRAPPER_IMPL
#include "wrapper.h"
int wrapperFunc1 (...) {
printf("Wrapper1 called\n");
origFunc1(...);
}
Your wrapper's C file obviously needs to #define
WRAPPER_IMPL
before including the header.
That is neither nice nor clean (and if someone wants to cheat, he could simply define WRAPPER_IMPL
), but at least some way to go.
Upvotes: 1
Reputation: 180898
You have several options, none of them wonderful.
static
and put the wrappers in the same source files, then you can ensure that the originals are called only via the wrappers. Example:static int api_func_real(int arg);
int api_func(int arg) {
// ... instrumentation ...
int result = api_func_real(arg);
// ... instrumentation ...
return result;
}
static int api_func_real(int arg) {
// ...
}
The preprocessor can help you with that, but I hesitate to recommend specifics without any details to work with.
#define api_func api_func_wrapper
You would then implement the various api_func_wrapper()
functions.
Among the ways those cases differ is that if you change the legacy function names, then internal calls among those functions will go through the wrappers bearing the original names (unless you change the calls, too), but if you implement wrappers with new names then they will be used only when called explicitly, which will not happen for internal calls within the legacy code (unless, again, you modify those calls).
Upvotes: 1