-- -- vs200x_vcproj.lua -- Generate a Visual Studio 2002-2008 C/C++ project. -- Copyright (c) 2009-2014 Jason Perkins and the Premake project -- premake.vstudio.vc200x = {} local m = premake.vstudio.vc200x local p = premake local vstudio = p.vstudio local context = p.context local project = p.project local config = p.config local fileconfig = p.fileconfig m.elements = {} --- -- Generate a Visual Studio 200x C++ or Makefile project. --- m.elements.project = function(prj) return { m.xmlElement, m.visualStudioProject, m.platforms, m.toolFiles, m.configurations, m.references, m.files, m.globals } end function m.generate(prj) p.indent("\t") p.callArray(m.elements.project, prj) p.pop('') end --- -- Write the opening element of the project file. -- In this case, the call list is for XML attributes rather than elements. --- m.elements.visualStudioProject = function(prj) return { m.projectType, m.version, m.projectName, m.projectGUID, m.rootNamespace, m.keyword, m.targetFrameworkVersion } end function m.visualStudioProject(prj) p.push('') end --- -- Write out the element group, enumerating each of the -- configuration-architecture pairings. --- function m.configurations(prj) p.push('') -- Visual Studio requires each configuration to be paired up with each -- architecture, even if the pairing doesn't make any sense (i.e. Win32 -- DLL DCRT|PS3). Start by building a map between configurations and -- their Visual Studio names. I will use this to determine which -- pairings are "real", and which need to be synthesized. local mapping = {} for cfg in project.eachconfig(prj) do local name = vstudio.projectConfig(cfg) mapping[cfg] = name mapping[name] = cfg end -- Now enumerate each configuration and architecture pairing for cfg in project.eachconfig(prj) do for i, arch in ipairs(architectures) do local target -- Generate a Visual Studio name from this pairing and see if -- it matches. If so, I can go ahead and output the markup for -- this configuration. local testName = vstudio.projectConfig(cfg, arch) if testName == mapping[cfg] then target = cfg -- Okay, this pairing doesn't match this configuration. Check -- the mapping to see if it matches some *other* configuration. -- If it does, I can ignore it as it will getting written on -- another pass through the loop. If it does not, then this is -- one of those fake configurations that I have to synthesize. elseif not mapping[testName] then target = { fake = true } end -- If I'm not ignoring this pairing, output the result now if target then m.configuration(target, testName) m.tools(target) p.pop('') end end end p.pop('') end --- -- Write out the element, describing a specific Premake -- build configuration/platform pairing. --- m.elements.configuration = function(cfg) if cfg.fake then return { m.intermediateDirectory, m.configurationType } else return { m.outputDirectory, m.intermediateDirectory, m.configurationType, m.useOfMFC, m.characterSet, m.managedExtensions, } end end function m.configuration(cfg, name) p.push('') end --- -- Return the list of tools required to build a specific configuration. -- Each tool gets represented by an XML element in the project file, all -- of which are implemented farther down in this file. -- -- @param cfg -- The configuration being written. --- m.elements.tools = function(cfg) if vstudio.isMakefile(cfg) and not cfg.fake then return { m.VCNMakeTool } end if cfg.system == p.XBOX360 then return { m.VCPreBuildEventTool, m.VCCustomBuildTool, m.VCXMLDataGeneratorTool, m.VCWebServiceProxyGeneratorTool, m.VCMIDLTool, m.VCCLCompilerTool, m.VCManagedResourceCompilerTool, m.VCResourceCompilerTool, m.VCPreLinkEventTool, m.VCLinkerTool, m.VCALinkTool, m.VCX360ImageTool, m.VCBscMakeTool, m.VCX360DeploymentTool, m.VCPostBuildEventTool, m.DebuggerTool, } else return { m.VCPreBuildEventTool, m.VCCustomBuildTool, m.VCXMLDataGeneratorTool, m.VCWebServiceProxyGeneratorTool, m.VCMIDLTool, m.VCCLCompilerTool, m.VCManagedResourceCompilerTool, m.VCResourceCompilerTool, m.VCPreLinkEventTool, m.VCLinkerTool, m.VCALinkTool, m.VCManifestTool, m.VCXDCMakeTool, m.VCBscMakeTool, m.VCFxCopTool, m.VCAppVerifierTool, m.VCPostBuildEventTool, } end end function m.tools(cfg) premake.callArray(m.elements.tools, cfg, config.toolset(cfg)) end --- -- Write out the element group. --- m.elements.references = function(prj) return { m.assemblyReferences, m.projectReferences, } end function m.references(prj) p.push('') p.callArray(m.elements.references, prj) p.pop('') end --- -- Write out the element group. --- function m.files(prj) local tr = m.filesSorted(prj) p.push('') p.tree.traverse(tr, { onbranchenter = m.filesFilterStart, onbranchexit = m.filesFilterEnd, onleaf = m.filesFile, }, false) p.pop('') end function m.filesSorted(prj) -- Fetch the source tree, sorted how Visual Studio likes it: alpha -- sorted, with any leading ../ sequences ignored. At the top level -- of the tree, files go after folders, otherwise before. return project.getsourcetree(prj, function(a,b) local istop = (a.parent.parent == nil) local aSortName = a.name local bSortName = b.name -- Only file nodes have a relpath field; folder nodes do not if a.relpath then if not b.relpath then return not istop end aSortName = a.relpath:gsub("%.%.%/", "") end if b.relpath then if not a.relpath then return istop end bSortName = b.relpath:gsub("%.%.%/", "") end return aSortName < bSortName end) end function m.filesFilterStart(node) p.push('') end function m.filesFilterEnd(node) p.pop('') end function m.filesFile(node) p.push('') local prj = node.project for cfg in project.eachconfig(prj) do m.fileConfiguration(cfg, node) end p.pop('') end m.elements.fileConfigurationAttributes = function(filecfg) return { m.excludedFromBuild, } end function m.fileConfiguration(cfg, node) local filecfg = fileconfig.getconfig(node, cfg) -- Generate the individual sections of the file configuration -- element and capture the results to a buffer. I will only -- write the file configuration if the buffers are not empty. local configAttribs = p.capture(function () p.push() p.callArray(m.elements.fileConfigurationAttributes, filecfg) p.pop() end) local compilerAttribs = p.capture(function () p.push() m.VCCLCompilerTool(filecfg) p.pop() end) -- lines() > 3 skips empty elements if #configAttribs > 0 or compilerAttribs:lines() > 3 then p.push(' 0 then p.outln(configAttribs) end p.w('>') p.outln(compilerAttribs) p.pop('') end end --- -- I don't do anything with globals yet, but here it is if you want to -- extend it. --- m.elements.globals = function(prj) return {} end function m.globals(prj) p.push('') p.callArray(m.elements.globals, prj) p.pop('') end --------------------------------------------------------------------------- -- -- Handlers for the individual tool sections of the project. -- -- There is a lot of repetition here; most of these tools are just -- placeholders for modules to override as needed. -- --------------------------------------------------------------------------- --- -- The implementation of a "normal" tool. Writes the opening tool element -- and name attribute, calls the corresponding function list, and then -- closes the element. -- -- @param name -- The name of the tool, e.g. "VCCustomBuildTool". -- @param ... -- Any additional arguments required by the call list. --- function m.VCTool(name, cfg, ...) p.push('') end ------------ m.elements.DebuggerTool = function(cfg) return {} end function m.DebuggerTool(cfg) p.push('') end ------------ m.elements.VCALinkTool = function(cfg) return {} end function m.VCALinkTool(cfg) m.VCTool("VCALinkTool", cfg) end ------------ m.elements.VCAppVerifierTool = function(cfg) return {} end function m.VCAppVerifierTool(cfg) if cfg.kind ~= p.STATICLIB then m.VCTool("VCAppVerifierTool", cfg) end end ------------ m.elements.VCBscMakeTool = function(cfg) return {} end function m.VCBscMakeTool(cfg) m.VCTool("VCBscMakeTool", cfg) end ------------ m.elements.VCCLCompilerTool = function(cfg, toolset) if not toolset then -- not a custom tool, use the standard set of attributes return { m.customBuildTool, m.objectFile, m.additionalCompilerOptions, m.optimization, m.additionalIncludeDirectories, m.wholeProgramOptimization, m.preprocessorDefinitions, m.minimalRebuild, m.basicRuntimeChecks, m.bufferSecurityCheck, m.stringPooling, m.exceptionHandling, m.runtimeLibrary, m.enableFunctionLevelLinking, m.enableEnhancedInstructionSet, m.floatingPointModel, m.runtimeTypeInfo, m.treatWChar_tAsBuiltInType, m.usePrecompiledHeader, m.programDataBaseFileName, m.warnings, m.debugInformationFormat, m.compileAs, m.forcedIncludeFiles, m.omitDefaultLib, } else -- custom tool, use subset of attributes return { m.additionalExternalCompilerOptions, m.additionalIncludeDirectories, m.preprocessorDefinitions, m.usePrecompiledHeader, m.programDataBaseFileName, m.debugInformationFormat, m.compileAs, m.forcedIncludeFiles, } end end function m.VCCLCompilerToolName(cfg) local prjcfg, filecfg = config.normalize(cfg) if filecfg and fileconfig.hasCustomBuildRule(filecfg) then return "VCCustomBuildTool" elseif prjcfg and prjcfg.system == p.XBOX360 then return "VCCLX360CompilerTool" else return "VCCLCompilerTool" end end function m.VCCLCompilerTool(cfg, toolset) m.VCTool("VCCLCompilerTool", cfg, toolset) end ------------ m.elements.VCCustomBuildTool = function(cfg) return {} end function m.VCCustomBuildTool(cfg) m.VCTool("VCCustomBuildTool", cfg) end ------------ m.elements.VCFxCopTool = function(cfg) return {} end function m.VCFxCopTool(cfg) m.VCTool("VCFxCopTool", cfg) end ------------ m.elements.VCLinkerTool = function(cfg, toolset) if cfg.kind ~= p.STATICLIB then return { m.linkLibraryDependencies, m.ignoreImportLibrary, m.additionalLinkerOptions, m.additionalDependencies, m.outputFile, m.linkIncremental, m.additionalLibraryDirectories, m.moduleDefinitionFile, m.generateManifest, m.generateDebugInformation, m.programDatabaseFile, m.subSystem, m.optimizeReferences, m.enableCOMDATFolding, m.entryPointSymbol, m.importLibrary, m.targetMachine, } else return { m.additionalLinkerOptions, m.additionalDependencies, m.outputFile, m.additionalLibraryDirectories, } end end function m.VCLinkerToolName(cfg) if cfg.kind == p.STATICLIB then return "VCLibrarianTool" elseif cfg.system == p.XBOX360 then return "VCX360LinkerTool" else return "VCLinkerTool" end end function m.VCLinkerTool(cfg, toolset) m.VCTool("VCLinkerTool", cfg, toolset) end ------------ m.elements.VCManagedResourceCompilerTool = function(cfg) return {} end function m.VCManagedResourceCompilerTool(cfg) m.VCTool("VCManagedResourceCompilerTool", cfg) end ------------ m.elements.VCManifestTool = function(cfg) return { m.additionalManifestFiles, } end function m.VCManifestTool(cfg) if cfg.kind ~= p.STATICLIB then m.VCTool("VCManifestTool", cfg) end end ------------ m.elements.VCMIDLTool = function(cfg) return { m.targetEnvironment } end function m.VCMIDLTool(cfg) m.VCTool("VCMIDLTool", cfg) end ------------ m.elements.VCNMakeTool = function(cfg) return { m.buildCommandLine, m.reBuildCommandLine, m.cleanCommandLine, m.output, m.preprocessorDefinitions, m.includeSearchPath, m.forcedIncludes, m.assemblySearchPath, m.forcedUsingAssemblies, m.compileAsManaged, } end function m.VCNMakeTool(cfg) m.VCTool("VCNMakeTool", cfg) end ------------ m.elements.VCBuildTool = function(cfg, stage) return { m.commandLine, } end function m.VCBuildToolName(cfg, stage) return "VC" .. stage .. "EventTool" end function m.VCPreBuildEventTool(cfg) m.VCTool("VCBuildTool", cfg, "PreBuild") end function m.VCPreLinkEventTool(cfg) m.VCTool("VCBuildTool", cfg, "PreLink") end function m.VCPostBuildEventTool(cfg) m.VCTool("VCBuildTool", cfg, "PostBuild") end ------------ m.elements.VCResourceCompilerTool = function(cfg) return { m.additionalResourceOptions, m.resourcePreprocessorDefinitions, m.additionalResourceIncludeDirectories, m.culture, } end function m.VCResourceCompilerTool(cfg) m.VCTool("VCResourceCompilerTool", cfg) end ------------ m.elements.VCWebServiceProxyGeneratorTool = function(cfg) return {} end function m.VCWebServiceProxyGeneratorTool(cfg) m.VCTool("VCWebServiceProxyGeneratorTool", cfg) end ------------ m.elements.VCX360DeploymentTool = function(cfg) return { m.deploymentType, m.additionalDeploymentOptions, } end function m.VCX360DeploymentTool(cfg) m.VCTool("VCX360DeploymentTool", cfg) end ------------ m.elements.VCX360ImageTool = function(cfg) return { m.additionalImageOptions, m.outputFileName, } end function m.VCX360ImageTool(cfg) m.VCTool("VCX360ImageTool", cfg) end ------------ m.elements.VCXDCMakeTool = function(cfg) return {} end function m.VCXDCMakeTool(cfg) m.VCTool("VCXDCMakeTool", cfg) end ------------ m.elements.VCXMLDataGeneratorTool = function(cfg) return {} end function m.VCXMLDataGeneratorTool(cfg) m.VCTool("VCXMLDataGeneratorTool", cfg) end --------------------------------------------------------------------------- -- -- EVERYTHING BELOW THIS NEEDS REWORK, which I'm in the process of -- doing right now. Hold on tight. -- --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- -- Support functions -- --------------------------------------------------------------------------- -- -- Build a list architectures which are used by a project. -- -- @param prj -- The project under consideration. -- @return -- An array of Visual Studio architectures. -- function m.architectures(prj) architectures = {} for cfg in project.eachconfig(prj) do local arch = vstudio.archFromConfig(cfg, true) if not table.contains(architectures, arch) then table.insert(architectures, arch) end end return architectures end -- -- Return the debugging symbol level for a configuration. -- function m.symbols(cfg) if not cfg.flags.Symbols then return 0 elseif cfg.debugformat == "c7" then return 1 else -- Edit-and-continue doesn't work for some configurations if cfg.flags.NoEditAndContinue or config.isOptimizedBuild(cfg) or cfg.flags.Managed or cfg.system == "x64" or cfg.platform == "x64" -- TODO: remove this when the _ng stuff goes live then return 3 else return 4 end end end --------------------------------------------------------------------------- -- -- Handlers for individual project elements -- --------------------------------------------------------------------------- function m.additionalCompilerOptions(cfg) local opts = cfg.buildoptions if cfg.flags.MultiProcessorCompile then table.insert(opts, "/MP") end if #opts > 0 then p.x('AdditionalOptions="%s"', table.concat(opts, " ")) end end function m.additionalDependencies(cfg, toolset) if #cfg.links == 0 then return end local ex = vstudio.needsExplicitLink(cfg) local links if not toolset then local scope = iif(ex, "all", "system") links = config.getlinks(cfg, scope, "fullpath") for i, link in ipairs(links) do if link:find(" ", 1, true) then link = '"' .. link .. '"' end links[i] = path.translate(link) end else links = toolset.getlinks(cfg, not ex) end if #links > 0 then p.x('AdditionalDependencies="%s"', table.concat(links, " ")) end end function m.additionalDeploymentOptions(cfg) if #cfg.deploymentoptions > 0 then p.x('AdditionalOptions="%s"', table.concat(cfg.deploymentoptions, " ")) end end function m.additionalExternalCompilerOptions(cfg, toolset) local buildoptions = table.join(toolset.getcflags(cfg), toolset.getcxxflags(cfg), cfg.buildoptions) if not cfg.flags.NoPCH and cfg.pchheader then table.insert(buildoptions, '--use_pch="$(IntDir)/$(TargetName).pch"') end if #buildoptions > 0 then p.x('AdditionalOptions="%s"', table.concat(buildoptions, " ")) end end function m.additionalImageOptions(cfg) if #cfg.imageoptions > 0 then p.x('AdditionalOptions="%s"', table.concat(cfg.imageoptions, " ")) end end function m.additionalIncludeDirectories(cfg) if #cfg.includedirs > 0 then local dirs = project.getrelative(cfg.project, cfg.includedirs) p.x('AdditionalIncludeDirectories="%s"', path.translate(table.concat(dirs, ";"))) end end function m.additionalLibraryDirectories(cfg) if #cfg.libdirs > 0 then local dirs = table.concat(project.getrelative(cfg.project, cfg.libdirs), ";") p.x('AdditionalLibraryDirectories="%s"', path.translate(dirs)) end end function m.additionalLinkerOptions(cfg, toolset) local flags = cfg.linkoptions if toolset then flags = table.join(toolset.getldflags(cfg), flags) end if #flags > 0 then p.x('AdditionalOptions="%s"', table.concat(flags, " ")) end end function m.additionalManifestFiles(cfg) local manifests = {} for i, 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.x('AdditionalManifestFiles="%s"', table.concat(manifests, ";")) end end function m.additionalResourceIncludeDirectories(cfg) local dirs = table.join(cfg.includedirs, cfg.resincludedirs) if #dirs > 0 then dirs = project.getrelative(cfg.project, dirs) p.x('AdditionalIncludeDirectories="%s"', path.translate(table.concat(dirs, ";"))) end end function m.additionalResourceOptions(cfg) if #cfg.resoptions > 0 then p.x('AdditionalOptions="%s"', table.concat(cfg.resoptions, " ")) end end function m.assemblyReferences(prj) -- Visual Studio doesn't support per-config references local cfg = project.getfirstconfig(prj) local refs = config.getlinks(cfg, "system", "fullpath", "managed") table.foreachi(refs, function(value) p.push('') end) end function m.assemblySearchPath(cfg) p.w('AssemblySearchPath=""') end function m.basicRuntimeChecks(cfg) local cfg, filecfg = config.normalize(cfg) if not filecfg and not config.isOptimizedBuild(cfg) and not cfg.flags.Managed and not cfg.flags.NoRuntimeChecks then p.w('BasicRuntimeChecks="3"') end end function m.bufferSecurityCheck(cfg) if cfg.flags.NoBufferSecurityCheck then p.w('BufferSecurityCheck="false"') end end function m.buildCommandLine(cfg) commands = table.concat(cfg.buildcommands, "\r\n") p.x('BuildCommandLine="%s"', commands) end function m.characterSet(cfg) if not vstudio.isMakefile(cfg) then p.w('CharacterSet="%s"', iif(cfg.flags.Unicode, 1, 2)) end end function m.cleanCommandLine(cfg) commands = table.concat(cfg.cleancommands, "\r\n") p.x('CleanCommandLine="%s"', commands) end function m.commandLine(cfg, stage) local field = stage:lower() local steps = cfg[field .. "commands"] local msg = cfg[field .. "message"] if #steps > 0 then if msg then p.x('Description="%s"', msg) end p.x('CommandLine="%s"', table.implode(steps, "", "", "\r\n")) end end function m.compileAs(cfg, toolset) local cfg, filecfg = config.normalize(cfg) local c = project.isc(cfg) if filecfg then if path.iscfile(filecfg.name) ~= c then if path.iscppfile(filecfg.name) then local value = iif(c, 2, 1) p.w('CompileAs="%s"', value) end end else local compileAs if toolset then compileAs = "0" elseif c then compileAs = "1" end if compileAs then p.w('CompileAs="%s"', compileAs) end end end function m.compileAsManaged(cfg) p.w('CompileAsManaged=""') end function m.configurationType(cfg) local cfgtypes = { Makefile = 0, None = 0, SharedLib = 2, StaticLib = 4, } p.w('ConfigurationType="%s"', cfgtypes[cfg.kind] or 1) end function m.culture(cfg) local value = vstudio.cultureForLocale(cfg.locale) if value then p.w('Culture="%d"', value) end end function m.customBuildTool(cfg) local cfg, filecfg = config.normalize(cfg) if filecfg and fileconfig.hasCustomBuildRule(filecfg) then p.x('CommandLine="%s"', table.concat(filecfg.buildcommands,'\r\n')) local outputs = project.getrelative(filecfg.project, filecfg.buildoutputs) p.x('Outputs="%s"', table.concat(outputs, ' ')) end end function m.debugInformationFormat(cfg, toolset) local prjcfg, filecfg = config.normalize(cfg) if not filecfg then local fmt = iif(toolset, "0", m.symbols(cfg)) p.w('DebugInformationFormat="%s"', fmt) end end function m.deploymentType(cfg) p.w('DeploymentType="0"') end function m.enableCOMDATFolding(cfg, toolset) if config.isOptimizedBuild(cfg) and not toolset then p.w('EnableCOMDATFolding="2"') end end function m.enableEnhancedInstructionSet(cfg) local map = { SSE = "1", SSE2 = "2" } local value = map[cfg.vectorextensions] if value and cfg.system ~= "Xbox360" and cfg.architecture ~= "x64" then p.w('EnableEnhancedInstructionSet="%d"', value) end end function m.enableFunctionLevelLinking(cfg) local cfg, filecfg = config.normalize(cfg) if not filecfg then p.w('EnableFunctionLevelLinking="true"') end end function m.entryPointSymbol(cfg, toolset) if (cfg.kind == "ConsoleApp" or cfg.kind == "WindowedApp") and not cfg.flags.WinMain and not toolset then p.w('EntryPointSymbol="mainCRTStartup"') end end function m.exceptionHandling(cfg) if cfg.flags.NoExceptions then p.w('ExceptionHandling="%s"', iif(_ACTION < "vs2005", "FALSE", 0)) elseif cfg.flags.SEH and _ACTION > "vs2003" then p.w('ExceptionHandling="2"') end end function m.excludedFromBuild(filecfg) if not filecfg or filecfg.flags.ExcludeFromBuild then p.w('ExcludedFromBuild="true"') end end function m.floatingPointModel(cfg) local map = { Strict = "1", Fast = "2" } local value = map[cfg.floatingpoint] if value then p.w('FloatingPointModel="%d"', value) end end function m.forcedIncludeFiles(cfg) if #cfg.forceincludes > 0 then local includes = path.translate(project.getrelative(cfg.project, cfg.forceincludes)) p.w('ForcedIncludeFiles="%s"', table.concat(includes, ';')) end if #cfg.forceusings > 0 then local usings = path.translate(project.getrelative(cfg.project, cfg.forceusings)) p.w('ForcedUsingFiles="%s"', table.concat(usings, ';')) end end function m.forcedIncludes(cfg) p.w('ForcedIncludes=""') end function m.forcedUsingAssemblies(cfg) p.w('ForcedUsingAssemblies=""') end function m.keyword(prj) local windows, managed, makefile for cfg in project.eachconfig(prj) do if cfg.system == p.WINDOWS then windows = true end if cfg.flags.Managed then managed = true end if vstudio.isMakefile(cfg) then makefile = true end end if windows then local keyword = "Win32Proj" if managed then keyword = "ManagedCProj" end if makefile then keyword = "MakeFileProj" end p.w('Keyword="%s"', keyword) end end function m.generateDebugInformation(cfg, toolset) if not toolset then p.w('GenerateDebugInformation="%s"', tostring(m.symbols(cfg) ~= 0)) end end function m.generateManifest(cfg, toolset) if cfg.flags.NoManifest or toolset then p.w('GenerateManifest="false"') end end function m.ignoreImportLibrary(cfg, toolset) if cfg.flags.NoImportLib and not toolset then p.w('IgnoreImportLibrary="true"') end end function m.importLibrary(cfg, toolset) if cfg.kind == p.SHAREDLIB and not toolset then local implibdir = cfg.linktarget.abspath -- I can't actually stop the import lib, but I can hide it in the objects directory if cfg.flags.NoImportLib then implibdir = path.join(cfg.objdir, path.getname(implibdir)) end implibdir = project.getrelative(cfg.project, implibdir) p.x('ImportLibrary="%s"', path.translate(implibdir)) end end function m.includeSearchPath(cfg) p.w('IncludeSearchPath=""') end function m.intermediateDirectory(cfg) local objdir if not cfg.fake then objdir = project.getrelative(cfg.project, cfg.objdir) else objdir = "$(PlatformName)/$(ConfigurationName)" end p.x('IntermediateDirectory="%s"', path.translate(objdir)) end function m.linkIncremental(cfg, toolset) local value if not toolset then value = iif(config.canLinkIncremental(cfg) , 2, 1) else value = 0 end p.w('LinkIncremental="%s"', value) end function m.linkLibraryDependencies(cfg, toolset) if vstudio.needsExplicitLink(cfg) and not toolset then p.w('LinkLibraryDependencies="false"') end end function m.managedExtensions(cfg) if cfg.flags.Managed then p.w('ManagedExtensions="1"') end end function m.minimalRebuild(cfg) if config.isDebugBuild(cfg) and cfg.debugformat ~= "c7" and not cfg.flags.NoMinimalRebuild and not cfg.flags.Managed and not cfg.flags.MultiProcessorCompile then p.w('MinimalRebuild="true"') end end function m.moduleDefinitionFile(cfg, toolset) if not toolset then local deffile = config.findfile(cfg, ".def") if deffile then p.w('ModuleDefinitionFile="%s"', deffile) end end end function m.objectFile(cfg) local cfg, filecfg = config.normalize(cfg) if filecfg and path.iscppfile(filecfg.name) then if filecfg.objname ~= path.getbasename(filecfg.abspath) then p.x('ObjectFile="$(IntDir)\\%s.obj"', filecfg.objname) end end end function m.omitDefaultLib(cfg) if cfg.flags.OmitDefaultLibrary then p.w('OmitDefaultLibName="true"') end end function m.omitFramePointers(cfg) if cfg.flags.NoFramePointer then p.w('OmitFramePointers="true"') end end function m.optimization(cfg) local map = { Off=0, On=3, Debug=0, Full=3, Size=1, Speed=2 } local value = map[cfg.optimize] if value or not cfg.abspath then p.w('Optimization="%s"', value or 0) end end function m.optimizeReferences(cfg, toolset) if config.isOptimizedBuild(cfg) and not toolset then p.w('OptimizeReferences="2"') end end function m.output(cfg) p.w('Output="$(OutDir)%s"', cfg.buildtarget.name) end function m.outputDirectory(cfg) local outdir = project.getrelative(cfg.project, cfg.buildtarget.directory) p.x('OutputDirectory="%s"', path.translate(outdir)) end function m.outputFile(cfg) p.x('OutputFile="$(OutDir)\\%s"', cfg.buildtarget.name) end function m.outputFileName(cfg) if cfg.imagepath ~= nil then p.x('OutputFileName="%s"', path.translate(cfg.imagepath)) end end function m.platforms(prj) p.push('') table.foreachi(m.architectures(prj), function(arch) p.push('') end) p.pop('') end function m.preprocessorDefinitions(cfg) if #cfg.defines > 0 or vstudio.isMakefile(cfg) then p.x('PreprocessorDefinitions="%s"', table.concat(cfg.defines, ";")) end end function m.programDatabaseFile(cfg, toolset) if toolset then p.w('ProgramDatabaseFile=""') end end function m.programDataBaseFileName(cfg, toolset) if toolset then p.w('ProgramDataBaseFileName=""') end end function m.projectGUID(prj) p.w('ProjectGUID="{%s}"', prj.uuid) end function m.projectName(prj) p.x('Name="%s"', prj.name) end function m.projectReferences(prj) local deps = project.getdependencies(prj) if #deps > 0 then -- This is a little odd: Visual Studio wants the "relative path to project" -- to be relative to the *solution*, rather than the project doing the -- referencing. Which, in theory, would break if the project is included -- in more than one solution. But that's how they do it. for i, dep in ipairs(deps) do local relpath = path.getrelative(prj.solution.location, vstudio.projectfile(dep)) -- Visual Studio wants the path to start with ./ or ../ if not relpath:startswith(".") then relpath = "./" .. relpath end p.push('') end end end function m.projectType(prj) p.w('ProjectType="Visual C++"') end function m.reBuildCommandLine(cfg) commands = table.concat(cfg.rebuildcommands, "\r\n") p.x('ReBuildCommandLine="%s"', commands) end function m.resourcePreprocessorDefinitions(cfg) local defs = table.join(cfg.defines, cfg.resdefines) if #defs > 0 then p.x('PreprocessorDefinitions="%s"', table.concat(defs, ";")) end end function m.rootNamespace(prj) local hasWindows = project.hasConfig(prj, function(cfg) return cfg.system == p.WINDOWS end) -- Technically, this should be skipped for pure makefile projects that -- do not contain any empty configurations. But I need to figure out a -- a good way to check the empty configuration bit first. if hasWindows and _ACTION > "vs2003" then p.x('RootNamespace="%s"', prj.name) end end function m.runtimeLibrary(cfg) local cfg, filecfg = config.normalize(cfg) if not filecfg then local runtimes = { StaticRelease = 0, StaticDebug = 1, SharedRelease = 2, SharedDebug = 3, } p.w('RuntimeLibrary="%s"', runtimes[config.getruntime(cfg)]) end end function m.runtimeTypeInfo(cfg) if cfg.flags.NoRTTI and not cfg.flags.Managed then p.w('RuntimeTypeInfo="false"') end end function m.stringPooling(cfg) if config.isOptimizedBuild(cfg) then p.w('StringPooling="true"') end end function m.subSystem(cfg, toolset) if not toolset then p.w('SubSystem="%s"', iif(cfg.kind == "ConsoleApp", 1, 2)) end end function m.targetEnvironment(cfg) if cfg.architecture == "x64" then p.w('TargetEnvironment="3"') end end function m.targetFrameworkVersion(prj) local windows, makefile for cfg in project.eachconfig(prj) do if cfg.system == p.WINDOWS then windows = true end if vstudio.isMakefile(cfg) then makefile = true end end local version = 0 if makefile or not windows then version = 196613 end p.w('TargetFrameworkVersion="%d"', version) end function m.targetMachine(cfg, toolset) if not toolset then p.w('TargetMachine="%d"', iif(cfg.architecture == "x64", 17, 1)) end end function m.toolFiles(prj) if _ACTION > "vs2003" then p.w('') p.w('') end end function m.treatWChar_tAsBuiltInType(cfg) local map = { On = "true", Off = "false" } local value = map[cfg.nativewchar] if value then p.w('TreatWChar_tAsBuiltInType="%s"', value) end end function m.useOfMFC(cfg) if (cfg.flags.MFC) then p.w('UseOfMFC="%d"', iif(cfg.flags.StaticRuntime, 1, 2)) end end function m.usePrecompiledHeader(cfg) local prj, file = config.normalize(cfg) if file then if prj.pchsource == file.abspath and not prj.flags.NoPCH and prj.system ~= p.PS3 then p.w('UsePrecompiledHeader="1"') end else if not prj.flags.NoPCH and prj.pchheader then p.w('UsePrecompiledHeader="%s"', iif(_ACTION < "vs2005", 3, 2)) p.x('PrecompiledHeaderThrough="%s"', prj.pchheader) else p.w('UsePrecompiledHeader="%s"', iif(_ACTION > "vs2003" or prj.flags.NoPCH, 0, 2)) end end end function m.version(prj) local map = { vs2002 = '7.0', vs2003 = '7.1', vs2005 = '8.0', vs2008 = '9.0' } p.w('Version="%s0"', map[_ACTION]) end function m.warnings(cfg) local prjcfg, filecfg = config.normalize(cfg) local level if cfg.warnings == "Off" then level = "0" elseif cfg.warnings == "Extra" then level = "4" elseif not filecfg then level = "3" end if level then p.w('WarningLevel="%s"', level) end if cfg.flags.FatalCompileWarnings and cfg.warnings ~= "Off" then p.w('WarnAsError="true"') end if _ACTION < "vs2008" and not cfg.flags.Managed and cfg.warnings ~= "Off" and not filecfg then p.w('Detect64BitPortabilityProblems="%s"', tostring(not cfg.flags.No64BitChecks)) end end function m.wholeProgramOptimization(cfg) if cfg.flags.LinkTimeOptimization then p.x('WholeProgramOptimization="true"') end end function m.xmlElement() p.w('') end