Remove scons support

This commit is contained in:
Brad Chase
2018-03-02 14:18:03 -05:00
committed by Nikolaos D. Bougalis
parent b4e1b3c1b1
commit f0b9506617
42 changed files with 312 additions and 15913 deletions

View File

@@ -1,188 +0,0 @@
# Beast.py
# Copyright 2014 by:
# Vinnie Falco <vinnie.falco@gmail.com>
# Tom Ritchford <?>
# Nik Bougalis <?>
# This file is part of Beast: http://github.com/vinniefalco/Beast
from __future__ import absolute_import, division, print_function, unicode_literals
import os
import platform
import subprocess
import sys
import SCons.Node
import SCons.Util
#-------------------------------------------------------------------------------
#
# Environment
#
#-------------------------------------------------------------------------------
def _execute(args, include_errors=True, **kwds):
"""Execute a shell command and return the value. If args is a string,
it's split on spaces - if some of your arguments contain spaces, args should
instead be a list of arguments."""
def single_line(line, report_errors=True, joiner='+'):
"""Force a string to be a single line with no carriage returns, and report
a warning if there was more than one line."""
lines = line.strip().splitlines()
if report_errors and len(lines) > 1:
print('multiline result:', lines)
return joiner.join(lines)
def is_string(s):
"""Is s a string? - in either Python 2.x or 3.x."""
return isinstance(s, (str, unicode))
if is_string(args):
args = args.split()
stderr = subprocess.STDOUT if include_errors else None
return single_line(subprocess.check_output(args, stderr=stderr, **kwds))
class __System(object):
"""Provides information about the host platform"""
def __init__(self):
self.name = platform.system()
self.linux = self.name == 'Linux'
self.osx = self.name == 'Darwin'
self.windows = self.name == 'Windows'
self.distro = None
self.version = None
# True if building under the Travis CI (http://travis-ci.org)
self.travis = (
os.environ.get('TRAVIS', '0') == 'true') and (
os.environ.get('CI', '0') == 'true')
if self.linux:
self.distro, self.version, _ = platform.linux_distribution()
self.__display = '%s %s (%s)' % (self.distro, self.version, self.name)
elif self.osx:
parts = platform.mac_ver()[0].split('.')
while len(parts) < 3:
parts.append('0')
self.__display = '%s %s' % (self.name, '.'.join(parts))
elif self.windows:
release, version, csd, ptype = platform.win32_ver()
self.__display = '%s %s %s (%s)' % (self.name, release, version, ptype)
else:
raise Exception('Unknown system platform "' + self.name + '"')
self.platform = self.distro or self.name
def __str__(self):
return self.__display
class Git(object):
"""Provides information about git and the repository we are called from"""
def __init__(self, env):
self.tags = self.branch = self.user = ''
self.exists = env.Detect('git')
if self.exists:
try:
self.tags = _execute('git describe --tags')
self.branch = _execute('git rev-parse --abbrev-ref HEAD')
remote = _execute('git config remote.origin.url')
self.user = remote.split(':')[1].split('/')[0]
except:
self.exists = False
system = __System()
#-------------------------------------------------------------------------------
def printChildren(target):
def doPrint(tgt, level, found):
for item in tgt:
if SCons.Util.is_List(item):
doPrint(item, level, found)
else:
if item.abspath in found:
continue
found[item.abspath] = False
print('\t'*level + item.path)
#DoPrint(item.children(scan=1), level+1, found)
item.scan()
doPrint(item.all_children(), level+1, found)
doPrint(target, 0, {})
def variantFile(path, variant_dirs):
'''Returns the path to the corresponding dict entry in variant_dirs'''
path = str(path)
for dest, source in variant_dirs.items():
common = os.path.commonprefix([path, source])
if common == source:
return os.path.join(dest, path[len(common)+1:])
return path
def variantFiles(files, variant_dirs):
'''Returns a list of files remapped to their variant directories'''
result = []
for path in files:
result.append(variantFile(path, variant_dirs))
return result
def printEnv(env, keys):
if type(keys) != list:
keys = list(keys)
s = ''
for key in keys:
if key in env:
value = env[key]
else:
value = ''
s+=('%s=%s, ' % (key, value))
print('[' + s + ']')
#-------------------------------------------------------------------------------
#
# Output
#
#-------------------------------------------------------------------------------
# See https://stackoverflow.com/questions/7445658/how-to-detect-if-the-console-does-support-ansi-escape-codes-in-python
CAN_CHANGE_COLOR = (
hasattr(sys.stderr, "isatty")
and sys.stderr.isatty()
and not system.windows
and not os.environ.get('INSIDE_EMACS')
)
# See https://en.wikipedia.org/wiki/ANSI_escape_code
BLUE = 94
GREEN = 92
RED = 91
YELLOW = 93
def add_mode(text, *modes):
if CAN_CHANGE_COLOR:
modes = ';'.join(str(m) for m in modes)
return '\033[%sm%s\033[0m' % (modes, text)
else:
return text
def blue(text):
return add_mode(text, BLUE)
def green(text):
return add_mode(text, GREEN)
def red(text):
return add_mode(text, RED)
def yellow(text):
return add_mode(text, YELLOW)
def warn(text, print=print):
print('%s %s' % (red('WARNING:'), text))
# Prints command lines using environment substitutions
def print_coms(coms, env):
if type(coms) is str:
coms=list(coms)
for key in coms:
cmdline = env.subst(env[key], 0,
env.File('<target>'), env.File('<sources>'))
print (green(cmdline))

