最近,我的公司想要将编译器从gcc-3.4更新到gcc-4.5。但是,我们客户的机器可能没有最新的libstdc++.so
,因此我们希望静态链接我们的二进制文件。
我们的计划需要定制malloc()/free()
以满足极高的性能要求。
我修改了makefile,在链接时添加了-static
,并收到以下错误消息:
/usr/lib64/libc.a(malloc.o)(.text+0x18c0): In function `free':
: multiple definition of `free'
../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o)(.text+0x3430): first defined here
/usr/bin/ld: Warning: size of symbol `free' changed from 271 in ../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o) to 255 in /usr/lib64/libc.a(malloc.o)
/usr/lib64/libc.a(malloc.o)(.text+0x3970): In function `malloc':
: multiple definition of `malloc'
../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o)(.text+0x29c0): first defined here
/usr/bin/ld: Warning: size of symbol `malloc' changed from 281 in ../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o) to 461 in /usr/lib64/libc.a(malloc.o)
/usr/lib64/libc.a(malloc.o)(.text+0x4050): In function `realloc':
: multiple definition of `realloc'
../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o)(.text+0x3e80): first defined here
/usr/bin/ld: Warning: size of symbol `realloc' changed from 335 in ../../ic/src/memmgr/libmemmgr_mt_thread.a(memmgr_mt_thread.o) to 927 in /usr/lib64/libc.a(malloc.o)
好的,这是合理的,因为libc.a
已经有malloc()/free()
。
但令我困惑的是动态链接时没有错误的原因。我搜索过,发现了这个问题:How to redefine malloc() in Linux for use in C++ new。答案是链接器以不同方式处理库文件(.a)和目标文件(.o)。现在我知道静态链接发生错误的原因,而不是动态错误。
但是,我尝试了该答案中描述的解决方案,直接用目标文件替换了库文件,但没有区别。我仍然有多个定义链接错误。我也试过-static-libgcc
(因为我不知道该怎么做,我只是尝试了我在gcc
手册页中看到的所有内容),但它也无济于事。
我不必使用静态链接。我只想解决libstdc++.so
版本问题。任何建议将不胜感激。
提前致谢。
编辑:对不起,我没有说清楚。使用#define malloc ...
可能无济于事。因为我们的程序是C ++。 #define
成语只能影响malloc()/free()
函数。但我们的程序实际上使用new/delete
来分配/释放内存。无论如何,谢谢:D
答案 0 :(得分:5)
如果您主要关心的是libstdc ++的可用性,那么在目标系统中,为什么不简单地将新版本与您的应用程序一起分发呢?
我认为静态链接在任何情况下都不是一个好的解决方案,编译项目会变得更加困难,如果你自己使用共享对象(例如使用自己的插件时),那么静态链接就会停止工作,因为静态库的单独副本需要链接到二进制文件的每个,可执行文件等等。你能想象如果在加载时同一程序中有多个全局变量,锁等实例会发生什么?我告诉你:崩溃。
所以不要静态链接,复制libstdc ++。所以到私有目录(我不知道你的应用程序安装在哪里,但如果它有一个私有前缀,那很简单,使用$ prefix / lib)。 / p>
然后设置LD_LIBRARY_PATH,或使用-rpath将路径编码为二进制文件,以便链接器找到它。当然,这意味着您链接的所有库,也可能使用libstdc ++,也应该与您的应用程序一起分发。
但从大小来看,它大致相同,静态链接也会带有代码。
答案 1 :(得分:3)
您可以使用rpath进行动态链接。见“man ld”和“man ld.so”。
$ ORIGIN扩展可能很有用:捆绑每个.so你需要在与程序(或子目录)相同的目录中,并在链接时使用“-rpath $ ORIGIN”或“-rpath,'$ ORIGIN / lib”与ld。
许多程序使用这种方法捆绑自己的私有库。
另一种方法是使用.sh脚本设置LD_LIBRARY_PATH,然后调用真实程序(下载firefox二进制文件并查看run-mozilla.sh)。但是LD_LIBRARY_PATH将泄漏到子进程。所以它不是那么干净,但可能更容易移植到非GNU系统。
答案 2 :(得分:2)
您应该在项目中使用自己的free / alloc / realloc函数,但我强烈建议您使用与标准库相同的名称。
例如
void* myProject_malloc(...)
void myProject_free()
您可以将它与宏结合使用,将分配功能重定向到您的功能,但我真的不想让您这样做。您有义务检查所有源代码是否包含此头文件,并且编译器可以使您了解宏重定义(取决于编译器和您使用的选项)
#define malloc(x) myProject_malloc(x)
#define free() myProject_free()
如果您不想使用标准库,则应使用gcc选项:“ - nostdlib”。但是如果你这样做,你就不能使用标准库的任何其他功能。
答案 3 :(得分:1)
如果您使用的是GNU libc,则可以使用GNU malloc Hooks。我对这个API的设计不太满意所以我不建议使用它。
您可以尝试修补libc。删除malloc/
中的所有代码,并将其替换为您的实现。
使用相同的想法,您可能会尝试删除libc.a
,删除包含.o
和朋友的所有malloc
个文件(这应该是所有.o
个文件对应malloc/*.c
)并重新加载libc.a
与您的实施。
答案 4 :(得分:0)
很可能您需要更改自定义分配例程的名称。之后,您应该使用答案中描述的方法来节省时间,这样您就不必更改所有对新名称的调用:
#define malloc myMalloc
#define free myFree
答案 5 :(得分:0)
如果您只需要为C ++执行此操作,则可以覆盖new,delete,new [],delete []运算符。请参见18.6.1“存储分配和释放”
void* operator new(std::size_t size);
[...]
void operator delete(void* ptr);
“可替换:C ++程序可以使用此函数签名定义一个函数,取代C ++标准库定义的默认版本。”
我不知道它是否适用于静态链接(不知道它是如何实现的)。