Официальный форум СВД Встраиваемые Системы
10 Декабря, 2016, 15:44:13 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.

Войти
 
 
 Сайт СВД ВС  Начало   Помощь Поиск Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Статическая C библиотека в С++, Реально?  (Прочитано 1723 раз)
ad
Пользователь

Сообщений: 69


« : 13 Марта, 2014, 21:35:56 »

Можно ли использовать статическую библиотеку, написанную на C, в проекте на С++? Сделал эксперимент: пересобрал библиотеку компилятором С++, подсунул в проект - ошибок линковки не выдает, а когда сую С библиотеку - ошибки линкования. Можно ли так делать? Если можно, то как именно?
Записан
Олег Большаков
Администратор
Житель форума

Сообщений: 2934



WWW
« Ответ #1 : 13 Марта, 2014, 21:47:58 »

Приведите, пожалуйста, текст сообщений об ошибках.
« Последнее редактирование: 14 Марта, 2014, 06:58:37 от Олег Большаков » Записан

ad
Пользователь

Сообщений: 69


« Ответ #2 : 14 Марта, 2014, 16:28:39 »

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

Да....
Код:
extern "C"
не помогло. Sad
Записан
Олег Большаков
Администратор
Житель форума

Сообщений: 2934



WWW
« Ответ #3 : 18 Марта, 2014, 11:41:03 »

Приведите, пожалуйста, точные технические данные — укажите версию QNX, сообщение об ошибке, команду компиляции и линковки. Если возможно, то вышлите целиком минимальный пример проекта, с которым данная ситуация воспроизводится.
Записан

ad
Пользователь

Сообщений: 69


« Ответ #4 : 19 Марта, 2014, 19:14:17 »

Приведите, пожалуйста, точные технические данные — укажите версию QNX, сообщение об ошибке, команду компиляции и линковки. Если возможно, то вышлите целиком минимальный пример проекта, с которым данная ситуация воспроизводится.
Операционная система - QNX 6.5.0.
Компилятор - GCC 4.2.2.


Вот полное описание ошибок:

Цитировать
...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);
}

/**@}*/
Записан
ad
Пользователь

Сообщений: 69


« Ответ #5 : 19 Марта, 2014, 19:19:33 »

Вот пример, на котором библиотека применялась:

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)); }
Записан
Олег Большаков
Администратор
Житель форума

Сообщений: 2934



WWW
« Ответ #6 : 25 Марта, 2014, 15:09:33 »

Провели сборку библиотеки и исполняемого модуля. Программа собирается без ошибок. Скорее всего у Вас ошибки связаны с настройками проекта. Попробуйте собрать что-то попроще — одну библиотеку и один исполняемый файл.
Записан

ad
Пользователь

Сообщений: 69


« Ответ #7 : 27 Марта, 2014, 20:36:21 »

Провели сборку библиотеки и исполняемого модуля. Программа собирается без ошибок. Скорее всего у Вас ошибки связаны с настройками проекта. Попробуйте собрать что-то попроще — одну библиотеку и один исполняемый файл.
Ага. Спасибо. Уже собрал. Видимо, либо забыл новый хедер добавить в программе - заменить старый хедерник библиотеки новым, либо еще что-то. Все заработало. Спасибо за помощь.

Т.е. для полного счастья строчек:
Код:
#ifdef __cplusplus
  extern "C" {
#endif
и в конце закрывающая скобка в заголовочном файле библиотеки вполне хватает! Smiley
« Последнее редактирование: 27 Марта, 2014, 20:42:37 от ad » Записан
Олег Большаков
Администратор
Житель форума

Сообщений: 2934



WWW
« Ответ #8 : 27 Марта, 2014, 21:42:07 »

Хорошо, что всё удачно разрешилось. Smiley
Записан

Страниц: [1]   Вверх
  Печать  
 
Перейти в:  

Powered by MySQL Powered by PHP © 2002-2016 СВД Встраиваемые Системы.
При использовании материалов сайта ссылка на forum.kpda.ru обязательна.

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines | © Aiwan. Kolobok smiles | Sitemap
Valid XHTML 1.0! Valid CSS!
Сайт СВД ВС

В последний раз google посещал эту страницу 23 Октября, 2016, 20:41:52