I've project where I need to distinguish files belongs to linux daemon (witten in C) and simple linux program (written in C++). Those two projects used 2 shared files (helpers_functions). Daemon and program has different logging system. Daemon write to file, program to stdout.
我的项目中,我需要区分文件属于linux守护进程(在C语言中是witten)和简单的linux程序(用c++编写)。这两个项目使用了两个共享文件(helpers_functions)。守护进程和程序有不同的日志记录系统。守护进程写入文件,程序输出到stdout。
Problem occurs when I want to log something in common functions for both programs (inside helper_functions file). I don't want to pass via parameter, that this is program A, or program B.
当我想为两个程序(在helper_functions文件中)在通用函数中记录一些内容时,就会出现问题。我不想通过参数传递,这是程序A,或者程序B。
I've compile files belongs to separate programs with g++ flag -D, but what can I do, when I want to log from common files? I cannot define there anything, because I don't know when I use it for program A, or when for program B.
我已经编译了属于g++标记-D的独立程序的文件,但是当我想从公共文件中进行日志记录时,我能做什么呢?我不能定义任何东西,因为我不知道什么时候用在程序A上,什么时候用在程序B上。
3 个解决方案
#1
1
You could add a global variable
你可以添加一个全局变量。
const int iamprogram = ...;
which is defined to be PROGRAM_A
in program A and PROGRAM_B
in program B to solve the immediate problem. You could also make this variable directly contain the file you want to log to:
定义为程序A中的PROGRAM_A,程序B中的PROGRAM_B,以解决当前问题。您还可以使该变量直接包含您想要登录的文件:
const char *program_logfile = "/path/to/logfileA";
In the long run, I suggest you to refactor your code such that the common code doesn't depend on which program it is part of. That's much more maintainable and expandable for the case where you want to use the code for a third program as well.
从长远来看,我建议您重构代码,使公共代码不依赖于它所在的程序。对于您希望将代码用于第三个程序的情况,这更易于维护和扩展。
#2
1
You could implement a callback for getting the program specific output. There's two benefits: no dependency from common part to application (common part defines the interface) and you can make the distinction at run time vs compile time, which gives more legroom for future development, such as changing the output via command line parameters or user interaction.
您可以实现一个回调来获取特定于程序的输出。有两个好处:从公共部分到应用程序没有依赖(公共部分定义接口),您可以在运行时与编译时进行区分,这为将来的开发提供了更大的空间,例如通过命令行参数或用户交互更改输出。
In the following example, let's refer to the common code part as "library".
在下面的示例中,让我们将公共代码部分称为“library”。
library.h
library.h
typedef void (*logFunc_t)( logBuffer_t );
void setLogOutput( logFunc_t applicationLog );
library.c
library.c
logFunc_t logger; // might be good idea to initialize to an empty function, but omitted here
void setLogOutput( logFunc_t applicationLog )
{
logger = applicationLog;
}
void log( logBuffer_t data )
{
logger( data );
}
application.cpp / application.c
应用程序。cpp / application.c
// here you should have the extern "C" in C++ application to ensure linkage compatibility
// I am assuming your shared code is C
extern "C" void myLogger( logBuffer_t data );
int main( int argc, char* agv[] )
{
setLogOutput( &myLogger );
// ...do your thing
return 0;
}
void myLogger( logBuffer_t data )
{
// ...log wherever
}
#3
0
I'm not 100% sure if runtime dynamic linking can handle this. It would definitely work if you statically link the helper functions into each executable.
我不能100%确定运行时动态链接是否能够处理这个问题。如果静态地将helper函数链接到每个可执行文件中,它肯定会工作。
Provide a logging function with the same API in both programs. Have the library functions that want to log something call this function. They get the implementation provided by the program that's using the library.
在两个程序中提供具有相同API的日志记录函数。让库函数来记录一些东西,调用这个函数。它们得到了使用库的程序提供的实现。
Header file included by each program, and by the library
// common_log.h
#ifdef __cplusplus
extern "C" // for the following definition only, no opening {
#endif
// used by code that can be part of either program
void common_log(char *msg, int log_prio);
Implementation in the tty C++ program (simple logging):
#include "common_log.h"
#include <iostream>
// used by the rest of the C++ program
void simple_logger(char *msg) {
cerr << msg;
}
extern "C" void common_log(char *msg, int log_prio) {
simple_logger(msg);
}
Implementation in the daemon C program:
#include "common_log.h"
#include <stdio.h>
#include <errno.h>
static FILE *logfp;
static int log_level;
// used by daemon code
void fancy_logger(char *msg, int log_prio) {
if (log_prio < log_level)
return;
if (EOF == fputs(logfp, msg)) {
perror("failed to write log message to log file: ");
}
}
// or use linker tricks to make common_log an alias for fancy_log,
// if they both have the same signature and you don't need to do anything in the wrapper.
//extern "C" // this is already C
void common_log(char *msg, int log_prio) {
fancy_logger(msg, log_prio);
}
This requires the linker to be able to resolve undefined symbols in the library using symbols from the program that's linked against it. I think that works, similar to a library providing a weak definition of a global variable, so the main program's definition takes precedence.
这要求链接器能够使用与它链接的程序中的符号解析库中的未定义符号。我认为这是可行的,类似于提供全局变量弱定义的库,所以主程序的定义优先。
If it was ok for simple_logger
to also be extern "C"
and have the same signature, you could just name them the same and avoid the bounce function. Or if the common function could be an alias for the program's own logging function in either of the programs, I think there are linker tricks to actually do that, instead of compiling to a single jmp
instruction (tail-call optimization).
如果simple_logger也可以是extern“C”且具有相同签名时,则只需将它们命名为相同并避免使用bounce函数即可。或者,如果通用函数可以是程序自己的日志记录函数的别名,那么我认为有链接器技巧可以实现这一点,而不是编译到单个jmp指令(尾部调用优化)。
#1
1
You could add a global variable
你可以添加一个全局变量。
const int iamprogram = ...;
which is defined to be PROGRAM_A
in program A and PROGRAM_B
in program B to solve the immediate problem. You could also make this variable directly contain the file you want to log to:
定义为程序A中的PROGRAM_A,程序B中的PROGRAM_B,以解决当前问题。您还可以使该变量直接包含您想要登录的文件:
const char *program_logfile = "/path/to/logfileA";
In the long run, I suggest you to refactor your code such that the common code doesn't depend on which program it is part of. That's much more maintainable and expandable for the case where you want to use the code for a third program as well.
从长远来看,我建议您重构代码,使公共代码不依赖于它所在的程序。对于您希望将代码用于第三个程序的情况,这更易于维护和扩展。
#2
1
You could implement a callback for getting the program specific output. There's two benefits: no dependency from common part to application (common part defines the interface) and you can make the distinction at run time vs compile time, which gives more legroom for future development, such as changing the output via command line parameters or user interaction.
您可以实现一个回调来获取特定于程序的输出。有两个好处:从公共部分到应用程序没有依赖(公共部分定义接口),您可以在运行时与编译时进行区分,这为将来的开发提供了更大的空间,例如通过命令行参数或用户交互更改输出。
In the following example, let's refer to the common code part as "library".
在下面的示例中,让我们将公共代码部分称为“library”。
library.h
library.h
typedef void (*logFunc_t)( logBuffer_t );
void setLogOutput( logFunc_t applicationLog );
library.c
library.c
logFunc_t logger; // might be good idea to initialize to an empty function, but omitted here
void setLogOutput( logFunc_t applicationLog )
{
logger = applicationLog;
}
void log( logBuffer_t data )
{
logger( data );
}
application.cpp / application.c
应用程序。cpp / application.c
// here you should have the extern "C" in C++ application to ensure linkage compatibility
// I am assuming your shared code is C
extern "C" void myLogger( logBuffer_t data );
int main( int argc, char* agv[] )
{
setLogOutput( &myLogger );
// ...do your thing
return 0;
}
void myLogger( logBuffer_t data )
{
// ...log wherever
}
#3
0
I'm not 100% sure if runtime dynamic linking can handle this. It would definitely work if you statically link the helper functions into each executable.
我不能100%确定运行时动态链接是否能够处理这个问题。如果静态地将helper函数链接到每个可执行文件中,它肯定会工作。
Provide a logging function with the same API in both programs. Have the library functions that want to log something call this function. They get the implementation provided by the program that's using the library.
在两个程序中提供具有相同API的日志记录函数。让库函数来记录一些东西,调用这个函数。它们得到了使用库的程序提供的实现。
Header file included by each program, and by the library
// common_log.h
#ifdef __cplusplus
extern "C" // for the following definition only, no opening {
#endif
// used by code that can be part of either program
void common_log(char *msg, int log_prio);
Implementation in the tty C++ program (simple logging):
#include "common_log.h"
#include <iostream>
// used by the rest of the C++ program
void simple_logger(char *msg) {
cerr << msg;
}
extern "C" void common_log(char *msg, int log_prio) {
simple_logger(msg);
}
Implementation in the daemon C program:
#include "common_log.h"
#include <stdio.h>
#include <errno.h>
static FILE *logfp;
static int log_level;
// used by daemon code
void fancy_logger(char *msg, int log_prio) {
if (log_prio < log_level)
return;
if (EOF == fputs(logfp, msg)) {
perror("failed to write log message to log file: ");
}
}
// or use linker tricks to make common_log an alias for fancy_log,
// if they both have the same signature and you don't need to do anything in the wrapper.
//extern "C" // this is already C
void common_log(char *msg, int log_prio) {
fancy_logger(msg, log_prio);
}
This requires the linker to be able to resolve undefined symbols in the library using symbols from the program that's linked against it. I think that works, similar to a library providing a weak definition of a global variable, so the main program's definition takes precedence.
这要求链接器能够使用与它链接的程序中的符号解析库中的未定义符号。我认为这是可行的,类似于提供全局变量弱定义的库,所以主程序的定义优先。
If it was ok for simple_logger
to also be extern "C"
and have the same signature, you could just name them the same and avoid the bounce function. Or if the common function could be an alias for the program's own logging function in either of the programs, I think there are linker tricks to actually do that, instead of compiling to a single jmp
instruction (tail-call optimization).
如果simple_logger也可以是extern“C”且具有相同签名时,则只需将它们命名为相同并避免使用bounce函数即可。或者,如果通用函数可以是程序自己的日志记录函数的别名,那么我认为有链接器技巧可以实现这一点,而不是编译到单个jmp指令(尾部调用优化)。