Reputation: 12150
Although I read questions similar to this one on SO, it still seems none of them provided a solution to my problem.
I have a header only utility, let's call it hutil.h
, which contains a function, let's call it hutil_func
. I created a small tool which has a header file, let's call it tool.h
, and also a source file, let's call it tool.c
. In tool.c
I implemented some "extra functionality" which uses the hutil_func
but I don't want to force the user, to use the hutil.h
file if the user doesn't need its extra capabilities.
So lets assume the user has a main.c
file, something like this:
// #include "hutil.h" <-- How to handle if this is removed?
#include "tool.h"
int main(void)
{
a_function_from_tool(); // <-- This can use hutil_func if hutil.h included
return 0;
}
Now, I'm looking for a solution -- hopefully a macro to deal with this situation at compile time -- which will replace the hutil_func
for example with an empty #define hutil_func()
macro.
Thanks in advance!
UPDATE1:
hutil.h
cannot be included into tool.c
, since that's exactly what I want to avoid: if the user doesn't want to use hutil.h
, then the user won't place it next to tool.c
.
UPDATE2:
The function hutil_func
is called inside a_function_from_tool
.
Upvotes: 1
Views: 136
Reputation: 25908
Attempting to do this using headers just seems like a bad design, and breaks modularity.
It's probably better to specify this as a compile time option. Your user can either use some kind of configure script, or just modify your makefile directly, and so if they choose to use this functionality, you end up calling something like:
gcc -o tool.o tool.c -c -DUSE_HUTILS
Then, in tool.c
you can do something like:
#ifdef USE_HUTILS
#include "hutils.h"
#endif
...
int a_function_from_tools(void) {
/* Some code */
#ifdef USE_HUTILS
int n = hutil_func();
#else
int n = get_n_some_other_way();
#endif
return n;
}
That way, tool.c
doesn't depend on, and doesn't care about, what was or was not included in main.c
, which is how it should be.
If it can feasibly work for the specific code you're doing, you could avoid multiple conditional compilation blocks within the function itself by doing:
#ifdef USE_HUTILS
#include "hutils.h"
#else
#include "hutils_fake.h"
#endif
where hutils_fake.h
contains the same interface as hutils.h
, but that interface basically expands to nothing along the lines of what you refer to as "an empty #define hutil_func()
macro." Alternatively, you could just do the check for #ifdef USE_HUTILS
within hutils.h
itself, and define real functionality if it's defined, and fake functionality if it isn't.
Doing something along these lines to provide different functionality which can optionally be compiled into or out of an application is fairly normal.
Upvotes: 2
Reputation: 94614
EDIT oops, misread the question. my bad.
The whole thing depends on if you've got code in tool.h
or just declarations.
If you've got code, then you should be able to leverage something like the typical guard mechanism for the hutil.h
file. In the hutil.h
file you should have lines like:
#ifndef HUTIL_H_
#define HUTIL_H_
...
#endif
in tool.h
, you guard the code that invokes the function from tool using:
#ifdef HUTIL_H_
hutil_func();
#endif
This only works if you've got code in tool.h
that can be guarded in this manner.
To accomplish this where tool.h
is a header-only file, you're going to need some indirection.
Firstly you need to be able to tell the routine in tool.h
what the function is that it should be able to use (this can be expanded for N entries using a struct pointer), so we modify the tool.h
routine to take an extra parameter hutil_func, which is a pointer to a function which matches the calling pattern of the hutil_func, and give the routine a different name to the name we use when calling it e.g. a_function_from_tool_internal
, so it looks like:
void a_function_from_tool_internal((void)(*utilfunc)(void), other_parameters);
in tool.c
, where the code is being invoked, you check if utilfunc is NULL
:
if (utilfunc != NULL)
utilfunc();
Then we put the following in the tool.h
:
#ifdef HUTIL_H_
#define a_function_from_tool(other_parameters) a_function_from_tool(hutil_func, other_parameters)
#else
#define a_function_from_tool(other_parameters) a_function_from_tool(0, other_parameters)
#endif
This sort of stuff is ugly, and falls down if you're using #pragma once
, but it may allow you to get the kind of functionality you're looking for.
Upvotes: 2
Reputation: 1493
You can include hutil.h in tool.c. In that case hutil.h won't be visible in main.c.
Upvotes: 0