KhronosGroup / SPIRV-Cross

SPIRV-Cross is a practical tool and library for performing reflection on SPIR-V and disassembling SPIR-V back to high level languages.
Apache License 2.0
1.96k stars 549 forks source link

compiler is optimizing unreferenced parameter in CompilerGLSL::type_to_array_glsl and causing linking issues #2338

Open ArturSchuetz opened 2 weeks ago

ArturSchuetz commented 2 weeks ago

in file spirv_glsl.cpp you have a definition of this function:

string CompilerGLSL::type_to_array_glsl(const SPIRType &type, uint32_t)
{

as you can see, the second parameter is unnamed and unused. This is causing problems if I try to use this function from outside the library:

59>------ Build started: Project: VulkanRenderDevice, Configuration: Debug x64 ------
57>spirv_cross_c.cpp
58>main.cpp
57>spirv-cross-c.vcxproj -> F:\Projects\long-bow-engine\build\Debug\spirv-cross-cd.lib
58>spirv-cross.vcxproj -> F:\Projects\long-bow-engine\build\Debug\spirv-cross.exe
59>   Creating library F:/Projects/long-bow-engine/build/Debug/VulkanRenderDeviced.lib and object F:/Projects/long-bow-engine/build/Debug/VulkanRenderDeviced.exp
59>BowVulkanShaderProgram.obj : error LNK2001: unresolved external symbol "protected: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl spirv_cross::CompilerGLSL::type_to_array_glsl(struct spirv_cross::SPIRType const &)" (?type_to_array_glsl@CompilerGLSL@spirv_cross@@MEAA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBUSPIRType@2@@Z)
59>F:\Projects\long-bow-engine\build\Debug\VulkanRenderDeviced.dll : fatal error LNK1120: 1 unresolved externals
59>Done building project "VulkanRenderDevice.vcxproj" -- FAILED.

As you can see my compiler is trying to link this function which does not exist: spirv_cross::CompilerGLSL::type_to_array_glsl(struct spirv_cross::SPIRType const &)

I fixed it for me by declaring and defning a second function, which takes only one parameter:

spirv_glsl.hpp:

virtual std::string type_to_array_glsl(const SPIRType &type);
virtual std::string type_to_array_glsl(const SPIRType &type, uint32_t variable_id);

spirv_glsl.cpp:

string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
{
    return type_to_array_glsl(type, 0);
}

string CompilerGLSL::type_to_array_glsl(const SPIRType &type, uint32_t)
{
cdavis5e commented 2 weeks ago

Are you sure you declared that method correctly in your own sources? Where is that reference to std::string CompilerGLSL::type_to_array_glsl(const SPIRType &) coming from? Are you attempting to override it?

ArturSchuetz commented 2 weeks ago

This is how I used it in my own sources:

#include <spirv_cross/spirv_cross.hpp>
#include <spirv_cross/spirv_glsl.hpp>

ShaderVertexAttributeMap VulkanShaderProgram::FindVertexAttributes(const std::vector<uint32_t> &program)
{
    spirv_cross::CompilerGLSL compiler(program);
    spirv_cross::ShaderResources resources = compiler.get_shader_resources();

    ShaderVertexAttributeMap vertexAttributes;

    LOG_TRACE("Shader Resources: %zu stage inputs found", resources.stage_inputs.size());
    for (const auto &resource : resources.stage_inputs)
    {
        const spirv_cross::SPIRType &type = compiler.get_type(resource.type_id);
        std::string name = compiler.get_name(resource.id);
        uint32_t location = compiler.get_decoration(resource.id, spv::DecorationLocation);

        if (name.empty())
        {
            name = resource.name;
        }

        if (name.rfind("gl_", 0) == 0) // Skip built-in attributes
        {
            continue;
        }

        ShaderVertexAttributeType attributeType = VulkanTypeConverter::ToShaderVertexAttributeType(type);

        LOG_TRACE("\tResource ID: %u, \tName: %s, \tLocation: %d", resource.id, name.c_str(), location);
        vertexAttributes.insert(
            std::make_pair(name, std::make_shared<ShaderVertexAttribute>(location, attributeType, type.vecsize)));
    }
    return vertexAttributes;
}

the first Line of code here already caused this linker error spirv_cross::CompilerGLSL compiler(program);

I am compiling a DLL on Windows with Visual Studio v143 and ISO C++ 17 Standard

HansKristian-Work commented 2 weeks ago

I have no idea what is going on here. MSVC is built in CI and it links fine there. There are no uses of type_to_array_glsl with one argument in the code base.

ArturSchuetz commented 2 weeks ago

I am also quite confused because this method is never called even after I was able to successfully build and run it. But my compiler does not let me build it without this workaround.

HansKristian-Work commented 2 weeks ago

If there is a rational explanation for this, I can consider it, but I won't add a random hack like this without understanding the root cause. Does this reproduce when building SPIRV-Cross as-is?

ArturSchuetz commented 2 weeks ago

I will investigate this further. I actually used dumpbin to see if the symbol is exported and it actually is, which confuses me even more. symbols.txt

I don’t expect you to add hacky code. I just wanted to point out that I encountered the problem because it took me a day just to figure out why my compiler is giving me a linker error even though everything seems to be correct.

I just don't understand why my compiler is expecting spirv_cross::CompilerGLSL::type_to_array_glsl(struct spirv_cross::SPIRType const &) instead of spirv_cross::CompilerGLSL::type_to_array_glsl(struct spirv_cross::SPIRType const &, uint32_t). I see that it could be some compiler optimizations because the second parameter is never used and omitted completely by the compiler.

I am actually building my Project using CMake and added the SPIRV-Cross as a submodule into my Project, which could be one factor, which causes this problem. If other people encounter the same problem, at least there is already a quick solution. But I try to look into it and try to understand this linker error.

Building SPIRV-Cross as-is does not causes any problems. Building my Project, and only including the headers works too.

#include <spirv_cross/spirv_cross.hpp>
#include <spirv_cross/spirv_glsl.hpp>

Only after adding this line of code spirv_cross::CompilerGLSL compiler(program); I get this linker error.