如何编译 cpp 然后将其链接到共享库

Posted

技术标签:

【中文标题】如何编译 cpp 然后将其链接到共享库【英文标题】:How to compile a cpp and then link it to a shared library 【发布时间】:2016-04-28 09:45:21 【问题描述】:

我想让另一个.cpp 文件中定义的函数在另一个模拟工具中可用。

我在这个问题中找到了以下代码:-finstrument-functions doesn't work with dynamically loaded g++ shared objects (.so)

Trace.cpp

#include <stdio.h>
#ifdef __cplusplus
extern "C"

    void __cyg_profile_func_enter(void *this_fn, void *call_site)
        __attribute__((no_instrument_function));
    void __cyg_profile_func_exit(void *this_fn, void *call_site)
        __attribute__((no_instrument_function));

#endif

void __cyg_profile_func_enter(void* this_fn, void* call_site)

    printf("entering %p\n", (int*)this_fn);


void __cyg_profile_func_exit(void* this_fn, void* call_site)

    printf("exiting %p\n", (int*)this_fn);

Trace.cpp 是这样编译的:

g++ -g -finstrument-functions -Wall -Wl,-soname,libMyLib.so.0 -shared -fPIC -rdynamic MyLib.cpp MyLibStub.cpp Trace.cpp -o libMyLib.so.0.0  
ln -s libMyLib.so.0.0 libMyLib.so.0  
ln -s libMyLib.so.0.0 libMyLib.so  
g++ MainStatic.cpp -g -Wall -lMyLib -L./ -o MainStatic   
g++ MainDynamic.cpp -g -Wall -ldl -o MainDynamic

请注意,我不需要:MyLib.cppMyLibStub.cpp

而是编译Trace.cpp做:

g++ -g -finstrument-functions -Wall -Wl,-soname,libMyLib.so.0 -shared -fPIC -rdynamic Trace.cpp -o libMyLib.so.0.0 

我的尝试:

我想拥有Trace.cpp的共享对象通过以下方式获得:

opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet 

我添加了-L-l

opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins -L /home/user/Desktop/test/ -lMyLib -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet 

得到:

/usr/bin/ld: 找不到-lMyLib

我也试过了:

opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins /home/user/Desktop/test/libMyLib.so.0.0 -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet 

编译成功但应用程序崩溃:

启动时出错:无法加载库 '../../src//libveins.so': libMyLib.so.0: 无法打开共享对象 文件:没有这样的文件或目录。


问题:

    如何正确编译Trace.cpp? 如何将它与共享库的其余部分链接?

您可能会注意到,我在编译、链接和类似方面不是很有经验。因此,非常欢迎任何额外的解释!

【问题讨论】:

您在其他地方的 cmets 中提出的问题的答案在您链接的问题中给出:“您必须在 libc.so.6 之前的某个地方获得自己的 __cyg_profile_func_enter。一种方法可以做到这一点是将其链接到您的主可执行文件。或者将其链接到直接链接到您的可执行文件的共享库(即不是 dlopen()d 之一)。“。除此之外,这个问题似乎是一个通用的“我如何链接它?”您选择的构建工具的文档中涵盖了这一点。 嗯,好的..这就是我现在想要弄清楚的。棘手的部分是我正在使用的工具使用脚本生成生成文件,该脚本最终将 3 个模拟工具“合并”在一起......最终的制作是这样的:pastebin.com/EiXGiHbK......所以真正的问题是如何做我将我的实现放在来自libc.so.6 的那个之前? :// 【参考方案1】:

正如@Flexo 重申@EmployedRussian 在链接问题中所说的那样,重点是在libc.so.6 提供的实现之前实现__cyg_profile_func_***

一种方法是使用LD_PRELOAD 环境变量。 Here 您可以阅读 LD_PRELOAD 的作用及其工作原理。

要使用LD_PRELOAD trick,您需要将上述函数的实现编译为共享库。

你可以这样做:

g++ -shared -fPIC myImp.cc -o myImp.so -ldl

获得.so 文件后,导航到可执行文件所在的目录并执行以下操作:

LD_PRELOAD=<path/to/myImp.so>- ./<myExecutable>

对于共享库,使用动态链接。含义:

解析一些未定义的符号(被推迟)直到程序运行。

通过使用LD_PRELOAD,您可以先解决您感兴趣的符号,然后再让链接执行此操作。


这里有一个myImp.cc 的实现,我取自:https://groups.google.com/forum/#!topic/gnu.gcc.help/a-hvguqe10I

当前版本缺少__cyg_profile_func_exit 的正确实现,我无法解开函数名称。

#ifdef __cplusplus
extern "C"


        #include <stdio.h>
        #include <stdlib.h>
        #include <sys/types.h>
        #include <sys/stat.h>
        #include <unistd.h>
    #include <dlfcn.h>


        void __cyg_profile_func_enter(void *this_fn, void *call_site)__attribute__((no_instrument_function));
        void __cyg_profile_func_exit(void *this_fn, void *call_site)__attribute__((no_instrument_function));



#endif
static FILE *fp;
int call_level=0;
void * last_fn;
void __cyg_profile_func_enter(void *this_fn, void *call_site)


    Dl_info di; 

        if (fp == NULL) fp = fopen( "trace.txt", "w" );
        if (fp == NULL) exit(-1);

        if ( this_fn!=last_fn) ++call_level;
        for (int i=0;i<=call_level;i++) 
    
        fprintf(fp,"\t");
    
        //fprintf(fp,  "entering %p\n", (int *)this_fn);
        fprintf(fp,  "entering %p", (int *)this_fn);
        if (dladdr(this_fn, &di)) 
          fprintf(fp,  " %s (%s)", di.dli_sname ? di.dli_sname : "<unknown>", di.dli_fname);
        
        fputs("\n", fp);
        (void)call_site;
        last_fn = this_fn;


void __cyg_profile_func_exit(void *this_fn, void *call_site)

        --call_level;
        for (int i=0;i<=call_level;i++) fprintf(fp,"\t");
        fprintf(fp, "exiting %p\n", (int *)this_fn);
        (void)call_site;



LTTng 在Function Tracing 部分使用了另一个使用LD_PRELOAD 的函数跟踪选项,但我从未使用过它...

【讨论】:

以上是关于如何编译 cpp 然后将其链接到共享库的主要内容,如果未能解决你的问题,请参考以下文章

如何测试共享对象/共享库是否已正确编译?

无法链接到共享库

如何通过 GNU Autotools 链接共享库

链接 Yaml-cpp 和 Armadillo 共享库的 CMake 项目

无法链接到 OpenCV (Linux) 的共享库

如何将共享库链接到Linux中的其他共享库?