premake/src/actions/vstudio/vs2010_vcxproj.lua

1864 lines
42 KiB
Lua
Raw Normal View History

--
-- vs2010_vcxproj.lua
-- Generate a Visual Studio 201x C/C++ project.
-- Copyright (c) 2009-2015 Jason Perkins and the Premake project
--
premake.vstudio.vc2010 = {}
local p = premake
local vstudio = p.vstudio
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
local tree = p.tree
local m = p.vstudio.vc2010
---
-- Add namespace for element definition lists for premake.callArray()
---
m.elements = {}
--
-- Generate a Visual Studio 201x C++ project, with support for the new platforms API.
--
m.elements.project = function(prj)
return {
2015-07-27 17:30:51 +00:00
m.xmlDeclaration,
m.project,
m.projectConfigurations,
m.globals,
m.importDefaultProps,
m.configurationPropertiesGroup,
m.importExtensionSettings,
m.propertySheetGroup,
m.userMacros,
m.outputPropertiesGroup,
m.itemDefinitionGroups,
m.assemblyReferences,
m.files,
m.projectReferences,
m.importExtensionTargets,
}
end
function m.generate(prj)
p.utf8()
p.callArray(m.elements.project, prj)
p.out('</Project>')
end
--
-- Output the XML declaration and opening <Project> tag.
--
function m.project(prj)
local action = p.action.current()
p.push('<Project DefaultTargets="Build" ToolsVersion="%s" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">',
action.vstudio.toolsVersion)
end
--
-- Write out the list of project configurations, which pairs build
-- configurations with architectures.
--
function m.projectConfigurations(prj)
-- build a list of all architectures used in this project
local platforms = {}
for cfg in project.eachconfig(prj) do
local arch = vstudio.archFromConfig(cfg, true)
if not table.contains(platforms, arch) then
table.insert(platforms, arch)
end
end
local configs = {}
p.push('<ItemGroup Label="ProjectConfigurations">')
for cfg in project.eachconfig(prj) do
for _, arch in ipairs(platforms) do
local prjcfg = vstudio.projectConfig(cfg, arch)
if not configs[prjcfg] then
configs[prjcfg] = prjcfg
p.push('<ProjectConfiguration Include="%s">', vstudio.projectConfig(cfg, arch))
p.x('<Configuration>%s</Configuration>', vstudio.projectPlatform(cfg))
p.w('<Platform>%s</Platform>', arch)
p.pop('</ProjectConfiguration>')
end
end
end
p.pop('</ItemGroup>')
end
--
-- Write out the TargetFrameworkVersion property.
--
function m.targetFramework(prj)
local action = p.action.current()
local tools = string.format(' ToolsVersion="%s"', action.vstudio.toolsVersion)
local framework = prj.framework or action.vstudio.targetFramework or "4.0"
p.w('<TargetFrameworkVersion>v%s</TargetFrameworkVersion>', framework)
end
--
-- Write out the Globals property group.
--
m.elements.globals = function(prj)
return {
m.projectGuid,
m.ignoreWarnDuplicateFilename,
m.keyword,
m.projectName,
}
end
function m.globals(prj)
m.propertyGroup(nil, "Globals")
p.callArray(m.elements.globals, prj)
p.pop('</PropertyGroup>')
end
--
-- Write out the configuration property group: what kind of binary it
-- produces, and some global settings.
--
m.elements.configurationProperties = function(cfg)
if cfg.kind == p.UTILITY then
return {
m.configurationType,
}
else
return {
m.configurationType,
m.useDebugLibraries,
m.useOfMfc,
m.useOfAtl,
m.clrSupport,
m.characterSet,
m.platformToolset,
m.wholeProgramOptimization,
m.nmakeOutDirs,
}
end
end
function m.configurationProperties(cfg)
m.propertyGroup(cfg, "Configuration")
p.callArray(m.elements.configurationProperties, cfg)
p.pop('</PropertyGroup>')
end
function m.configurationPropertiesGroup(prj)
for cfg in project.eachconfig(prj) do
m.configurationProperties(cfg)
end
end
--
-- Write the output property group, which includes the output and intermediate
-- directories, manifest, etc.
--
m.elements.outputProperties = function(cfg)
if cfg.kind == p.UTILITY then
return {
m.outDir,
m.intDir,
m.extensionsToDeleteOnClean,
}
else
return {
m.linkIncremental,
m.ignoreImportLibrary,
m.outDir,
m.outputFile,
m.intDir,
m.targetName,
m.targetExt,
m.includePath,
m.libraryPath,
m.imageXexOutput,
m.generateManifest,
m.extensionsToDeleteOnClean,
2015-03-25 16:47:05 +00:00
m.executablePath,
}
end
end
function m.outputProperties(cfg)
if not vstudio.isMakefile(cfg) then
m.propertyGroup(cfg)
p.callArray(m.elements.outputProperties, cfg)
p.pop('</PropertyGroup>')
end
end
function m.outputPropertiesGroup(prj)
for cfg in project.eachconfig(prj) do
m.outputProperties(cfg)
m.nmakeProperties(cfg)
end
end
--
-- Write the NMake property group for Makefile projects, which includes the custom
-- build commands, output file location, etc.
--
function m.nmakeProperties(cfg)
if vstudio.isMakefile(cfg) then
m.propertyGroup(cfg)
m.nmakeOutput(cfg)
m.nmakeCommandLine(cfg, cfg.buildcommands, "Build")
m.nmakeCommandLine(cfg, cfg.rebuildcommands, "ReBuild")
m.nmakeCommandLine(cfg, cfg.cleancommands, "Clean")
p.pop('</PropertyGroup>')
end
end
--
-- Write a configuration's item definition group, which contains all
-- of the per-configuration compile and link settings.
--
m.elements.itemDefinitionGroup = function(cfg)
if cfg.kind == p.UTILITY then
return {
m.ruleVars,
m.buildEvents,
}
else
return {
m.clCompile,
m.resourceCompile,
m.linker,
m.manifest,
m.buildEvents,
m.imageXex,
m.deploy,
m.ruleVars,
m.buildLog,
}
end
end
function m.itemDefinitionGroup(cfg)
if not vstudio.isMakefile(cfg) then
p.push('<ItemDefinitionGroup %s>', m.condition(cfg))
p.callArray(m.elements.itemDefinitionGroup, cfg)
p.pop('</ItemDefinitionGroup>')
else
if cfg == project.getfirstconfig(cfg.project) then
p.w('<ItemDefinitionGroup>')
p.w('</ItemDefinitionGroup>')
end
end
end
function m.itemDefinitionGroups(prj)
for cfg in project.eachconfig(prj) do
m.itemDefinitionGroup(cfg)
end
end
--
-- Write the the <ClCompile> compiler settings block.
--
m.elements.clCompile = function(cfg)
return {
m.precompiledHeader,
m.warningLevel,
m.treatWarningAsError,
m.disableSpecificWarnings,
m.treatSpecificWarningsAsErrors,
m.basicRuntimeChecks,
m.clCompilePreprocessorDefinitions,
m.clCompileUndefinePreprocessorDefinitions,
m.clCompileAdditionalIncludeDirectories,
m.clCompileAdditionalUsingDirectories,
m.forceIncludes,
m.debugInformationFormat,
m.programDataBaseFileName,
m.optimization,
m.functionLevelLinking,
m.intrinsicFunctions,
m.minimalRebuild,
m.omitFramePointers,
m.stringPooling,
m.runtimeLibrary,
m.omitDefaultLib,
m.exceptionHandling,
m.runtimeTypeInfo,
m.bufferSecurityCheck,
m.treatWChar_tAsBuiltInType,
m.floatingPointModel,
2015-06-08 18:06:18 +00:00
m.inlineFunctionExpansion,
m.enableEnhancedInstructionSet,
m.multiProcessorCompilation,
m.additionalCompileOptions,
m.compileAs,
m.callingConvention,
}
end
function m.clCompile(cfg)
p.push('<ClCompile>')
p.callArray(m.elements.clCompile, cfg)
p.pop('</ClCompile>')
end
--
-- Write out the resource compiler block.
--
m.elements.resourceCompile = function(cfg)
return {
m.resourcePreprocessorDefinitions,
m.resourceAdditionalIncludeDirectories,
m.culture,
}
end
function m.resourceCompile(cfg)
if cfg.system ~= p.XBOX360 and config.hasResourceFiles(cfg) then
local contents = p.capture(function ()
p.push()
p.callArray(m.elements.resourceCompile, cfg)
p.pop()
end)
if #contents > 0 then
p.push('<ResourceCompile>')
p.outln(contents)
p.pop('</ResourceCompile>')
end
2013-03-07 17:14:03 +00:00
end
end
--
-- Write out the linker tool block.
--
m.elements.linker = function(cfg, explicit)
return {
m.link,
m.lib,
m.linkLibraryDependencies,
}
end
function m.linker(cfg)
local explicit = vstudio.needsExplicitLink(cfg)
p.callArray(m.elements.linker, cfg, explicit)
end
m.elements.link = function(cfg, explicit)
if cfg.kind == p.STATICLIB then
return {
m.subSystem,
m.generateDebugInformation,
m.optimizeReferences,
}
else
return {
m.subSystem,
m.generateDebugInformation,
m.optimizeReferences,
m.additionalDependencies,
m.additionalLibraryDirectories,
m.importLibrary,
m.entryPointSymbol,
m.generateMapFile,
m.moduleDefinitionFile,
m.treatLinkerWarningAsErrors,
m.ignoreDefaultLibraries,
m.additionalLinkOptions,
}
end
end
function m.link(cfg, explicit)
local contents = p.capture(function ()
p.push()
p.callArray(m.elements.link, cfg, explicit)
p.pop()
end)
if #contents > 0 then
p.push('<Link>')
p.outln(contents)
p.pop('</Link>')
end
end
m.elements.lib = function(cfg, explicit)
if cfg.kind == p.STATICLIB then
return {
m.treatLinkerWarningAsErrors,
m.additionalLinkOptions,
}
else
return {}
end
end
function m.lib(cfg, explicit)
local contents = p.capture(function ()
p.push()
p.callArray(m.elements.lib, cfg, explicit)
p.pop()
end)
if #contents > 0 then
p.push('<Lib>')
p.outln(contents)
p.pop('</Lib>')
end
end
--
-- Write the manifest section.
--
function m.manifest(cfg)
if cfg.kind ~= p.STATICLIB then
-- get the manifests files
local manifests = {}
for _, fname in ipairs(cfg.files) do
if path.getextension(fname) == ".manifest" then
table.insert(manifests, project.getrelative(cfg.project, fname))
end
end
if #manifests > 0 then
p.push('<Manifest>')
m.element("AdditionalManifestFiles", nil, "%s %%(AdditionalManifestFiles)", table.concat(manifests, " "))
p.pop('</Manifest>')
end
end
end
---
-- Write out the pre- and post-build event settings.
---
function m.buildEvents(cfg)
local write = function (event)
local name = event .. "Event"
local field = event:lower()
local steps = cfg[field .. "commands"]
local msg = cfg[field .. "message"]
if #steps > 0 then
steps = os.translateCommands(steps, p.WINDOWS)
p.push('<%s>', name)
p.x('<Command>%s</Command>', table.implode(steps, "", "", "\r\n"))
if msg then
p.x('<Message>%s</Message>', msg)
end
p.pop('</%s>', name)
end
end
write("PreBuild")
write("PreLink")
write("PostBuild")
end
---
-- Write out project-level custom rule variables.
---
function m.ruleVars(cfg)
for i = 1, #cfg.rules do
local rule = p.global.getRule(cfg.rules[i])
local contents = p.capture(function ()
p.push()
for prop in p.rule.eachProperty(rule) do
local fld = p.rule.getPropertyField(rule, prop)
local value = cfg[fld.name]
if value ~= nil then
if fld.kind == "path" then
value = vstudio.path(cfg, value)
else
value = p.rule.getPropertyString(rule, prop, value)
end
if value ~= nil and #value > 0 then
m.element(prop.name, nil, '%s', value)
end
end
end
p.pop()
end)
if #contents > 0 then
p.push('<%s>', rule.name)
p.outln(contents)
p.pop('</%s>', rule.name)
end
end
end
--
-- Reference any managed assemblies listed in the links()
--
function m.assemblyReferences(prj)
-- Visual Studio doesn't support per-config references; use
-- whatever is contained in the first configuration
local cfg = project.getfirstconfig(prj)
local refs = config.getlinks(cfg, "system", "fullpath", "managed")
2015-07-27 17:30:51 +00:00
if #refs > 0 then
p.push('<ItemGroup>')
for i = 1, #refs do
local value = refs[i]
-- If the link contains a '/' then it is a relative path to
-- a local assembly. Otherwise treat it as a system assembly.
if value:find('/', 1, true) then
p.push('<Reference Include="%s">', path.getbasename(value))
p.x('<HintPath>%s</HintPath>', path.translate(value))
p.pop('</Reference>')
else
p.x('<Reference Include="%s" />', path.getbasename(value))
end
2015-07-27 17:30:51 +00:00
end
p.pop('</ItemGroup>')
end
end
---
-- Write out the list of source code files, and any associated configuration.
---
m.elements.files = function(prj, groups)
return {
m.clIncludeFiles,
m.clCompileFiles,
m.noneFiles,
m.resourceCompileFiles,
m.customBuildFiles,
m.customRuleFiles,
m.midlFiles
2015-07-27 17:30:51 +00:00
}
end
2015-07-27 17:30:51 +00:00
function m.files(prj)
local groups = m.categorizeSources(prj)
p.callArray(m.elements.files, prj, groups)
end
m.elements.ClCompileFile = function(cfg, file)
return {}
end
m.elements.ClCompileFileCfg = function(fcfg, condition)
if fcfg then
return {
m.excludedFromBuild,
m.objectFileName,
m.clCompilePreprocessorDefinitions,
m.clCompileUndefinePreprocessorDefinitions,
m.optimization,
m.forceIncludes,
m.precompiledHeader,
m.enableEnhancedInstructionSet,
m.additionalCompileOptions,
m.disableSpecificWarnings,
m.treatSpecificWarningsAsErrors
}
else
return {
m.excludedFromBuild
}
end
end
function m.clCompileFiles(prj, groups)
m.emitFiles(prj, groups, "ClCompile")
end
m.elements.ClIncludeFile = function(cfg, file)
return {}
end
m.elements.ClIncludeFileCfg = function(fcfg, condition)
return {}
end
function m.clIncludeFiles(prj, groups)
m.emitFiles(prj, groups, "ClInclude")
end
m.elements.CustomBuildFile = function(cfg, file)
return {
m.fileType
}
end
m.elements.CustomBuildFileCfg = function(fcfg, condition)
return {
m.excludedFromBuild,
m.buildCommands,
m.buildOutputs,
m.buildMessage,
m.buildAdditionalInputs
}
end
function m.customBuildFiles(prj, groups)
m.emitFiles(prj, groups, "CustomBuild", function (cfg, fcfg)
return fileconfig.hasCustomBuildRule(fcfg)
end)
end
function m.customRuleFiles(prj, groups)
for i = 1, #prj.rules do
local rule = p.global.getRule(prj.rules[i])
local files = groups[rule.name]
if files and #files > 0 then
p.push('<ItemGroup>')
for _, file in ipairs(files) do
local contents = p.capture(function()
p.push()
for prop in p.rule.eachProperty(rule) do
local fld = p.rule.getPropertyField(rule, prop)
for cfg in project.eachconfig(prj) do
local fcfg = fileconfig.getconfig(file, cfg)
if fcfg and fcfg[fld.name] then
local value = p.rule.getPropertyString(rule, prop, fcfg[fld.name])
if value and #value > 0 then
m.element(prop.name, m.condition(cfg), '%s', value)
end
end
end
end
p.pop()
end)
if #contents > 0 then
p.push('<%s Include=\"%s\">', rule.name, path.translate(file.relpath))
p.outln(contents)
p.pop('</%s>', rule.name)
else
p.x('<%s Include=\"%s\" />', rule.name, path.translate(file.relpath))
end
end
p.pop('</ItemGroup>')
end
end
end
m.elements.NoneFile = function(cfg, file)
return {}
end
2015-07-27 17:30:51 +00:00
m.elements.NoneFileCfg = function(fcfg, condition)
return {}
end
2015-07-27 17:30:51 +00:00
function m.noneFiles(prj, groups)
m.emitFiles(prj, groups, "None")
end
m.elements.ResourceCompileFile = function(cfg, file)
return {}
end
m.elements.ResourceCompileFileCfg = function(fcfg, condition)
return {
m.excludedFromBuild
}
end
function m.resourceCompileFiles(prj, groups)
m.emitFiles(prj, groups, "ResourceCompile", function(cfg)
return cfg.system == p.WINDOWS
end)
end
m.elements.MidlFile = function(cfg, file)
return {}
end
2015-07-27 17:30:51 +00:00
m.elements.MidlFileCfg = function(fcfg, condition)
return {
m.excludedFromBuild
}
end
function m.midlFiles(prj, groups)
m.emitFiles(prj, groups, "Midl", function(cfg)
return cfg.system == p.WINDOWS
end)
end
function m.categorizeSources(prj)
local groups = prj._vc2010_sources
if groups then
return groups
end
groups = {}
prj._vc2010_sources = groups
local tr = project.getsourcetree(prj)
tree.traverse(tr, {
onleaf = function(node)
local cat = m.categorizeFile(prj, node)
groups[cat] = groups[cat] or {}
table.insert(groups[cat], node)
end
})
-- sort by relative-to path; otherwise VS will reorder the files
for group, files in pairs(groups) do
table.sort(files, function (a, b)
return a.relpath < b.relpath
end)
end
return groups
end
function m.categorizeFile(prj, file)
-- If any configuration for this file uses a custom build step,
-- that's the category to use
for cfg in project.eachconfig(prj) do
local fcfg = fileconfig.getconfig(file, cfg)
if fileconfig.hasCustomBuildRule(fcfg) then
return "CustomBuild"
end
end
-- If there is a custom rule associated with it, use that
local rule = p.global.getRuleForFile(file.name, prj.rules)
if rule then
return rule.name
end
-- Otherwise use the file extension to deduce a category
if path.iscppfile(file.name) then
return "ClCompile"
elseif path.iscppheader(file.name) then
return "ClInclude"
elseif path.isresourcefile(file.name) then
return "ResourceCompile"
elseif path.isidlfile(file.name) then
return "Midl"
else
return "None"
end
end
function m.emitFiles(prj, groups, group, check)
local files = groups[group]
if files and #files > 0 then
p.push('<ItemGroup>')
for _, file in ipairs(files) do
2014-06-12 20:14:42 +00:00
local contents = p.capture(function ()
p.push()
p.callArray(m.elements[group .. "File"], cfg, file)
for cfg in project.eachconfig(prj) do
local fcfg = fileconfig.getconfig(file, cfg)
if not check or check(cfg, fcfg) then
p.callArray(m.elements[group .. "FileCfg"], fcfg, m.condition(cfg))
end
end
p.pop()
end)
local rel = path.translate(file.relpath)
if #contents > 0 then
p.push('<%s Include="%s">', group, rel)
p.outln(contents)
p.pop('</%s>', group)
else
p.x('<%s Include="%s" />', group, rel)
end
end
p.pop('</ItemGroup>')
end
end
--
-- Generate the list of project dependencies.
--
m.elements.projectReferences = function(prj, ref)
if prj.clr ~= p.OFF then
return {
m.referenceProject,
m.referencePrivate,
m.referenceOutputAssembly,
m.referenceCopyLocalSatelliteAssemblies,
m.referenceLinkLibraryDependencies,
m.referenceUseLibraryDependences,
}
else
return {
m.referenceProject,
}
end
end
function m.projectReferences(prj)
local refs = project.getdependencies(prj)
if #refs > 0 then
p.push('<ItemGroup>')
for _, ref in ipairs(refs) do
local relpath = vstudio.path(prj, vstudio.projectfile(ref))
p.push('<ProjectReference Include=\"%s\">', relpath)
p.callArray(m.elements.projectReferences, prj, ref)
p.pop('</ProjectReference>')
end
p.pop('</ItemGroup>')
end
end
2013-03-07 17:14:03 +00:00
---------------------------------------------------------------------------
--
2013-03-07 17:14:03 +00:00
-- Handlers for individual project elements
--
2013-03-07 17:14:03 +00:00
---------------------------------------------------------------------------
function m.additionalDependencies(cfg, explicit)
local links
-- check to see if this project uses an external toolset. If so, let the
-- toolset define the format of the links
local toolset = config.toolset(cfg)
if toolset then
links = toolset.getlinks(cfg, not explicit)
else
links = vstudio.getLinks(cfg, explicit)
end
if #links > 0 then
links = path.translate(table.concat(links, ";"))
m.element("AdditionalDependencies", nil, "%s;%%(AdditionalDependencies)", links)
end
end
function m.additionalIncludeDirectories(cfg, includedirs)
if #includedirs > 0 then
local dirs = vstudio.path(cfg, includedirs)
2015-03-25 16:47:05 +00:00
if #dirs > 0 then
m.element("AdditionalIncludeDirectories", nil, "%s;%%(AdditionalIncludeDirectories)", table.concat(dirs, ";"))
2015-03-25 16:47:05 +00:00
end
end
end
function m.additionalLibraryDirectories(cfg)
if #cfg.libdirs > 0 then
local dirs = table.concat(vstudio.path(cfg, cfg.libdirs), ";")
m.element("AdditionalLibraryDirectories", nil, "%s;%%(AdditionalLibraryDirectories)", dirs)
end
end
function m.additionalUsingDirectories(cfg)
if #cfg.usingdirs > 0 then
local dirs = table.concat(vstudio.path(cfg, cfg.usingdirs), ";")
m.element("AdditionalUsingDirectories", nil, "%s;%%(AdditionalUsingDirectories)", dirs)
end
2013-11-15 22:17:41 +00:00
end
function m.additionalCompileOptions(cfg, condition)
if #cfg.buildoptions > 0 then
local opts = table.concat(cfg.buildoptions, " ")
m.element("AdditionalOptions", condition, '%s %%(AdditionalOptions)', opts)
end
end
function m.additionalLinkOptions(cfg)
if #cfg.linkoptions > 0 then
local opts = table.concat(cfg.linkoptions, " ")
m.element("AdditionalOptions", nil, "%s %%(AdditionalOptions)", opts)
end
end
function m.basicRuntimeChecks(cfg)
2015-06-10 23:26:51 +00:00
local runtime = config.getruntime(cfg)
if cfg.flags.NoRuntimeChecks or (config.isOptimizedBuild(cfg) and runtime:endswith("Debug")) then
m.element("BasicRuntimeChecks", nil, "Default")
end
end
function m.buildAdditionalInputs(fcfg, condition)
if fcfg.buildinputs and #fcfg.buildinputs > 0 then
local inputs = project.getrelative(fcfg.project, fcfg.buildinputs)
m.element("AdditionalInputs", condition, '%s', table.concat(inputs, ";"))
end
end
function m.buildCommands(fcfg, condition)
local commands = os.translateCommands(fcfg.buildcommands, p.WINDOWS)
commands = table.concat(commands,'\r\n')
m.element("Command", condition, '%s', commands)
end
function m.buildLog(cfg)
if cfg.buildlog and #cfg.buildlog > 0 then
p.push('<BuildLog>')
m.element("Path", nil, "%s", vstudio.path(cfg, cfg.buildlog))
p.pop('</BuildLog>')
end
end
function m.buildMessage(fcfg, condition)
if fcfg.buildmessage then
m.element("Message", condition, '%s', fcfg.buildmessage)
end
end
function m.buildOutputs(fcfg, condition)
local outputs = project.getrelative(fcfg.project, fcfg.buildoutputs)
m.element("Outputs", condition, '%s', table.concat(outputs, ";"))
end
function m.characterSet(cfg)
if not vstudio.isMakefile(cfg) then
m.element("CharacterSet", nil, iif(cfg.flags.Unicode, "Unicode", "MultiByte"))
end
end
function m.wholeProgramOptimization(cfg)
if cfg.flags.LinkTimeOptimization then
m.element("WholeProgramOptimization", nil, "true")
end
end
function m.clCompileAdditionalIncludeDirectories(cfg)
m.additionalIncludeDirectories(cfg, cfg.includedirs)
end
function m.clCompileAdditionalUsingDirectories(cfg)
m.additionalUsingDirectories(cfg, cfg.usingdirs)
2013-11-15 22:17:41 +00:00
end
function m.clCompilePreprocessorDefinitions(cfg, condition)
m.preprocessorDefinitions(cfg, cfg.defines, false, condition)
end
function m.clCompileUndefinePreprocessorDefinitions(cfg, condition)
m.undefinePreprocessorDefinitions(cfg, cfg.undefines, false, condition)
end
function m.clrSupport(cfg)
local value
if cfg.clr == "On" or cfg.clr == "Unsafe" then
value = "true"
elseif cfg.clr ~= p.OFF then
value = cfg.clr
end
if value then
m.element("CLRSupport", nil, value)
end
end
function m.compileAs(cfg)
if cfg.project.language == "C" then
m.element("CompileAs", nil, "CompileAsC")
end
end
function m.configurationType(cfg)
local types = {
SharedLib = "DynamicLibrary",
StaticLib = "StaticLibrary",
ConsoleApp = "Application",
WindowedApp = "Application",
Makefile = "Makefile",
None = "Makefile",
2014-03-01 17:20:06 +00:00
Utility = "Utility",
}
m.element("ConfigurationType", nil, types[cfg.kind])
end
function m.culture(cfg)
local value = vstudio.cultureForLocale(cfg.locale)
if value then
m.element("Culture", nil, "0x%04x", tostring(value))
end
end
function m.debugInformationFormat(cfg)
local value
if cfg.flags.Symbols then
if cfg.debugformat == "c7" then
value = "OldStyle"
elseif cfg.architecture == "x86_64" or
cfg.clr ~= p.OFF or
config.isOptimizedBuild(cfg) or
cfg.editandcontinue == p.OFF
then
value = "ProgramDatabase"
else
value = "EditAndContinue"
end
end
if value then
m.element("DebugInformationFormat", nil, value)
end
end
function m.deploy(cfg)
if cfg.system == p.XBOX360 then
p.push('<Deploy>')
m.element("DeploymentType", nil, "CopyToHardDrive")
m.element("DvdEmulationType", nil, "ZeroSeekTimes")
m.element("DeploymentFiles", nil, "$(RemoteRoot)=$(ImagePath);")
p.pop('</Deploy>')
2013-03-07 17:14:03 +00:00
end
end
function m.enableEnhancedInstructionSet(cfg, condition)
2015-03-26 14:22:55 +00:00
local v
local x = cfg.vectorextensions
2015-03-26 14:22:55 +00:00
if x == "AVX" and _ACTION > "vs2010" then
v = "AdvancedVectorExtensions"
elseif x == "AVX2" and _ACTION > "vs2012" then
v = "AdvancedVectorExtensions2"
2015-05-19 00:54:02 +00:00
elseif cfg.architecture ~= "x86_64" then
if x == "SSE2" or x == "SSE3" or x == "SSSE3" or x == "SSE4.1" then
v = "StreamingSIMDExtensions2"
elseif x == "SSE" then
v = "StreamingSIMDExtensions"
end
end
2015-03-26 14:22:55 +00:00
if v then
m.element('EnableEnhancedInstructionSet', condition, v)
end
end
function m.entryPointSymbol(cfg)
2015-07-27 17:30:51 +00:00
if cfg.entrypoint then
m.element("EntryPointSymbol", nil, cfg.entrypoint)
else
if (cfg.kind == premake.CONSOLEAPP or cfg.kind == premake.WINDOWEDAPP) and
not cfg.flags.WinMain and
cfg.clr == p.OFF and
cfg.system ~= p.XBOX360
then
m.element("EntryPointSymbol", nil, "mainCRTStartup")
end
end
end
function m.exceptionHandling(cfg)
local value
if cfg.exceptionhandling == p.OFF then
m.element("ExceptionHandling", nil, "false")
elseif cfg.exceptionhandling == "SEH" then
m.element("ExceptionHandling", nil, "Async")
end
end
function m.excludedFromBuild(filecfg, condition)
if not filecfg or filecfg.flags.ExcludeFromBuild then
m.element("ExcludedFromBuild", condition, "true")
end
end
function m.extensionsToDeleteOnClean(cfg)
if #cfg.cleanextensions > 0 then
local value = table.implode(cfg.cleanextensions, "*", ";", "")
m.element("ExtensionsToDeleteOnClean", nil, value .. "$(ExtensionsToDeleteOnClean)")
end
end
function m.fileType(cfg, file)
m.element("FileType", nil, "Document")
end
function m.floatingPointModel(cfg)
if cfg.floatingpoint then
m.element("FloatingPointModel", nil, cfg.floatingpoint)
end
end
2015-06-08 18:06:18 +00:00
function m.inlineFunctionExpansion(cfg)
if cfg.inlining then
local types = {
Default = "Default",
Disabled = "Disabled",
Explicit = "OnlyExplicitInline",
2015-06-22 15:25:18 +00:00
Auto = "AnySuitable",
2015-06-08 18:06:18 +00:00
}
m.element("InlineFunctionExpansion", nil, types[cfg.inlining])
2015-06-08 18:06:18 +00:00
end
end
function m.forceIncludes(cfg, condition)
if #cfg.forceincludes > 0 then
local includes = vstudio.path(cfg, cfg.forceincludes)
if #includes > 0 then
m.element("ForcedIncludeFiles", condition, table.concat(includes, ';'))
end
end
2013-02-20 14:57:37 +00:00
if #cfg.forceusings > 0 then
local usings = vstudio.path(cfg, cfg.forceusings)
if #usings > 0 then
m.element("ForcedUsingFiles", condition, table.concat(usings, ';'))
end
2013-02-20 14:57:37 +00:00
end
end
function m.functionLevelLinking(cfg)
if config.isOptimizedBuild(cfg) then
m.element("FunctionLevelLinking", nil, "true")
end
end
function m.generateDebugInformation(cfg)
m.element("GenerateDebugInformation", nil, tostring(cfg.flags.Symbols ~= nil))
end
function m.generateManifest(cfg)
if cfg.flags.NoManifest then
m.element("GenerateManifest", nil, "false")
end
end
function m.generateMapFile(cfg)
if cfg.flags.Maps then
m.element("GenerateMapFile", nil, "true")
end
end
function m.ignoreDefaultLibraries(cfg)
if #cfg.ignoredefaultlibraries > 0 then
local ignored = cfg.ignoredefaultlibraries
for i = 1, #ignored do
-- Add extension if required
if not p.tools.msc.getLibraryExtensions()[ignored[i]:match("[^.]+$")] then
ignored[i] = path.appendextension(ignored[i], ".lib")
end
end
m.element("IgnoreSpecificDefaultLibraries", condition, table.concat(ignored, ';'))
end
end
function m.ignoreWarnDuplicateFilename(prj)
-- VS 2013 warns on duplicate file names, even those files which are
-- contained in different, mututally exclusive configurations. See:
-- http://connect.microsoft.com/VisualStudio/feedback/details/797460/incorrect-warning-msb8027-reported-for-files-excluded-from-build
-- Premake already adds unique object names to conflicting file names, so
-- just go ahead and disable that warning.
if _ACTION > "vs2012" then
m.element("IgnoreWarnCompileDuplicatedFilename", nil, "true")
end
end
function m.ignoreImportLibrary(cfg)
if cfg.kind == p.SHAREDLIB and cfg.flags.NoImportLib then
m.element("IgnoreImportLibrary", nil, "true")
end
end
function m.imageXex(cfg)
if cfg.system == p.XBOX360 then
p.push('<ImageXex>')
if cfg.configfile then
m.element("ConfigurationFile", nil, "%s", cfg.configfile)
else
p.w('<ConfigurationFile>')
p.w('</ConfigurationFile>')
end
p.w('<AdditionalSections>')
p.w('</AdditionalSections>')
p.pop('</ImageXex>')
2013-03-07 17:14:03 +00:00
end
end
function m.imageXexOutput(cfg)
if cfg.system == p.XBOX360 then
m.element("ImageXexOutput", nil, "%s", "$(OutDir)$(TargetName).xex")
2013-03-07 17:14:03 +00:00
end
end
function m.importExtensionTargets(prj)
p.w('<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.targets" />')
p.push('<ImportGroup Label="ExtensionTargets">')
for i = 1, #prj.rules do
local rule = p.global.getRule(prj.rules[i])
local loc = vstudio.path(prj, p.filename(rule, ".targets"))
p.x('<Import Project="%s" />', loc)
end
p.pop('</ImportGroup>')
end
function m.importDefaultProps(prj)
p.w('<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />')
end
function m.importExtensionSettings(prj)
p.w('<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props" />')
p.push('<ImportGroup Label="ExtensionSettings">')
for i = 1, #prj.rules do
local rule = p.global.getRule(prj.rules[i])
local loc = vstudio.path(prj, p.filename(rule, ".props"))
p.x('<Import Project="%s" />', loc)
end
p.pop('</ImportGroup>')
end
function m.importLibrary(cfg)
if cfg.kind == p.SHAREDLIB then
m.element("ImportLibrary", nil, "%s", path.translate(cfg.linktarget.relpath))
end
end
function m.includePath(cfg)
local dirs = vstudio.path(cfg, cfg.sysincludedirs)
if #dirs > 0 then
m.element("IncludePath", nil, "%s;$(IncludePath)", table.concat(dirs, ";"))
end
end
function m.intDir(cfg)
local objdir = vstudio.path(cfg, cfg.objdir)
m.element("IntDir", nil, "%s\\", objdir)
end
function m.intrinsicFunctions(cfg)
if config.isOptimizedBuild(cfg) then
m.element("IntrinsicFunctions", nil, "true")
end
end
function m.keyword(prj)
-- try to determine what kind of targets we're building here
local isWin, isManaged, isMakefile
for cfg in project.eachconfig(prj) do
if cfg.system == p.WINDOWS then
isWin = true
end
if cfg.clr ~= p.OFF then
isManaged = true
end
if vstudio.isMakefile(cfg) then
isMakefile = true
end
end
if isWin then
if isMakefile then
m.element("Keyword", nil, "MakeFileProj")
else
if isManaged then
m.targetFramework(prj)
m.element("Keyword", nil, "ManagedCProj")
else
m.element("Keyword", nil, "Win32Proj")
end
m.element("RootNamespace", nil, "%s", prj.name)
end
end
end
function m.libraryPath(cfg)
local dirs = vstudio.path(cfg, cfg.syslibdirs)
if #dirs > 0 then
m.element("LibraryPath", nil, "%s;$(LibraryPath)", table.concat(dirs, ";"))
end
end
function m.linkIncremental(cfg)
if cfg.kind ~= p.STATICLIB then
m.element("LinkIncremental", nil, "%s", tostring(config.canLinkIncremental(cfg)))
end
end
function m.linkLibraryDependencies(cfg, explicit)
-- Left to its own devices, VS will happily link against a project dependency
-- that has been excluded from the build. As a workaround, disable dependency
-- linking and list all siblings explicitly
if explicit then
p.push('<ProjectReference>')
m.element("LinkLibraryDependencies", nil, "false")
p.pop('</ProjectReference>')
end
end
function m.minimalRebuild(cfg)
if config.isOptimizedBuild(cfg) or
cfg.flags.NoMinimalRebuild or
cfg.flags.MultiProcessorCompile or
cfg.debugformat == p.C7
then
m.element("MinimalRebuild", nil, "false")
end
end
function m.moduleDefinitionFile(cfg)
local df = config.findfile(cfg, ".def")
if df then
m.element("ModuleDefinitionFile", nil, "%s", df)
end
end
function m.multiProcessorCompilation(cfg)
if cfg.flags.MultiProcessorCompile then
m.element("MultiProcessorCompilation", nil, "true")
end
end
function m.nmakeCommandLine(cfg, commands, phase)
if #commands > 0 then
commands = os.translateCommands(commands, p.WINDOWS)
commands = table.concat(p.esc(commands), p.eol())
p.w('<NMake%sCommandLine>%s</NMake%sCommandLine>', phase, commands, phase)
end
end
function m.nmakeOutDirs(cfg)
if vstudio.isMakefile(cfg) then
m.outDir(cfg)
m.intDir(cfg)
end
end
function m.nmakeOutput(cfg)
m.element("NMakeOutput", nil, "$(OutDir)%s", cfg.buildtarget.name)
end
function m.objectFileName(fcfg)
if fcfg.objname ~= fcfg.basename then
m.element("ObjectFileName", m.condition(fcfg.config), "$(IntDir)\\%s.obj", fcfg.objname)
end
end
function m.omitDefaultLib(cfg)
if cfg.flags.OmitDefaultLibrary then
m.element("OmitDefaultLibName", nil, "true")
end
end
function m.omitFramePointers(cfg)
if cfg.flags.NoFramePointer then
m.element("OmitFramePointers", nil, "true")
end
end
function m.optimizeReferences(cfg)
if config.isOptimizedBuild(cfg) then
m.element("EnableCOMDATFolding", nil, "true")
m.element("OptimizeReferences", nil, "true")
end
end
function m.optimization(cfg, condition)
local map = { Off="Disabled", On="Full", Debug="Disabled", Full="Full", Size="MinSpace", Speed="MaxSpeed" }
local value = map[cfg.optimize]
if value or not condition then
m.element('Optimization', condition, value or "Disabled")
end
end
function m.outDir(cfg)
local outdir = vstudio.path(cfg, cfg.buildtarget.directory)
m.element("OutDir", nil, "%s\\", outdir)
end
function m.outputFile(cfg)
if cfg.system == p.XBOX360 then
m.element("OutputFile", nil, "$(OutDir)%s", cfg.buildtarget.name)
end
end
2015-03-25 16:47:05 +00:00
function m.executablePath(cfg)
local dirs = vstudio.path(cfg, cfg.bindirs)
2015-03-25 16:47:05 +00:00
if #dirs > 0 then
m.element("ExecutablePath", nil, "%s;$(ExecutablePath)", table.concat(dirs, ";"))
2015-03-25 16:47:05 +00:00
end
end
function m.platformToolset(cfg)
local tool, version = p.config.toolset(cfg)
if version then
version = "v" .. version
else
local action = p.action.current()
version = action.vstudio.platformToolset
end
if version then
-- should only be written if there is a C/C++ file in the config
for i = 1, #cfg.files do
if path.iscppfile(cfg.files[i]) then
m.element("PlatformToolset", nil, version)
break
end
end
end
end
function m.precompiledHeader(cfg, condition)
prjcfg, filecfg = p.config.normalize(cfg)
if filecfg then
if prjcfg.pchsource == filecfg.abspath and not prjcfg.flags.NoPCH then
m.element('PrecompiledHeader', condition, 'Create')
elseif filecfg.flags.NoPCH then
m.element('PrecompiledHeader', condition, 'NotUsing')
end
else
if not prjcfg.flags.NoPCH and prjcfg.pchheader then
m.element("PrecompiledHeader", nil, "Use")
m.element("PrecompiledHeaderFile", nil, "%s", prjcfg.pchheader)
else
m.element("PrecompiledHeader", nil, "NotUsing")
end
end
end
function m.preprocessorDefinitions(cfg, defines, escapeQuotes, condition)
if #defines > 0 then
defines = table.concat(defines, ";")
if escapeQuotes then
defines = defines:gsub('"', '\\"')
end
defines = p.esc(defines) .. ";%%(PreprocessorDefinitions)"
m.element('PreprocessorDefinitions', condition, defines)
end
end
function m.undefinePreprocessorDefinitions(cfg, undefines, escapeQuotes, condition)
if #undefines > 0 then
undefines = table.concat(undefines, ";")
if escapeQuotes then
undefines = undefines:gsub('"', '\\"')
end
undefines = p.esc(undefines) .. ";%%(UndefinePreprocessorDefinitions)"
m.element('UndefinePreprocessorDefinitions', condition, undefines)
end
end
function m.programDataBaseFileName(cfg)
2015-08-01 01:17:00 +00:00
if cfg.debugformat ~= "c7" and cfg.flags.Symbols then
p.w('<ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>')
end -- end if
end
function m.projectGuid(prj)
m.element("ProjectGuid", nil, "{%s}", prj.uuid)
end
function m.projectName(prj)
if prj.name ~= prj.filename then
m.element("ProjectName", nil, "%s", prj.name)
end
end
function m.propertyGroup(cfg, label)
local cond
if cfg then
cond = string.format(' %s', m.condition(cfg))
end
if label then
label = string.format(' Label="%s"', label)
end
p.push('<PropertyGroup%s%s>', cond or "", label or "")
end
function m.propertySheets(cfg)
p.push('<ImportGroup Label="PropertySheets" %s>', m.condition(cfg))
p.w('<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists(\'$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\')" Label="LocalAppDataPlatform" />')
p.pop('</ImportGroup>')
end
function m.propertySheetGroup(prj)
for cfg in project.eachconfig(prj) do
m.propertySheets(cfg)
end
end
function m.referenceCopyLocalSatelliteAssemblies(prj, ref)
m.element("CopyLocalSatelliteAssemblies", nil, "false")
end
function m.referenceLinkLibraryDependencies(prj, ref)
m.element("LinkLibraryDependencies", nil, "true")
end
function m.referenceOutputAssembly(prj, ref)
m.element("ReferenceOutputAssembly", nil, "true")
end
function m.referencePrivate(prj, ref)
m.element("Private", nil, "true")
end
function m.referenceProject(prj, ref)
m.element("Project", nil, "{%s}", ref.uuid)
end
function m.referenceUseLibraryDependences(prj, ref)
m.element("UseLibraryDependencyInputs", nil, "false")
end
function m.resourceAdditionalIncludeDirectories(cfg)
m.additionalIncludeDirectories(cfg, table.join(cfg.includedirs, cfg.resincludedirs))
end
function m.resourcePreprocessorDefinitions(cfg)
m.preprocessorDefinitions(cfg, table.join(cfg.defines, cfg.resdefines), true)
end
function m.runtimeLibrary(cfg)
local runtimes = {
2015-06-10 23:26:51 +00:00
StaticDebug = "MultiThreadedDebug",
StaticRelease = "MultiThreaded",
}
local runtime = runtimes[config.getruntime(cfg)]
if runtime then
m.element("RuntimeLibrary", nil, runtime)
end
end
function m.callingConvention(cfg)
if cfg.callingconvention then
m.element("CallingConvention", nil, cfg.callingconvention)
end
end
function m.runtimeTypeInfo(cfg)
if cfg.rtti == p.OFF and cfg.clr == p.OFF then
m.element("RuntimeTypeInfo", nil, "false")
elseif cfg.rtti == p.ON then
m.element("RuntimeTypeInfo", nil, "true")
end
end
function m.bufferSecurityCheck(cfg)
if cfg.flags.NoBufferSecurityCheck then
m.element("BufferSecurityCheck", nil, "false")
end
end
function m.stringPooling(cfg)
if config.isOptimizedBuild(cfg) then
m.element("StringPooling", nil, "true")
end
end
function m.subSystem(cfg)
if cfg.system ~= p.XBOX360 then
local subsystem = iif(cfg.kind == p.CONSOLEAPP, "Console", "Windows")
m.element("SubSystem", nil, subsystem)
2013-03-07 17:14:03 +00:00
end
end
function m.targetExt(cfg)
local ext = cfg.buildtarget.extension
if ext ~= "" then
m.element("TargetExt", nil, "%s", ext)
else
p.w('<TargetExt>')
p.w('</TargetExt>')
end
end
function m.targetName(cfg)
m.element("TargetName", nil, "%s%s", cfg.buildtarget.prefix, cfg.buildtarget.basename)
end
function m.treatLinkerWarningAsErrors(cfg)
if cfg.flags.FatalLinkWarnings then
local el = iif(cfg.kind == p.STATICLIB, "Lib", "Linker")
m.element("Treat" .. el .. "WarningAsErrors", nil, "true")
end
end
function m.treatWChar_tAsBuiltInType(cfg)
local map = { On = "true", Off = "false" }
local value = map[cfg.nativewchar]
if value then
m.element("TreatWChar_tAsBuiltInType", nil, value)
end
end
function m.treatWarningAsError(cfg)
if cfg.flags.FatalCompileWarnings and cfg.warnings ~= p.OFF then
m.element("TreatWarningAsError", nil, "true")
end
end
function m.disableSpecificWarnings(cfg, condition)
if #cfg.disablewarnings > 0 then
local warnings = table.concat(cfg.disablewarnings, ";")
warnings = p.esc(warnings) .. ";%%(DisableSpecificWarnings)"
m.element('DisableSpecificWarnings', condition, warnings)
end
end
2015-03-26 14:22:55 +00:00
function m.treatSpecificWarningsAsErrors(cfg, condition)
if #cfg.fatalwarnings > 0 then
local fatal = table.concat(cfg.fatalwarnings, ";")
fatal = p.esc(fatal) .. ";%%(TreatSpecificWarningsAsErrors)"
m.element('TreatSpecificWarningsAsErrors', condition, fatal)
end
end
function m.useDebugLibraries(cfg)
local runtime = config.getruntime(cfg)
m.element("UseDebugLibraries", nil, tostring(runtime:endswith("Debug")))
end
function m.useOfMfc(cfg)
if cfg.flags.MFC then
m.element("UseOfMfc", nil, iif(cfg.flags.StaticRuntime, "Static", "Dynamic"))
end
end
function m.useOfAtl(cfg)
2014-02-27 15:47:43 +00:00
if cfg.atl then
m.element("UseOfATL", nil, cfg.atl)
2014-02-27 12:47:51 +00:00
end
end
function m.userMacros(cfg)
p.w('<PropertyGroup Label="UserMacros" />')
end
function m.warningLevel(cfg)
local map = { Off = "TurnOffAllWarnings", Extra = "Level4" }
m.element("WarningLevel", nil, "%s", map[cfg.warnings] or "Level3")
end
function m.xmlDeclaration()
p.xmlUtf8()
end
---------------------------------------------------------------------------
--
-- Support functions
--
---------------------------------------------------------------------------
--
-- Format and return a Visual Studio Condition attribute.
--
function m.condition(cfg)
return string.format('Condition="\'$(Configuration)|$(Platform)\'==\'%s\'"', p.esc(vstudio.projectConfig(cfg)))
end
--
-- Output an individual project XML element, with an optional configuration
-- condition.
--
-- @param depth
-- How much to indent the element.
-- @param name
-- The element name.
-- @param condition
-- An optional configuration condition, formatted with vc2010.condition().
-- @param value
-- The element value, which may contain printf formatting tokens.
-- @param ...
-- Optional additional arguments to satisfy any tokens in the value.
--
function m.element(name, condition, value, ...)
if select('#',...) == 0 then
value = p.esc(value)
end
local format
if condition then
format = string.format('<%s %s>%s</%s>', name, condition, value, name)
else
format = string.format('<%s>%s</%s>', name, value, name)
end
p.x(format, ...)
end