Using SpdLog With Modules/C++20 Gives Internal Compiler Error (MSVC 2022)

544 Views Asked by At

I am trying to encapsulate the header-only spdlog logging library in a C++20 module that keeps the spdlog library internal to the module. The Logger class is a Meyers-style singleton which I thought would be straightforward but is giving me a lot of trouble. Here's the simplified version I'm trying to troubleshoot (please note that while I develop in C# professionally, I am still quite new to C++).

My Logger.cppm module looks like this:

module;

#pragma once

#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"

export module Logger;

import <memory>;

export namespace ThreeSpace
{
    class Logger final
    {
    public:
        Logger(const Logger&) = delete;
        Logger& operator=(const Logger&) = delete;

        static void Trace() { Get()->trace("Test"); }

    private:
        std::shared_ptr<spdlog::logger> s_logger;

        Logger() : s_logger(spdlog::stdout_color_mt("Logger Name"))
        {}

        ~Logger() = default;

        static std::shared_ptr<spdlog::logger>& Get()
        {
            static Logger instance;
            return instance.s_logger;
        }
    };  
}

This is in a project named "Core" in my Visual Studio 2022 solution. The project builds as a static library successfully without any trouble.

However, in my application project (executable), which references the "Core" project, I have a simple "Main.cppm" module that attempts to use the logger:

export module Main;

import Logger;

export int main()
{
    ThreeSpace::Logger::Trace();
}

This project does not build successfully. I get the following in the build log:

Build started...
1>------ Build started: Project: ThreeSpace, Configuration: Debug x64 ------
1>Scanning sources for module dependencies...
1>Scanning sources for module dependencies...
1>Main.cppm
1>Compiling...
1>Main.cppm
1>C:\Dev\ThreeSpace\ThreeSpace\src\Main.cppm(9): fatal  error C1001: Internal compiler error.
1>(compiler file 'msc1.cpp', line 1589)
1> To work around this problem, try simplifying or changing the program near the locations listed above.
1>If possible please provide a repro here: https://developercommunity.visualstudio.com
1>Please choose the Technical Support command on the Visual C++
1> Help menu, or open the Technical Support help file for more information
1>INTERNAL COMPILER ERROR in 'C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.36.32532\bin\HostX64\x64\CL.exe'
1>    Please choose the Technical Support command on the Visual C++
1>    Help menu, or open the Technical Support help file for more information
1>Done building project "ThreeSpace.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========
========== Build started at 10:21 PM and took 02.443 seconds ==========

If I comment out the call to ThreeSpace::Logger::Trace();, the app runs fine.

Any ideas what I'm doing wrong? It's 2023 and to get such a generic "Internal Compiler Error" for C++20 code is pretty frustrating!

1

There are 1 best solutions below

0
Todd Burch On

Well, after random experimentation, I fixed it. All I had to do was turn my Trace() definition into a declaration, then define the method outside of the class, like so:

module;

#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"

export module Logger;

import <memory>;

export namespace ThreeSpace
{
    class Logger final
    {
    public:
        static void Trace();  //This is now just a declaration.
        Logger(const Logger&) = delete;
        Logger& operator=(const Logger&) = delete;

    private:
        std::shared_ptr<spdlog::logger> s_logger;

        Logger() :
            s_logger(spdlog::stdout_color_mt("Logger Name"))
        { }

        ~Logger() = default;

        static std::shared_ptr<spdlog::logger>& Get()
        {
            static Logger instance;
            return instance.s_logger;
        }
    };  

    //The definition of the method is now outside the class.
    void Logger::Trace() { Get()->trace("Test"); }
}

I don't know why this fixes the issue, but it does!