View File

@@ -1,97 +0,0 @@
#
# Copyright (c) 2009 Scott Stafford
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Author : Scott Stafford
# Date : 2009-12-09 20:36:14
#
# Changes : Vinnie Falco <vinnie.falco@gmail.com>
# Date : 2014--4-25
"""
Protoc.py: Protoc Builder for SCons
This Builder invokes protoc to generate C++ and Python from a .proto file.
NOTE: Java is not currently supported.
"""
__author__ = "Scott Stafford"
import SCons.Action
import SCons.Builder
import SCons.Defaults
import SCons.Node.FS
import SCons.Util
from SCons.Script import File, Dir
import os.path
protocs = 'protoc'
ProtocAction = SCons.Action.Action('$PROTOCCOM', '$PROTOCCOMSTR')
def ProtocEmitter(target, source, env):
PROTOCOUTDIR = env['PROTOCOUTDIR']
PROTOCPYTHONOUTDIR = env['PROTOCPYTHONOUTDIR']
for source_path in [str(x) for x in source]:
base = os.path.splitext(os.path.basename(source_path))[0]
if PROTOCOUTDIR:
target.extend([os.path.join(PROTOCOUTDIR, base + '.pb.cc'),
os.path.join(PROTOCOUTDIR, base + '.pb.h')])
if PROTOCPYTHONOUTDIR:
target.append(os.path.join(PROTOCPYTHONOUTDIR, base + '_pb2.py'))
try:
target.append(env['PROTOCFDSOUT'])
except KeyError:
pass
#print "PROTOC SOURCE:", [str(s) for s in source]
#print "PROTOC TARGET:", [str(s) for s in target]
return target, source
ProtocBuilder = SCons.Builder.Builder(
action = ProtocAction,
emitter = ProtocEmitter,
srcsuffix = '$PROTOCSRCSUFFIX')
def generate(env):
"""Add Builders and construction variables for protoc to an Environment."""
try:
bld = env['BUILDERS']['Protoc']
except KeyError:
bld = ProtocBuilder
env['BUILDERS']['Protoc'] = bld
env['PROTOC'] = env.Detect(protocs) or 'protoc'
env['PROTOCFLAGS'] = SCons.Util.CLVar('')
env['PROTOCPROTOPATH'] = SCons.Util.CLVar('')
env['PROTOCCOM'] = '$PROTOC ${["-I%s"%x for x in PROTOCPROTOPATH]} $PROTOCFLAGS --cpp_out=$PROTOCCPPOUTFLAGS$PROTOCOUTDIR ${PROTOCPYTHONOUTDIR and ("--python_out="+PROTOCPYTHONOUTDIR) or ""} ${PROTOCFDSOUT and ("-o"+PROTOCFDSOUT) or ""} ${SOURCES}'
env['PROTOCOUTDIR'] = '${SOURCE.dir}'
env['PROTOCPYTHONOUTDIR'] = "python"
env['PROTOCSRCSUFFIX'] = '.proto'
def exists(env):
return env.Detect(protocs)

View File

