[英]Segmentation fault when logging using spdlog in an app that includes another spdlog
[英]Logging from library with spdlog
我试图在一个涉及 windows 下库的项目中使用spdlog 。 我创建了两个记录器。 一种用于使用库的应用程序,一种用于库本身。 库的记录器是从应用程序创建的,但是当库想要添加消息时,它会崩溃。
下面是一个简化的例子。
图书馆
类文件
#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");
}
应用程序
主程序
#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;
}
Spdlog 使用单例注册表来跟踪可用的记录器。 但是,每个 dll 和 exe 都会获得该注册表的一个实例。
当您在 exe 中创建记录器时,它会添加到 exe 的注册表中,但不会添加到 dll 中。 当您在 dll 中使用spdlog::get(myLoggerName)
时,您正在查询不包含“lib_logger”的 dll 的注册表,因此您将获得一个空的 shared_ptr。
可能的解决方案是:如果您只在 dll 中使用它,则在 lib 中创建 lib_logger 而不是 exe,或者将记录器从 exe 传递到 dll 并在调用spdlog::get(myLoggerName)
之前在 dll 中使用它调用spdlog::register_logger
spdlog::get(myLoggerName)
。 然后您可以使用来自 exe 和 dll 的相同记录器。
可以在https://github.com/gabime/spdlog/wiki/How-to-use-spdlog-in-DLLs 中找到如何跨 dll 边界注册记录器的示例
或使用您的代码的示例:
图书馆
类文件
#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
确保与 Windows 上的 DLL 运行时链接。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.