如何编译一个cpp然后link它到一个共享库
How to compile a cpp and then link it to a shared library
我想让另一个 .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.cpp
和 MyLibStub.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: cannot find -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
编译成功但应用程序崩溃:
Error during startup: Cannot load library
'../../src//libveins.so': libMyLib.so.0: cannot open shared object
file: No such file or directory.
问题:
- 如何正确编译
Trace.cpp
?
- 如何 link 它与共享库的其余部分一起使用?
正如您可能注意到的那样,我在编译、linking 和类似方面不是很有经验。所以,非常欢迎任何额外的解释!
由于@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>
对于共享库,使用动态链接。含义:
resolving of some undefined symbols (is postponed) until a program is run.
通过使用 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
文件中定义的函数在另一个模拟工具中可用。
我在这个问题中找到了以下代码:-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.cpp
和 MyLibStub.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: cannot find -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
编译成功但应用程序崩溃:
Error during startup: Cannot load library '../../src//libveins.so': libMyLib.so.0: cannot open shared object file: No such file or directory.
问题:
- 如何正确编译
Trace.cpp
? - 如何 link 它与共享库的其余部分一起使用?
正如您可能注意到的那样,我在编译、linking 和类似方面不是很有经验。所以,非常欢迎任何额外的解释!
由于@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>
对于共享库,使用动态链接。含义:
resolving of some undefined symbols (is postponed) until a program is run.
通过使用 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
的函数跟踪选项,但我从未使用过它...