@@ -1,894 +0,0 @@
# 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'
V14DSPHeader = """\
<?xml version="1.0" encoding="%(encoding)s"?>\r
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
"""
V14DSPProjectConfiguration = """\
<ProjectConfiguration Include="%(variant)s|%(platform)s">\r
<Configuration>%(variant)s</Configuration>\r
<Platform>%(platform)s</Platform>\r
</ProjectConfiguration>\r
"""
V14DSPGlobals = """\
<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
"""
V14DSPPropertyGroup = """\
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='%(variant)s|%(platform)s'" Label="Configuration">\r
<CharacterSet>MultiByte</CharacterSet>\r
<ConfigurationType>Application</ConfigurationType>\r
<PlatformToolset>v140</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
"""
V14DSPImportGroup= """\
<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
"""
V14DSPItemDefinitionGroup= """\
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='%(variant)s|%(platform)s'">\r
"""
V14CustomBuildProtoc= """\
<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
"""
V14DSPFiltersHeader = (
'''<?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(V14DSPHeader % locals())
f.write(V14DSPGlobals % locals())
f.write(' <ItemGroup Label="ProjectConfigurations">\r\n')
for config in self.configs:
variant = config.variant
platform = config.platform
f.write(V14DSPProjectConfiguration % 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(V14DSPPropertyGroup % 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(V14DSPImportGroup % locals())
f.write(' <PropertyGroup Label="UserMacros" />\r\n')
for config in self.configs:
variant = config.variant
platform = config.platform
f.write(V14DSPItemDefinitionGroup % 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 += V14CustomBuildProtoc % 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(V14DSPFiltersHeader)
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

View File

@@ -138,11 +138,6 @@ std::unique_ptr <Checkpointer> makeCheckpointer (soci::session&, JobQueue&, Logs
} // ripple
// Do not remove this dead code. It forces `scons vcxproj` to include version.h.
#if 0
#include "version.h"
#endif
#if defined(__clang__)
#pragma clang diagnostic pop
#endif

View File

@@ -1,84 +0,0 @@
# Copyright (c) 2014 The Native Client Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import atexit
import os
import sys
import SCons.Action
# This implements a Ninja backend for SCons. This allows SCons to be used
# as a Ninja file generator, similar to how Gyp will generate Ninja files.
#
# This is a way to bypass SCons's slow startup time. After running SCons
# to generate a Ninja file (which is fairly slow), you can rebuild targets
# quickly using Ninja, as long as the .scons files haven't changed.
#
# The implementation is fairly hacky: It hooks PRINT_CMD_LINE_FUNC to
# discover the build commands that SCons would normally run.
#
# A cleaner implementation would traverse the node graph instead.
# Traversing the node graph is itself straightforward, but finding the
# command associated with a node is not -- I couldn't figure out how to do
# that.
# This is necessary to handle SCons's "variant dir" feature. The filename
# associated with a Scons node can be ambiguous: it might come from the
# build dir or the source dir.
def GetRealNode(node):
src = node.srcnode()
if src.stat() is not None:
return src
return node
def GenerateNinjaFile(envs, dest_file):
# Tell SCons not to run any commands, just report what would be run.
for e in envs:
e.SetOption('no_exec', True)
# Tell SCons that everything needs rebuilding.
e.Decider(lambda dependency, target, prev_ni: True)
# Use a list to ensure that the output is ordered deterministically.
node_list = []
node_map = {}
def CustomCommandPrinter(cmd, targets, source, env):
for node in targets:
# There can sometimes be multiple commands per target (e.g. ar+ranlib).
# We must collect these together to output a single Ninja rule.
if node not in node_map:
node_list.append(node)
node_map.setdefault(node, []).append(cmd)
for e in envs:
e.Append(PRINT_CMD_LINE_FUNC=CustomCommandPrinter)
def WriteFile():
dest_temp = '%s.tmp' % dest_file
ninja_fh = open(dest_temp, 'w')
ninja_fh.write("""\
# Generated by scons_to_ninja.py
# Generic rule for handling any command.
rule cmd
command = $cmd
# NaCl overrides SCons's Install() step to create hard links, for speed.
# To coexist with that, we must remove the file before copying, otherwise
# cp complains the source and dest "are the same file". We also create
# hard links here (with -l) for speed.
rule install
command = rm -f $out && cp -l $in $out
""")
for node in node_list:
dest_path = node.get_path()
cmds = node_map[node]
deps = [GetRealNode(dep).get_path() for dep in node.all_children()]
action = node.builder.action
if type(action) == SCons.Action.FunctionAction:
funcname = action.function_name()
if funcname == 'installFunc':
assert len(deps) == 1, len(deps)
ninja_fh.write('\nbuild %s: install %s\n'
% (dest_path, ' '.join(deps)))
continue
else:
sys.stderr.write('Unknown FunctionAction, %r: skipping target %r\n'
% (funcname, dest_path))
continue
ninja_fh.write('\nbuild %s: cmd %s\n'
% (dest_path, ' '.join(deps)))
ninja_fh.write(' cmd = %s\n' % ' && '.join(cmds))
# Make the result file visible atomically.
os.rename(dest_temp, dest_file)
atexit.register(WriteFile)