maslokarol
maslokarol

Reputation: 43

How to distinguish files of two separate programs with common file

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.

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.

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.

Upvotes: 2

Views: 150

Answers (3)

sendaran
sendaran

Reputation: 616

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.h

typedef void (*logFunc_t)( logBuffer_t );
void setLogOutput( logFunc_t applicationLog );

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

// 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
}

Upvotes: 1

Peter Cordes
Peter Cordes

Reputation: 365951

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.

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.

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).

Upvotes: 1

fuz
fuz

Reputation: 93172

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:

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.

Upvotes: 1

Related Questions