mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-05 16:57:56 +00:00
Beast SCons tools:
* Add VSProject SCons Builder * Add Protoc SCons Builder * Add Beast build utilities python module
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,10 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import copy
|
||||
import itertools
|
||||
import ntpath
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
def add_beast_to_path():
|
||||
@@ -24,7 +27,7 @@ VARIANT_DIRECTORIES = {
|
||||
'modules': ('bin', 'modules'),
|
||||
}
|
||||
|
||||
BOOST_LIBRARIES = 'boost_system',
|
||||
BOOST_LIBRARIES = '' #boost_system'
|
||||
MAIN_PROGRAM_FILE = 'beast/unit_test/tests/main.cpp'
|
||||
DOTFILE = '~/.scons'
|
||||
|
||||
@@ -43,6 +46,94 @@ def main():
|
||||
for name, path in VARIANT_DIRECTORIES.items():
|
||||
env.VariantDir(os.path.join(*path), name, duplicate=0)
|
||||
env.Replace(PRINT_CMD_LINE_FUNC=Print.print_cmd_line)
|
||||
Tests.run_tests(env, MAIN_PROGRAM_FILE, '.', '.test.cpp')
|
||||
#Tests.run_tests(env, MAIN_PROGRAM_FILE, '.', '.test.cpp')
|
||||
|
||||
#main()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def is_unity(path):
|
||||
b, e = os.path.splitext(path)
|
||||
return os.path.splitext(b)[1] == '.unity' and e in ['.c', '.cpp']
|
||||
|
||||
def files(base):
|
||||
for parent, _, files in os.walk(base):
|
||||
for path in files:
|
||||
path = os.path.join(parent, path)
|
||||
yield os.path.normpath(path)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
'''
|
||||
/MP /GS /W3 /wd"4018" /wd"4244" /wd"4267" /Gy- /Zc:wchar_t
|
||||
/I"D:\lib\OpenSSL-Win64\include" /I"D:\lib\boost_1_55_0"
|
||||
/I"..\..\src\protobuf\src" /I"..\..\src\protobuf\vsprojects"
|
||||
/I"..\..\src\leveldb" /I"..\..\src\leveldb\include" /I"..\..\build\proto"
|
||||
/Zi /Gm- /Od /Fd"..\..\build\obj\VisualStudio2013\Debug.x64\vc120.pdb"
|
||||
/fp:precise /D "_CRTDBG_MAP_ALLOC" /D "WIN32" /D "_DEBUG" /D "_CONSOLE"
|
||||
/D "_VARIADIC_MAX=10" /D "_WIN32_WINNT=0x0600" /D "_SCL_SECURE_NO_WARNINGS"
|
||||
/D "_CRT_SECURE_NO_WARNINGS" /D "_MBCS" /errorReport:prompt /WX- /Zc:forScope
|
||||
/RTC1 /GR /Gd /MTd /openmp- /Fa"..\..\build\obj\VisualStudio2013\Debug.x64\"
|
||||
/EHa /nologo /Fo"..\..\build\obj\VisualStudio2013\Debug.x64\"
|
||||
/Fp"..\..\build\obj\VisualStudio2013\Debug.x64\rippled.pch"
|
||||
'''
|
||||
|
||||
# Path to this SConstruct file
|
||||
base_dir = Dir('#').srcnode().get_abspath()
|
||||
|
||||
base_env = Environment(
|
||||
tools = ['default', 'VSProject'],
|
||||
CCCOMSTR = '',
|
||||
CMDLINE_QUIET = 1,
|
||||
CPPPATH = [
|
||||
os.environ['BOOST_ROOT'],
|
||||
os.environ['OPENSSL_ROOT']
|
||||
],
|
||||
CPPDEFINES = [
|
||||
'_WIN32_WINNT=0x6000']
|
||||
)
|
||||
|
||||
#base_env.Replace(PRINT_CMD_LINE_FUNC=Print.print_cmd_line)
|
||||
|
||||
env = base_env
|
||||
|
||||
bin_dir = os.path.join(base_dir, 'bin')
|
||||
|
||||
srcs = filter(is_unity, list(files('beast')) + list(files('modules')))
|
||||
for variant in ['Debug']: #, 'Release']:
|
||||
for platform in ['Win32']:
|
||||
#env = base_env.Clone()
|
||||
#env.Replace(PRINT_CMD_LINE_FUNC=Print.print_cmd_line)
|
||||
variant_dir = os.path.join(bin_dir, variant + '.' + platform)
|
||||
env.VariantDir(os.path.join(variant_dir, 'beast'), 'beast', duplicate=0)
|
||||
env.VariantDir(os.path.join(variant_dir, 'modules'), 'modules', duplicate=0)
|
||||
env.Append(CCFLAGS=[
|
||||
'/EHsc',
|
||||
'/bigobj',
|
||||
'/Fd${TARGET}.pdb'
|
||||
])
|
||||
if variant == 'Debug':
|
||||
env.Append(CCFLAGS=[
|
||||
'/MTd',
|
||||
'/Od',
|
||||
'/Zi'
|
||||
])
|
||||
else:
|
||||
env.Append(CCFLAGS=[
|
||||
'/MT',
|
||||
'/Ox'
|
||||
])
|
||||
variant_srcs = [os.path.join(variant_dir, os.path.relpath(f, base_dir)) for f in srcs]
|
||||
|
||||
beast = env.StaticLibrary(
|
||||
target = os.path.join(variant_dir, 'beast.lib'),
|
||||
source = variant_srcs)
|
||||
|
||||
env.VSProject (
|
||||
'out',
|
||||
buildtarget = beast,
|
||||
source = filter(is_unity, list(files('beast')) + list(files('modules'))))
|
||||
|
||||
env.Default ('out.vcxproj')
|
||||
#env.Default (os.path.join(bin_dir,'Debug.Win32', 'beast.lib'))
|
||||
|
||||
main()
|
||||
|
||||
@@ -21,4 +21,10 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "beast_core.beast_core.unity.cpp"
|
||||
#undef BEAST_COMPILE_OBJECTIVE_CPP
|
||||
#define BEAST_COMPILE_OBJECTIVE_CPP 1
|
||||
|
||||
#include "beast_core.unity.cpp"
|
||||
|
||||
#undef BEAST_COMPILE_OBJECTIVE_CPP
|
||||
#define BEAST_COMPILE_OBJECTIVE_CPP 0
|
||||
|
||||
@@ -59,12 +59,13 @@ private:
|
||||
// Called at program exit when destructors for objects
|
||||
// with static storage duration are invoked.
|
||||
//
|
||||
void doStaticDetruction ()
|
||||
void doStaticDestruction ()
|
||||
{
|
||||
// In theory this shouldn't be needed (?)
|
||||
ScopedLockType lock (m_mutex);
|
||||
|
||||
bassert (! m_didStaticDestruction);
|
||||
m_didStaticDestruction = true;
|
||||
|
||||
for (List <Item>::iterator iter (m_list.begin()); iter != m_list.end();)
|
||||
{
|
||||
@@ -82,7 +83,7 @@ private:
|
||||
{
|
||||
~StaticDestructor ()
|
||||
{
|
||||
Manager::get().doStaticDetruction();
|
||||
Manager::get().doStaticDestruction();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
Python code for the beast and scons.
|
||||
|
||||
Scripts you can run from this directory.
|
||||
|
||||
./run-tests.sh
|
||||
Runs the unit tests.
|
||||
|
||||
./clean-python.sh
|
||||
If you remove or rename any Python files, you should run this script to
|
||||
prevent old .pyc files from hiding bugs.
|
||||
11
src/beast/python/beast/env/AddCommonFlags.py
vendored
11
src/beast/python/beast/env/AddCommonFlags.py
vendored
@@ -1,11 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from beast.util import Boost
|
||||
from beast.util import Git
|
||||
|
||||
def add_common_flags(env):
|
||||
git_flag = '-DTIP_BRANCH="%s"' % Git.describe()
|
||||
env['CPPFLAGS'] = '%s %s' % (env['CPPFLAGS'], git_flag)
|
||||
env['CPPPATH'].insert(0, Boost.CPPPATH)
|
||||
env['LIBPATH'].append(Boost.LIBPATH)
|
||||
env['BOOST_HOME'] = Boost.CPPPATH
|
||||
38
src/beast/python/beast/env/AddUserEnv.py
vendored
38
src/beast/python/beast/env/AddUserEnv.py
vendored
@@ -1,38 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import os
|
||||
import shlex
|
||||
|
||||
from beast.env.ReadEnvFile import read_env_file
|
||||
from beast.util.String import is_string
|
||||
from beast.util.Terminal import warn
|
||||
|
||||
_BAD_VARS_ERROR = """
|
||||
the following variables appearing in %s were not understood:
|
||||
%s"""
|
||||
|
||||
def add_user_env(env, dotfile, print=print):
|
||||
df = os.path.expanduser(dotfile)
|
||||
try:
|
||||
with open(df, 'r') as f:
|
||||
dotvars = read_env_file(f.read())
|
||||
except IOError:
|
||||
if os.path.exists(df):
|
||||
warn("Dotfile %s exists but can't be read." % dotfile, print)
|
||||
dotvars = {}
|
||||
|
||||
bad_names = []
|
||||
for name, value in dotvars.items():
|
||||
if name in env:
|
||||
if is_string(env[name]):
|
||||
env[name] = value
|
||||
else:
|
||||
env[name] = shlex.split(value)
|
||||
else:
|
||||
bad_names.append(name)
|
||||
if bad_names:
|
||||
error = _BAD_VARS_ERROR % (dotfile, '\n '.join(bad_names))
|
||||
warn(error, print)
|
||||
|
||||
for name, default in env.items():
|
||||
env[name] = os.environ.get(name, default)
|
||||
41
src/beast/python/beast/env/Print.py
vendored
41
src/beast/python/beast/env/Print.py
vendored
@@ -1,41 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import textwrap
|
||||
|
||||
from beast.util import String
|
||||
from beast.util import Terminal
|
||||
|
||||
FIELD_WIDTH = 10
|
||||
LINE_WIDTH = 69
|
||||
|
||||
EMPTY_NAME = ' ' * FIELD_WIDTH
|
||||
|
||||
TEXT_WRAPPER = textwrap.TextWrapper(
|
||||
break_long_words=False,
|
||||
break_on_hyphens=False,
|
||||
width=LINE_WIDTH,
|
||||
)
|
||||
|
||||
DISPLAY_EMPTY_ENVS = True
|
||||
|
||||
def print_build_vars(name, value, same, print=print):
|
||||
"""Pretty-print values as a build configuration."""
|
||||
name = '%s' % name.rjust(FIELD_WIDTH)
|
||||
color = Terminal.blue if same else Terminal.green
|
||||
|
||||
for line in TEXT_WRAPPER.wrap(String.stringify(value, ' ')):
|
||||
print(' '.join([name, color(line)]))
|
||||
name = EMPTY_NAME
|
||||
|
||||
def print_cmd_line(s, target, source, env):
|
||||
print(EMPTY_NAME + Terminal.blue(String.stringify(target)))
|
||||
|
||||
def print_build_config(env, original, print=print):
|
||||
print('\nConfiguration:')
|
||||
for name, value in env.items():
|
||||
if value or DISPLAY_EMPTY_ENVS:
|
||||
same = (value == original[name])
|
||||
if not same:
|
||||
print('"%s" != "%s"' % (value, original[name]))
|
||||
print_build_vars(name, value, same, print=print)
|
||||
print()
|
||||
34
src/beast/python/beast/env/ReadEnvFile.py
vendored
34
src/beast/python/beast/env/ReadEnvFile.py
vendored
@@ -1,34 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
from beast.util import String
|
||||
from beast.util.Terminal import warn
|
||||
|
||||
ENV_LINE_MATCH = re.compile(r'(?: export \s+)? \s* ([^=\s]*) \s* = (.*)',
|
||||
re.VERBOSE)
|
||||
|
||||
def read_env_file(data, print=print):
|
||||
try:
|
||||
return json.loads(data)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
bad_lines = []
|
||||
results = {}
|
||||
for number, raw_line in enumerate(data.splitlines()):
|
||||
line = String.remove_comment(raw_line).strip()
|
||||
if line:
|
||||
match = ENV_LINE_MATCH.match(line)
|
||||
if match:
|
||||
name, value = match.groups()
|
||||
results[name.strip()] = String.remove_quotes(value.strip())
|
||||
else:
|
||||
bad_lines.append([number, raw_line])
|
||||
if bad_lines:
|
||||
warn("Didn't understand the following environment file lines:", print)
|
||||
for number, line in bad_lines:
|
||||
print('%d. >>> %s' % (number + 1, line))
|
||||
|
||||
return results
|
||||
51
src/beast/python/beast/env/ReadEnvFile_test.py
vendored
51
src/beast/python/beast/env/ReadEnvFile_test.py
vendored
@@ -1,51 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from unittest import TestCase
|
||||
from beast.env.ReadEnvFile import read_env_file
|
||||
|
||||
from beast.util import Terminal
|
||||
Terminal.CAN_CHANGE_COLOR = False
|
||||
|
||||
JSON = """
|
||||
{
|
||||
"FOO": "foo",
|
||||
"BAR": "bar bar bar",
|
||||
"CPPFLAGS": "-std=c++11 -frtti -fno-strict-aliasing -DWOMBAT"
|
||||
}"""
|
||||
|
||||
ENV = """
|
||||
# An env file.
|
||||
|
||||
FOO=foo
|
||||
export BAR="bar bar bar"
|
||||
CPPFLAGS=-std=c++11 -frtti -fno-strict-aliasing -DWOMBAT
|
||||
|
||||
# export BAZ=baz should be ignored.
|
||||
|
||||
"""
|
||||
|
||||
RESULT = {
|
||||
'FOO': 'foo',
|
||||
'BAR': 'bar bar bar',
|
||||
'CPPFLAGS': '-std=c++11 -frtti -fno-strict-aliasing -DWOMBAT',
|
||||
}
|
||||
|
||||
BAD_ENV = ENV + """
|
||||
This line isn't right.
|
||||
NO SPACES IN NAMES="valid value"
|
||||
"""
|
||||
|
||||
class test_ReadEnvFile(TestCase):
|
||||
def test_read_json(self):
|
||||
self.assertEqual(read_env_file(JSON), RESULT)
|
||||
|
||||
def test_read_env(self):
|
||||
self.assertEqual(read_env_file(ENV), RESULT)
|
||||
|
||||
def test_read_env_error(self):
|
||||
errors = []
|
||||
self.assertEqual(read_env_file(BAD_ENV, errors.append), RESULT)
|
||||
self.assertEqual(errors, [
|
||||
"WARNING: Didn't understand the following environment file lines:",
|
||||
"11. >>> This line isn't right.",
|
||||
'12. >>> NO SPACES IN NAMES="valid value"'])
|
||||
17
src/beast/python/beast/env/Tags.py
vendored
17
src/beast/python/beast/env/Tags.py
vendored
@@ -1,17 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from beast.util.Terminal import warn
|
||||
|
||||
_TAGS = frozenset(['debug', 'optimize'])
|
||||
|
||||
def _to_tag(name, value):
|
||||
return '%s%s' % ('' if value else 'no', name)
|
||||
|
||||
def get_tags(arguments, print=print):
|
||||
result = {}
|
||||
bad_tags = set(arguments) - _TAGS
|
||||
if bad_tags:
|
||||
warn("don't understand tags " + ' '.join(bad_tags), print=print)
|
||||
debug = result.get('debug', True)
|
||||
optimize = result.get('optimize', not debug)
|
||||
return _to_tag('debug', debug), _to_tag('optimize', optimize)
|
||||
0
src/beast/python/beast/env/__init__.py
vendored
0
src/beast/python/beast/env/__init__.py
vendored
@@ -1,59 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from beast.platform import Platform
|
||||
from beast.util import Dict
|
||||
from beast.env import Tags
|
||||
|
||||
_DEFAULTS = {
|
||||
'': {
|
||||
'BOOST_HOME': None,
|
||||
'CC': 'gcc',
|
||||
'CCFLAGS': None,
|
||||
'CFLAGS': None,
|
||||
'CXX': 'g++',
|
||||
'CPPFLAGS': '-std=c++11 -frtti -fno-strict-aliasing',
|
||||
'CPPPATH': [],
|
||||
'LIBPATH': [],
|
||||
'LIBS': [],
|
||||
'LINKFLAGS': '',
|
||||
},
|
||||
|
||||
'Darwin': {
|
||||
'CC': 'clang',
|
||||
'CXX': 'clang++',
|
||||
'CPPFLAGS': '-x c++ -stdlib=libc++ -std=c++11 -frtti',
|
||||
'LINKFLAGS': '-stdlib=libc++',
|
||||
},
|
||||
|
||||
'FreeBSD': {
|
||||
'CC': 'gcc46',
|
||||
'CXX': 'g++46',
|
||||
'CCFLAGS': '-Wl,-rpath=/usr/local/lib/gcc46',
|
||||
'LINKFLAGS': '-Wl,-rpath=/usr/local/lib/gcc46',
|
||||
'LIBS': ['kvm'],
|
||||
},
|
||||
|
||||
# TODO: specific flags for Windows, Linux platforms.
|
||||
}
|
||||
|
||||
TAGS = {
|
||||
'debug': {
|
||||
'CPPFLAGS': '-g -DDEBUG'
|
||||
},
|
||||
|
||||
'optimize': {
|
||||
'CPPFLAGS': '-O3',
|
||||
},
|
||||
|
||||
'nooptimize': {
|
||||
'CPPFLAGS': '-O0',
|
||||
}
|
||||
}
|
||||
|
||||
def get_environment(arguments):
|
||||
tags = Tags.get_tags(arguments)
|
||||
env = Dict.compose_prefix_dicts(Platform.PLATFORM, _DEFAULTS)
|
||||
for tag in tags or []:
|
||||
for k, v in TAGS.get(tag, {}).items():
|
||||
env[k] = '%s %s' % (env[k], v)
|
||||
return env
|
||||
@@ -1,27 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import platform
|
||||
|
||||
def _get_platform_string():
|
||||
system = platform.system()
|
||||
parts = [system]
|
||||
linux = system == 'Linux'
|
||||
if linux:
|
||||
flavor, version, _ = platform.linux_distribution()
|
||||
# Arch still has issues with the platform module
|
||||
parts[0] = flavor.capitalize() or 'Archlinux'
|
||||
parts.extend(version.split('.'))
|
||||
elif system == 'Darwin':
|
||||
ten, major, minor = platform.mac_ver()[0].split('.')
|
||||
parts.extend([ten, major, minor])
|
||||
elif system == 'Windows':
|
||||
release, version, csd, ptype = platform.win32_ver()
|
||||
parts.extend([release, version, csd, ptype])
|
||||
elif system == 'FreeBSD':
|
||||
# No other variables to pass with FreeBSD that Python provides and I could find
|
||||
pass
|
||||
else:
|
||||
raise Exception("Don't understand how to build for platform " + system)
|
||||
return '.'.join(parts), linux
|
||||
|
||||
PLATFORM, IS_LINUX = _get_platform_string()
|
||||
@@ -1,61 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
ROOT_ENV_VARIABLE = 'BOOST_ROOT'
|
||||
MINIMUM_VERSION = 1, 55, 0
|
||||
VERSION_FILE = 'boost', 'version.hpp'
|
||||
LIBRARY_PATH_SEGMENT = 'stage', 'lib'
|
||||
VERSION_MATCHER = re.compile(r'#define\s+BOOST_VERSION\s+(\d+)')
|
||||
|
||||
CANT_OPEN_VERSION_FILE_ERROR = """Unable to open boost version file %s.
|
||||
You have set the environment variable BOOST_ROOT to be %s.
|
||||
Please check to make sure that this points to a valid installation of boost."""
|
||||
|
||||
CANT_UNDERSTAND_VERSION_ERROR = (
|
||||
"Didn't understand version string '%s' from file %s'")
|
||||
VERSION_TOO_OLD_ERROR = ('Your version of boost, %s, is older than the minimum '
|
||||
'required, %s.')
|
||||
|
||||
def _text(major, minor, release):
|
||||
return '%d.%02d.%02d' % (major, minor, release)
|
||||
|
||||
def _raw_boost_path():
|
||||
try:
|
||||
path = os.environ[ROOT_ENV_VARIABLE]
|
||||
if path:
|
||||
return os.path.normpath(path)
|
||||
except KeyError:
|
||||
pass
|
||||
raise KeyError('%s environment variable is not set.' % ROOT_ENV_VARIABLE)
|
||||
|
||||
def _get_version_number(path):
|
||||
version_file = os.path.join(path, *VERSION_FILE)
|
||||
try:
|
||||
with open(version_file) as f:
|
||||
for line in f:
|
||||
match = VERSION_MATCHER.match(line)
|
||||
if match:
|
||||
version = match.group(1)
|
||||
try:
|
||||
return int(version)
|
||||
except ValueError:
|
||||
raise Exception(CANT_UNDERSTAND_VERSION_ERROR %
|
||||
(version, version_file))
|
||||
except IOError:
|
||||
raise Exception(CANT_OPEN_VERSION_FILE_ERROR % (version_file, path))
|
||||
|
||||
def _validate_version(v):
|
||||
version = v // 100000, (v // 100) % 100, v % 100
|
||||
if version < MINIMUM_VERSION:
|
||||
raise Exception(VERSION_TOO_OLD_ERROR % (
|
||||
_text(*version), _text(*MINIMUM_VERSION)))
|
||||
|
||||
def _boost_path():
|
||||
path = _raw_boost_path()
|
||||
_validate_version(_get_version_number(path))
|
||||
return path
|
||||
|
||||
CPPPATH = _boost_path()
|
||||
LIBPATH = os.path.join(CPPPATH, *LIBRARY_PATH_SEGMENT)
|
||||
@@ -1,77 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
# Copyright 2014, Tom Ritchford <tom@swirly.com>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
# ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
Cleans C++ files according to a consistent standard.
|
||||
|
||||
Trims trailing whitespace; converts files encoded in Latin-1 to UTF-8.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
def process_file(filename, process):
|
||||
with open(filename) as infile:
|
||||
lines = infile.read().strip().splitlines()
|
||||
outfd, outname = tempfile.mkstemp(dir=os.path.dirname(filename))
|
||||
with os.fdopen(outfd, 'w') as outfile:
|
||||
for number, line in enumerate(lines):
|
||||
try:
|
||||
result = process(line, filename, number).encode('utf-8')
|
||||
outfile.write(result)
|
||||
except Exception as e:
|
||||
if True: raise
|
||||
raise Exception('%s on line %d in file %s' %
|
||||
(e.message, number + 1, filename))
|
||||
os.rename(outname, filename)
|
||||
|
||||
def walk_and_process(root, process, condition, message=None):
|
||||
for root, dirs, files in os.walk(root):
|
||||
for f in files:
|
||||
filename = os.path.join(root, f)
|
||||
if condition(filename):
|
||||
if message:
|
||||
print(message % filename)
|
||||
process_file(filename, process)
|
||||
|
||||
def clean_line_endings(root, endings=None, message=None):
|
||||
if endings == None:
|
||||
endings = '.h', '.cpp', '.sh'
|
||||
def condition(filename):
|
||||
return os.path.splitext(filename)[1] in endings
|
||||
|
||||
def process(line, filename, number):
|
||||
try:
|
||||
return line.decode('utf-8').rstrip() + '\n'
|
||||
except:
|
||||
result = line.decode('latin-1').rstrip() + '\n'
|
||||
print('Found a non UTF-8 line at %s:%d' % (filename, number + 1))
|
||||
return result
|
||||
|
||||
walk_and_process(root, process, condition, message)
|
||||
|
||||
if __name__ == "__main__":
|
||||
path = '.'
|
||||
if len(sys.argv) > 1:
|
||||
path = sys.argv[1]
|
||||
clean_line_endings(os.path.abspath(path)) #, message='processing %s')
|
||||
@@ -1,17 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
def compose(*dicts):
|
||||
result = {}
|
||||
for d in dicts:
|
||||
result.update(**d)
|
||||
return result
|
||||
|
||||
def get_items_with_prefix(key, mapping):
|
||||
"""Get all elements from the mapping whose keys are a prefix of the given
|
||||
key, sorted by increasing key length."""
|
||||
for k, v in sorted(mapping.items()):
|
||||
if key.startswith(k):
|
||||
yield v
|
||||
|
||||
def compose_prefix_dicts(key, mapping):
|
||||
return compose(*get_items_with_prefix(key, mapping))
|
||||
@@ -1,56 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from beast.util import Dict
|
||||
|
||||
DICT = {
|
||||
'': {
|
||||
'foo': 'foo-default',
|
||||
'bar': 'bar-default',
|
||||
},
|
||||
|
||||
'Darwin': {
|
||||
'foo': 'foo-darwin',
|
||||
'baz': 'baz-darwin',
|
||||
},
|
||||
|
||||
'Darwin.10.8': {
|
||||
'foo': 'foo-darwin-10.8',
|
||||
'bing': 'bing-darwin-10.8',
|
||||
},
|
||||
}
|
||||
|
||||
class test_Dict(TestCase):
|
||||
def computeMapValue(self, config, key):
|
||||
return Dict.compose(*Dict.get_items_with_prefix(config, DICT))[key]
|
||||
|
||||
def assertMapValue(self, config, key, result):
|
||||
self.assertEquals(self.computeMapValue(config, key), result)
|
||||
|
||||
def testDefault1(self):
|
||||
self.assertMapValue('', 'foo', 'foo-default')
|
||||
|
||||
def testDefault2(self):
|
||||
self.assertMapValue('Darwin.10.8', 'bar', 'bar-default')
|
||||
|
||||
def testPrefix1(self):
|
||||
self.assertMapValue('Darwin', 'foo', 'foo-darwin')
|
||||
|
||||
def testPrefix2(self):
|
||||
self.assertMapValue('Darwin.10.8', 'foo', 'foo-darwin-10.8')
|
||||
|
||||
def testPrefix3(self):
|
||||
self.assertMapValue('Darwin', 'baz', 'baz-darwin')
|
||||
|
||||
def testPrefix4(self):
|
||||
self.assertMapValue('Darwin.10.8', 'bing', 'bing-darwin-10.8')
|
||||
|
||||
def testFailure1(self):
|
||||
self.assertRaises(KeyError, self.computeMapValue, '', 'baz')
|
||||
|
||||
def testFailure2(self):
|
||||
self.assertRaises(KeyError, self.computeMapValue, '', 'bing')
|
||||
|
||||
def testFailure2(self):
|
||||
self.assertRaises(KeyError, self.computeMapValue, 'Darwin', 'bing')
|
||||
@@ -1,14 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import subprocess
|
||||
|
||||
from beast.util import String
|
||||
|
||||
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."""
|
||||
if String.is_string(args):
|
||||
args = args.split()
|
||||
stderr = subprocess.STDOUT if include_errors else None
|
||||
return subprocess.check_output(args, stderr=stderr, **kwds)
|
||||
@@ -1,42 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from beast.util import String
|
||||
|
||||
import os
|
||||
|
||||
LIBRARY_PATTERNS = 'lib%s.a', 'lib%s.dylib'
|
||||
|
||||
def first_fields_after_prefix(filename, prefix):
|
||||
with open(filename, 'r') as f:
|
||||
return String.first_fields_after_prefix(prefix, f)
|
||||
|
||||
def find_files_with_suffix(base, suffix):
|
||||
for parent, _, files in os.walk(base):
|
||||
for path in files:
|
||||
path = os.path.join(parent, path)
|
||||
if path.endswith(suffix):
|
||||
yield os.path.normpath(path)
|
||||
|
||||
def child_files(parent, files):
|
||||
return [os.path.normpath(os.path.join(parent, f)) for f in files]
|
||||
|
||||
def sibling_files(path, files):
|
||||
return child_files(os.path.dirname(path), files)
|
||||
|
||||
def replace_extension(file, ext):
|
||||
return os.path.splitext(file)[0] + ext
|
||||
|
||||
def validate_libraries(path, libraries):
|
||||
bad = []
|
||||
for lib in libraries:
|
||||
found = False
|
||||
for pat in LIBRARY_PATTERNS:
|
||||
libfile = os.path.join(path, pat % lib)
|
||||
if os.path.isfile(libfile):
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
bad.append(libfile)
|
||||
if bad:
|
||||
libs = 'library' if len(bad) == 1 else 'libraries'
|
||||
raise Exception('Missing %s: %s' % (libs, ', '.join(bad)))
|
||||
@@ -1,9 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
from beast.util import Execute
|
||||
from beast.util import String
|
||||
|
||||
def describe(**kwds):
|
||||
return String.single_line(Execute.execute('git describe --tags', **kwds))
|
||||
@@ -1,7 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
def first(condition, sequence):
|
||||
for i in sequence:
|
||||
result = condition(i)
|
||||
if result:
|
||||
return result
|
||||
@@ -1,60 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import functools
|
||||
|
||||
from beast.util import Iter
|
||||
from beast.util.Terminal import warn
|
||||
|
||||
def is_string(s):
|
||||
"""Is s a string? - in either Python 2.x or 3.x."""
|
||||
return isinstance(s, (str, unicode))
|
||||
|
||||
def stringify(item, joiner=''):
|
||||
"""If item is not a string, stringify its members and join them."""
|
||||
try:
|
||||
len(item)
|
||||
except:
|
||||
return str(item)
|
||||
if not item or is_string(item):
|
||||
return item or ''
|
||||
else:
|
||||
return joiner.join(str(i) for i in item)
|
||||
|
||||
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)
|
||||
|
||||
# Copied from
|
||||
# https://github.com/lerugray/pickett/blob/master/pickett/ParseScript.py
|
||||
def remove_comment(line):
|
||||
"""Remove trailing comments from one line."""
|
||||
start = 0
|
||||
while True:
|
||||
loc = line.find('#', start)
|
||||
if loc == -1:
|
||||
return line.replace('\\#', '#')
|
||||
elif not (loc and line[loc - 1] == '\\'):
|
||||
return line[:loc].replace('\\#', '#')
|
||||
start = loc + 1
|
||||
|
||||
def remove_quotes(line, quote='"', print=print):
|
||||
if not line.startswith(quote):
|
||||
return line
|
||||
if line.endswith(quote):
|
||||
return line[1:-1]
|
||||
|
||||
warn('line started with %s but didn\'t end with one:' % quote, print)
|
||||
print(line)
|
||||
return line[1:]
|
||||
|
||||
def fields_after_prefix(prefix, line):
|
||||
line = line.strip()
|
||||
return line.startswith(prefix) and line[len(prefix):].split()
|
||||
|
||||
def first_fields_after_prefix(prefix, sequence):
|
||||
condition = functools.partial(fields_after_prefix, prefix)
|
||||
return Iter.first(condition, sequence) or []
|
||||
@@ -1,36 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from beast.util import String
|
||||
from beast.util import Terminal
|
||||
|
||||
Terminal.CAN_CHANGE_COLOR = False
|
||||
|
||||
class String_test(TestCase):
|
||||
def test_comments(self):
|
||||
self.assertEqual(String.remove_comment(''), '')
|
||||
self.assertEqual(String.remove_comment('#'), '')
|
||||
self.assertEqual(String.remove_comment('# a comment'), '')
|
||||
self.assertEqual(String.remove_comment('hello # a comment'), 'hello ')
|
||||
self.assertEqual(String.remove_comment(
|
||||
r'hello \# not a comment # a comment'),
|
||||
'hello # not a comment ')
|
||||
|
||||
def test_remove_quotes(self):
|
||||
errors = []
|
||||
self.assertEqual(String.remove_quotes('hello', print=errors.append),
|
||||
'hello')
|
||||
self.assertEqual(String.remove_quotes('"hello"', print=errors.append),
|
||||
'hello')
|
||||
self.assertEqual(String.remove_quotes('hello"', print=errors.append),
|
||||
'hello"')
|
||||
self.assertEqual(errors, [])
|
||||
|
||||
def test_remove_quotes_error(self):
|
||||
errors = []
|
||||
self.assertEqual(String.remove_quotes('"hello', print=errors.append),
|
||||
'hello')
|
||||
self.assertEqual(errors,
|
||||
['WARNING: line started with " but didn\'t end with one:',
|
||||
'"hello'])
|
||||
@@ -1,36 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import sys
|
||||
|
||||
from beast.platform.Platform import PLATFORM
|
||||
|
||||
# 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 PLATFORM.startswith('Windows'))
|
||||
|
||||
|
||||
# See https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
RED = 91
|
||||
GREEN = 92
|
||||
BLUE = 94
|
||||
|
||||
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 warn(text, print=print):
|
||||
print('%s %s' % (red('WARNING:'), text))
|
||||
@@ -1,31 +0,0 @@
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
from beast.util import File
|
||||
|
||||
LIBS_PREFIX = '// LIBS:'
|
||||
MODS_PREFIX = '// MODULES:'
|
||||
|
||||
def build_executable(env, path, main_program_file):
|
||||
"""Build a stand alone executable that runs
|
||||
all the test suites in one source file."""
|
||||
libs = File.first_fields_after_prefix(path, LIBS_PREFIX)
|
||||
source_modules = File.first_fields_after_prefix(path, MODS_PREFIX)
|
||||
source_modules = File.sibling_files(path, source_modules)
|
||||
|
||||
bin = os.path.basename(os.path.splitext(path)[0])
|
||||
bin = os.path.join('bin', bin)
|
||||
|
||||
# All paths get normalized here, so we can use posix
|
||||
# forward slashes for everything including on Windows
|
||||
srcs = File.child_files('bin', [main_program_file, path] + source_modules)
|
||||
objs = [File.replace_extension(f, '.o') for f in srcs]
|
||||
if libs:
|
||||
env.Append(LIBS=libs) # DANGER: will append the file over and over.
|
||||
env.Program(bin, srcs)
|
||||
|
||||
def run_tests(env, main_program_file, root, suffix):
|
||||
root = os.path.normpath(root)
|
||||
for path in File.find_files_with_suffix(root, suffix):
|
||||
build_executable(env, path, main_program_file)
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Remove all the compiled .pyc files at or below this directory.
|
||||
|
||||
find . -name \*.pyc | xargs rm
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run all the beast Python unit tests.
|
||||
|
||||
python -m unittest discover -p \*_test.py
|
||||
180
src/beast/site_scons/Beast.py
Normal file
180
src/beast/site_scons/Beast.py
Normal file
@@ -0,0 +1,180 @@
|
||||
# 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:
|
||||
ten, major, minor = platform.mac_ver()[0].split('.')
|
||||
self.__display = '%s %s.%s.%s' % (self.name, ten, major, minor)
|
||||
|
||||
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 + '"')
|
||||
|
||||
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.exists = env.Detect('git')
|
||||
if self.exists:
|
||||
self.commit_id = _execute('git describe --tags')
|
||||
else:
|
||||
self.commit_id = None
|
||||
|
||||
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.iteritems():
|
||||
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))
|
||||
@@ -28,7 +28,7 @@
|
||||
# Date : 2014--4-25
|
||||
|
||||
"""
|
||||
protoc.py: Protoc Builder for SCons
|
||||
Protoc.py: Protoc Builder for SCons
|
||||
|
||||
This Builder invokes protoc to generate C++ and Python from a .proto file.
|
||||
|
||||
@@ -72,9 +72,10 @@ def ProtocEmitter(target, source, env):
|
||||
|
||||
return target, source
|
||||
|
||||
ProtocBuilder = SCons.Builder.Builder(action = ProtocAction,
|
||||
emitter = ProtocEmitter,
|
||||
srcsuffix = '$PROTOCSRCSUFFIX')
|
||||
ProtocBuilder = SCons.Builder.Builder(
|
||||
action = ProtocAction,
|
||||
emitter = ProtocEmitter,
|
||||
srcsuffix = '$PROTOCSRCSUFFIX')
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for protoc to an Environment."""
|
||||
862
src/beast/site_scons/site_tools/VSProject.py
Normal file
862
src/beast/site_scons/site_tools/VSProject.py
Normal file
@@ -0,0 +1,862 @@
|
||||
# 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
|
||||
|
||||
import sys
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# 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 itemList(items, sep):
|
||||
if type(items) == str: # Won't work in Python 3.
|
||||
return items
|
||||
def gen():
|
||||
for item in sorted(items):
|
||||
if type(item) == dict:
|
||||
for k, v in item.items():
|
||||
yield k + '=' + v
|
||||
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):
|
||||
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']
|
||||
|
||||
def getXml(self, switches, prefix = ''):
|
||||
if type(switches) != list:
|
||||
switches = list(switches)
|
||||
xml = []
|
||||
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:
|
||||
xml.sort()
|
||||
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'],
|
||||
}
|
||||
# Ideas from Google's Generate Your Project
|
||||
'''
|
||||
_Same(_compile, 'AdditionalIncludeDirectories', _folder_list) # /I
|
||||
|
||||
_Same(_compile, 'PreprocessorDefinitions', _string_list) # /D
|
||||
_Same(_compile, 'DisableSpecificWarnings', _string_list) # /wd
|
||||
_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)
|
||||
|
||||
class LinkSwitchConverter(SwitchConverter):
|
||||
def __init__(self):
|
||||
# Based on code in Generate Your Project
|
||||
booltable = {
|
||||
'/DEBUG' : ['GenerateDebugInformation'],
|
||||
'/DYNAMICBASE' : ['RandomizedBaseAddress'],
|
||||
'/DYNAMICBASE' : ['RandomizedBaseAddress'],
|
||||
'/DYNAMICBASE' : ['RandomizedBaseAddress'],
|
||||
'/DYNAMICBASE' : ['RandomizedBaseAddress'],
|
||||
'/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 = sorted(env['VSPROJECT_CONFIGS'], key=lambda x: x.name)
|
||||
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.cpppath = []
|
||||
for path in [os.path.abspath(x) for x in makeList(env['CPPPATH'])]:
|
||||
common = os.path.commonprefix([path, self.root_dir])
|
||||
if len(common) == len(self.root_dir):
|
||||
self.cpppath.append(winpath(os.path.relpath(path, self.project_dir)))
|
||||
#else:
|
||||
# self.cpppath.append(path)
|
||||
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 = sorted([v for k, v in items.iteritems()], key=lambda x: x.path)
|
||||
|
||||
def makeListTag(self, items, tag, prefix='', 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>' % 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)))
|
||||
items.sort()
|
||||
return items
|
||||
|
||||
def makePaths(self, paths, extra = None):
|
||||
'''Returns a semicolon delimited string formed from a list
|
||||
of root relative paths converted to be project relative.'''
|
||||
s = ''
|
||||
sep = ''
|
||||
root_dir = os.getcwd()
|
||||
for path in sorted(paths):
|
||||
common = os.path.commonprefix([os.path.abspath(path), root_dir])
|
||||
if len(common) == len(root_dir):
|
||||
s += sep
|
||||
s += winpath(os.path.relpath(path, self.project_dir))
|
||||
sep = ';'
|
||||
if extra:
|
||||
s += sep + extra
|
||||
return s
|
||||
|
||||
def writeHeader(self):
|
||||
global clSwitches
|
||||
|
||||
encoding = 'utf-8'
|
||||
project_guid = self.guid
|
||||
name = 'RippleD'
|
||||
|
||||
f = self.project_file
|
||||
f.write(UnicodeByteMarker)
|
||||
f.write(V12DSPHeader % 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(V12DSPGlobals % locals())
|
||||
|
||||
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(os.path.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(
|
||||
#' <PrecompiledHeader />\r\n'
|
||||
' <PreprocessorDefinitions>%s%%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n' % (
|
||||
itemList(config.env['CPPDEFINES'], ';')))
|
||||
props = ''
|
||||
props += self.makeListTag(
|
||||
[x for x in config.env['CPPPATH'] if is_subdir(x, self.root_dir)
|
||||
], 'AdditionalIncludeDirectories', ' ', True)
|
||||
f.write(props)
|
||||
f.write(CLSWITCHES.getXml(config.env['CCFLAGS'], ' '))
|
||||
f.write(' </ClCompile>\r\n')
|
||||
|
||||
f.write(' <Link>\r\n')
|
||||
props = ''
|
||||
props += self.makeListTag([x for x in config.env['LIBS']
|
||||
], 'AdditionalDependencies', ' ', True)
|
||||
props += self.makeListTag(
|
||||
[x for x in config.env['LIBPATH'] if is_subdir(x, self.root_dir)
|
||||
], 'AdditionalLibraryDirectories', ' ', True)
|
||||
f.write(props)
|
||||
f.write(LINKSWITCHES.getXml(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))
|
||||
props = ''
|
||||
tag = item.tag()
|
||||
if item.is_excluded():
|
||||
props = ' <ExcludedFromBuild>True</ExcludedFromBuild>\r\n'
|
||||
elif item.builder() == 'Object':
|
||||
props = ''
|
||||
for config, output in item.node.iteritems():
|
||||
name = config.name
|
||||
env = output.get_build_env()
|
||||
inc_dirs = self.makePaths(env['CPPPATH'])
|
||||
props += self.makeListTag(self.relPaths(env['CPPPATH']),
|
||||
'AdditionalIncludeDirectories', ' ', True)
|
||||
elif item.builder() == 'Protoc':
|
||||
for config, output in item.node.iteritems():
|
||||
name = config.name
|
||||
out_dir = os.path.relpath(os.path.dirname(str(output)), self.project_dir)
|
||||
cpp_out = winpath(out_dir)
|
||||
base_out = os.path.join(out_dir, os.path.splitext(os.path.basename(item.path()))[0])
|
||||
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 sorted(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
|
||||
Reference in New Issue
Block a user