premake / premake-core

Premake
https://premake.github.io/
BSD 3-Clause "New" or "Revised" License
3.13k stars 611 forks source link

Object File Collision Detection Part II: Visual Studio C++ modules #2177

Open larioteo opened 6 months ago

larioteo commented 6 months ago

What seems to be the problem? The bug is related to same modules with same file names in a project. The compiler puts everything under the same intermediate directory, due to generated project configuration. Later the linker cannot find either the first or the second module, depending on the compile order. In the past there was the same issue for C++ in Visual Studio 1182.

What did you expect to happen? Premake should either set the macro "$(IntDir)\%(RelativeDir)", which would solve a lot of other stuff that could happen, or extend the old logic to generate numbered file names also for modules.

The second option could interfere with other stuff that are beyond my knoweledge. As example IntelliSense seems to also build a lot of stuff, to be able to support modules.

image

What have you tried so far? Fixed it manually in Visual Studio under: " -> Right Click -> Properties -> Configuration Properties / C/C++ / Output Files"

image

Also checked everything around, the good thing with the macro, this issue would never ever happen again.

Before that I tried a lot around setting the objdir properly, but it seems that premake5 is limited in that case 283.

How can we reproduce this? Yeah, just put a basic Visual Studio 2022 C++ 20 project with two modules in different directories with the same name. Premake generates the following for the second module:

image

Manual fix:

image

What version of Premake are you using? premake5 5.0.0-beta2

Anything else we should know? Thank you guys for this amazing build tool!

larioteo commented 6 months ago

Hello again,

Today, I found a relatively easy fix with an custom override, but certain conditions must be met for it to work. I've set objdir globally under the solution (workspace) with this value "%{wks.location}/Cache/%{prj.name}/%{cfg.buildcfg}". So I don't need to set it per project anyway.

Than, I tried to set Output Files under Project Properties and realized that they are stored separately under the global ClCompile.

image

It looks like this in the project file:

image

Notice that Premake updates these properties in the project file:

image

So it seems that the settings don't interfere, which is nice.

It also looks like that Premake with this new approach doesn't generate the numbered object files, which is also a nice side effect.

--
-- @brief Visual Studio: Bugfix for C++ Modules (same module file name per project)
--
require("vstudio")
premake.override(premake.vstudio.vc2010.elements, "clCompile", function(base, prj)
    local m = premake.vstudio.vc2010
    local calls = base(prj)

    if premake.project.iscpp(prj) then
        table.insertafter(calls, premake.xmlDeclaration,  function()
            premake.w('<ModuleDependenciesFile>$(IntDir)\\%%(RelativeDir)</ModuleDependenciesFile>')
            premake.w('<ModuleOutputFile>$(IntDir)\\%%(RelativeDir)</ModuleOutputFile>')
            premake.w('<ObjectFileName>$(IntDir)\\%%(RelativeDir)</ObjectFileName>')
        end)
    end

    return calls
end)