premake/modules/gmake2/gmake2_csharp.lua
2017-06-13 14:46:49 -07:00

318 lines
7.6 KiB
Lua

--
-- gmake2_csharp.lua
-- Generate a C# project makefile.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local gmake2 = p.modules.gmake2
gmake2.cs = {}
local cs = gmake2.cs
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
--
-- Add namespace for element definition lists for p.callarray()
--
cs.elements = {}
--
-- Generate a GNU make C++ project makefile, with support for the new platforms API.
--
cs.elements.makefile = function(prj)
return {
gmake2.header,
gmake2.phonyRules,
gmake2.csConfigs,
gmake2.csProjectConfig,
gmake2.csSources,
gmake2.csEmbedFiles,
gmake2.csCopyFiles,
gmake2.csResponseFile,
gmake2.shellType,
gmake2.csAllRules,
gmake2.csTargetRules,
gmake2.targetDirRules,
gmake2.csResponseRules,
gmake2.objDirRules,
gmake2.csCleanRules,
gmake2.preBuildRules,
gmake2.preLinkRules,
gmake2.csFileRules,
}
end
--
-- Generate a GNU make C# project makefile, with support for the new platforms API.
--
function cs.generate(prj)
p.eol("\n")
local toolset = p.tools.dotnet
p.callArray(cs.elements.makefile, prj, toolset)
end
--
-- Write out the settings for a particular configuration.
--
cs.elements.configuration = function(cfg)
return {
gmake2.csTools,
gmake2.target,
gmake2.objdir,
gmake2.csFlags,
gmake2.csLinkCmd,
gmake2.preBuildCmds,
gmake2.preLinkCmds,
gmake2.postBuildCmds,
gmake2.settings,
}
end
function gmake2.csConfigs(prj, toolset)
for cfg in project.eachconfig(prj) do
_x('ifeq ($(config),%s)', cfg.shortname)
p.callArray(cs.elements.configuration, cfg, toolset)
_p('endif')
_p('')
end
end
--
-- Given a .resx resource file, builds the path to corresponding .resource
-- file, matching the behavior and naming of Visual Studio.
--
function cs.getresourcefilename(cfg, fname)
if path.getextension(fname) == ".resx" then
local name = cfg.buildtarget.basename .. "."
local dir = path.getdirectory(fname)
if dir ~= "." then
name = name .. path.translate(dir, ".") .. "."
end
return "$(OBJDIR)/" .. p.esc(name .. path.getbasename(fname)) .. ".resources"
else
return fname
end
end
--
-- Iterate and output some selection of the source code files.
--
function cs.listsources(prj, selector)
local tr = project.getsourcetree(prj)
p.tree.traverse(tr, {
onleaf = function(node, depth)
local value = selector(node)
if value then
_x('\t%s \\', value)
end
end
})
end
---------------------------------------------------------------------------
--
-- Handlers for individual makefile elements
--
---------------------------------------------------------------------------
function gmake2.csAllRules(prj, toolset)
_p('all: $(TARGETDIR) $(OBJDIR) prebuild $(EMBEDFILES) $(COPYFILES) prelink $(TARGET)')
_p('')
end
function gmake2.csCleanRules(prj, toolset)
--[[
-- porting from 4.x
_p('clean:')
_p('\t@echo Cleaning %s', prj.name)
_p('ifeq (posix,$(SHELLTYPE))')
_p('\t$(SILENT) rm -f $(TARGETDIR)/%s.* $(COPYFILES)', target.basename)
_p('\t$(SILENT) rm -rf $(OBJDIR)')
_p('else')
_p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGETDIR)/%s) del $(subst /,\\\\,$(TARGETDIR)/%s.*)', target.name, target.basename)
for target, source in pairs(cfgpairs[anycfg]) do
_p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target)
end
for target, source in pairs(copypairs) do
_p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target)
end
_p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))')
_p('endif')
_p('')
--]]
end
function gmake2.csCopyFiles(prj, toolset)
--[[
-- copied from 4.x; needs more porting
_p('COPYFILES += \\')
for target, source in pairs(cfgpairs[anycfg]) do
_p('\t%s \\', target)
end
for target, source in pairs(copypairs) do
_p('\t%s \\', target)
end
_p('')
--]]
end
function cs.getresponsefilename(prj)
return '$(OBJDIR)/' .. prj.filename .. '.rsp'
end
function gmake2.csResponseFile(prj, toolset)
_x('RESPONSE += ' .. gmake2.cs.getresponsefilename(prj))
end
function gmake2.csResponseRules(prj)
local toolset = p.tools.dotnet
local ext = gmake2.getmakefilename(prj, true)
local makefile = path.getname(p.filename(prj, ext))
local response = gmake2.cs.getresponsefilename(prj)
_p('$(RESPONSE): %s', makefile)
_p('\t@echo Generating response file', prj.name)
_p('ifeq (posix,$(SHELLTYPE))')
_x('\t$(SILENT) rm -f $(RESPONSE)')
_p('else')
_x('\t$(SILENT) if exist $(RESPONSE) del %s', path.translate(response, '\\'))
_p('endif')
local sep = os.istarget("windows") and "\\" or "/"
local tr = project.getsourcetree(prj)
p.tree.traverse(tr, {
onleaf = function(node, depth)
if toolset.fileinfo(node).action == "Compile" then
_x('\t@echo %s >> $(RESPONSE)', path.translate(node.relpath, sep))
end
end
})
_p('')
end
function gmake2.csEmbedFiles(prj, toolset)
local cfg = project.getfirstconfig(prj)
_p('EMBEDFILES += \\')
cs.listsources(prj, function(node)
local fcfg = fileconfig.getconfig(node, cfg)
local info = toolset.fileinfo(fcfg)
if info.action == "EmbeddedResource" then
return cs.getresourcefilename(cfg, node.relpath)
end
end)
_p('')
end
function gmake2.csFileRules(prj, toolset)
--[[
-- porting from 4.x
_p('# Per-configuration copied file rules')
for cfg in p.eachconfig(prj) do
_x('ifneq (,$(findstring %s,$(config)))', cfg.name:lower())
for target, source in pairs(cfgpairs[cfg]) do
p.make_copyrule(source, target)
end
_p('endif')
_p('')
end
_p('# Copied file rules')
for target, source in pairs(copypairs) do
p.make_copyrule(source, target)
end
_p('# Embedded file rules')
for _, fname in ipairs(embedded) do
if path.getextension(fname) == ".resx" then
_x('%s: %s', getresourcefilename(prj, fname), fname)
_p('\t$(SILENT) $(RESGEN) $^ $@')
end
_p('')
end
--]]
end
function gmake2.csFlags(cfg, toolset)
_p(' FLAGS =%s', gmake2.list(toolset.getflags(cfg)))
end
function gmake2.csLinkCmd(cfg, toolset)
local deps = p.esc(config.getlinks(cfg, "dependencies", "fullpath"))
_p(' DEPENDS =%s', gmake2.list(deps))
_p(' REFERENCES = %s', table.implode(deps, "/r:", "", " "))
end
function gmake2.csProjectConfig(prj, toolset)
-- To maintain compatibility with Visual Studio, these values must
-- be set on the project level, and not per-configuration.
local cfg = project.getfirstconfig(prj)
local kindflag = "/t:" .. toolset.getkind(cfg):lower()
local libdirs = table.implode(p.esc(cfg.libdirs), "/lib:", "", " ")
_p('FLAGS += %s', table.concat(table.join(kindflag, libdirs), " "))
local refs = p.esc(config.getlinks(cfg, "system", "fullpath"))
_p('REFERENCES += %s', table.implode(refs, "/r:", "", " "))
_p('')
end
function gmake2.csSources(prj, toolset)
local cfg = project.getfirstconfig(prj)
_p('SOURCES += \\')
cs.listsources(prj, function(node)
local fcfg = fileconfig.getconfig(node, cfg)
local info = toolset.fileinfo(fcfg)
if info.action == "Compile" then
return node.relpath
end
end)
_p('')
end
function gmake2.csTargetRules(prj, toolset)
_p('$(TARGET): $(SOURCES) $(EMBEDFILES) $(DEPENDS) $(RESPONSE)')
_p('\t$(SILENT) $(CSC) /nologo /out:$@ $(FLAGS) $(REFERENCES) @$(RESPONSE) $(patsubst %%,/resource:%%,$(EMBEDFILES))')
_p('\t$(POSTBUILDCMDS)')
_p('')
end
function gmake2.csTools(cfg, toolset)
_p(' CSC = %s', toolset.gettoolname(cfg, "csc"))
_p(' RESGEN = %s', toolset.gettoolname(cfg, "resgen"))
end