Вход из библиотеки с помощью spdlog
Я пытаюсь использовать spdlog в проекте с использованием библиотеки под Windows. Я создаю два регистратора. Один для приложения, использующего библиотеку, другой для самой библиотеки. Логгер библиотеки создается из приложения, но когда библиотека хочет добавить сообщение, происходит сбой.
Ниже приведен упрощенный пример.
Библиотека
libclass.h
#ifndef LIBCLASS_H
#define LIBCLASS_H
#include <spdlog/spdlog.h>
#ifdef WIN32
# ifdef BUILD_APPLIB_SHARED
# define APPLIB_EXPORT __declspec(dllexport)
# else
# define APPLIB_EXPORT
# endif //BUILD_APPLIB_SHARED
#else
# define APPLIB_EXPORT
#endif // WIN32
class APPLIB_EXPORT LibClass
{
public:
LibClass();
~LibClass();
static std::string loggerName();
void testLog();
private:
std::shared_ptr<spdlog::logger> m_logger;
};
#endif //LIBCLASS_H
libclass.cpp
#include "libclass.h"
const std::string myLoggerName = "lib_logger";
LibClass::LibClass()
{
m_logger = spdlog::get(myLoggerName);
}
LibClass::~LibClass()
{ }
std::string LibClass::loggerName()
{
return myLoggerName;
}
void LibClass::testLog()
{
m_logger->info("Log from library");
}
Приложение
main.cpp
#include <spdlog/spdlog.h>
#include <applib/libclass.h>
void logtest()
{
auto logger = spdlog::get("app_logger");
logger->info("Log from application");
}
int main(int argc, char *argv[])
{
// create loggers
auto appLogger = spdlog::stdout_logger_mt("app_logger");
auto libLogger = spdlog::stdout_logger_mt(LibClass::loggerName());
// log from app
logtest();
// log from lib
LibClass lc;
lc.testLog();
return 0;
}
1 ответ
Spdlog использует одноэлементный реестр для отслеживания доступных регистраторов. Однако вы получаете по одному экземпляру этого реестра на каждую dll и exe.
Когда вы создаете регистратор в exe, он добавляется в реестр exe, но не в библиотеки DLL. Когда вы используетеspdlog::get(myLoggerName)
в вашей dll вы запрашиваете реестр dll, который не содержит "lib_logger", и, таким образом, вы получаете null shared_ptr.
Возможные решения: создайте lib_logger в lib вместо exe, если вы все равно используете его только в dll, или передайте регистратор из exe в dll и вызовите spdlog::register_logger
с ним внутри dll перед вызовом spdlog::get(myLoggerName)
. Затем вы можете использовать один и тот же регистратор как из exe, так и из dll.
Пример того, как можно регистрировать регистраторы через границы dll, можно найти на https://github.com/gabime/spdlog/wiki/How-to-use-spdlog-in-DLLs
Или пример с использованием вашего кода:
Библиотека
libclass.h
#ifndef LIBCLASS_H
#define LIBCLASS_H
#include <spdlog/spdlog.h>
#ifdef WIN32
# ifdef BUILD_APPLIB_SHARED
# define APPLIB_EXPORT __declspec(dllexport)
# else
# define APPLIB_EXPORT
# endif //BUILD_APPLIB_SHARED
#else
# define APPLIB_EXPORT
#endif // WIN32
class APPLIB_EXPORT LibClass
{
public:
LibClass();
~LibClass();
static std::string loggerName();
void testLog();
private:
std::shared_ptr<spdlog::logger> m_logger;
};
APPLIB_EXPORT void registerLogger(std::shared_ptr<spdlog::logger> logger);
#endif //LIBCLASS_H
libclass.cpp
#include "libclass.h"
const std::string myLoggerName = "lib_logger";
LibClass::LibClass()
{
m_logger = spdlog::get(myLoggerName);
}
LibClass::~LibClass()
{ }
std::string LibClass::loggerName()
{
return myLoggerName;
}
void LibClass::testLog()
{
m_logger->info("Log from library");
}
APPLIB_EXPORT void registerLogger(std::shared_ptr<spdlog::logger> logger)
{
spdlog::register_logger(logger);
}
Приложение main.cpp
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_sinks.h>
#include <applib/libclass.h>
void logtest()
{
auto logger = spdlog::get("app_logger");
logger->info("Log from application");
}
int main(int argc, char* argv[])
{
// create loggers
auto appLogger = spdlog::stdout_logger_mt("app_logger");
auto libLogger = spdlog::stdout_logger_mt(LibClass::loggerName());
registerLogger(libLogger);
// log from app
logtest();
// log from lib
LibClass lc;
lc.testLog();
return 0;
}
Ваш пример отлично работает на текущей версии spdlog:
$ g++ -std=c++11 main.cpp libclass.cpp -I .
$ ./a.out
[2015-08-24 07:29:04.502] [app_logger] [info] Log from application
[2015-08-24 07:29:04.502] [lib_logger] [info] Log from library
То же самое при использовании общей библиотеки:
# CMake config:
project(TEST)
include_directories(.)
add_library(class SHARED libclass.cpp)
target_compile_options(class PUBLIC -std=c++11)
add_executable(main main.cpp)
target_link_libraries(main class)
Результаты:
$ cmake .
$ make
$ ldd main
...
libclass.so => ...
$ ./main
[2015-08-25 08:57:51.864] [app_logger] [info] Log from application
[2015-08-25 08:57:51.864] [lib_logger] [info] Log from library
Убедитесь, что вы связываете с DLL времени выполнения в Windows.