我有两个具有相同名称的函数,并想在我的应用程序中使用它。
我在这里提到了here之类的各种答案,但找不到明确的解决方案。
我具有以下功能
// 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);
原因有两个文件,xxxx_input
和yyyy_input
在内部工作方式不同。
修改功能并不容易,因为该代码是由外部方提供的,因此我们必须保留xxxx_input文件。
我们可以做的是修改yyyy_input.h
,但是input_system_easy_load
之类的函数必须保持一致,因为它们是在不同地方调用的。
有没有办法实现相同目标?
我尝试用xxxx_input
替换yyyy_input.h
,但是由于包含目录已经包含相同的功能,因此会出错。
input_system_init乘以xxxx_input.o和yyyy_input.o来定义。
答案 0 :(得分:8)
如果您拥有xxxx_input.h
和yyyy_input.h
中定义的函数的源代码,则可以使用命令行选项通过预处理器重新定义函数名称来编译两个模块:
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
然后,您将使用修改后的原型编译代码,并将所有3个模块链接在一起。
如果仅以对象形式提供模块,则可以定义包装函数xxxx_input_system_init
和xxxx_input_system_easy_load
,将它们与xxxx_input.o链接以生成动态库,而对于{ {1}}个替代方案。您将在模块中使用修改后的原型,并将其与动态库链接。
Mike Kinghan对yyyy
可用的系统上的对象文件和库显示了simpler approach。
要自动获取修改后的原型,可以使用以下包含文件:
my_input_system.h :
objcopy
答案 1 :(得分:7)
如果供应商给您编译了目标文件,我将介绍可使用的解决方案 适用于GNU / Linux计算机的GCC或Clang。
我的供应商给了我一个声明函数foo_a.h
的头文件foo
$cat foo_a.h
#pragma once
extern void foo(void);
和匹配的目标文件foo.o
:
$ nm foo_a.o
0000000000000000 T foo
U _GLOBAL_OFFSET_TABLE_
U puts
定义了foo
。
同样,他们给了我一个标头foo_b.h
,它也声明了foo
$ cat foo_b.h
#pragma once
extern void foo(void);
和匹配的目标文件foo_b.o
$ nm foo_b.o
0000000000000000 T foo
U _GLOBAL_OFFSET_TABLE_
U puts
还定义了foo
。
函数foo_a.o:foo
和foo_b.o:foo
的作用不同
事物(或同一事物的不同变体)。我想在同一个程序中做这两个事情,
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;
}
我可以制作这样的程序,
$ 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
现在,我制作了prog_foo_a.o
的副本foo_a.o
,其中的符号foo
为
重命名为foo_a
,并复制了prog_foo_b.o
的副本foo_b.o
,其中
符号foo
重命名为foo_b
。
然后我像这样编译并链接:
$ gcc -c -Wall -Wextra prog.c
$ gcc -o prog prog.o prog_foo_a.o prog_foo_b.o
prog
的运行方式如下:
$ ./prog
foo_a
foo_b
也许我的供应商在静态库foo_a.o
中给了我liba.a
还包含引用foo_a.o:foo
的其他目标文件?同样
与foo_b.o
。
没关系。代替:
$ 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
我将运行:
$ objcopy --redefine-sym foo=foo_a liba.a libprog_a.a
$ objcopy --redefine-sym foo=foo_b libb.a libprog_b.a
这将为我提供一个新的静态库libprog_a.a
其中foo
在文件中所有目标文件中都重命名为foo_a
。
图书馆。同样,foo
在整个foo_b
中都被重命名为libprog_b.a
。
然后我将链接prog
:
$ gcc -o prog prog.o -L. -lprog_a -lprog_b
考虑此解决方案的潜在缺点。我的供应商可能有
给了我foo_a.o
和foo_b.o
并提供了调试信息,我想
用它来用prog
调试我的gdb
吗?
我将原始符号名称从foo_a.o:foo
更改为foo_a
,并且
从foo_b.o:foo
到foo_b
,但我尚未更改关联的调试信息
这些符号。使用gdb
进行调试仍然可以,但是其中一些
调试输出将不正确,并可能造成混乱。例如。如果我放
foo_a
上的一个断点,gdb
会运行并停止,但是会说
它已从文件foo
在foo_a.c
处停止。然后如果我在foo_b
处设置断点,则gdb
将运行到
并再次说它位于foo
,但来自文件foo_b.c
。如果那个人在做
调试不知道程序是如何构建的,这肯定是
令人困惑。
但是为您提供带有二进制文件的调试信息距离为您提供 源代码,因此您可能没有源代码 调试信息,并不关心它。