Как отличить файлы двух отдельных программ с общим файлом

У меня есть проект, в котором мне нужно различать файлы, принадлежащие демону linux (написанному на C) и простой программе на Linux (написанной на C ++). Эти два проекта использовали 2 общих файла (helpers_functions). Демон и программа имеют разную систему регистрации. Запись демона в файл, программа в стандартный вывод.

Проблема возникает, когда я хочу записать что-то в общих функциях для обеих программ (внутри файла helper_functions). Я не хочу передавать через параметр, что это программа A или программа B.

У меня компиляция файлов принадлежит отдельным программам с флагом g ++ -D, но что я могу сделать, когда я хочу войти из общих файлов? Я не могу ничего там определить, потому что я не знаю, когда я использую это для программы A, или когда для программы B.

2

Решение

Вы можете добавить глобальную переменную

const int iamprogram = ...;

который определен как PROGRAM_A в программе А и PROGRAM_B в программе B, чтобы решить насущную проблему. Вы также можете сделать эту переменную напрямую содержащей файл, в который вы хотите войти:

const char *program_logfile = "/path/to/logfileA";

В долгосрочной перспективе я предлагаю вам реорганизовать свой код так, чтобы общий код не зависел от того, в какую программу он входит. Это гораздо удобнее в обслуживании и расширении для случая, когда вы хотите использовать код и для третьей программы.

1

Другие решения

Вы можете реализовать обратный вызов для получения выходных данных программы. Есть два преимущества: нет зависимости от общей части для приложения (общая часть определяет интерфейс), и вы можете провести различие во время выполнения и во время компиляции, что дает больше места для будущей разработки, такой как изменение вывода с помощью параметров командной строки или пользователя взаимодействие.

В следующем примере давайте обратимся к общей части кода как «библиотека».

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

Я не уверен на 100%, может ли динамическое связывание во время выполнения справиться с этим. Это определенно будет работать, если вы статически связываете вспомогательные функции в каждый исполняемый файл.

Предоставить функцию ведения журнала с одинаковым API в обеих программах. Иметь библиотечные функции, которые хотят что-то регистрировать, вызывают эту функцию. Они получают реализацию, предоставляемую программой, которая использует библиотеку.

Заголовочный файл, включаемый каждой программой и библиотекой

// 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);

Реализация в программе tty C ++ (простая регистрация):

#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);
}

Реализация в программе daemon C:

#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);
}

Это требует, чтобы компоновщик мог разрешать неопределенные символы в библиотеке, используя символы из программы, которая связана с ним. Я думаю, что это работает, подобно библиотеке, предоставляющей слабое определение глобальной переменной, поэтому определение основной программы имеет приоритет.


Если бы это было нормально для simple_logger также быть extern "C" и иметь одинаковую подпись, вы можете просто назвать их одинаковыми и избежать функции отказов. Или, если общая функция может быть псевдонимом для собственной функции журналирования программы в любой из программ, я думаю, что на самом деле есть трюки с компоновщиком, вместо компиляции в один jmp инструкция (оптимизация остаточного вызова).

0