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
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import itertools
|
||||||
|
import ntpath
|
||||||
import os
|
import os
|
||||||
|
import random
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def add_beast_to_path():
|
def add_beast_to_path():
|
||||||
@@ -24,7 +27,7 @@ VARIANT_DIRECTORIES = {
|
|||||||
'modules': ('bin', 'modules'),
|
'modules': ('bin', 'modules'),
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LIBRARIES = 'boost_system',
|
BOOST_LIBRARIES = '' #boost_system'
|
||||||
MAIN_PROGRAM_FILE = 'beast/unit_test/tests/main.cpp'
|
MAIN_PROGRAM_FILE = 'beast/unit_test/tests/main.cpp'
|
||||||
DOTFILE = '~/.scons'
|
DOTFILE = '~/.scons'
|
||||||
|
|
||||||
@@ -43,6 +46,94 @@ def main():
|
|||||||
for name, path in VARIANT_DIRECTORIES.items():
|
for name, path in VARIANT_DIRECTORIES.items():
|
||||||
env.VariantDir(os.path.join(*path), name, duplicate=0)
|
env.VariantDir(os.path.join(*path), name, duplicate=0)
|
||||||
env.Replace(PRINT_CMD_LINE_FUNC=Print.print_cmd_line)
|
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
|
// Called at program exit when destructors for objects
|
||||||
// with static storage duration are invoked.
|
// with static storage duration are invoked.
|
||||||
//
|
//
|
||||||
void doStaticDetruction ()
|
void doStaticDestruction ()
|
||||||
{
|
{
|
||||||
// In theory this shouldn't be needed (?)
|
// In theory this shouldn't be needed (?)
|
||||||
ScopedLockType lock (m_mutex);
|
ScopedLockType lock (m_mutex);
|
||||||
|
|
||||||
bassert (! m_didStaticDestruction);
|
bassert (! m_didStaticDestruction);
|
||||||
|
m_didStaticDestruction = true;
|
||||||
|
|
||||||
for (List <Item>::iterator iter (m_list.begin()); iter != m_list.end();)
|
for (List <Item>::iterator iter (m_list.begin()); iter != m_list.end();)
|
||||||
{
|
{
|
||||||
@@ -82,7 +83,7 @@ private:
|
|||||||
{
|
{
|
||||||
~StaticDestructor ()
|
~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
|
# 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.
|
This Builder invokes protoc to generate C++ and Python from a .proto file.
|
||||||
|
|
||||||
@@ -72,7 +72,8 @@ def ProtocEmitter(target, source, env):
|
|||||||
|
|
||||||
return target, source
|
return target, source
|
||||||
|
|
||||||
ProtocBuilder = SCons.Builder.Builder(action = ProtocAction,
|
ProtocBuilder = SCons.Builder.Builder(
|
||||||
|
action = ProtocAction,
|
||||||
emitter = ProtocEmitter,
|
emitter = ProtocEmitter,
|
||||||
srcsuffix = '$PROTOCSRCSUFFIX')
|
srcsuffix = '$PROTOCSRCSUFFIX')
|
||||||
|
|
||||||
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