Files
rippled/site_scons/site_tools/VSProject.py
2015-02-26 21:02:35 -05:00

895 lines
39 KiB
Python

# Copyright 2014 Vinnie Falco (vinnie.falco@gmail.com)
# Portions Copyright The SCons Foundation
# Portions Copyright Google, Inc.
# This file is part of beast
"""
A SCons tool to provide a family of scons builders that
generate Visual Studio project files
"""
import collections
import hashlib
import io
import itertools
import ntpath
import os
import pprint
import random
import re
import SCons.Builder
import SCons.Node.FS
import SCons.Node
import SCons.Script.Main
import SCons.Util
#-------------------------------------------------------------------------------
# Adapted from msvs.py
UnicodeByteMarker = '\xEF\xBB\xBF'
V12DSPHeader = """\
<?xml version="1.0" encoding="%(encoding)s"?>\r
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
"""
V12DSPProjectConfiguration = """\
<ProjectConfiguration Include="%(variant)s|%(platform)s">\r
<Configuration>%(variant)s</Configuration>\r
<Platform>%(platform)s</Platform>\r
</ProjectConfiguration>\r
"""
V12DSPGlobals = """\
<PropertyGroup Label="Globals">\r
<ProjectGuid>%(project_guid)s</ProjectGuid>\r
<Keyword>Win32Proj</Keyword>\r
<RootNamespace>%(name)s</RootNamespace>\r
<IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename>\r
</PropertyGroup>\r
"""
V12DSPPropertyGroup = """\
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='%(variant)s|%(platform)s'" Label="Configuration">\r
<CharacterSet>MultiByte</CharacterSet>\r
<ConfigurationType>Application</ConfigurationType>\r
<PlatformToolset>v120</PlatformToolset>\r
<LinkIncremental>False</LinkIncremental>\r
<UseDebugLibraries>%(use_debug_libs)s</UseDebugLibraries>\r
<UseOfMfc>False</UseOfMfc>\r
<WholeProgramOptimization>false</WholeProgramOptimization>\r
<IntDir>%(int_dir)s</IntDir>\r
<OutDir>%(out_dir)s</OutDir>\r
</PropertyGroup>\r
"""
V12DSPImportGroup= """\
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='%(variant)s|%(platform)s'" Label="PropertySheets">\r
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
</ImportGroup>\r
"""
V12DSPItemDefinitionGroup= """\
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='%(variant)s|%(platform)s'">\r
"""
V12CustomBuildProtoc= """\
<FileType>Document</FileType>\r
<Command Condition="'$(Configuration)|$(Platform)'=='%(name)s'">protoc --cpp_out=%(cpp_out)s --proto_path=%%(RelativeDir) %%(Identity)</Command>\r
<Outputs Condition="'$(Configuration)|$(Platform)'=='%(name)s'">%(base_out)s.pb.h;%(base_out)s.pb.cc</Outputs>\r
<Message Condition="'$(Configuration)|$(Platform)'=='%(name)s'">protoc --cpp_out=%(cpp_out)s --proto_path=%%(RelativeDir) %%(Identity)</Message>\r
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='%(name)s'">false</LinkObjects>\r
"""
V12DSPFiltersHeader = (
'''<?xml version="1.0" encoding="utf-8"?>\r
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
''')
#-------------------------------------------------------------------------------
def is_subdir(child, parent):
'''Determine if child is a subdirectory of parent'''
return os.path.commonprefix([parent, child]) == parent
def _key(item):
if isinstance(item, (str, unicode)):
return ('s', item.upper(), item)
elif isinstance(item, (int, long, float)):
return ('n', item)
elif isinstance(item, (list, tuple)):
return ('l', map(_key, item))
elif isinstance(item, dict):
return ('d', xsorted(item.keys()), xsorted(item.values()))
elif isinstance(item, Configuration):
return ('c', _key(item.name), _key(item.target), _key(item.variant), _key(item.platform))
elif isinstance(item, Item):
return ('i', _key(winpath(item.path())), _key(item.is_compiled()), _key(item.builder()), _key(item.tag()), _key(item.is_excluded()))
elif isinstance(item, SCons.Node.FS.File):
return ('f', _key(item.name), _key(item.suffix))
else:
return ('x', item)
def xsorted(tosort, **kwargs):
'''Performs sorted in a deterministic manner.'''
if 'key' in kwargs:
map(kwargs['key'], tosort)
kwargs['key'] = _key
return sorted(tosort, **kwargs)
def itemList(items, sep):
if type(items) == str: # Won't work in Python 3.
return items
def gen():
for item in xsorted(items):
if isinstance(item, dict):
for k, v in xsorted(item.items()):
yield k + '=' + v
elif isinstance(item, (tuple, list)):
assert len(item) == 2, "Item shoud have exactly two elements: " + str(item)
yield '%s=%s' % tuple(item)
else:
yield item
yield sep
return ''.join(gen())
#-------------------------------------------------------------------------------
class SwitchConverter(object):
'''Converts command line switches to MSBuild XML, using tables'''
def __init__(self, table, booltable, retable=None):
self.table = {}
for key in table:
self.table[key] = table[key]
for key in booltable:
value = booltable[key]
self.table[key] = [value[0], 'True']
self.table[key + '-'] = [value[0], 'False']
if retable != None:
self.retable = retable
else:
self.retable = []
def getXml(self, switches, prefix = ''):
switches = list(set(switches)) # Filter dupes because on windows platforms, /nologo is added automatically to the environment.
xml = []
for regex, tag in self.retable:
matches = []
for switch in switches[:]:
match = regex.match(switch)
if None != match:
matches.append(match.group(1))
switches.remove(switch)
if len(matches) > 0:
xml.append (
'%s<%s>%s</%s>\r\n' % (
prefix, tag, ';'.join(matches), tag))
unknown = []
for switch in switches:
try:
value = self.table[switch]
xml.append (
'%s<%s>%s</%s>\r\n' % (
prefix, value[0], value[1], value[0]))
except:
unknown.append(switch)
if unknown:
s = itemList(unknown, ' ')
tag = 'AdditionalOptions'
xml.append('%(prefix)s<%(tag)s>%(s)s%%(%(tag)s)</%(tag)s>\r\n' % locals())
if xml:
return ''.join(xml)
return ''
class ClSwitchConverter(SwitchConverter):
def __init__(self):
booltable = {
'/C' : ['KeepComments'],
'/doc' : ['GenerateXMLDocumentationFiles'],
'/FAu' : ['UseUnicodeForAssemblerListing'],
'/FC' : ['UseFullPaths'],
'/FR' : ['BrowseInformation'],
'/Fr' : ['BrowseInformation'],
'/Fx' : ['ExpandAttributedSource'],
'/GF' : ['StringPooling'],
'/GL' : ['WholeProgramOptimization'],
'/Gm' : ['MinimalRebuild'],
'/GR' : ['RuntimeTypeInfo'],
'/GS' : ['BufferSecurityCheck'],
'/GT' : ['EnableFiberSafeOptimizations'],
'/Gy' : ['FunctionLevelLinking'],
'/MP' : ['MultiProcessorCompilation'],
'/Oi' : ['IntrinsicFunctions'],
'/Oy' : ['OmitFramePointers'],
'/RTCc' : ['SmallerTypeCheck'],
'/u' : ['UndefineAllPreprocessorDefinitions'],
'/X' : ['IgnoreStandardIncludePath'],
'/WX' : ['TreatWarningAsError'],
'/Za' : ['DisableLanguageExtensions'],
'/Zl' : ['OmitDefaultLibName'],
'/fp:except' : ['FloatingPointExceptions'],
'/hotpatch' : ['CreateHotpatchableImage'],
'/nologo' : ['SuppressStartupBanner'],
'/openmp' : ['OpenMPSupport'],
'/showIncludes' : ['ShowIncludes'],
'/Zc:forScope' : ['ForceConformanceInForLoopScope'],
'/Zc:wchar_t' : ['TreatWChar_tAsBuiltInType'],
}
table = {
'/EHsc' : ['ExceptionHandling', 'Sync'],
'/EHa' : ['ExceptionHandling', 'Async'],
'/EHs' : ['ExceptionHandling', 'SyncCThrow'],
'/FA' : ['AssemblerOutput', 'AssemblyCode'],
'/FAcs' : ['AssemblerOutput', 'All'],
'/FAc' : ['AssemblerOutput', 'AssemblyAndMachineCode'],
'/FAs' : ['AssemblerOutput', 'AssemblyAndSourceCode'],
'/Gd' : ['CallingConvention', 'Cdecl'],
'/Gr' : ['CallingConvention', 'FastCall'],
'/Gz' : ['CallingConvention', 'StdCall'],
'/MT' : ['RuntimeLibrary', 'MultiThreaded'],
'/MTd' : ['RuntimeLibrary', 'MultiThreadedDebug'],
'/MD' : ['RuntimeLibrary', 'MultiThreadedDLL'],
'/MDd' : ['RuntimeLibrary', 'MultiThreadedDebugDLL'],
'/Od' : ['Optimization', 'Disabled'],
'/O1' : ['Optimization', 'MinSpace'],
'/O2' : ['Optimization', 'MaxSpeed'],
'/Ox' : ['Optimization', 'Full'],
'/Ob1' : ['InlineFunctionExpansion', 'OnlyExplicitInline'],
'/Ob2' : ['InlineFunctionExpansion', 'AnySuitable'],
'/Ot' : ['FavorSizeOrSpeed', 'Speed'],
'/Os' : ['FavorSizeOrSpeed', 'Size'],
'/RTCs' : ['BasicRuntimeChecks', 'StackFrameRuntimeCheck'],
'/RTCu' : ['BasicRuntimeChecks', 'UninitializedLocalUsageCheck'],
'/RTC1' : ['BasicRuntimeChecks', 'EnableFastChecks'],
'/TC' : ['CompileAs', 'CompileAsC'],
'/TP' : ['CompileAs', 'CompileAsCpp'],
'/W0' : [ 'WarningLevel', 'TurnOffAllWarnings'],
'/W1' : [ 'WarningLevel', 'Level1'],
'/W2' : [ 'WarningLevel', 'Level2'],
'/W3' : [ 'WarningLevel', 'Level3'],
'/W4' : [ 'WarningLevel', 'Level4'],
'/Wall' : [ 'WarningLevel', 'EnableAllWarnings'],
'/Yc' : ['PrecompiledHeader', 'Create'],
'/Yu' : ['PrecompiledHeader', 'Use'],
'/Z7' : ['DebugInformationFormat', 'OldStyle'],
'/Zi' : ['DebugInformationFormat', 'ProgramDatabase'],
'/ZI' : ['DebugInformationFormat', 'EditAndContinue'],
'/Zp1' : ['StructMemberAlignment', '1Byte'],
'/Zp2' : ['StructMemberAlignment', '2Bytes'],
'/Zp4' : ['StructMemberAlignment', '4Bytes'],
'/Zp8' : ['StructMemberAlignment', '8Bytes'],
'/Zp16' : ['StructMemberAlignment', '16Bytes'],
'/arch:IA32' : ['EnableEnhancedInstructionSet', 'NoExtensions'],
'/arch:SSE' : ['EnableEnhancedInstructionSet', 'StreamingSIMDExtensions'],
'/arch:SSE2' : ['EnableEnhancedInstructionSet', 'StreamingSIMDExtensions2'],
'/arch:AVX' : ['EnableEnhancedInstructionSet', 'AdvancedVectorExtensions'],
'/clr' : ['CompileAsManaged', 'True'],
'/clr:pure' : ['CompileAsManaged', 'Pure'],
'/clr:safe' : ['CompileAsManaged', 'Safe'],
'/clr:oldSyntax' : ['CompileAsManaged', 'OldSyntax'],
'/fp:fast' : ['FloatingPointModel', 'Fast'],
'/fp:precise' : ['FloatingPointModel', 'Precise'],
'/fp:strict' : ['FloatingPointModel', 'Strict'],
'/errorReport:none' : ['ErrorReporting', 'None'],
'/errorReport:prompt' : ['ErrorReporting', 'Prompt'],
'/errorReport:queue' : ['ErrorReporting', 'Queue'],
'/errorReport:send' : ['ErrorReporting', 'Send'],
}
retable = [
(re.compile(r'/wd\"(\d+)\"'), 'DisableSpecificWarnings'),
]
# Ideas from Google's Generate Your Project
'''
_Same(_compile, 'AdditionalIncludeDirectories', _folder_list) # /I
_Same(_compile, 'PreprocessorDefinitions', _string_list) # /D
_Same(_compile, 'ProgramDataBaseFileName', _file_name) # /Fd
_Same(_compile, 'AdditionalOptions', _string_list)
_Same(_compile, 'AdditionalUsingDirectories', _folder_list) # /AI
_Same(_compile, 'AssemblerListingLocation', _file_name) # /Fa
_Same(_compile, 'BrowseInformationFile', _file_name)
_Same(_compile, 'ForcedIncludeFiles', _file_list) # /FI
_Same(_compile, 'ForcedUsingFiles', _file_list) # /FU
_Same(_compile, 'UndefinePreprocessorDefinitions', _string_list) # /U
_Same(_compile, 'XMLDocumentationFileName', _file_name)
'' : ['EnablePREfast', _boolean) # /analyze Visible='false'
_Renamed(_compile, 'ObjectFile', 'ObjectFileName', _file_name) # /Fo
_Renamed(_compile, 'PrecompiledHeaderThrough', 'PrecompiledHeaderFile',
_file_name) # Used with /Yc and /Yu
_Renamed(_compile, 'PrecompiledHeaderFile', 'PrecompiledHeaderOutputFile',
_file_name) # /Fp
_ConvertedToAdditionalOption(_compile, 'DefaultCharIsUnsigned', '/J')
_MSBuildOnly(_compile, 'ProcessorNumber', _integer) # the number of processors
_MSBuildOnly(_compile, 'TrackerLogDirectory', _folder_name)
_MSBuildOnly(_compile, 'TreatSpecificWarningsAsErrors', _string_list) # /we
_MSBuildOnly(_compile, 'PreprocessOutputPath', _string) # /Fi
'''
SwitchConverter.__init__(self, table, booltable, retable)
class LinkSwitchConverter(SwitchConverter):
def __init__(self):
# Based on code in Generate Your Project
booltable = {
'/DEBUG' : ['GenerateDebugInformation'],
'/DYNAMICBASE' : ['RandomizedBaseAddress'],
'/NOLOGO' : ['SuppressStartupBanner'],
'/nologo' : ['SuppressStartupBanner'],
}
table = {
'/ERRORREPORT:NONE' : ['ErrorReporting', 'NoErrorReport'],
'/ERRORREPORT:PROMPT' : ['ErrorReporting', 'PromptImmediately'],
'/ERRORREPORT:QUEUE' : ['ErrorReporting', 'QueueForNextLogin'],
'/ERRORREPORT:SEND' : ['ErrorReporting', 'SendErrorReport'],
'/MACHINE:X86' : ['TargetMachine', 'MachineX86'],
'/MACHINE:ARM' : ['TargetMachine', 'MachineARM'],
'/MACHINE:EBC' : ['TargetMachine', 'MachineEBC'],
'/MACHINE:IA64' : ['TargetMachine', 'MachineIA64'],
'/MACHINE:MIPS' : ['TargetMachine', 'MachineMIPS'],
'/MACHINE:MIPS16' : ['TargetMachine', 'MachineMIPS16'],
'/MACHINE:MIPSFPU' : ['TargetMachine', 'MachineMIPSFPU'],
'/MACHINE:MIPSFPU16' : ['TargetMachine', 'MachineMIPSFPU16'],
'/MACHINE:SH4' : ['TargetMachine', 'MachineSH4'],
'/MACHINE:THUMB' : ['TargetMachine', 'MachineTHUMB'],
'/MACHINE:X64' : ['TargetMachine', 'MachineX64'],
'/NXCOMPAT' : ['DataExecutionPrevention', 'true'],
'/NXCOMPAT:NO' : ['DataExecutionPrevention', 'false'],
'/SUBSYSTEM:CONSOLE' : ['SubSystem', 'Console'],
'/SUBSYSTEM:WINDOWS' : ['SubSystem', 'Windows'],
'/SUBSYSTEM:NATIVE' : ['SubSystem', 'Native'],
'/SUBSYSTEM:EFI_APPLICATION' : ['SubSystem', 'EFI Application'],
'/SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER' : ['SubSystem', 'EFI Boot Service Driver'],
'/SUBSYSTEM:EFI_ROM' : ['SubSystem', 'EFI ROM'],
'/SUBSYSTEM:EFI_RUNTIME_DRIVER' : ['SubSystem', 'EFI Runtime'],
'/SUBSYSTEM:WINDOWSCE' : ['SubSystem', 'WindowsCE'],
'/SUBSYSTEM:POSIX' : ['SubSystem', 'POSIX'],
}
'''
/TLBID:1 /MANIFEST /MANIFESTUAC:level='asInvoker' uiAccess='false'
_Same(_link, 'AllowIsolation', _boolean) # /ALLOWISOLATION
_Same(_link, 'CLRUnmanagedCodeCheck', _boolean) # /CLRUNMANAGEDCODECHECK
_Same(_link, 'DelaySign', _boolean) # /DELAYSIGN
_Same(_link, 'EnableUAC', _boolean) # /MANIFESTUAC
_Same(_link, 'GenerateMapFile', _boolean) # /MAP
_Same(_link, 'IgnoreAllDefaultLibraries', _boolean) # /NODEFAULTLIB
_Same(_link, 'IgnoreEmbeddedIDL', _boolean) # /IGNOREIDL
_Same(_link, 'MapExports', _boolean) # /MAPINFO:EXPORTS
_Same(_link, 'StripPrivateSymbols', _file_name) # /PDBSTRIPPED
_Same(_link, 'PerUserRedirection', _boolean)
_Same(_link, 'Profile', _boolean) # /PROFILE
_Same(_link, 'RegisterOutput', _boolean)
_Same(_link, 'SetChecksum', _boolean) # /RELEASE
_Same(_link, 'SupportUnloadOfDelayLoadedDLL', _boolean) # /DELAY:UNLOAD
_Same(_link, 'SwapRunFromCD', _boolean) # /SWAPRUN:CD
_Same(_link, 'TurnOffAssemblyGeneration', _boolean) # /NOASSEMBLY
_Same(_link, 'UACUIAccess', _boolean) # /uiAccess='true'
_Same(_link, 'EnableCOMDATFolding', _newly_boolean) # /OPT:ICF
_Same(_link, 'FixedBaseAddress', _newly_boolean) # /FIXED
_Same(_link, 'LargeAddressAware', _newly_boolean) # /LARGEADDRESSAWARE
_Same(_link, 'OptimizeReferences', _newly_boolean) # /OPT:REF
_Same(_link, 'TerminalServerAware', _newly_boolean) # /TSAWARE
_Same(_link, 'AdditionalDependencies', _file_list)
_Same(_link, 'AdditionalLibraryDirectories', _folder_list) # /LIBPATH
_Same(_link, 'AdditionalManifestDependencies', _file_list) # /MANIFESTDEPENDENCY:
_Same(_link, 'AdditionalOptions', _string_list)
_Same(_link, 'AddModuleNamesToAssembly', _file_list) # /ASSEMBLYMODULE
_Same(_link, 'AssemblyLinkResource', _file_list) # /ASSEMBLYLINKRESOURCE
_Same(_link, 'BaseAddress', _string) # /BASE
_Same(_link, 'DelayLoadDLLs', _file_list) # /DELAYLOAD
_Same(_link, 'EmbedManagedResourceFile', _file_list) # /ASSEMBLYRESOURCE
_Same(_link, 'EntryPointSymbol', _string) # /ENTRY
_Same(_link, 'ForceSymbolReferences', _file_list) # /INCLUDE
_Same(_link, 'FunctionOrder', _file_name) # /ORDER
_Same(_link, 'HeapCommitSize', _string)
_Same(_link, 'HeapReserveSize', _string) # /HEAP
_Same(_link, 'ImportLibrary', _file_name) # /IMPLIB
_Same(_link, 'KeyContainer', _file_name) # /KEYCONTAINER
_Same(_link, 'KeyFile', _file_name) # /KEYFILE
_Same(_link, 'ManifestFile', _file_name) # /ManifestFile
_Same(_link, 'MapFileName', _file_name)
_Same(_link, 'MergedIDLBaseFileName', _file_name) # /IDLOUT
_Same(_link, 'MergeSections', _string) # /MERGE
_Same(_link, 'MidlCommandFile', _file_name) # /MIDL
_Same(_link, 'ModuleDefinitionFile', _file_name) # /DEF
_Same(_link, 'OutputFile', _file_name) # /OUT
_Same(_link, 'ProfileGuidedDatabase', _file_name) # /PGD
_Same(_link, 'ProgramDatabaseFile', _file_name) # /PDB
_Same(_link, 'StackCommitSize', _string)
_Same(_link, 'StackReserveSize', _string) # /STACK
_Same(_link, 'TypeLibraryFile', _file_name) # /TLBOUT
_Same(_link, 'TypeLibraryResourceID', _integer) # /TLBID
_Same(_link, 'Version', _string) # /VERSION
_Same(_link, 'AssemblyDebug',
_Enumeration(['',
'true', # /ASSEMBLYDEBUG
'false'])) # /ASSEMBLYDEBUG:DISABLE
_Same(_link, 'CLRImageType',
_Enumeration(['Default',
'ForceIJWImage', # /CLRIMAGETYPE:IJW
'ForcePureILImage', # /Switch="CLRIMAGETYPE:PURE
'ForceSafeILImage'])) # /Switch="CLRIMAGETYPE:SAFE
_Same(_link, 'CLRThreadAttribute',
_Enumeration(['DefaultThreadingAttribute', # /CLRTHREADATTRIBUTE:NONE
'MTAThreadingAttribute', # /CLRTHREADATTRIBUTE:MTA
'STAThreadingAttribute'])) # /CLRTHREADATTRIBUTE:STA
_Same(_link, 'Driver',
_Enumeration(['NotSet',
'Driver', # /Driver
'UpOnly', # /DRIVER:UPONLY
'WDM'])) # /DRIVER:WDM
_Same(_link, 'LinkTimeCodeGeneration',
_Enumeration(['Default',
'UseLinkTimeCodeGeneration', # /LTCG
'PGInstrument', # /LTCG:PGInstrument
'PGOptimization', # /LTCG:PGOptimize
'PGUpdate'])) # /LTCG:PGUpdate
_Same(_link, 'ShowProgress',
_Enumeration(['NotSet',
'LinkVerbose', # /VERBOSE
'LinkVerboseLib'], # /VERBOSE:Lib
new=['LinkVerboseICF', # /VERBOSE:ICF
'LinkVerboseREF', # /VERBOSE:REF
'LinkVerboseSAFESEH', # /VERBOSE:SAFESEH
'LinkVerboseCLR'])) # /VERBOSE:CLR
_Same(_link, 'UACExecutionLevel',
_Enumeration(['AsInvoker', # /level='asInvoker'
'HighestAvailable', # /level='highestAvailable'
'RequireAdministrator'])) # /level='requireAdministrator'
_Same(_link, 'MinimumRequiredVersion', _string)
_Same(_link, 'TreatLinkerWarningAsErrors', _boolean) # /WX
# Options found in MSVS that have been renamed in MSBuild.
_Renamed(_link, 'IgnoreDefaultLibraryNames', 'IgnoreSpecificDefaultLibraries',
_file_list) # /NODEFAULTLIB
_Renamed(_link, 'ResourceOnlyDLL', 'NoEntryPoint', _boolean) # /NOENTRY
_Renamed(_link, 'SwapRunFromNet', 'SwapRunFromNET', _boolean) # /SWAPRUN:NET
_Moved(_link, 'GenerateManifest', '', _boolean)
_Moved(_link, 'IgnoreImportLibrary', '', _boolean)
_Moved(_link, 'LinkIncremental', '', _newly_boolean)
_Moved(_link, 'LinkLibraryDependencies', 'ProjectReference', _boolean)
_Moved(_link, 'UseLibraryDependencyInputs', 'ProjectReference', _boolean)
# MSVS options not found in MSBuild.
_MSVSOnly(_link, 'OptimizeForWindows98', _newly_boolean)
_MSVSOnly(_link, 'UseUnicodeResponseFiles', _boolean)
# MSBuild options not found in MSVS.
_MSBuildOnly(_link, 'BuildingInIDE', _boolean)
_MSBuildOnly(_link, 'ImageHasSafeExceptionHandlers', _boolean) # /SAFESEH
_MSBuildOnly(_link, 'LinkDLL', _boolean) # /DLL Visible='false'
_MSBuildOnly(_link, 'LinkStatus', _boolean) # /LTCG:STATUS
_MSBuildOnly(_link, 'PreventDllBinding', _boolean) # /ALLOWBIND
_MSBuildOnly(_link, 'SupportNobindOfDelayLoadedDLL', _boolean) # /DELAY:NOBIND
_MSBuildOnly(_link, 'TrackerLogDirectory', _folder_name)
_MSBuildOnly(_link, 'MSDOSStubFileName', _file_name) # /STUB Visible='false'
_MSBuildOnly(_link, 'SectionAlignment', _integer) # /ALIGN
_MSBuildOnly(_link, 'SpecifySectionAttributes', _string) # /SECTION
_MSBuildOnly(_link, 'ForceFileOutput',
_Enumeration([], new=['Enabled', # /FORCE
# /FORCE:MULTIPLE
'MultiplyDefinedSymbolOnly',
'UndefinedSymbolOnly'])) # /FORCE:UNRESOLVED
_MSBuildOnly(_link, 'CreateHotPatchableImage',
_Enumeration([], new=['Enabled', # /FUNCTIONPADMIN
'X86Image', # /FUNCTIONPADMIN:5
'X64Image', # /FUNCTIONPADMIN:6
'ItaniumImage'])) # /FUNCTIONPADMIN:16
_MSBuildOnly(_link, 'CLRSupportLastError',
_Enumeration([], new=['Enabled', # /CLRSupportLastError
'Disabled', # /CLRSupportLastError:NO
# /CLRSupportLastError:SYSTEMDLL
'SystemDlls']))
'''
SwitchConverter.__init__(self, table, booltable)
CLSWITCHES = ClSwitchConverter()
LINKSWITCHES = LinkSwitchConverter()
#-------------------------------------------------------------------------------
# Return a Windows path from a native path
def winpath(path):
drive, rest = ntpath.splitdrive(path)
result = []
while rest and rest != ntpath.sep:
rest, part = ntpath.split(rest)
result.insert(0, part)
if rest:
result.insert(0, rest)
return ntpath.join(drive.upper(), *result)
def makeList(x):
if not x:
return []
if type(x) is not list:
return [x]
return x
#-------------------------------------------------------------------------------
class Configuration(object):
def __init__(self, variant, platform, target, env):
self.name = '%s|%s' % (variant, platform)
self.variant = variant
self.platform = platform
self.target = target
self.env = env
#-------------------------------------------------------------------------------
class Item(object):
'''Represents a file item in the Solution Explorer'''
def __init__(self, path, builder):
self._path = path
self._builder = builder
self.node = dict()
if builder == 'Object':
self._tag = 'ClCompile'
self._excluded = False
elif builder == 'Protoc':
self._tag = 'CustomBuild'
self._excluded = False
else:
ext = os.path.splitext(self._path)[1]
if ext in ['.c', '.cc', '.cpp']:
self._tag = 'ClCompile'
self._excluded = True
else:
if ext in ['.h', '.hpp', '.hxx', '.inl', '.inc']:
self._tag = 'ClInclude'
else:
self._tag = 'None'
self._excluded = False;
def __repr__(self):
return '<VSProject.Item "%s" %s>' % (
self.path, self.tag, str(self.node))
def path(self):
return self._path
def tag(self):
return self._tag
def builder(self):
return self._builder
def is_compiled(self):
return self._builder == 'Object'
def is_excluded(self):
return self._excluded
#-------------------------------------------------------------------------------
def _guid(seed, name = None):
m = hashlib.md5()
m.update(seed)
if name:
m.update(name)
d = m.hexdigest().upper()
guid = "{%s-%s-%s-%s-%s}" % (d[:8], d[8:12], d[12:16], d[16:20], d[20:32])
return guid
class _ProjectGenerator(object):
'''Generates a project file for Visual Studio 2013'''
def __init__(self, project_node, filters_node, env):
try:
self.configs = xsorted(env['VSPROJECT_CONFIGS'])
except KeyError:
raise ValueError ('Missing VSPROJECT_CONFIGS')
self.root_dir = os.getcwd()
self.root_dirs = [os.path.abspath(x) for x in makeList(env['VSPROJECT_ROOT_DIRS'])]
self.project_dir = os.path.dirname(os.path.abspath(str(project_node)))
self.project_node = project_node
self.project_file = None
self.filters_node = filters_node
self.filters_file = None
self.guid = _guid(os.path.basename(str(self.project_node)))
self.buildItemList(env)
def buildItemList(self, env):
'''Build the Item set associated with the configurations'''
items = {}
def _walk(target, items, prefix=''):
if os.path.isabs(str(target)):
return
if target.has_builder():
builder = target.get_builder().get_name(env)
bsources = target.get_binfo().bsources
if builder == 'Program':
for child in bsources:
_walk(child, items, prefix+' ')
else:
for child in bsources:
item = items.setdefault(str(child), Item(str(child), builder=builder))
item.node[config] = target
_walk(child, items, prefix+' ')
for child in target.children(scan=1):
if not os.path.isabs(str(child)):
item = items.setdefault(str(child), Item(str(child), builder=None))
_walk(child, items, prefix+' ')
for config in self.configs:
targets = config.target
for target in targets:
_walk(target, items)
self.items = xsorted(items.values())
def makeListTag(self, items, prefix, tag, attrs, inherit=True):
'''Builds an XML tag string from a list of items. If items is
empty, then the returned string is empty.'''
if not items:
return ''
s = '%(prefix)s<%(tag)s%(attrs)s>' % locals()
s += ';'.join(items)
if inherit:
s += ';%%(%(tag)s)' % locals()
s += '</%(tag)s>\r\n' % locals()
return s
def relPaths(self, paths):
items = []
for path in paths:
if not os.path.isabs(path):
items.append(winpath(os.path.relpath(path, self.project_dir)))
return items
def extraRelPaths(self, paths, base):
extras = []
for path in paths:
if not path in base:
extras.append(path)
return self.relPaths(extras)
def writeHeader(self):
global clSwitches
encoding = 'utf-8'
project_guid = self.guid
name = os.path.splitext(os.path.basename(str(self.project_node)))[0]
f = self.project_file
f.write(UnicodeByteMarker)
f.write(V12DSPHeader % locals())
f.write(V12DSPGlobals % locals())
f.write(' <ItemGroup Label="ProjectConfigurations">\r\n')
for config in self.configs:
variant = config.variant
platform = config.platform
f.write(V12DSPProjectConfiguration % locals())
f.write(' </ItemGroup>\r\n')
f.write(' <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r\n')
for config in self.configs:
variant = config.variant
platform = config.platform
use_debug_libs = variant == 'Debug'
variant_dir = os.path.relpath(os.path.dirname(
config.target[0].get_abspath()), self.project_dir)
out_dir = winpath(variant_dir) + ntpath.sep
int_dir = winpath(ntpath.join(variant_dir, 'src')) + ntpath.sep
f.write(V12DSPPropertyGroup % locals())
f.write(' <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r\n')
f.write(' <ImportGroup Label="ExtensionSettings" />\r\n')
for config in self.configs:
variant = config.variant
platform = config.platform
f.write(V12DSPImportGroup % locals())
f.write(' <PropertyGroup Label="UserMacros" />\r\n')
for config in self.configs:
variant = config.variant
platform = config.platform
f.write(V12DSPItemDefinitionGroup % locals())
# Cl options
f.write(' <ClCompile>\r\n')
f.write(
' <PreprocessorDefinitions>%s%%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n' % (
itemList(config.env['CPPDEFINES'], ';')))
props = ''
props += self.makeListTag(self.relPaths(xsorted(config.env['CPPPATH'])),
' ', 'AdditionalIncludeDirectories', '', True)
f.write(props)
f.write(CLSWITCHES.getXml(xsorted(config.env['CCFLAGS']), ' '))
f.write(' </ClCompile>\r\n')
f.write(' <Link>\r\n')
props = ''
props += self.makeListTag(xsorted(config.env['LIBS']),
' ', 'AdditionalDependencies', '', True)
try:
props += self.makeListTag(self.relPaths(xsorted(config.env['LIBPATH'])),
' ', 'AdditionalLibraryDirectories', '', True)
except:
pass
f.write(props)
f.write(LINKSWITCHES.getXml(xsorted(config.env['LINKFLAGS']), ' '))
f.write(' </Link>\r\n')
f.write(' </ItemDefinitionGroup>\r\n')
def writeProject(self):
self.writeHeader()
f = self.project_file
self.project_file.write(' <ItemGroup>\r\n')
for item in self.items:
path = winpath(os.path.relpath(item.path(), self.project_dir))
tag = item.tag()
props = ''
if item.builder() == 'Object':
props = ''
for config in self.configs:
name = config.name
variant = config.variant
platform = config.platform
if not config in item.node:
props += \
''' <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='%(variant)s|%(platform)s'">True</ExcludedFromBuild>\r\n''' % locals()
for config, output in xsorted(item.node.items()):
name = config.name
env = output.get_build_env()
variant = config.variant
platform = config.platform
props += self.makeListTag(self.extraRelPaths(xsorted(env['CPPPATH']), config.env['CPPPATH']),
' ', 'AdditionalIncludeDirectories',
''' Condition="'$(Configuration)|$(Platform)'=='%(variant)s|%(platform)s'"''' % locals(),
True)
elif item.is_excluded():
props = ' <ExcludedFromBuild>True</ExcludedFromBuild>\r\n'
elif item.builder() == 'Protoc':
for config, output in xsorted(item.node.items()):
name = config.name
out_dir = os.path.relpath(os.path.dirname(str(output)), self.project_dir)
cpp_out = winpath(out_dir)
out_parts = out_dir.split(os.sep)
out_parts.append(os.path.splitext(os.path.basename(item.path()))[0])
base_out = ntpath.join(*out_parts)
props += V12CustomBuildProtoc % locals()
f.write(' <%(tag)s Include="%(path)s">\r\n' % locals())
f.write(props)
f.write(' </%(tag)s>\r\n' % locals())
f.write(' </ItemGroup>\r\n')
f.write(
' <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r\n'
' <ImportGroup Label="ExtensionTargets">\r\n'
' </ImportGroup>\r\n'
'</Project>\r\n')
def writeFilters(self):
def getGroup(abspath):
abspath = os.path.dirname(abspath)
for d in self.root_dirs:
common = os.path.commonprefix([abspath, d])
if common == d:
return winpath(os.path.relpath(abspath, common))
return winpath(os.path.split(abspath)[1])
f = self.filters_file
f.write(UnicodeByteMarker)
f.write(V12DSPFiltersHeader)
f.write(' <ItemGroup>\r\n')
groups = set()
for item in self.items:
group = getGroup(os.path.abspath(item.path()))
while group != '':
groups.add(group)
group = ntpath.split(group)[0]
for group in xsorted(groups):
guid = _guid(self.guid, group)
f.write(
' <Filter Include="%(group)s">\r\n'
' <UniqueIdentifier>%(guid)s</UniqueIdentifier>\r\n'
' </Filter>\r\n' % locals())
f.write(' </ItemGroup>\r\n')
f.write(' <ItemGroup>\r\n')
for item in self.items:
path = os.path.abspath(item.path())
group = getGroup(path)
path = winpath(os.path.relpath(path, self.project_dir))
tag = item.tag()
f.write (
' <%(tag)s Include="%(path)s">\r\n'
' <Filter>%(group)s</Filter>\r\n'
' </%(tag)s>\r\n' % locals())
f.write(' </ItemGroup>\r\n')
f.write('</Project>\r\n')
def build(self):
try:
self.project_file = open(str(self.project_node), 'wb')
except IOError, detail:
raise SCons.Errors.InternalError('Unable to open "' +
str(self.project_node) + '" for writing:' + str(detail))
try:
self.filters_file = open(str(self.filters_node), 'wb')
except IOError, detail:
raise SCons.Errors.InternalError('Unable to open "' +
str(self.filters_node) + '" for writing:' + str(detail))
self.writeProject()
self.writeFilters()
self.project_file.close()
self.filters_file.close()
#-------------------------------------------------------------------------------
class _SolutionGenerator(object):
def __init__(self, slnfile, projfile, env):
pass
def build(self):
pass
#-------------------------------------------------------------------------------
# Generate the VS2013 project
def buildProject(target, source, env):
if env.get('auto_build_solution', 1):
if len(target) != 3:
raise ValueError ("Unexpected len(target) != 3")
if not env.get('auto_build_solution', 1):
if len(target) != 2:
raise ValueError ("Unexpected len(target) != 2")
g = _ProjectGenerator (target[0], target[1], env)
g.build()
if env.get('auto_build_solution', 1):
g = _SolutionGenerator (target[2], target[0], env)
g.build()
def projectEmitter(target, source, env):
if len(target) != 1:
raise ValueError ("Exactly one target must be specified")
# If source is unspecified this condition will be true
if not source or source[0] == target[0]:
source = []
outputs = []
for node in list(target):
path = env.GetBuildPath(node)
outputs.extend([
path + '.vcxproj',
path + '.vcxproj.filters'])
if env.get('auto_build_solution', 1):
outputs.append(path + '.sln')
return outputs, source
projectBuilder = SCons.Builder.Builder(
action = SCons.Action.Action(buildProject, "Building ${TARGET}"),
emitter = projectEmitter)
def createConfig(self, variant, platform, target, env):
return Configuration(variant, platform, target, env)
def generate(env):
'''Add Builders and construction variables for Microsoft Visual
Studio project files to an Environment.'''
try:
env['BUILDERS']['VSProject']
except KeyError:
env['BUILDERS']['VSProject'] = projectBuilder
env.AddMethod(createConfig, 'VSProjectConfig')
def exists(env):
return True