0

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!

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
Todd Burch
  • 200
  • 8
  • "Internal compiler error" basically means the compiler crashed. They almost always represent compiler bugs. Like, even if the code you wrote is wrong according to the standard, the compiler still shouldn't crash on it. – Nicol Bolas Aug 01 '23 at 05:57
  • I have not seen `main` as a module before. I would try that as a normal .cpp file, without `export`. Also, `#pragma once` is not needed with modules, as the module itself is never `#include`'d anywhere. (All module parts are source files, and not headers). – BoP Aug 01 '23 at 09:16
  • Thanks, I will try both ideas. Worth noting that removing the call to Trace() will compile and run fine though. – Todd Burch Aug 01 '23 at 09:43
  • Update: I removed the #pragma once from the logger module and converted main() so that it's no longer in a module. (I had to keep it as a .cppm file so Visual Studio would understand that it's a file that interacts with modules). The error unfortunately persisted. I think I will report this to Microsoft as a compiler bug. – Todd Burch Aug 02 '23 at 00:59

1 Answers1

0

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!

Todd Burch
  • 200
  • 8