--
-- 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