首页 > 解决方案 > spdlog 工厂方法崩溃

问题描述

昨天我已经开始spdlog在我的一个个人项目中加入日志记录。到目前为止,我在让库包含工作方面遇到了一些问题,但现在已经完全解决了。

现在一切都编译得很好,但是当我尝试创建记录器或简单地设置记录代码崩溃的模式时,发现了所有标头。更具体地说,无论我spdlog在程序中第一次从命名空间调用哪个函数都会导致崩溃。

我有一个类从spdlog(基于this repo)中抽象出一些部分,如下所示:

//Logger.hpp
#ifndef TE_LOGGER_HPP
#define TE_LOGGER_HPP

#include <spdlog/spdlog.h>

namespace te {

class Logger {
public:
    static void Init();

    inline static std::shared_ptr<spdlog::logger> &getCoreLogger() {
        return sCoreLogger;
    }
    inline static std::shared_ptr<spdlog::logger> &getClientLogger() {
        return sClientLogger;
    }

private:
    static std::shared_ptr<spdlog::logger> sCoreLogger;
    static std::shared_ptr<spdlog::logger> sClientLogger;
};

}
#endif //TE_LOGGER_HPP

//Logger.cpp
#include "Logger.hpp"
#include <spdlog/sinks/stdout_color_sinks.h>

std::shared_ptr<spdlog::logger> te::Logger::sCoreLogger;
std::shared_ptr<spdlog::logger> te::Logger::sClientLogger;

void te::Logger::Init() {
    //The first of any of the following three lines cause a crash
    //no matter the order, regardless of the pattern used in set_pattern
    spdlog::set_pattern("%v");
    sCoreLogger = spdlog::stdout_color_mt("CORE");
    sClientLogger = spdlog::stdout_color_mt("CORE");

    sCoreLogger->set_level(spdlog::level::trace);
    sClientLogger->set_level(spdlog::level::trace);
}

从堆栈跟踪来看,问题似乎在于由于某种原因在库中的某处设置了formatter类。我正在使用最新的 CLion,C++14(我知道 spdlog 是 C++11,但我需要 14 以后的功能,设置 -std=c++11 也不能解决问题)以及 Ubuntu 18.04 上截至昨天的最新版本(直接从他们的 GitHub 存储库中提取)。spdlognullspdlog

编辑:根据评论中的要求,我创建了一个小项目(单个 cpp 文件,包括我在真实项目中的操作方式,或者与从文件引用并链接到spdlog的真实项目中相同的代码和库设置main.cpp) 旨在重现该问题,这是我的发现: * 当我spdlog直接在可执行文件中使用时,问题不存在 * 如果 Logger 类被移动到共享库并从那里链接到,则存在问题

这是我收到的错误消息:

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

还有我正在使用的 CMakeLists.txt 文件(我将库的一个嵌套到项目中,因为到目前为止 CLion 不支持“同一解决方案中的多个项目”,例如 VS):#CMakeLists.txt for Library cmake_minimum_required(VERSION 3.10 致命错误)

project(TokenEngine VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)

set(SOURCE_FILES src/Application.cpp src/Application.hpp src/EntryPoint.hpp src/Logger.cpp src/Logger.hpp)

#include_directories("${CMAKE_CURRENT_SOURCE_DIR}/libs/")
add_library(TokenEngine SHARED ${SOURCE_FILES})

target_include_directories(TokenEngine PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/libs/spdlog-1.x/include")

#Expose the public API of the engine to any project that might use it
target_include_directories(TokenEngine PUBLIC include)

#CMakeLists.txt for top level project
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")

add_definitions(-DTE_PLATFORM_LINUX)

project(Build CXX)

add_subdirectory(TokenEngine)
add_subdirectory(Sandbox)

标签: c++loggingspdlog

解决方案


问题可能是 spdlog 的静态对象被定义了两次 - 从共享库内部和包含您的记录器标头(包括 spdlog.h)的客户端代码。

尝试从头文件中删除对 spdlog.h 的包含(并改用 spdlog::logger 的前向声明),并仅从 Logger.cpp 文件中包含 spdlog.h。

编辑

spdlog::logger 不能跨编译单元边界向前声明。解决方案是使用 logger.cpp 中定义的一些简单类来包装记录器,并仅将其导出到 logger.h


推荐阅读