如何覆盖C库中的fprintf? 如何将GCC选项添加到顶层CMakeLists.txt?

我知道如何在简单的示例中覆盖C-lib函数。 但我需要的是一个真正的项目,它有数百个调用fprintf的文件。

在每个文件中,都有一个"#include " ,以及数十或数百个fprintf调用。 我想让所有这些fprintf做我自己的工作。 我无法删除"stdio.h"并添加"#include " ,其中myprint.h定义了自己的工作的fprintf的实际function或宏。 "stdio.h"在项目中有许多其他调用。 我想要一个简单的解决方案。

谢谢!

我的问题是否足够明确?…

2014.03.08更新:首先向所有女性致敬……

请看下面的第二篇文章。

例如,如果您使用gcc,则可以通过以下方式调用它:

 gcc -include myheader.h -Dfprintf=myfprintf file.c 

这将包括myheader.h之前在myfprintf每个其他include头之前,并将fprintf重新定义为myfprintf

你可以在这里找到更多细节

问题更新概述:我在CMAKE中添加了GCC选项,但似乎无效。

======我的第一次发布解决方案======

大家好,

至于我在第一篇文章中的问题,我找到了一个钩子解决方案如下:

 #define _GNU_SOURCE // for time() and localtime() #include  // for fprintf/fwrite #include  // for va_* functions #include  // for dlsym #include  // compile command line: gcc -shared -Wl,--no-as-needed -ldl -fPIC -Wall hooktest.c -o hooktest.so // how to use: LD_PRELOAD=hooktest.so ./hooktestprog, where hooktestprog includes stdio.h and calls fprintf // a helper function void print_time(FILE *fp, const char *format, ...) { va_list args; va_start(args, format); vfprintf(fp, format, args); va_end(args); } // GCC optimizes fprintf to fwrite // to make original program use fprintf exactly, compile the program (not this library) with -fno-builtin-fprintf int fprintf(FILE *stream, const char *format, ...) { static int (*my_fprintf)(FILE *stream, const char *format, ...) = NULL; if (NULL == my_fprintf) { my_fprintf = (int (*)(FILE *stream, const char *format, ...))dlsym(RTLD_NEXT, "fprintf"); } va_list args; va_start(args, format); time_t tNow = time(NULL); struct tm *tmNow = localtime(&tNow); print_time(stream, "%04d/%02d/%02d %02d:%02d:%02d === ", tmNow->tm_year+1900, tmNow->tm_mon+1, tmNow->tm_mday, tmNow->tm_hour, tmNow->tm_min, tmNow->tm_sec); my_fprintf(stream, format, args); va_end(args); return 0; } // GCC optimizes fprintf to fwrite // to make original program use fprintf exactly, compile the program (not this library) with -fno-builtin-fprintf /* size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { static size_t (*my_fwrite)(const void *, size_t, size_t, FILE *) = NULL; if (NULL == my_fwrite) { my_fwrite = (size_t (*)(const void *, size_t, size_t, FILE *))dlsym(RTLD_NEXT, "fwrite"); } time_t tNow = time(NULL); struct tm *tmNow = localtime(&tNow); print_time(stream, "%04d/%02d/%02d %02d:%02d:%02d === ", tmNow->tm_year+1900, tmNow->tm_mon+1, tmNow->tm_mday, tmNow->tm_hour, tmNow->tm_min, tmNow->tm_sec); my_fwrite(ptr, size, nmemb, stream); FILE *fp = fopen("/home/idesclient/log_freerdp.log", "a"); if (NULL != fp) { print_time(fp, "%04d/%02d/%02d %02d:%02d:%02d === ", tmNow->tm_year+1900, tmNow->tm_mon+1, tmNow->tm_mday, tmNow->tm_hour, tmNow->tm_min, tmNow->tm_sec); my_fwrite(ptr, size, nmemb, fp); fclose(fp); } return nmemb; } */ 

我想覆盖fprintf,但GCC优化fprintf到fwrite。 您可以通过编写调用fprintf的示例,编译它并使用命令“nm yoursample | grep @ GLIBC_2.0”来检查这一点。 你可以看到像“fwrite@GLIBC_2.0”这样的东西,而且没有“fprintf@GLIBC_2.0”。

但是我无法覆盖fwrite,因为我的项目中还有其他的fwrite调用。 如你所见,我注释掉了fwrite()。

我找到了另一个解决方案:在编译示例程序时添加“-fno-builtin-fprintf”,现在示例正常工作。 注意:只有示例工作,而不是我的项目工作…命令行如下:

 >gcc -shared -Wl,--no-as-needed -ldl -fPIC -Wall hooktest.c -o hooktest.so >gcc -fno-builtin-fprintf sample.c -o sample # where sample.c calls fprintf >LD_PRELOAD=./hooktest.so ./sample 

现在我可以看到fprintf添加时间信息 – fprintf被挂钩。

======新问题在这里开始======

到现在为止,似乎我可以在我的顶级CMakeLists.txt中添加“-fno-builtin-fprintf”(该项目有很多子目录,这是一个非常复杂的项目),并且每个人都应该工作。 但在实际操作中,它没有。

我的顶级CMakeLists.txt中有以下几行:

 if(CMAKE_COMPILER_IS_GNUCC) xxxxxx (this is the original definitions in my project) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-builtin-fprintf") endif() 

但是在我编译项目之后,使用“LD_PRELOAD = / xxx / hooktest.so / xxx / project / bin / somebinary”,fprintf没有被挂钩。

我做了另一个测试。 在我上面的C代码中,我评论fprintf并取消注释fwrite(GCC将fprintf优化为fwrite,参见上面的expaination),并删除顶层CMakeLists.txt中的“-fno-builtin-fprintf”。 我可以看到fprintf在我的代码中挂钩到fwrite,但只有fprintf(stderr,“xxx”)挂钩,但fprintf(stderr,“xxx%s%d xxx”,somestring,someinteger)没有挂钩。 似乎fprintf与%和2个以上的参数无法挂钩。

请帮忙调试一下。 谢谢!