-- -- vs2010_vcxproj.lua -- Generate a Visual Studio 2010 C/C++ project. -- Copyright (c) 2009-2011 Jason Perkins and the Premake project -- premake.vstudio.vc2010 = { } local vc2010 = premake.vstudio.vc2010 local vstudio = premake.vstudio local function vs2010_config(prj) _p(1,'') for _, cfginfo in ipairs(prj.solution.vstudio_configs) do _p(2,'', premake.esc(cfginfo.name)) _p(3,'%s',cfginfo.buildcfg) _p(3,'%s',cfginfo.platform) _p(2,'') end _p(1,'') end local function vs2010_globals(prj) _p(1,'') _p(2,'{%s}',prj.uuid) _p(2,'%s',prj.name) --if prj.flags is required as it is not set at project level for tests??? --vs200x generator seems to swap a config for the prj in test setup if prj.flags and prj.flags.Managed then _p(2,'v4.0') _p(2,'ManagedCProj') else _p(2,'Win32Proj') end _p(1,'') end function vc2010.config_type(config) local t = { SharedLib = "DynamicLibrary", StaticLib = "StaticLibrary", ConsoleApp = "Application", WindowedApp = "Application" } return t[config.kind] end local function if_config_and_platform() return 'Condition="\'$(Configuration)|$(Platform)\'==\'%s\'"' end local function optimisation(cfg) local result = "Disabled" for _, value in ipairs(cfg.flags) do if (value == "Optimize") then result = "Full" elseif (value == "OptimizeSize") then result = "MinSpace" elseif (value == "OptimizeSpeed") then result = "MaxSpeed" end end return result end -- -- This property group describes a particular configuration: what -- kind of binary it produces, and some global settings. -- function vc2010.configurationPropertyGroup(cfg, cfginfo) _p(1,'' , premake.esc(cfginfo.name)) _p(2,'%s',vc2010.config_type(cfg)) _p(2,'%s', iif(optimisation(cfg) == "Disabled","true","false")) _p(2,'%s',iif(cfg.flags.Unicode,"Unicode","MultiByte")) local toolsets = { vs2012 = "v110", vs2013 = "v120", vs2015 = "v140", vs2017 = "v141" } local toolset = toolsets[_ACTION] if toolset then _p(2,'%s', toolset) end if cfg.flags.MFC then _p(2,'%s', iif(cfg.flags.StaticRuntime, "Static", "Dynamic")) end if cfg.flags.ATL or cfg.flags.StaticATL then _p(2,'%s', iif(cfg.flags.StaticATL, "Static", "Dynamic")) end if cfg.flags.Managed then _p(2,'true') end _p(1,'') end local function import_props(prj) for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) _p(1,'' ,premake.esc(cfginfo.name)) _p(2,'') _p(1,'') end end function vc2010.outputProperties(prj) for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) local target = cfg.buildtarget _p(1,'', premake.esc(cfginfo.name)) _p(2,'%s\\', premake.esc(target.directory)) if cfg.platform == "Xbox360" then _p(2,'$(OutDir)%s', premake.esc(target.name)) end _p(2,'%s\\', premake.esc(cfg.objectsdir)) _p(2,'%s', premake.esc(path.getbasename(target.name))) _p(2,'%s', premake.esc(path.getextension(target.name))) if cfg.kind == "SharedLib" then local ignore = (cfg.flags.NoImportLib ~= nil) _p(2,'%s', tostring(ignore)) end if cfg.kind ~= "StaticLib" then _p(2,'%s', tostring(premake.config.isincrementallink(cfg))) end if cfg.flags.NoManifest then _p(2,'false') end _p(1,'') end end local function runtime(cfg) local runtime local flags = cfg.flags if premake.config.isdebugbuild(cfg) then runtime = iif(flags.StaticRuntime and not flags.Managed, "MultiThreadedDebug", "MultiThreadedDebugDLL") else runtime = iif(flags.StaticRuntime and not flags.Managed, "MultiThreaded", "MultiThreadedDLL") end return runtime end local function precompiled_header(cfg) if not cfg.flags.NoPCH and cfg.pchheader then _p(3,'Use') _p(3,'%s', cfg.pchheader) else _p(3,'') end end local function preprocessor(indent,cfg) if #cfg.defines > 0 then _p(indent,'%s;%%(PreprocessorDefinitions)' ,premake.esc(table.concat(cfg.defines, ";"))) else _p(indent,'') end end local function include_dirs(indent,cfg) if #cfg.includedirs > 0 then _p(indent,'%s;%%(AdditionalIncludeDirectories)' ,premake.esc(path.translate(table.concat(cfg.includedirs, ";"), '\\'))) end end local function resinclude_dirs(indent,cfg) if #cfg.includedirs > 0 or #cfg.resincludedirs > 0 then local dirs = table.join(cfg.includedirs, cfg.resincludedirs) _p(indent,'%s;%%(AdditionalIncludeDirectories)' ,premake.esc(path.translate(table.concat(dirs, ";"), '\\'))) end end local function resource_compile(cfg) _p(2,'') preprocessor(3,cfg) resinclude_dirs(3,cfg) _p(2,'') end local function exceptions(cfg) if cfg.flags.NoExceptions then _p(2,'false') elseif cfg.flags.SEH then _p(2,'Async') --SEH is not required for Managed and is implied end end local function rtti(cfg) if cfg.flags.NoRTTI and not cfg.flags.Managed then _p(3,'false') end end local function wchar_t_buildin(cfg) if cfg.flags.NativeWChar then _p(3,'true') elseif cfg.flags.NoNativeWChar then _p(3,'false') end end local function sse(cfg) if cfg.flags.EnableSSE then _p(3,'StreamingSIMDExtensions') elseif cfg.flags.EnableSSE2 then _p(3,'StreamingSIMDExtensions2') end end local function floating_point(cfg) if cfg.flags.FloatFast then _p(3,'Fast') elseif cfg.flags.FloatStrict and not cfg.flags.Managed then _p(3,'Strict') end end local function debug_info(cfg) -- -- EditAndContinue /ZI -- ProgramDatabase /Zi -- OldStyle C7 Compatible /Z7 -- local debug_info = '' if cfg.flags.Symbols then if cfg.platform == "x64" or cfg.flags.Managed or premake.config.isoptimizedbuild(cfg.flags) or cfg.flags.NoEditAndContinue then debug_info = "ProgramDatabase" else debug_info = "EditAndContinue" end end _p(3,'%s',debug_info) end local function minimal_build(cfg) if premake.config.isdebugbuild(cfg) and not cfg.flags.NoMinimalRebuild then _p(3,'true') else _p(3,'false') end end local function compile_language(cfg) if cfg.language == "C" then _p(3,'CompileAsC') end end local function vs10_clcompile(cfg) _p(2,'') if #cfg.buildoptions > 0 then _p(3,'%s %%(AdditionalOptions)', table.concat(premake.esc(cfg.buildoptions), " ")) end _p(3,'%s',optimisation(cfg)) include_dirs(3,cfg) preprocessor(3,cfg) minimal_build(cfg) if not premake.config.isoptimizedbuild(cfg.flags) then if not cfg.flags.Managed then _p(3,'EnableFastChecks') end if cfg.flags.ExtraWarnings then _p(3,'true') end else _p(3,'true') end _p(3,'%s', runtime(cfg)) _p(3,'true') precompiled_header(cfg) if cfg.flags.ExtraWarnings then _p(3,'Level4') else _p(3,'Level3') end if cfg.flags.FatalWarnings then _p(3,'true') end exceptions(cfg) rtti(cfg) wchar_t_buildin(cfg) sse(cfg) floating_point(cfg) debug_info(cfg) if cfg.flags.Symbols then _p(3,'$(OutDir)%s.pdb' , path.getbasename(cfg.buildtarget.name)) end if cfg.flags.NoFramePointer then _p(3,'true') end compile_language(cfg) _p(2,'') end local function event_hooks(cfg) if #cfg.postbuildcommands> 0 then _p(2,'') _p(3,'%s',premake.esc(table.implode(cfg.postbuildcommands, "", "", "\r\n"))) _p(2,'') end if #cfg.prebuildcommands> 0 then _p(2,'') _p(3,'%s',premake.esc(table.implode(cfg.prebuildcommands, "", "", "\r\n"))) _p(2,'') end if #cfg.prelinkcommands> 0 then _p(2,'') _p(3,'%s',premake.esc(table.implode(cfg.prelinkcommands, "", "", "\r\n"))) _p(2,'') end end local function additional_options(indent,cfg) if #cfg.linkoptions > 0 then _p(indent,'%s %%(AdditionalOptions)', table.concat(premake.esc(cfg.linkoptions), " ")) end end local function link_target_machine(index,cfg) local platforms = {x32 = 'MachineX86', x64 = 'MachineX64'} if platforms[cfg.platform] then _p(index,'%s', platforms[cfg.platform]) end end local function item_def_lib(cfg) -- The Xbox360 project files are stored in another place in the project file. if cfg.kind == 'StaticLib' and cfg.platform ~= "Xbox360" then _p(1,'') _p(2,'$(OutDir)%s',cfg.buildtarget.name) additional_options(2,cfg) link_target_machine(2,cfg) _p(1,'') end end local function import_lib(cfg) --Prevent the generation of an import library for a Windows DLL. if cfg.kind == "SharedLib" then local implibname = cfg.linktarget.fullpath _p(3,'%s',iif(cfg.flags.NoImportLib, cfg.objectsdir .. "\\" .. path.getname(implibname), implibname)) end end -- -- Generate the element and its children. -- function vc2010.link(cfg) _p(2,'') _p(3,'%s', iif(cfg.kind == "ConsoleApp", "Console", "Windows")) _p(3,'%s', tostring(cfg.flags.Symbols ~= nil)) if premake.config.isoptimizedbuild(cfg.flags) then _p(3,'true') _p(3,'true') end if cfg.kind ~= 'StaticLib' then vc2010.additionalDependencies(cfg) _p(3,'$(OutDir)%s', cfg.buildtarget.name) if #cfg.libdirs > 0 then _p(3,'%s;%%(AdditionalLibraryDirectories)', premake.esc(path.translate(table.concat(cfg.libdirs, ';'), '\\'))) end if vc2010.config_type(cfg) == 'Application' and not cfg.flags.WinMain and not cfg.flags.Managed then _p(3,'%s', iif(cfg.flags.Unicode, "wmainCRTStartup", "mainCRTStartup")) end import_lib(cfg) local deffile = premake.findfile(cfg, ".def") if deffile then _p(3,'%s', deffile) end link_target_machine(3,cfg) additional_options(3,cfg) end _p(2,'') end -- -- Generate the element, which links in system -- libraries required by the project (but not sibling projects; that's handled -- by an ). -- function vc2010.additionalDependencies(cfg) local links = premake.getlinks(cfg, "system", "fullpath") if #links > 0 then _p(3,'%s;%%(AdditionalDependencies)', table.concat(links, ";")) end end local function item_definitions(prj) for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) _p(1,'' ,premake.esc(cfginfo.name)) vs10_clcompile(cfg) resource_compile(cfg) item_def_lib(cfg) vc2010.link(cfg) event_hooks(cfg) _p(1,'') end end -- -- Retrieve a list of files for a particular build group, one of -- "ClInclude", "ClCompile", "ResourceCompile", and "None". -- function vc2010.getfilegroup(prj, group) local sortedfiles = prj.vc2010sortedfiles if not sortedfiles then sortedfiles = { ClCompile = {}, ClInclude = {}, None = {}, ResourceCompile = {}, } for file in premake.project.eachfile(prj) do if path.iscppfile(file.name) then table.insert(sortedfiles.ClCompile, file) elseif path.iscppheader(file.name) then table.insert(sortedfiles.ClInclude, file) elseif path.isresourcefile(file.name) then table.insert(sortedfiles.ResourceCompile, file) else table.insert(sortedfiles.None, file) end end -- Cache the sorted files; they are used several places prj.vc2010sortedfiles = sortedfiles end return sortedfiles[group] end -- -- Write the files section of the project file. -- function vc2010.files(prj) vc2010.simplefilesgroup(prj, "ClInclude") vc2010.compilerfilesgroup(prj) vc2010.simplefilesgroup(prj, "None") vc2010.simplefilesgroup(prj, "ResourceCompile") end function vc2010.simplefilesgroup(prj, section) local files = vc2010.getfilegroup(prj, section) if #files > 0 then _p(1,'') for _, file in ipairs(files) do _p(2,'<%s Include=\"%s\" />', section, path.translate(file.name, "\\")) end _p(1,'') end end function vc2010.individualSourceFile(prj, config_mappings, file) local configs = prj.solution.vstudio_configs local translatedpath = path.translate(file.name, "\\") _p(2,'', translatedpath) for _, cfginfo in ipairs(configs) do if config_mappings[cfginfo] and translatedpath == config_mappings[cfginfo] then _p(3,'Create', premake.esc(cfginfo.name)) config_mappings[cfginfo] = nil --only one source file per pch end end if path.iscfile(file.name) ~= premake.project.iscproject(prj) then _p(3,'%s', iif(path.iscfile(file.name), 'CompileAsC', 'CompileAsCpp')) end _p(2,'') end function vc2010.compilerfilesgroup(prj) local configs = prj.solution.vstudio_configs local files = vc2010.getfilegroup(prj, "ClCompile") if #files > 0 then local config_mappings = {} for _, cfginfo in ipairs(configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) if cfg.pchheader and cfg.pchsource and not cfg.flags.NoPCH then config_mappings[cfginfo] = path.translate(cfg.pchsource, "\\") end end _p(1,'') for _, file in ipairs(files) do vc2010.individualSourceFile(prj, config_mappings, file) end _p(1,'') end end -- -- Output the VC2010 project file header -- function vc2010.header(targets) io.eol = "\r\n" _p('') local t = "" if targets then t = ' DefaultTargets="' .. targets .. '"' end _p('', t) end -- -- Output the VC2010 C/C++ project file -- function premake.vs2010_vcxproj(prj) io.indent = " " vc2010.header("Build") vs2010_config(prj) vs2010_globals(prj) _p(1,'') for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) vc2010.configurationPropertyGroup(cfg, cfginfo) end _p(1,'') --check what this section is doing _p(1,'') _p(1,'') import_props(prj) --what type of macros are these? _p(1,'') vc2010.outputProperties(prj) item_definitions(prj) vc2010.files(prj) vc2010.projectReferences(prj) _p(1,'') _p(1,'') _p(1,'') _p('') end -- -- Generate the list of project dependencies. -- function vc2010.projectReferences(prj) local deps = premake.getdependencies(prj) if #deps > 0 then _p(1,'') for _, dep in ipairs(deps) do local deppath = path.getrelative(prj.location, vstudio.projectfile(dep)) _p(2,'', path.translate(deppath, "\\")) _p(3,'{%s}', dep.uuid) _p(2,'') end _p(1,'') end end -- -- Generate the .vcxproj.user file -- function vc2010.debugdir(cfg) if cfg.debugdir then _p(' %s', path.translate(cfg.debugdir, '\\')) _p(' WindowsLocalDebugger') end if cfg.debugargs then _p(' %s', table.concat(cfg.debugargs, " ")) end end function vc2010.debugenvs(cfg) if cfg.debugenvs and #cfg.debugenvs > 0 then _p(2,'%s%s',table.concat(cfg.debugenvs, "\n") ,iif(cfg.flags.DebugEnvsInherit,'\n$(LocalDebuggerEnvironment)','') ) if cfg.flags.DebugEnvsDontMerge then _p(2,'false') end end end function premake.vs2010_vcxproj_user(prj) io.indent = " " vc2010.header() for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) _p(' ', premake.esc(cfginfo.name)) vc2010.debugdir(cfg) vc2010.debugenvs(cfg) _p(' ') end _p('') end