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

How to compile a cpp and then link it to a shared library

本文关键字:链接 共享 然后 何编译 编译 cpp      更新时间:2023-10-16

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

我在这个问题中找到了以下代码:-finstrument-functions 不适用于动态加载的 g++ 共享对象 (.so)

跟踪.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 %pn", (int*)this_fn);
}
void __cyg_profile_func_exit(void* this_fn, void* call_site)
{
    printf("exiting %pn", (int*)this_fn);
}

跟踪.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: 无法打开共享对象 文件:没有此类文件或目录。


问题:

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

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

正如@Flexo重申@EmployedRussian在链接问题中所说的内容时,重点是在libc.so.6提供的内容之前获得__cyg_profile_func_***的实现。

执行此操作的一种方法是使用 LD_PRELOAD 环境变量。在这里,您可以阅读LD_PRELOAD的作用及其工作原理。

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

您可以通过执行以下操作来执行此操作:

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 %pn", (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 %pn", (int *)this_fn);
        (void)call_site;
}

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