premake/premake-4.x

Resource defines not applied for VC201x projects (at all!)

assarbad opened this issue · 3 comments

The current code, namely vs2010_vcxproj.lua doesn't use resdefines at all. I just noticed this by accident. I'll definitely write a Lua-only workaround for this, but I still need to set up myself to contribute back changes from my (still Mercurial based) repo.

Unfortunately the function preprocessor is a local one, which makes the planned workaround more cumbersome than it would otherwise be. Likely another case where io.capture() is called for.

do -- local scope ...
    -- Borrowed from setLocal() at https://stackoverflow.com/a/22752379
    local function getLocal(stkidx, name)
        local index = 1
        while true do
            local var_name, var_value = debug.getlocal(stkidx, index)
            if not var_name then break end
            if var_name == name then 
                return var_value
            end
            index = index + 1
        end
    end
    local orig_premake_vs2010_vcxproj = premake.vs2010_vcxproj
    premake.vs2010_vcxproj = function(prj)
        -- The whole stunt below is necessary in order to modify the resource_compile()
        -- output. Given it's a local function we have to go through hoops.
        local orig_p = _G._p
        local besilent = false
        -- We patch the global _p() function
        _G._p = function(indent, msg, ...)
            -- Look for indent values of 2
            if indent == 2 and msg ~= nil then
                -- ... with msg value of <ResourceCompile>
                if msg == "<ResourceCompile>" then
                    local cfg = getLocal(3, "e") -- with LuaSrcDiet
                    if cfg == nil then
                        cfg = getLocal(3, "cfg") -- without LuaSrcDiet
                    end
                    assert(type(cfg) == "table" and cfg["resdefines"] ~= nil)
                    orig_p(indent, msg, ...) -- spit the original line out
                    local indent = indent + 1
                    if #cfg.defines > 0 or #cfg.resdefines then
                        local defines = table.join(cfg.defines, cfg.resdefines)
                        orig_p(indent,'<PreprocessorDefinitions>%s;%%(PreprocessorDefinitions)</PreprocessorDefinitions>'
                            ,premake.esc(table.concat(premake.esc(defines), ";")))
                    else
                        orig_p(indent,'<PreprocessorDefinitions></PreprocessorDefinitions>')
                    end
                    if #cfg.includedirs > 0 or #cfg.resincludedirs > 0 then
                        local dirs = table.join(cfg.includedirs, cfg.resincludedirs)
                        orig_p(indent,'<AdditionalIncludeDirectories>%s;%%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>'
                                ,premake.esc(path.translate(table.concat(dirs, ";"), '\\')))
                    end
                    besilent = true
                end
                -- ... or msg value of <ResourceCompile>
                if msg == "</ResourceCompile>" then
                    besilent = false
                    -- fall through
                end
            end
            if not besilent then -- should we be silent?
                orig_p(indent, msg, ...)
            end
        end
        -- do whatever else is called for ...
        orig_premake_vs2010_vcxproj(prj)
        _G._p = orig_p -- restore in any case
    end
end

Other solutions are obviously possible, notably io.capture(), but I have noticed that this method seems to be lighter on resources, despite using introspection features.

We're looking for the name "e" first, because LuaSrcDiet shortens the variable name "cfg" to that. If we fail, we try again with the original name. After that we assert that it's non-nil and contains the key resdefines ... voila, problem solved.

If you submit this as a PR (as a direct modification of the core core, rather than a patch) I'll be happy to merge it.

Hey @starkos , of course this above solution makes no sense as PR. Because it should be fixed in Premake4 so that above workaround isn't necessary anymore (simply by patching vs2010_vcxproj.lua). What I'm trying with these workarounds is to patch the behavior of Premake4 with what I have, without having to recompile the binary all the time. And also in absence of some real patch management it's kinda hard to keep track. Premake would need something like in Vim where you can check which patches or features are available and execute something based on that condition. In the past I've done this by keeping some of the new symbols global so I could look out for them in my scripts and keep my scripts compatible across a wide range of Premake4 patch levels. No idea if you have something like this patch management planned for Premake5, but it'd definitely make sense to have this.

I'll try to submit the patches I have ready in my fork until the end of the year. No promises, though.

Until then I am keeping that cookbook article in the Wiki up-to-date. I hope that this will be valuable to others running into similar issues.