Цитата(Iron Bug @ 18.3.2014, 8:26)
кроме extern "C" ничего не надо. а про ошибки линковки: возможно, сама библиотека что-то ещё подтаскивает и это не прилинковано.
Ну не знаю уж. Вот полное описание ошибок:
Цитата
...Projects/fpo/mztf/bulat.ya1/kc-logger # make
make -j 1 -Cx86 -fMakefile
make[1]: Entering directory `/home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/x86'
make -j 1 -Co -fMakefile
make[2]: Entering directory `/home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/x86/o'
/usr/qnx650/host/qnx6/x86/usr/bin/qcc -Vgcc_ntox86 -c -Wc,-Wall -O -O3 -DNDEBUG -I. -I/home/ad/Projects/fp
o/mztf/bulat.ya1/kc-logger/x86/o -I/home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/x86 -I/home/ad/Projects/fpo/mztf/bu
lat.ya1/kc-logger -I/usr/qnx650/target/qnx6/usr/include -DBUILDENV_qss /home/ad/Projects/fpo/mztf/bulat.ya1/kc-l
ogger/bit_operations.cpp
/usr/qnx650/host/qnx6/x86/usr/bin/qcc -Vgcc_ntox86 -c -Wc,-Wall -O -O3 -DNDEBUG -I. -I/home/ad/Projects/fp
o/mztf/bulat.ya1/kc-logger/x86/o -I/home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/x86 -I/home/ad/Projects/fpo/mztf/bu
lat.ya1/kc-logger -I/usr/qnx650/target/qnx6/usr/include -DBUILDENV_qss /home/ad/Projects/fpo/mztf/bulat.ya1/kc-l
ogger/config_reader.cpp
/usr/qnx650/host/qnx6/x86/usr/bin/qcc -Vgcc_ntox86 -c -Wc,-Wall -O -O3 -DNDEBUG -I. -I/home/ad/Projects/fp
o/mztf/bulat.ya1/kc-logger/x86/o -I/home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/x86 -I/home/ad/Projects/fpo/mztf/bu
lat.ya1/kc-logger -I/usr/qnx650/target/qnx6/usr/include -DBUILDENV_qss /home/ad/Projects/fpo/mztf/bulat.ya1/kc-l
ogger/main.cpp
/usr/qnx650/host/qnx6/x86/usr/bin/qcc -Vgcc_ntox86 -c -Wc,-Wall -O -O3 -DNDEBUG -I. -I/home/ad/Projects/fp
o/mztf/bulat.ya1/kc-logger/x86/o -I/home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/x86 -I/home/ad/Projects/fpo/mztf/bu
lat.ya1/kc-logger -I/usr/qnx650/target/qnx6/usr/include -DBUILDENV_qss /home/ad/Projects/fpo/mztf/bulat.ya1/kc-l
ogger/str_functions.cpp
/bin/rm -f /home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/x86/o/kc-logger
/usr/qnx650/host/qnx6/x86/usr/bin/qcc -Vgcc_ntox86 -lang-c++ -lang-c++ -Wl,-S -o/home/ad/Projects/fpo/mztf/bulat.y
a1/kc-logger/x86/o/kc-logger bit_operations.o config_reader.o main.o str_functions.o -L . -L /home/ad/P
rojects/fpo/mztf/bulat.ya1/kc-logger/Libraries/x86/a -L /usr/qnx650/target/qnx6/x86/lib -L /usr/qnx650/target/qnx6/x8
6/usr/lib -Wl,--rpath-link . -Wl,--rpath-link /home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/Libraries/x86/a -Wl,--r
path-link /usr/qnx650/target/qnx6/x86/lib -Wl,--rpath-link /usr/qnx650/target/qnx6/x86/usr/lib -Bstatic -llogge
r -lpulsar_socket -lpulsar -Bdynamic -lmenu -lpanel -lncurses -lsocket
main.o: In function `main':
main.cpp:(.text+0x31): undefined reference to `lmsg_init(char const*, LoggerLevel, unsigned int, unsigned int, char*)
'
main.cpp:(.text+0x91): undefined reference to `lmsg_log(LoggerLevel, unsigned int, char const*, ...)'
main.cpp:(.text+0xad): undefined reference to `lmsg_log(LoggerLevel, unsigned int, char const*, ...)'
main.cpp:(.text+0xb2): undefined reference to `lmsg_close()'
cc: /usr/qnx650/host/qnx6/x86/usr/bin/ntox86-ld error 1
make[2]: *** [/home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/x86/o/kc-logger] Error 1
make[2]: Leaving directory `/home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/x86/o'
make[1]: *** [all] Error 2
make[1]: Leaving directory `/home/ad/Projects/fpo/mztf/bulat.ya1/kc-logger/x86'
make: *** [all] Error 2
Вот код библиотеки.
Header:
/** logger.h
* This file describes the log-functions and variables
**/
#ifndef LOGGER_H_05550
#define LOGGER_H_05550
#include <syslog.h>
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_APP_NAME_LEN 1024
typedef uint32_t LoggerVerbosityLevel; ///< in debug each loop level should increment it
typedef enum { LogEmerg = 0, LogAlert, LogCrit, LogErr, LogWarning, LogNotice, LogInfo, LogDebug } LoggerLevel;
#define LOG_OUTPUT_NONE 0
#define LOG_OUTPUT_SYSLOG 1
#define LOG_OUTPUT_TTY 2
/// 3, 7, 15, 31 and etc is not defined, because in binary mode they are consist from units
#define LOG_OUTPUT_FILE 4
#define LOGGER_OUTPUT_MASK 0x7
/// Structure of the log message
typedef struct
{
LoggerLevel level; ///< log level of the message
char* header; ///< header of the message
char* text; ///< text of the message
FILE* file; ///< possibility of writing to file
} LMessage;
/**
* @brief Initialization the logger
* @param app_name - name of the application
* @param log_level - level of the log message
* @param verbosity - type of the log verbosity
* @param dev - output device (tty, or file, or syslog)
* @param file_name - name of the file (if the file is exist)
**/
void lmsg_init(const char* app_name, LoggerLevel log_level, LoggerVerbosityLevel
verbosity, uint32_t dev, char* file_name);
/**
* @brief Prints the message to an output device
* @param log_level - level of the log message
* @param verbosity - type of the log verbosity
* @param message - outputing message
**/
void lmsg_log(LoggerLevel log_level, LoggerVerbosityLevel verbosity,
const char* message, ...);
/** @brief Closes the logger output and free memory **/
void lmsg_close();
#ifdef __cplusplus
};
#endif
#endif //LOGGER_H_05550
Realization:
#include "logger.h"
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <stdlib.h>
/// @name Declaration
/**@{*/
/// @name Global variables
/**@{*/
static struct timespec last_time = {}; ///< time of the log writing
static char* application_name = NULL; ///< name of the application
static LoggerLevel init_level; ///< level of the messages
static LoggerVerbosityLevel init_verb; ///< verbosity of the messages
static char* init_fname = NULL; ///< file name of the output file
static FILE* log_file = NULL; ///< log-file
static uint32_t output_flags = 0; ///< flags which determine the output
typedef void(*out_method)(LMessage* message); ///< callback for the output method
static out_method* output_methods = NULL; ///< pointer to the current output method
static pthread_mutex_t log_lock; /// mutex which locks for writing
/**@}*/
/// @name Global functions
/**@{*/
static void to_syslog(LMessage* message); ///< print the message to syslog
static void to_tty(LMessage* message); ///< print the message to screen
static void to_file(LMessage* message); ///< print the message to file
static char* getHeader(LoggerLevel log_level); ///< get the header of the each message
static const int level2syslog(LoggerLevel log_level); ///< translation the level to syslog type
static const char* level2str(LoggerLevel log_level); ///< translation the level to string
/**@}*/
/**@}*/
/// @name Realization
/**@{*/
/// Initialization the logger
void lmsg_init(const char* app_name, LoggerLevel log_level, LoggerVerbosityLevel
verbosity, uint32_t dev, char* file_name)
{
init_level = log_level;
init_verb = verbosity;
output_flags = (dev & LOGGER_OUTPUT_MASK);
init_fname = file_name;
pthread_mutex_init(&log_lock, NULL);
const char default_app_name[] = "unknown application";
int sl = strlen(app_name);
if(sl > MAX_APP_NAME_LEN - 1) sl = MAX_APP_NAME_LEN - 1;
if(!sl)
{
sl = strlen(default_app_name);
app_name = default_app_name;
}
application_name = malloc(sl);
strcpy(application_name, app_name);
if(init_fname) log_file = fopen(init_fname, "a");
uint32_t tmp_m = output_flags;
int c = 0;
while(tmp_m)
{
if(tmp_m & 0x1)
++c;
tmp_m = (tmp_m >> 1);
}
output_methods = (out_method*)malloc(c + 1);
output_methods[c] = NULL;
c = 0;
if(output_flags & LOG_OUTPUT_SYSLOG)
{
openlog(application_name, 0, LOG_DAEMON);
output_methods[c] = &to_syslog;
++c;
}
if(output_flags & LOG_OUTPUT_TTY)
{
output_methods[c] = &to_tty;
++c;
}
if(output_flags & LOG_OUTPUT_FILE)
{
output_methods[c] = &to_file;
++c;
}
}
/// Print the message to an output device
void lmsg_log(LoggerLevel log_level, LoggerVerbosityLevel verbosity,
const char* message, ...)
{
if(init_level < log_level || init_verb < verbosity) return;
static char buffer[4 * MAX_APP_NAME_LEN] = {};
static LMessage msg_struct;
pthread_mutex_lock(&log_lock);
va_list args;
va_start(args, message);
vsprintf(buffer, message, args);
va_end(args);
msg_struct.level = log_level;
msg_struct.header = getHeader(log_level);
msg_struct.text = buffer;
msg_struct.file = log_file;
int i = -111111;
for(i=0; output_methods[i]; ++i)
output_methods[i](&msg_struct);
pthread_mutex_unlock(&log_lock);
}
/// Print the message to syslog
static void to_syslog(LMessage* message)
{ syslog(level2syslog(message -> level), "%s", message -> text); }
/// Print the message to screen
static void to_tty(LMessage* message)
{
printf("%s %s\n", message -> header, message -> text);
fflush(stdout);
}
/// Print the message to file
static void to_file(LMessage* message)
{
FILE* thf = message -> file;
if(!thf) return;
fputs(message -> header, thf);
fputs(message -> text, thf);
fputs("\n", thf);
fflush(thf);
}
/// Get the header of the each message
static char* getHeader(LoggerLevel log_level)
{
static char header_str[MAX_APP_NAME_LEN];
static struct timespec rawtime = {};
static struct tm* timeinfo = NULL;
memset(header_str, 0, MAX_APP_NAME_LEN);
if(clock_gettime(CLOCK_REALTIME, &rawtime) != -1)
{
timeinfo = localtime(&rawtime.tv_sec);
static char tmp_t[21] = {}, tmp_t1[11] = {};
if((!timeinfo -> tm_hour && !timeinfo -> tm_min && !timeinfo -> tm_sec) ||
(!last_time.tv_sec && !last_time.tv_nsec))
{
strftime(tmp_t, sizeof(tmp_t), "%d.%m.%Y %A", timeinfo);
strftime(tmp_t1, sizeof(tmp_t1), "%T", timeinfo);
sprintf(header_str, "%s %s\n%s%s: ", tmp_t, application_name, level2str(log_level), tmp_t1);
}
else
{
strftime(tmp_t, sizeof(tmp_t), "%T", timeinfo);
sprintf(header_str, "%s%s: ", level2str(log_level), tmp_t);
}
last_time = rawtime;
}
return header_str;
}
/// Translation the level to syslog type
static const int level2syslog(LoggerLevel log_level)
{
static const int translation[] = { LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE,
LOG_INFO, LOG_DEBUG };
return translation[log_level];
}
/// Translation the level to string
static const char* level2str(LoggerLevel log_level)
{
static const char* translation[] = { "EMERG ", "ALERT ", "CRIT ", "ERROR ", "WARNING ",
"NOTICE ", "INFO ", "DEBUG " };
return translation[log_level];
}
/// Close the logger output and free memory
void lmsg_close()
{
if(log_file)
fclose(log_file);
if(output_flags & LOG_OUTPUT_SYSLOG)
closelog();
if(output_methods)
free(output_methods);
free(application_name);
}
/**@}*/
Операционная система - QNX 6.5.0.
Компилятор - GCC 4.2.2.
Вот пример, на котором библиотека применялась:
main.cpp
#include <stdio.h>
#include "bit_operations.h"
#include "logger.h"
int main(int argc, char* argv[])
{
char* fl_name = (char*)("/ram/logger_log.txt");
lmsg_init("kc-logger", LogDebug, 11, LOG_OUTPUT_FILE, fl_name);
printf("Welcome to the application kc-logger\n");
int a = 1;
printf("Before bit setting a = %i\n", a);
int a_new = setBit4(a, 3);
printf("After bit setting a = %i\n", a_new);
lmsg_log(LogDebug, 9, "tttttt");
lmsg_log(LogDebug, 9, "1111");
lmsg_close();
return 0;
}
bit_operations.h и bit_operations.cpp определены в этом тестовом примерчике:
bit_operations.h:
/** bit_operations.h
* This file describes the functions set/clear/check bit in byte
**/
#ifndef BIT_OPERATIONS_H_05550
#define BIT_OPERATIONS_H_05550
#include <stdbool.h>
/**
* @brief Sets a bit into 1 of the arg argument according to specified bit number num_bit
* @param arg - source argument
* @param num_bit - bit number
* @return New value of the argument arg
**/
unsigned char setBit1(unsigned char arg, unsigned int num_bit);
unsigned int setBit4(unsigned int arg, unsigned int num_bit);
/**
* @brief Sets a bit into 0 of the arg argument according to specified bit number num_bit
* @param arg - source argument
* @param num_bit - bit number
* @return New value of the argument arg
**/
unsigned char clearBit1(unsigned char arg, unsigned int num_bit);
unsigned int clearBit4(unsigned int arg, unsigned int num_bit);
/**
* @brief Checks a bit of the arg argument according to specified bit number num_bit
* @param arg - source argument
* @param num_bit - bit number
* @return True if the bit in argument arg is equal 1, false - otherwise
**/
bool checkBit1(unsigned char arg, unsigned int num_bit);
bool checkBit4(unsigned int arg, unsigned int num_bit);
/**
* @brief Extracts bits from bit number num_bit1 by bit number num_bit2
* @param arg - source argument
* @param num_bit1 - first bit number
* @param num_bit2 - second bit number
* @return Result of the extracting bits
**/
unsigned char extractBits1(unsigned char arg, unsigned int num_bit1, unsigned int num_bit2);
unsigned int extractBits4(unsigned int arg, unsigned int num_bit1, unsigned int num_bit2);
#endif // BIT_OPERATIONS_H_05550
bit_operations.cpp:
#include "bit_operations.h"
/// Sets a bit into 1 of the arg argument according to specified bit number num_bit
unsigned char setBit1(unsigned char arg, unsigned int num_bit)
{ arg |= (1 << num_bit); return arg; }
unsigned int setBit4(unsigned int arg, unsigned int num_bit)
{ arg |= (1L << num_bit); return arg; }
/// Sets a bit into 0 of the arg argument according to specified bit number num_bit
unsigned char clearBit1(unsigned char arg, unsigned int num_bit)
{ arg &= ~(1 << num_bit); return arg; }
unsigned int clearBit4(unsigned int arg, unsigned int num_bit)
{ arg &= ~(1L << num_bit); return arg; }
/// Checks a bit of the arg argument according to specified bit number num_bit
bool checkBit1(unsigned char arg, unsigned int num_bit)
{ return (arg & (1 << num_bit)); }
bool checkBit4(unsigned int arg, unsigned int num_bit)
{ return (arg & (1L << num_bit)); }
/// Extracts bits from bit number num_bit1 by bit number num_bit2
unsigned char extractBits1(unsigned char arg, unsigned int num_bit1, unsigned int num_bit2)
{ return (((arg & (((1 << (num_bit2 - num_bit1 + 1)) - 1) << num_bit1)) >> num_bit1)); }
unsigned int extractBits4(unsigned int arg, unsigned int num_bit1, unsigned int num_bit2)
{ return (((arg & (((1L << (num_bit2 - num_bit1 + 1)) - 1) << num_bit1)) >> num_bit1)); }