-- -- vs2010_vcxproj.lua -- Generate a Visual Studio 201x C/C++ project. -- Copyright (c) 2009-2014 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 { 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) io.utf8() m.xmlDeclaration() m.project() p.callArray(m.elements.project, prj) p.out('') end -- -- Output the XML declaration and opening tag. -- function m.project() local action = premake.action.current() p.push('', 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(1,'') 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 _x(2,'', vstudio.projectConfig(cfg, arch)) _x(3,'%s', vstudio.projectPlatform(cfg)) _p(3,'%s', arch) _p(2,'') end end end _p(1,'') end -- -- Write out the TargetFrameworkVersion property. -- function m.targetFramework(prj) local action = premake.action.current() local tools = string.format(' ToolsVersion="%s"', action.vstudio.toolsVersion) local framework = prj.framework or action.vstudio.targetFramework or "4.0" _p(2,'v%s', 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(1,'') 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(1,'') 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.imageXexOutput, m.generateManifest, m.extensionsToDeleteOnClean, } end end function m.outputProperties(cfg) if not vstudio.isMakefile(cfg) then m.propertyGroup(cfg) p.callArray(m.elements.outputProperties, cfg) _p(1,'') 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(1,'') 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, } end end function m.itemDefinitionGroup(cfg) if not vstudio.isMakefile(cfg) then p.push('', m.condition(cfg)) p.callArray(m.elements.itemDefinitionGroup, cfg) p.pop('') else if cfg == project.getfirstconfig(cfg.project) then p.w('') p.w('') end end end function m.itemDefinitionGroups(prj) for cfg in project.eachconfig(prj) do m.itemDefinitionGroup(cfg) end end -- -- Write the the 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, m.enableEnhancedInstructionSet, m.multiProcessorCompilation, m.additionalCompileOptions, m.compileAs, } end function m.clCompile(cfg) p.push('') p.callArray(m.elements.clCompile, cfg) p.pop('') 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 ~= premake.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('') p.outln(contents) p.pop('') end 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.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('') p.outln(contents) p.pop('') 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('') p.outln(contents) p.pop('') end end -- -- Write the manifest section. -- function m.manifest(cfg) -- no additional manifests in static lib if cfg.kind == premake.STATICLIB then return end -- 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 -- when a project is not using manifest files, visual studio doesn't write the section. if #manifests == 0 then return end p.push('') m.element("AdditionalManifestFiles", nil, "%s %%(AdditionalManifestFiles)", table.concat(manifests, " ")) p.pop('') 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(2,'<%s>', name) _x(3,'%s', table.implode(steps, "", "", "\r\n")) if msg then _x(3,'%s', msg) end _p(2,'', 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 value = p.rule.getPropertyString(rule, prop, value) 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('', 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") if #refs > 0 then _p(1,'') table.foreachi(refs, function(value) -- 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 _x(2,'', path.getbasename(value)) _x(3,'%s', path.translate(value)) _p(2,'') else _x(2,'', path.getbasename(value)) end end) _p(1,'') end end --- -- Write out the list of source code files, and any associated configuration. --- m.elements.fileGroups = { "clInclude", "clCompile", "none", "resourceCompile", "customBuild", "customRule" } m.elements.files = function(prj, groups) local calls = {} for i, group in ipairs(m.elements.fileGroups) do calls[i] = m[group .. "Files"] end return calls end function m.files(prj) -- Categorize the source files in groups by build rule; each will -- be written to a separate item group by one of the handlers local groups = m.categorizeSources(prj) p.callArray(m.elements.files, prj, groups) end function m.clCompileFiles(prj, group) local files = group.ClCompile or {} if #files > 0 then p.push('') for _, file in ipairs(files) do local contents = p.capture(function () p.push() for cfg in project.eachconfig(prj) do local fcfg = fileconfig.getconfig(file, cfg) m.excludedFromBuild(cfg, fcfg) if fcfg then local condition = m.condition(cfg) m.objectFileName(fcfg) m.clCompilePreprocessorDefinitions(fcfg, condition) m.clCompileUndefinePreprocessorDefinitions(fcfg, condition) m.optimization(fcfg, condition) m.forceIncludes(fcfg, condition) m.precompiledHeader(cfg, fcfg, condition) m.enableEnhancedInstructionSet(fcfg, condition) m.additionalCompileOptions(fcfg, condition) m.disableSpecificWarnings(fcfg, condition) m.treatSpecificWarningsAsErrors(fcfg, condition) end end p.pop() end) if #contents > 0 then p.push('', path.translate(file.relpath)) p.outln(contents) p.pop('') else p.x('', path.translate(file.relpath)) end end p.pop('') end end function m.clIncludeFiles(prj, groups) local files = groups.ClInclude or {} if #files > 0 then p.push('') for i, file in ipairs(files) do p.x('', path.translate(file.relpath)) end p.pop('') end end function m.customBuildFiles(prj, groups) local files = groups.CustomBuild or {} if #files > 0 then p.push('') for _, file in ipairs(files) do p.push('', path.translate(file.relpath)) p.w('Document') for cfg in project.eachconfig(prj) do local condition = m.condition(cfg) local filecfg = fileconfig.getconfig(file, cfg) if fileconfig.hasCustomBuildRule(filecfg) then m.excludedFromBuild(cfg, filecfg) local commands = os.translateCommands(filecfg.buildcommands, p.WINDOWS) commands = table.concat(commands,'\r\n') m.element("Command", condition, '%s', commands) local outputs = project.getrelative(prj, filecfg.buildoutputs) m.element("Outputs", condition, '%s', table.concat(outputs, ";")) if filecfg.buildmessage then m.element("Message", condition, '%s', filecfg.buildmessage) end if filecfg.buildinputs and #filecfg.buildinputs > 0 then local inputs = project.getrelative(prj, filecfg.buildinputs) m.element("AdditionalInputs", condition, '%s', table.concat(inputs, ";")) end end end p.pop('') end p.pop('') 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('') 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('', rule.name) else p.x('<%s Include=\"%s\" />', rule.name, path.translate(file.relpath)) end end p.pop('') end end end function m.noneFiles(prj, groups) local files = groups.None or {} if #files > 0 then p.push('') for i, file in ipairs(files) do p.x('', path.translate(file.relpath)) end p.pop('') end end function m.resourceCompileFiles(prj, groups) local files = groups.ResourceCompile or {} if #files > 0 then p.push('') for i, file in ipairs(files) do local contents = p.capture(function () p.push() for cfg in project.eachconfig(prj) do local condition = m.condition(cfg) local filecfg = fileconfig.getconfig(file, cfg) if cfg.system == premake.WINDOWS then m.excludedFromBuild(cfg, filecfg) end end p.pop() end) if #contents > 0 then p.push('', path.translate(file.relpath)) p.outln(contents) p.pop('') else p.x('', path.translate(file.relpath)) end end p.pop('') end end function m.categorize(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" else return "None" 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.categorize(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 -- -- 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('') for _, ref in ipairs(refs) do local relpath = project.getrelative(prj, vstudio.projectfile(ref)) p.push('', path.translate(relpath)) p.callArray(m.elements.projectReferences, prj, ref) p.pop('') end p.pop('') end end --------------------------------------------------------------------------- -- -- Handlers for individual project elements -- --------------------------------------------------------------------------- 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, ";")) p.x('%s;%%(AdditionalDependencies)', links) end end function m.additionalIncludeDirectories(cfg, includedirs) if #includedirs > 0 then local dirs = project.getrelative(cfg.project, includedirs) dirs = path.translate(table.concat(dirs, ";")) p.x('%s;%%(AdditionalIncludeDirectories)', dirs) end end function m.additionalLibraryDirectories(cfg) if #cfg.libdirs > 0 then local dirs = project.getrelative(cfg.project, cfg.libdirs) dirs = path.translate(table.concat(dirs, ";")) _x(3,'%s;%%(AdditionalLibraryDirectories)', dirs) end end function m.additionalUsingDirectories(cfg) if #cfg.usingdirs > 0 then local dirs = project.getrelative(cfg.project, cfg.usingdirs) dirs = path.translate(table.concat(dirs, ";")) p.x('%s;%%(AdditionalUsingDirectories)', dirs) end 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, " ") _x(3, '%s %%(AdditionalOptions)', opts) end end function m.basicRuntimeChecks(cfg) if cfg.flags.NoRuntimeChecks then p.w('Default') end end function m.characterSet(cfg) if not vstudio.isMakefile(cfg) then _p(2,'%s', iif(cfg.flags.Unicode, "Unicode", "MultiByte")) end end function m.wholeProgramOptimization(cfg) if cfg.flags.LinkTimeOptimization then _p(2,'true') end end function m.clCompileAdditionalIncludeDirectories(cfg) m.additionalIncludeDirectories(cfg, cfg.includedirs) end function m.clCompileAdditionalUsingDirectories(cfg) m.additionalUsingDirectories(cfg, cfg.usingdirs) 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 p.w('%s', value) end end function m.compileAs(cfg) if cfg.project.language == "C" then _p(3,'CompileAsC') end end function m.configurationType(cfg) local types = { SharedLib = "DynamicLibrary", StaticLib = "StaticLibrary", ConsoleApp = "Application", WindowedApp = "Application", Makefile = "Makefile", None = "Makefile", Utility = "Utility", } _p(2,'%s', types[cfg.kind]) end function m.culture(cfg) local value = vstudio.cultureForLocale(cfg.locale) if value then p.w('0x%04x', value) end end function m.debugInformationFormat(cfg) local value if cfg.flags.Symbols then if cfg.debugformat == "c7" then value = "OldStyle" elseif cfg.architecture == "x64" or cfg.clr ~= p.OFF or config.isOptimizedBuild(cfg) or not cfg.editAndContinue then value = "ProgramDatabase" else value = "EditAndContinue" end end if value then p.w('%s', value) end end function m.deploy(cfg) if cfg.system == premake.XBOX360 then _p(2,'') _p(3,'CopyToHardDrive') _p(3,'ZeroSeekTimes') _p(3,'$(RemoteRoot)=$(ImagePath);') _p(2,'') end end function m.enableEnhancedInstructionSet(cfg, condition) local value local x = cfg.vectorextensions if _ACTION > "vc2010" and x == "AVX" then value = "AdvancedVectorExtensions" elseif x == "SSE2" then value = "StreamingSIMDExtensions2" elseif x == "SSE" then value = "StreamingSIMDExtensions" end if value then m.element('EnableEnhancedInstructionSet', condition, value) end end function m.entryPointSymbol(cfg) if (cfg.kind == premake.CONSOLEAPP or cfg.kind == premake.WINDOWEDAPP) and not cfg.flags.WinMain and cfg.clr == p.OFF and cfg.system ~= premake.XBOX360 then _p(3,'mainCRTStartup') end end function m.exceptionHandling(cfg) if cfg.flags.NoExceptions then p.w('false') elseif cfg.flags.SEH then p.w('Async') end end function m.excludedFromBuild(cfg, filecfg) if not filecfg or filecfg.flags.ExcludeFromBuild then m.element("ExcludedFromBuild", m.condition(cfg), "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.floatingPointModel(cfg) if cfg.floatingpoint then p.w('%s', cfg.floatingpoint) end end function m.forceIncludes(cfg, condition) if #cfg.forceincludes > 0 then local includes = path.translate(project.getrelative(cfg.project, cfg.forceincludes)) m.element("ForcedIncludeFiles", condition, table.concat(includes, ';')) end if #cfg.forceusings > 0 then local usings = path.translate(project.getrelative(cfg.project, cfg.forceusings)) m.element("ForcedUsingFiles", condition, table.concat(usings, ';')) end end function m.functionLevelLinking(cfg) if config.isOptimizedBuild(cfg) then p.w('true') end end function m.generateDebugInformation(cfg) _p(3,'%s', tostring(cfg.flags.Symbols ~= nil)) end function m.generateManifest(cfg) if cfg.flags.NoManifest then _p(2,'false') end end function m.generateMapFile(cfg) if cfg.flags.Maps then _p(3,'true') 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 p.w('true') end end function m.ignoreImportLibrary(cfg) if cfg.kind == premake.SHAREDLIB and cfg.flags.NoImportLib then _p(2,'true'); end end function m.imageXex(cfg) if cfg.system == premake.XBOX360 then _p(2,'') if cfg.configFile then _p(3,'%s', cfg.configFile) else _p(3,'') _p(3,'') end _p(3,'') _p(3,'') _p(2,'') end end function m.imageXexOutput(cfg) if cfg.system == premake.XBOX360 then _x(2,'$(OutDir)$(TargetName).xex') end end function m.importExtensionTargets(prj) p.w('') p.push('') for i = 1, #prj.rules do local rule = p.global.getRule(prj.rules[i]) local loc = project.getrelative(prj, premake.filename(rule, ".targets")) p.x('', path.translate(loc)) end p.pop('') end function m.importDefaultProps(prj) _p(1,'') end function m.importExtensionSettings(prj) p.w('') p.push('') for i = 1, #prj.rules do local rule = p.global.getRule(prj.rules[i]) local loc = project.getrelative(prj, premake.filename(rule, ".props")) p.x('', path.translate(loc)) end p.pop('') end function m.importLibrary(cfg) if cfg.kind == premake.SHAREDLIB then _x(3,'%s', path.translate(cfg.linktarget.relpath)) end end function m.intDir(cfg) local objdir = project.getrelative(cfg.project, cfg.objdir) _x(2,'%s\\', path.translate(objdir)) end function m.intrinsicFunctions(cfg) if config.isOptimizedBuild(cfg) then p.w('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 == premake.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 _p(2,'MakeFileProj') else if isManaged then m.targetFramework(prj) _p(2,'ManagedCProj') else _p(2,'Win32Proj') end _p(2,'%s', prj.name) end end end function m.linkIncremental(cfg) if cfg.kind ~= premake.STATICLIB then _p(2,'%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(2,'') _p(3,'false') _p(2,'') end end function m.minimalRebuild(cfg) if config.isOptimizedBuild(cfg) or cfg.flags.NoMinimalRebuild or cfg.flags.MultiProcessorCompile or cfg.debugformat == premake.C7 then p.w('false') end end function m.moduleDefinitionFile(cfg) local df = config.findfile(cfg, ".def") if df then _p(3,'%s', df) end end function m.multiProcessorCompilation(cfg) if cfg.flags.MultiProcessorCompile then p.w('true') end end function m.nmakeCommandLine(cfg, commands, phase) if #commands > 0 then commands = os.translateCommands(commands, p.WINDOWS) commands = table.concat(premake.esc(commands), p.eol()) _p(2, '%s', 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) _p(2,'$(OutDir)%s', cfg.buildtarget.name) end function m.objectFileName(fcfg) if fcfg.objname ~= fcfg.basename then p.w('$(IntDir)\\%s.obj', m.condition(fcfg.config), fcfg.objname) end end function m.omitDefaultLib(cfg) if cfg.flags.OmitDefaultLibrary then p.w('true') end end function m.omitFramePointers(cfg) if cfg.flags.NoFramePointer then p.w('true') end end function m.optimizeReferences(cfg) if config.isOptimizedBuild(cfg) then _p(3,'true') _p(3,'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 = project.getrelative(cfg.project, cfg.buildtarget.directory) _x(2,'%s\\', path.translate(outdir)) end function m.outputFile(cfg) if cfg.system == premake.XBOX360 then _p(2,'$(OutDir)%s', cfg.buildtarget.name) end end function m.platformToolset(cfg) local map = { vs2012 = "v110", vs2013 = "v120" } local value = map[_ACTION] if value 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 _p(2,'%s', value) return end end end end function m.precompiledHeader(cfg, filecfg, condition) if filecfg then if cfg.pchsource == filecfg.abspath and not cfg.flags.NoPCH then m.element('PrecompiledHeader', condition, 'Create') elseif filecfg.flags.NoPCH then m.element('PrecompiledHeader', condition, 'NotUsing') end else if not cfg.flags.NoPCH and cfg.pchheader then p.w('Use') p.x('%s', cfg.pchheader) else p.w('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 = premake.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 = premake.esc(undefines) .. ";%%(UndefinePreprocessorDefinitions)" m.element('UndefinePreprocessorDefinitions', condition, undefines) end end function m.programDataBaseFileName(cfg) -- just a placeholder for overriding; will use the default VS name end function m.projectGuid(prj) _p(2,'{%s}', prj.uuid) end function m.projectName(prj) if prj.name ~= prj.filename then _x(2,'%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(1,'', cond or "", label or "") end function m.propertySheets(cfg) _p(1,'', m.condition(cfg)) _p(2,'') _p(1,'') end function m.propertySheetGroup(prj) for cfg in project.eachconfig(prj) do m.propertySheets(cfg) end end function m.referenceCopyLocalSatelliteAssemblies(prj, ref) p.w('false') end function m.referenceLinkLibraryDependencies(prj, ref) p.w('true') end function m.referenceOutputAssembly(prj, ref) p.w('true') end function m.referencePrivate(prj, ref) p.w('true') end function m.referenceProject(prj, ref) p.w('{%s}', ref.uuid) end function m.referenceUseLibraryDependences(prj, ref) p.w('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 = { StaticDebug = "MultiThreadedDebug", StaticRelease = "MultiThreaded", } local runtime = runtimes[config.getruntime(cfg)] if runtime then p.w('%s', runtime) end end function m.runtimeTypeInfo(cfg) if cfg.flags.NoRTTI and cfg.clr == p.OFF then _p(3,'false') end end function m.bufferSecurityCheck(cfg) if cfg.flags.NoBufferSecurityCheck then p.w('false') end end function m.stringPooling(cfg) if config.isOptimizedBuild(cfg) then p.w('true') end end function m.subSystem(cfg) if cfg.system ~= premake.XBOX360 then local subsystem = iif(cfg.kind == premake.CONSOLEAPP, "Console", "Windows") _p(3,'%s', subsystem) end end function m.targetExt(cfg) local ext = cfg.buildtarget.extension if ext ~= "" then _x(2,'%s', ext) else _p(2,'') _p(2,'') end end function m.targetName(cfg) _x(2,'%s%s', cfg.buildtarget.prefix, cfg.buildtarget.basename) end function m.treatLinkerWarningAsErrors(cfg) if cfg.flags.FatalLinkWarnings then local el = iif(cfg.kind == premake.STATICLIB, "Lib", "Linker") _p(3,'true', el, el) end end function m.treatWChar_tAsBuiltInType(cfg) local map = { On = "true", Off = "false" } local value = map[cfg.nativewchar] if value then p.w('%s', value) end end function m.treatWarningAsError(cfg) if cfg.flags.FatalCompileWarnings and cfg.warnings ~= p.OFF then p.w('true') end end function m.disableSpecificWarnings(cfg, condition) if #cfg.disablewarnings > 0 then local warnings = table.concat(cfg.disablewarnings, ";") warnings = premake.esc(warnings) .. ";%%(DisableSpecificWarnings)" m.element('DisableSpecificWarnings', condition, warnings) end end function m.treatSpecificWarningsAsErrors(cfg, condition) if #cfg.fatalwarnings > 0 then local fatal = table.concat(cfg.fatalwarnings, ";") fatal = premake.esc(fatal) .. ";%%(TreatSpecificWarningsAsErrors)" m.element('TreatSpecificWarningsAsErrors', condition, fatal) end end function m.useDebugLibraries(cfg) local runtime = config.getruntime(cfg) _p(2,'%s', tostring(runtime:endswith("Debug"))) end function m.useOfMfc(cfg) if cfg.flags.MFC then _p(2,'%s', iif(cfg.flags.StaticRuntime, "Static", "Dynamic")) end end function m.useOfAtl(cfg) if cfg.atl then _p(2,'%s', cfg.atl) end end function m.userMacros(cfg) _p(1,'') 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\'"', premake.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 = premake.esc(value) end local format if condition then format = string.format('<%s %s>%s', name, condition, value, name) else format = string.format('<%s>%s', name, value, name) end p.x(format, ...) end