-- -- dotnet.lua -- Interface for the C# compilers, all of which are flag compatible. -- Copyright (c) 2002-2013 Jason Perkins and the Premake project -- local p = premake p.tools.dotnet = {} local dotnet = p.tools.dotnet local project = p.project local config = p.config -- -- Examine the file and project configurations to glean additional -- information about a source code in a C# project. -- -- @param fcfg -- The file configuration to consider. -- @return -- A table containing the following keys: -- -- action: the build action for the file; one of "Compile", "Copy", -- "EmbeddedResource", or "None". -- subtype: an additional categorization of the file type, or nil if -- no subtype is required. -- dependency: a related file name, (i.e. *.Designer.cs) if appropriate -- for the file action and subtype. -- function dotnet.fileinfo(fcfg) local info = {} if (fcfg == nil) then return info end local fname = fcfg.abspath local ext = path.getextension(fname):lower() -- Determine the build action for the file, falling back to the file -- extension if no explicit action is available. if fcfg.buildaction == "Compile" or ext == ".cs" or ext == ".fs" then info.action = "Compile" elseif fcfg.buildaction == "Embed" or ext == ".resx" then info.action = "EmbeddedResource" elseif fcfg.buildaction == "Copy" or ext == ".asax" or ext == ".aspx" or ext == ".dll" or ext == ".tt" then info.action = "Content" elseif fcfg.buildaction == "Resource" then info.action = "Resource" elseif ext == ".xaml" then if fcfg.buildaction == "Application" or path.getbasename(fname) == "App" then if fcfg.project.kind == p.SHAREDLIB then info.action = "None" else info.action = "ApplicationDefinition" end else info.action = "Page" end else info.action = "None" end -- Try to work out any subtypes, based on the files in the project if info.action == "Compile" and fname:endswith(".cs") then if fname:endswith(".Designer.cs") then local basename = fname:sub(1, -13) -- Look for associated files: .resx, .settings, .cs, .xsd local testname = basename .. ".resx" if project.hasfile(fcfg.project, testname) then info.AutoGen = "True" info.DependentUpon = testname end testname = basename .. ".settings" if project.hasfile(fcfg.project, testname) then info.AutoGen = "True" info.DependentUpon = testname info.DesignTimeSharedInput = "True" end testname = basename .. ".cs" if project.hasfile(fcfg.project, testname) then info.AutoGen = nil info.SubType = "Dependency" info.DependentUpon = testname end testname = basename .. ".xsd" if project.hasfile(fcfg.project, testname) then info.AutoGen = "True" info.DesignTime = "True" info.DependentUpon = testname end elseif fname:endswith(".xaml.cs") then info.SubType = "Code" info.DependentUpon = fname:sub(1, -4) else local basename = fname:sub(1, -4) -- Is there a matching *.xsd? testname = basename .. ".xsd" if project.hasfile(fcfg.project, testname) then info.DependentUpon = testname end -- Is there a matching *.Designer.cs? testname = basename .. ".Designer.cs" if project.hasfile(fcfg.project, testname) then info.SubType = "Form" end testname = basename .. ".tt" if project.hasfile(fcfg.project, testname) then info.AutoGen = "True" info.DesignTime = "True" info.DependentUpon = testname end end -- Allow C# object type build actions to override the default if fcfg.buildaction == "Component" or fcfg.buildaction == "Form" or fcfg.buildaction == "UserControl" then info.SubType = fcfg.buildaction end -- This flag is deprecated, will remove eventually if fcfg.flags and fcfg.flags.Component then info.SubType = "Component" end end if info.action == "Content" then info.CopyToOutputDirectory = "PreserveNewest" end if info.action == "EmbeddedResource" and fname:endswith(".resx") then local basename = fname:sub(1, -6) -- Is there a matching *.cs file? local testname = basename .. ".cs" if project.hasfile(fcfg.project, testname) then info.DependentUpon = testname if project.hasfile(fcfg.project, basename .. ".Designer.cs") then info.SubType = "DesignerType" end else -- Is there a matching *.Designer.cs? testname = basename .. ".Designer.cs" if project.hasfile(fcfg.project, testname) then info.SubType = "Designer" local resourceAccessGenerator = "ResXFileCodeGenerator" if fcfg.project.resourcegenerator then if fcfg.project.resourcegenerator == "public" then resourceAccessGenerator = "PublicResXFileCodeGenerator" end end info.Generator = resourceAccessGenerator info.LastGenOutput = path.getname(testname) end end end if info.action == "None" and fname:endswith(".settings") then local testname = fname:sub(1, -10) .. ".Designer.cs" if project.hasfile(fcfg.project, testname) then info.Generator = "SettingsSingleFileGenerator" info.LastGenOutput = path.getname(testname) end end if info.action == "Content" and fname:endswith(".tt") then local testname = fname:sub(1, -4) .. ".cs" if project.hasfile(fcfg.project, testname) then info.Generator = "TextTemplatingFileGenerator" info.LastGenOutput = path.getname(testname) info.CopyToOutputDirectory = nil end end if info.action == "None" and fname:endswith(".xsd") then local testname = fname:sub(1, -5) .. ".Designer.cs" if project.hasfile(fcfg.project, testname) then info.SubType = "Designer" info.Generator = "MSDataSetGenerator" info.LastGenOutput = path.getname(testname) end end if info.action == "None" and (fname:endswith(".xsc") or fname:endswith(".xss")) then local testname = fname:sub(1, -5) .. ".xsd" if project.hasfile(fcfg.project, testname) then info.DependentUpon = testname end end if fname:endswith(".xaml") then local testname = fname .. ".cs" if project.hasfile(fcfg.project, testname) then info.SubType = "Designer" info.Generator = "MSBuild:Compile" end end if info.DependentUpon then info.DependentUpon = path.getname(info.DependentUpon) end return info end -- -- Retrieves the executable command name for a tool, based on the -- provided configuration and the operating environment. -- -- @param cfg -- The configuration to query. -- @param tool -- The tool to fetch, one of "csc" for the C# compiler, or -- "resgen" for the resource compiler. -- @return -- The executable command name for a tool, or nil if the system's -- default value should be used. -- function dotnet.gettoolname(cfg, tool) local compilers = { msnet = "csc", mono = "mcs", pnet = "cscc", } if tool == "csc" then local toolset = _OPTIONS.dotnet or "msnet" return compilers[toolset] else return "resgen" end end -- -- Returns a list of compiler flags, based on the supplied configuration. -- dotnet.flags = { clr = { Unsafe = "/unsafe", }, flags = { FatalWarning = "/warnaserror", }, optimize = { On = "/optimize", Size = "/optimize", Speed = "/optimize", }, symbols = { On = "/debug", } } function dotnet.getflags(cfg) local flags = config.mapFlags(cfg, dotnet.flags) -- Tells the compiler not to include the csc.rsp response file which -- it does by default and references all the assemblies shipped with -- the .NET Framework. VS sets this flag by default for C# projects. table.insert(flags, '/noconfig') if cfg.project.icon then local fn = project.getrelative(cfg.project, cfg.project.icon) table.insert(flags, string.format('/win32icon:"%s"', fn)) end if #cfg.defines > 0 then table.insert(flags, table.implode(cfg.defines, "/d:", "", " ")) end if cfg.csversion ~= nil then table.insert(flags, '/langversion:' .. cfg.csversion) end return table.join(flags, cfg.buildoptions) end -- -- Translates the Premake kind into the CSC kind string. -- function dotnet.getkind(cfg) if (cfg.kind == "ConsoleApp") then return "Exe" elseif (cfg.kind == "WindowedApp") then return "WinExe" elseif (cfg.kind == "SharedLib") then return "Library" else error("invalid dotnet kind " .. cfg.kind .. ". Valid kinds are ConsoleApp, WindowsApp, SharedLib") end end -- -- Returns makefile-specific configuration rules. -- function dotnet.getmakesettings(cfg) return nil end