Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function with same names in different files - C

Tags:

c

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).

like image 393
Electronics Dev Avatar asked May 22 '20 10:05

Electronics Dev


2 Answers

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.

like image 140
Mike Kinghan Avatar answered Oct 13 '22 18:10

Mike Kinghan


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@
like image 36
chqrlie Avatar answered Oct 13 '22 20:10

chqrlie