All the shader* commands in Premake5 (current version 5.0.0-beta7) are scoped to the project (per-configuration). They do not work at file-scope (per-configuration) and no amount of file filtering can change that.
Shader files participate in a build by adding them to your Visual Studio project. You achieve that in Premake5 by adding them to your project's files{} table.
That's all you need to do to enable the HLSL Compiler properties in Visual Studio. It won't appear at all if there are no shaders participating in the build.
In Premake5, HLSL files in the files {} table are automatically tagged "FxCompile", but they will not compile until you set the appropriate shader types.
Solution
First, prefix encode the shader types in the shader file names:
cs_*.hlsl = Compute Shader
ds*.hlsl = Domain Shader
gs_*.hlsl = Geometry Shader
hs_*.hlsl = Hull Shader
ps_*.hlsl = Pixel Shader
vs_*.hlsl = Vertex Shader
Next, add all shaders to your premake5.lua files{} table.
Next, give all your include shaders a .hlsli extension. This automatically excludes them from the build (you'll have to view all files to see/edit them).
Next, add a helper function to your project's override.lua file:
local function get_shader_type(filename)
local shader_type = nil
if string.startswith(filename, "cs_") then
shader_type = "Compute"
elseif string.startswith(filename, "ds_") then
shader_type = "Domain"
elseif string.startswith(filename, "gs_") then
shader_type = "Geometry"
elseif string.startswith(filename, "hs_") then
shader_type = "Hull"
elseif string.startswith(filename, "ps_") then
shader_type = "Pixel"
elseif string.startswith(filename, "vs_") then
shader_type = "Vertex"
end
return shader_type
end
Finally, override the emitFiles() function (the base function can be found in Premake5's vs2010_vcxproj.lua).
require('vstudio')
local p = premake
local project = p.project
local fileconfig = p.fileconfig
local dotnetbase = p.vstudio.dotnetbase
local m = p.vstudio.vc2010
p.override(m, "emitFiles", function(base, prj, group, tag, fileFunc, fileCfgFunc, checkFunc)
local files = group.files
if files and #files > 0 then
p.push('<ItemGroup>')
for _, file in ipairs(files) do
local fcfg = nil
local contents = p.capture(function ()
p.push()
p.callArray(fileFunc, nil, file)
m.conditionalElements = {}
for cfg in project.eachconfig(prj) do
fcfg = fileconfig.getconfig(file, cfg)
if not checkFunc or checkFunc(cfg, fcfg) then
if tag == "FxCompile" then
shader_type = get_shader_type(path.getbasename(file.name))
if shader_type then
condition = string.gsub(dotnetbase.condition(cfg), "%s+", "")
p.w("<ShaderType "..condition..">"..shader_type.."</ShaderType>")
end
else
p.callArray(fileCfgFunc, fcfg, m.configPair(cfg))
end
end
end
if #m.conditionalElements > 0 then
m.emitConditionalElements(prj)
end
p.pop()
end)
local rel = path.translate(file.relpath)
-- SharedItems projects paths are prefixed with a magical variable
if prj.kind == p.SHAREDITEMS then
rel = "$(MSBuildThisFileDirectory)" .. rel
end
if #contents > 0 then
p.push('<%s Include="%s">', tag, rel)
p.outln(contents)
p.pop('</%s>', tag)
else
p.x('<%s Include="%s" />', tag, rel)
end
end
p.pop('</ItemGroup>')
end
end)
With all that done, include the override.lua in your project's premake5.lua.
More Information
The bulk of the override function is just a duplicate of the base function. The base function creates an <ItemGroup> block in your vcxproj file based upon the tag parameter. For a file tagged "FxCompile", no per-configuration contents are captured, so the function emits a single line <FxCompile> tag in the Visual Studio project which simply states the file participates in all build configurations. But that file will fail to compile because no shader type attributes are attached to the tag. The override adds these missing attributes.
The only change from the base implementation is from this:
p.callArray(fileCfgFunc, fcfg, m.configPair(cfg))
To this:
if tag == "FxCompile" then
shader_type = get_shader_type(path.getbasename(file.name))
if shader_type then
condition = string.gsub(dotnetbase.condition(cfg), "%s+", "")
p.w("<ShaderType "..condition..">"..shader_type.."</ShaderType>")
end
else
p.callArray(fileCfgFunc, fcfg, m.configPair(cfg))
end
In essence, when the tag is "FxCompile", the call to p.callArray(fileCfgFunc, fcfg, m.configPair(cfg)) will not generate any contents because there are none to generate. So, rather than calling a function that returns no content, we generate the required per-configuration contents ourselves, by determining the shader type from the file name prefix, constructing the required condition, and writing to contents. Those writes will be captured by the contents variable which will be written later in the function, once all the configurations for the file have been captured.
Including the override and adding some HLSL files to your project is all you need to do. No need to filter shader files or call buildaction("FxCompile"); that's all done automatically as soon as you add a shader file to your premake5.lua.