I have two functions with same name and want to use it in my application.
I referred various answers like here and here but couldn't get clear solution.
I have following functions
// xxxx_input.h
int8_t input_system_init(InputParams params);
int8_t input_system_easy_load(uint32_t interval_ms);
// yyyy_input.h
int8_t input_system_init(InputParams params);
int8_t input_system_easy_load(uint32_t interval_ms);
Reason there are two files is xxxx_input
and yyyy_input
work way different internally.
Modifying the function isn't easy since the code is provided by external party and we have to keep the xxxx_input files.
What we can do is modify yyyy_input.h
but functions like input_system_easy_load
are to be kept consistent as they are called from different places.
Is there a way we can achieve the same?
I tried replacing xxxx_input
with yyyy_input.h
but since the include directory already contains the same function it gives error.
input_system_init multiply defined (by xxxx_input.o and yyyy_input.o).
I'll walk through a solution you can use if your supplier has given you object files compiled with GCC or Clang for GNU/Linux computers.
My supplier has given me a header foo_a.h
file that declares function foo
$cat foo_a.h
#pragma once
extern void foo(void);
and the matching object file foo.o
:
$ nm foo_a.o
0000000000000000 T foo
U _GLOBAL_OFFSET_TABLE_
U puts
that defines foo
.
Likewise they've given me a header foo_b.h
that also declares foo
$ cat foo_b.h
#pragma once
extern void foo(void);
and the matching object file foo_b.o
$ nm foo_b.o
0000000000000000 T foo
U _GLOBAL_OFFSET_TABLE_
U puts
that also defines foo
.
The functions foo_a.o:foo
and foo_b.o:foo
do different
things (or different variations of the same thing). I want to do both these things in the same program,
prog.c
:
$ cat prog.c
extern void foo_a(void);
extern void foo_b(void);
int main(void)
{
foo_a(); // Calls `foo_a.o:foo`
foo_b(); // Calls `foo_b.o:foo`
return 0;
}
I can make such a program as follows:
$ objcopy --redefine-sym foo=foo_a foo_a.o prog_foo_a.o
$ objcopy --redefine-sym foo=foo_b foo_b.o prog_foo_b.o
Now I have made a copy prog_foo_a.o
of foo_a.o
in which the symbol foo
is
renamed foo_a
, and a copy prog_foo_b.o
of foo_b.o
in which
the symbol foo
is renamed foo_b
.
Then I compile and link like this:
$ gcc -c -Wall -Wextra prog.c
$ gcc -o prog prog.o prog_foo_a.o prog_foo_b.o
And prog
runs like:
$ ./prog
foo_a
foo_b
Perhaps my supplier has given me foo_a.o
within a static library liba.a
that also contains other object files that refer to foo_a.o:foo
? And similarly
with foo_b.o
.
That's OK. Instead of:
$ objcopy --redefine-sym foo=foo_a foo_a.o prog_foo_a.o
$ objcopy --redefine-sym foo=foo_b foo_b.o prog_foo_b.o
I will run:
$ objcopy --redefine-sym foo=foo_a liba.a libprog_a.a
$ objcopy --redefine-sym foo=foo_b libb.a libprog_b.a
and this will give me a new static library libprog_a.a
in which foo
is renamed foo_a
in all the object files in the
library. Similarly foo
is renamed foo_b
throughout libprog_b.a
.
Then I'll link prog
:
$ gcc -o prog prog.o -L. -lprog_a -lprog_b
Consider a potential drawback with this solution. Possibly my supplier has
given me foo_a.o
and foo_b.o
with debugging information in them, and I want to
used it for debugging my prog
with gdb
?
I have changed the original symbol names, foo_a.o:foo
to foo_a
and
foo_b.o:foo
to foo_b
, but I haven't changed the debugging info associated
with those symbols. Debugging with gdb
will still work, but some of the
debugging output will be incorrect and possibly confusing. E.g. if I put
a breakpoint on foo_a
, gdb
will run to it and stop, but it will say
it has stopped at foo
from file foo_a.c
. And if I then breakpoint at foo_b
, gdb
will run to
it and again say it is at foo
, but from file foo_b.c
. If the person doing
the debugging doesn't know how the program was built, this would certainly be
confusing.
But giving you debugging info with binaries is not far from giving you the source code, so as you haven't got source code you likely don't have debugging info and are not concerned about it.
If you have the source code to the functions defined in xxxx_input.h
and yyyy_input.h
, you could compile both modules with command line options redefining the function names via the preprocessor:
gcc -Dinput_system_init=xxxx_input_system_init -Dinput_system_easy_load=xxxx_input_system_easy_load xxxx_input.c
gcc -Dinput_system_init=yyyy_input_system_init -Dinput_system_easy_load=yyyy_input_system_easy_load yyyy_input.c
You would then compile your code with modified prototypes and you could link all 3 modules together.
If the modules are provided in object form only, you could define wrapper functions xxxx_input_system_init
and xxxx_input_system_easy_load
that you would link with the xxxx_input.o to produce a dynamic library, and the same for the yyyy
alternatives. You would use modified prototypes in your module and would link it with the dynamic libraries.
Mike Kinghan showed a simpler approach for object files and libraries on systems where objcopy
is available.
To get modified prototypes automatically, you can use this include file:
my_input_system.h:
#define input_system_init xxxx_input_system_init
#define input_system_easy_load xxxx_input_system_easy_load
#include "xxxx_input.h"
#undef input_system_init
#undef input_system_easy_load
#define input_system_init yyyy_input_system_init
#define input_system_easy_load yyyy_input_system_easy_load
#include "yyyy_input.h"
#undef input_system_init
#undef input_system_easy_load
/* prevent direct use of the redefined functions */
#define input_system_init do_not_use_input_system_init@
#define input_system_easy_load do_not_use_input_system_easy_load@
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With