def __init__(self, options, build_dir, gcc_version, python_inc, cuda_inc,
                 build_environment, svn_roots):
        """Init method. """
        self.rules_buf = []
        self.options = options
        self.build_dir = build_dir
        self.gcc_version = gcc_version
        self.python_inc = python_inc
        self.cuda_inc = cuda_inc
        self.build_environment = build_environment
        self.ccflags_manager = CcFlagsManager(options)
        self.env_list = ['env_with_error', 'env_no_warning']

        self.svn_roots = svn_roots
        self.svn_info_map = {}

        self.version_cpp_compile_template = string.Template("""
env_version = Environment(ENV = os.environ)
env_version.Append(SHCXXCOMSTR = '%s$updateinfo%s' % (colors('cyan'), colors('end')))
env_version.Append(CPPFLAGS = '-m$m')
version_obj = env_version.SharedObject('$filename')
""")
        self.blade_config = configparse.blade_config
        self.distcc_enabled = self.blade_config.get_config(
            'distcc_config').get('enabled', False)
        self.dccc_enabled = self.blade_config.get_config('link_config').get(
            'enable_dccc', False)
Beispiel #2
0
    def __init__(self, options, build_dir, gcc_version,
                 python_inc, build_environment, svn_roots):
        """Init method. """
        self.rules_buf = []
        self.options = options
        self.build_dir = build_dir
        self.gcc_version = gcc_version
        self.python_inc = python_inc
        self.build_environment = build_environment
        self.ccflags_manager = CcFlagsManager(options)
        self.env_list = ['env_with_error', 'env_no_warning']

        self.svn_roots = svn_roots
        self.svn_info_map = {}

        self.version_cpp_compile_template = string.Template("""
env_version = Environment(ENV = os.environ)
env_version.Append(SHCXXCOMSTR = '%s$updateinfo%s' % (colors('cyan'), colors('end')))
env_version.Append(CPPFLAGS = '-m$m')
version_obj = env_version.SharedObject('$filename')
""")
        self.blade_config = configparse.blade_config
        self.distcc_enabled = self.blade_config.get_config(
                              'distcc_config').get('enabled', False)
        self.dccc_enabled = self.blade_config.get_config(
                              'link_config').get('enable_dccc', False)
    def __init__(self, options, build_dir, gcc_version,
                 python_inc, cuda_inc, build_environment, svn_roots):
        """Init method. """
        self.rules_buf = []
        self.options = options
        self.build_dir = build_dir
        self.gcc_version = gcc_version
        self.python_inc = python_inc
        self.cuda_inc = cuda_inc
        self.build_environment = build_environment
        self.ccflags_manager = CcFlagsManager(options, build_dir, gcc_version)
        self.svn_roots = svn_roots

        self.blade_config = configparse.blade_config
        self.distcc_enabled = self.blade_config.get_config(
                              'distcc_config').get('enabled', False)
        self.dccc_enabled = self.blade_config.get_config(
                              'link_config').get('enable_dccc', False)
 def __init__(self, options, build_dir, gcc_version, python_inc,
              build_environment):
     """Init method. """
     self.rules_buf = []
     self.options = options
     self.build_dir = build_dir
     self.gcc_version = gcc_version
     self.python_inc = python_inc
     self.build_environment = build_environment
     self.ccflags_manager = CcFlagsManager(options)
     self.env_list = ['env_with_error', 'env_no_warning']
    def __init__(self, options, build_dir, gcc_version, python_inc, cuda_inc,
                 build_environment, svn_roots):
        self.rules_buf = []
        self.options = options
        self.build_dir = build_dir
        self.gcc_version = gcc_version
        self.python_inc = python_inc
        self.cuda_inc = cuda_inc
        self.build_environment = build_environment
        self.ccflags_manager = CcFlagsManager(options, build_dir, gcc_version)
        self.svn_roots = svn_roots

        self.distcc_enabled = config.get_item('distcc_config', 'enabled')
Beispiel #6
0
class SconsFileHeaderGenerator(object):
    """SconsFileHeaderGenerator class"""
    def __init__(self, options, build_dir, gcc_version,
                 python_inc, build_environment, svn_roots):
        """Init method. """
        self.rules_buf = []
        self.options = options
        self.build_dir = build_dir
        self.gcc_version = gcc_version
        self.python_inc = python_inc
        self.build_environment = build_environment
        self.ccflags_manager = CcFlagsManager(options)
        self.env_list = ['env_with_error', 'env_no_warning']

        self.svn_roots = svn_roots
        self.svn_info_map = {}

        self.version_cpp_compile_template = string.Template("""
env_version = Environment(ENV = os.environ)
env_version.Append(SHCXXCOMSTR = '%s$updateinfo%s' % (colors('cyan'), colors('end')))
env_version.Append(CPPFLAGS = '-m$m')
version_obj = env_version.SharedObject('$filename')
""")
        self.blade_config = configparse.blade_config
        self.distcc_enabled = self.blade_config.get_config(
                              'distcc_config').get('enabled', False)
        self.dccc_enabled = self.blade_config.get_config(
                              'link_config').get('enable_dccc', False)

    def _add_rule(self, rule):
        """Append one rule to buffer. """
        self.rules_buf.append('%s\n' % rule)

    def _append_prefix_to_building_var(
                self,
                prefix='',
                building_var='',
                condition=False):
        """A helper method: append prefix to building var if condition is True."""
        if condition:
            return '%s %s' % (prefix, building_var)
        else:
            return building_var

    def _get_version_info(self):
        """Gets svn root dir info. """
        for root_dir in self.svn_roots:
            lc_all_env = os.environ
            lc_all_env['LC_ALL'] = 'POSIX'
            root_dir_realpath = os.path.realpath(root_dir)
            svn_working_dir = os.path.dirname(root_dir_realpath)
            svn_dir = os.path.basename(root_dir_realpath)

            if not os.path.exists('%s/.svn' % root_dir):
                console.warning('"%s" is not under version control' % root_dir)
                continue

            p = subprocess.Popen('svn info %s' % svn_dir,
                                 env=lc_all_env,
                                 cwd='%s' % svn_working_dir,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE,
                                 shell=True)
            std_out, std_err = p.communicate()
            if p.returncode:
                console.warning('failed to get version control info in %s' % root_dir)
            else:
                self.svn_info_map[root_dir] = std_out.replace('\n', '\\n\\\n')

    def generate_version_file(self):
        """Generate version information files. """
         # Generate easou style version info
        if os.path.exists("base/version.h.template"):
          easou_version_generator = VersionFileGenerator(self.options.profile)
          easou_version_generator._gen_easou_format_version_file()

        self._get_version_info()
        svn_info_len = len(self.svn_info_map)

        if not os.path.exists(self.build_dir):
            os.makedirs(self.build_dir)
        version_cpp = open('%s/version.cpp' % self.build_dir, 'w')

        print >>version_cpp, '/* This file was generated by blade */'
        print >>version_cpp, 'extern "C" {'
        print >>version_cpp, 'namespace binary_version {'
        print >>version_cpp, 'extern const int kSvnInfoCount = %d;' % svn_info_len

        svn_info_array = '{'
        for idx in range(svn_info_len):
            key_with_idx = self.svn_info_map.keys()[idx]
            svn_info_line = '"%s"' % self.svn_info_map[key_with_idx]
            svn_info_array += svn_info_line
            if idx != (svn_info_len - 1):
                svn_info_array += ','
        svn_info_array += '}'

        print >>version_cpp, 'extern const char* const kSvnInfo[%d] = %s;' % (
                svn_info_len, svn_info_array)
        print >>version_cpp, 'extern const char kBuildType[] = "%s";' % self.options.profile
        print >>version_cpp, 'extern const char kBuildTime[] = "%s";' % time.asctime()
        print >>version_cpp, 'extern const char kBuilderName[] = "%s";' % os.getenv('USER')
        print >>version_cpp, (
                'extern const char kHostName[] = "%s";' % socket.gethostname())
        compiler = 'GCC %s' % self.gcc_version
        print >>version_cpp, 'extern const char kCompiler[] = "%s";' % compiler
        print >>version_cpp, '}}'

        version_cpp.close()

        self._add_rule('VariantDir("%s", ".", duplicate=0)' % self.build_dir)
        self._add_rule(self.version_cpp_compile_template.substitute(
            updateinfo='Updating version information',
            m=self.options.m,
            filename='%s/version.cpp' % self.build_dir))

    def generate_imports_functions(self, blade_path):
        """Generates imports and functions. """
        self._add_rule(
            r"""
import sys
sys.path.insert(0, '%s')
""" % blade_path)
        self._add_rule(
            r"""
import os
import subprocess
import signal
import time
import socket
import glob

import blade_util
import console
import scons_helper

from build_environment import ScacheManager
from console import colors
from scons_helper import MakeAction
from scons_helper import create_fast_link_builders
from scons_helper import echospawn
from scons_helper import error_colorize
from scons_helper import generate_python_binary
from scons_helper import generate_resource_file
from scons_helper import generate_resource_header
""")

        if getattr(self.options, 'verbose', False):
            self._add_rule('scons_helper.option_verbose = True')

        self._add_rule((
                """if not os.path.exists('%s'):
    os.mkdir('%s')""") % (self.build_dir, self.build_dir))

    def generate_top_level_env(self):
        """generates top level environment. """
        self._add_rule('os.environ["LC_ALL"] = "C"')
        self._add_rule('top_env = Environment(ENV=os.environ)')

    def generate_compliation_verbose(self):
        """Generates color and verbose message. """
        self._add_rule('top_env.Decider("MD5-timestamp")')
        self._add_rule('console.color_enabled=%s' % console.color_enabled)

        if not getattr(self.options, 'verbose', False):
            self._add_rule('top_env["SPAWN"] = echospawn')

        self._add_rule(
                """
compile_proto_cc_message = '%sCompiling %s$SOURCE%s to cc source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_proto_java_message = '%sCompiling %s$SOURCE%s to java source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_proto_php_message = '%sCompiling %s$SOURCE%s to php source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_proto_python_message = '%sCompiling %s$SOURCE%s to python source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_thrift_cc_message = '%sCompiling %s$SOURCE%s to cc source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_thrift_java_message = '%sCompiling %s$SOURCE%s to java source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_thrift_python_message = '%sCompiling %s$SOURCE%s to python source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_resource_header_message = '%sGenerating resource header %s$TARGET%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_resource_message = '%sCompiling %s$SOURCE%s as resource file%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_source_message = '%sCompiling %s$SOURCE%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

assembling_source_message = '%sAssembling %s$SOURCE%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

link_program_message = '%sLinking Program %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end'))

link_library_message = '%sCreating Static Library %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end'))

ranlib_library_message = '%sRanlib Library %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end')) \

link_shared_library_message = '%sLinking Shared Library %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end'))

compile_java_jar_message = '%sGenerating java jar %s$TARGET%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_python_binary_message = '%sGenerating python binary %s$TARGET%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_yacc_message = '%sYacc %s$SOURCE%s to $TARGET%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_swig_python_message = '%sCompiling %s$SOURCE%s to python source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_swig_java_message = '%sCompiling %s$SOURCE%s to java source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_swig_php_message = '%sCompiling %s$SOURCE%s to php source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))
""")

        if not getattr(self.options, 'verbose', False):
            self._add_rule(
                    r"""
top_env.Append(
    CXXCOMSTR = compile_source_message,
    CCCOMSTR = compile_source_message,
    ASCOMSTR = assembling_source_message,
    SHCCCOMSTR = compile_source_message,
    SHCXXCOMSTR = compile_source_message,
    ARCOMSTR = link_library_message,
    RANLIBCOMSTR = ranlib_library_message,
    SHLINKCOMSTR = link_shared_library_message,
    LINKCOMSTR = link_program_message,
    JAVACCOMSTR = compile_source_message
)""")

    def _generate_fast_link_builders(self):
        """Generates fast link builders if it is specified in blade bash. """
        link_config = configparse.blade_config.get_config('link_config')
        enable_dccc = link_config['enable_dccc']
        if link_config['link_on_tmp']:
            if (not enable_dccc) or (
                    enable_dccc and not self.build_environment.dccc_env_prepared):
                self._add_rule('create_fast_link_builders(top_env)')

    def generate_builders(self):
        """Generates common builders. """
        # Generates builders specified in blade bash at first
        self._generate_fast_link_builders()

        proto_config = configparse.blade_config.get_config('proto_library_config')
        protoc_bin = proto_config['protoc']
        protobuf_path = proto_config['protobuf_path']

        protobuf_incs_str = _incs_list_to_string(proto_config['protobuf_incs'])
        protobuf_php_path = proto_config['protobuf_php_path']
        protoc_php_plugin = proto_config['protoc_php_plugin']
        # Genreates common builders now
        builder_list = []
        self._add_rule('time_value = Value("%s")' % time.asctime())
        self._add_rule(
            'proto_bld = Builder(action = MakeAction("%s --proto_path=. -I. %s'
            ' -I=`dirname $SOURCE` --cpp_out=%s $SOURCE", '
            'compile_proto_cc_message))' % (
                    protoc_bin, protobuf_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"Proto" : proto_bld}')

        self._add_rule(
            'proto_java_bld = Builder(action = MakeAction("%s --proto_path=. '
            '--proto_path=%s --java_out=%s/`dirname $SOURCE` $SOURCE", '
            'compile_proto_java_message))' % (
                    protoc_bin, protobuf_path, self.build_dir))
        builder_list.append('BUILDERS = {"ProtoJava" : proto_java_bld}')

        self._add_rule(
            'proto_php_bld = Builder(action = MakeAction("%s '
            '--proto_path=. --plugin=protoc-gen-php=%s '
            '-I. %s -I%s -I=`dirname $SOURCE` '
            '--php_out=%s/`dirname $SOURCE` '
            '$SOURCE", compile_proto_php_message))' % (
                    protoc_bin, protoc_php_plugin, protobuf_incs_str,
                    protobuf_php_path, self.build_dir))
        builder_list.append('BUILDERS = {"ProtoPhp" : proto_php_bld}')

        self._add_rule(
            'proto_python_bld = Builder(action = MakeAction("%s '
            '--proto_path=. '
            '-I. %s -I=`dirname $SOURCE` '
            '--python_out=%s '
            '$SOURCE", compile_proto_python_message))' % (
                    protoc_bin, protobuf_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"ProtoPython" : proto_python_bld}')

        # Generate thrift library builders.
        thrift_config = configparse.blade_config.get_config('thrift_config')
        thrift_incs_str = _incs_list_to_string(thrift_config['thrift_incs'])
        thrift_bin = thrift_config['thrift']
        if thrift_bin.startswith('//'):
            thrift_bin = thrift_bin.replace('//', self.build_dir + '/')
            thrift_bin = thrift_bin.replace(':', '/')

        # Genreates common builders now
        self._add_rule(
            'thrift_bld = Builder(action = MakeAction("%s '
            '--gen cpp:include_prefix -I . %s -I `dirname $SOURCE` -out %s/`dirname $SOURCE` '
            '$SOURCE", compile_thrift_cc_message))' % (
                    thrift_bin, thrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"Thrift" : thrift_bld}')

        self._add_rule(
            'thrift_java_bld = Builder(action = MakeAction("%s '
            '--gen java -I . %s -I `dirname $SOURCE` -out %s/`dirname $SOURCE` '
            '$SOURCE", compile_thrift_java_message))' % (
                    thrift_bin, thrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"ThriftJava" : thrift_java_bld}')

        self._add_rule(
            'thrift_python_bld = Builder(action = MakeAction("%s '
            '--gen py -I . %s -I `dirname $SOURCE` -out %s/`dirname $SOURCE` '
            '$SOURCE", compile_thrift_python_message))' % (
                    thrift_bin, thrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"ThriftPython" : thrift_python_bld}')

        self._add_rule(
                     r"""
blade_jar_bld = Builder(action = MakeAction('jar cf $TARGET -C `dirname $SOURCE` .',
    compile_java_jar_message))

yacc_bld = Builder(action = MakeAction('bison $YACCFLAGS -d -o $TARGET $SOURCE',
    compile_yacc_message))

resource_header_bld = Builder(action = MakeAction(generate_resource_header,
    compile_resource_header_message))

resource_file_bld = Builder(action = MakeAction(generate_resource_file,
    compile_resource_message))

python_binary_bld = Builder(action = MakeAction(generate_python_binary,
    compile_python_binary_message))
""")
        builder_list.append('BUILDERS = {"BladeJar" : blade_jar_bld}')
        builder_list.append('BUILDERS = {"Yacc" : yacc_bld}')
        builder_list.append('BUILDERS = {"ResourceHeader" : resource_header_bld}')
        builder_list.append('BUILDERS = {"ResourceFile" : resource_file_bld}')
        builder_list.append('BUILDERS = {"PythonBinary" : python_binary_bld}')

        for builder in builder_list:
            self._add_rule('top_env.Append(%s)' % builder)

    def generate_compliation_flags(self):
        """Generates compliation flags. """
        toolchain_dir = os.environ.get('TOOLCHAIN_DIR', '')
        if toolchain_dir and not toolchain_dir.endswith('/'):
            toolchain_dir += '/'
        cpp_str = toolchain_dir + os.environ.get('CPP', 'cpp')
        cc_str = toolchain_dir + os.environ.get('CC', 'gcc')
        cxx_str = toolchain_dir + os.environ.get('CXX', 'g++')
        ld_str = toolchain_dir + os.environ.get('LD', 'g++')
        console.info('CPP=%s' % cpp_str)
        console.info('CC=%s' % cc_str)
        console.info('CXX=%s' % cxx_str)
        console.info('LD=%s' % ld_str)

        self.ccflags_manager.set_cpp_str(cpp_str)

        # To modify CC, CXX, LD according to the building environment and
        # project configuration
        build_with_distcc = (self.distcc_enabled and
                             self.build_environment.distcc_env_prepared)
        cc_str = self._append_prefix_to_building_var(
                         prefix='distcc',
                         building_var=cc_str,
                         condition=build_with_distcc)

        cxx_str = self._append_prefix_to_building_var(
                         prefix='distcc',
                         building_var=cxx_str,
                         condition=build_with_distcc)

        build_with_ccache = self.build_environment.ccache_installed
        cc_str = self._append_prefix_to_building_var(
                         prefix='ccache',
                         building_var=cc_str,
                         condition=build_with_ccache)

        cxx_str = self._append_prefix_to_building_var(
                         prefix='ccache',
                         building_var=cxx_str,
                         condition=build_with_ccache)

        build_with_dccc = (self.dccc_enabled and
                           self.build_environment.dccc_env_prepared)
        ld_str = self._append_prefix_to_building_var(
                        prefix='dccc',
                        building_var=ld_str,
                        condition=build_with_dccc)

        cc_env_str = 'CC="%s", CXX="%s"' % (cc_str, cxx_str)
        ld_env_str = 'LINK="%s"' % ld_str

        cc_config = configparse.blade_config.get_config('cc_config')
        extra_incs = cc_config['extra_incs']
        extra_incs_str = ', '.join(['"%s"' % inc for inc in extra_incs])
        if not extra_incs_str:
            extra_incs_str = '""'

        (cppflags_except_warning, linkflags) = self.ccflags_manager.get_flags_except_warning()

        self._add_rule('top_env.Replace(%s, '
                       'CPPPATH=[%s, "%s", "%s"], '
                       'CPPFLAGS=%s, CFLAGS=%s, CXXFLAGS=%s, '
                       '%s, LINKFLAGS=%s)' %
                       (cc_env_str,
                        extra_incs_str, self.build_dir, self.python_inc,
                        cc_config['cppflags'] + cppflags_except_warning,
                        cc_config['cflags'],
                        cc_config['cxxflags'],
                        ld_env_str, linkflags))

        self._setup_cache()

        if build_with_distcc:
            self.build_environment.setup_distcc_env()

        for rule in self.build_environment.get_rules():
            self._add_rule(rule)

        self._setup_warnings()

    def _setup_warnings(self):
        for env in self.env_list:
            self._add_rule('%s = top_env.Clone()' % env)

        (warnings, cxx_warnings, c_warnings) = self.ccflags_manager.get_warning_flags()
        self._add_rule('%s.Append(CPPFLAGS=%s, CFLAGS=%s, CXXFLAGS=%s)' % (
            self.env_list[0],
            warnings, c_warnings, cxx_warnings))

    def _setup_cache(self):
        if self.build_environment.ccache_installed:
            self.build_environment.setup_ccache_env()
        else:
            cache_dir = os.path.expanduser('~/.bladescache')
            cache_size = 4 * 1024 * 1024 * 1024
            if hasattr(self.options, 'cache_dir'):
                if not self.options.cache_dir:
                    return
                cache_dir = self.options.cache_dir
            else:
                console.info('using default cache dir: %s' % cache_dir)

            if hasattr(self.options, 'cache_size') and (self.options.cache_size != -1):
                cache_size = self.options.cache_size

            self._add_rule('CacheDir("%s")' % cache_dir)
            self._add_rule('scache_manager = ScacheManager("%s", cache_limit=%d)' % (
                        cache_dir, cache_size))
            self._add_rule('Progress(scache_manager, interval=100)')

            self._add_rule('console.info("using cache directory %s")' % cache_dir)
            self._add_rule('console.info("scache size %d")' % cache_size)

    def generate(self, blade_path):
        """Generates all rules. """
        self.generate_imports_functions(blade_path)
        self.generate_top_level_env()
        self.generate_compliation_verbose()
        self.generate_version_file()
        self.generate_builders()
        self.generate_compliation_flags()
        return self.rules_buf
class SconsFileHeaderGenerator(object):
    """SconsFileHeaderGenerator class"""
    def __init__(self, options, build_dir, gcc_version, python_inc, cuda_inc,
                 build_environment, svn_roots):
        """Init method. """
        self.rules_buf = []
        self.options = options
        self.build_dir = build_dir
        self.gcc_version = gcc_version
        self.python_inc = python_inc
        self.cuda_inc = cuda_inc
        self.build_environment = build_environment
        self.ccflags_manager = CcFlagsManager(options)
        self.env_list = ['env_with_error', 'env_no_warning']

        self.svn_roots = svn_roots
        self.svn_info_map = {}

        self.version_cpp_compile_template = string.Template("""
env_version = Environment(ENV = os.environ)
env_version.Append(SHCXXCOMSTR = '%s$updateinfo%s' % (colors('cyan'), colors('end')))
env_version.Append(CPPFLAGS = '-m$m')
version_obj = env_version.SharedObject('$filename')
""")
        self.blade_config = configparse.blade_config
        self.distcc_enabled = self.blade_config.get_config(
            'distcc_config').get('enabled', False)
        self.dccc_enabled = self.blade_config.get_config('link_config').get(
            'enable_dccc', False)

    def _add_rule(self, rule):
        """Append one rule to buffer. """
        self.rules_buf.append('%s\n' % rule)

    def _append_prefix_to_building_var(self,
                                       prefix='',
                                       building_var='',
                                       condition=False):
        """A helper method: append prefix to building var if condition is True."""
        if condition:
            return '%s %s' % (prefix, building_var)
        else:
            return building_var

    def _get_version_info(self):
        """Gets svn root dir info. """
        for root_dir in self.svn_roots:
            lc_all_env = os.environ
            lc_all_env['LC_ALL'] = 'POSIX'
            root_dir_realpath = os.path.realpath(root_dir)
            svn_working_dir = os.path.dirname(root_dir_realpath)
            svn_dir = os.path.basename(root_dir_realpath)

            if not os.path.exists('%s/.svn' % root_dir):
                console.warning('"%s" is not under version control' % root_dir)
                continue

            p = subprocess.Popen('svn info %s' % svn_dir,
                                 env=lc_all_env,
                                 cwd='%s' % svn_working_dir,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE,
                                 shell=True)
            std_out, std_err = p.communicate()
            if p.returncode:
                console.warning('failed to get version control info in %s' %
                                root_dir)
            else:
                self.svn_info_map[root_dir] = std_out.replace('\n', '\\n\\\n')

    def generate_version_file(self):
        """Generate version information files. """
        self._get_version_info()
        svn_info_len = len(self.svn_info_map)

        if not os.path.exists(self.build_dir):
            os.makedirs(self.build_dir)
        version_cpp = open('%s/version.cpp' % self.build_dir, 'w')

        print >> version_cpp, '/* This file was generated by blade */'
        print >> version_cpp, 'extern "C" {'
        print >> version_cpp, 'namespace binary_version {'
        print >> version_cpp, 'extern const int kSvnInfoCount = %d;' % svn_info_len

        svn_info_array = '{'
        for idx in range(svn_info_len):
            key_with_idx = self.svn_info_map.keys()[idx]
            svn_info_line = '"%s"' % self.svn_info_map[key_with_idx]
            svn_info_array += svn_info_line
            if idx != (svn_info_len - 1):
                svn_info_array += ','
        svn_info_array += '}'

        print >> version_cpp, 'extern const char* const kSvnInfo[%d] = %s;' % (
            svn_info_len, svn_info_array)
        print >> version_cpp, 'extern const char kBuildType[] = "%s";' % self.options.profile
        print >> version_cpp, 'extern const char kBuildTime[] = "%s";' % time.asctime(
        )
        print >> version_cpp, 'extern const char kBuilderName[] = "%s";' % os.getenv(
            'USER')
        print >> version_cpp, ('extern const char kHostName[] = "%s";' %
                               socket.gethostname())
        compiler = 'GCC %s' % self.gcc_version
        print >> version_cpp, 'extern const char kCompiler[] = "%s";' % compiler
        print >> version_cpp, '}}'

        version_cpp.close()

        self._add_rule('VariantDir("%s", ".", duplicate=0)' % self.build_dir)
        self._add_rule(
            self.version_cpp_compile_template.substitute(
                updateinfo='Updating version information',
                m=self.options.m,
                filename='%s/version.cpp' % self.build_dir))

    def generate_imports_functions(self, blade_path):
        """Generates imports and functions. """
        self._add_rule(r"""
import sys
sys.path.insert(0, '%s')
""" % blade_path)
        self._add_rule(r"""
import os
import subprocess
import signal
import time
import socket
import glob

import blade_util
import console
import scons_helper

from build_environment import ScacheManager
from console import colors
from scons_helper import MakeAction
from scons_helper import create_fast_link_builders
from scons_helper import echospawn
from scons_helper import error_colorize
from scons_helper import generate_python_binary
from scons_helper import generate_resource_file
from scons_helper import generate_resource_header
""")

        if getattr(self.options, 'verbose', False):
            self._add_rule('scons_helper.option_verbose = True')

        self._add_rule(("""if not os.path.exists('%s'):
    os.mkdir('%s')""") % (self.build_dir, self.build_dir))

    def generate_top_level_env(self):
        """generates top level environment. """
        self._add_rule('os.environ["LC_ALL"] = "C"')
        self._add_rule('top_env = Environment(ENV=os.environ)')

    def generate_compliation_verbose(self):
        """Generates color and verbose message. """
        self._add_rule('top_env.Decider("MD5-timestamp")')
        self._add_rule('console.color_enabled=%s' % console.color_enabled)

        if not getattr(self.options, 'verbose', False):
            self._add_rule('top_env["SPAWN"] = echospawn')

        self._add_rule("""
compile_proto_cc_message = '%sCompiling %s$SOURCE%s to cc source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_proto_java_message = '%sCompiling %s$SOURCE%s to java source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_proto_php_message = '%sCompiling %s$SOURCE%s to php source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_proto_python_message = '%sCompiling %s$SOURCE%s to python source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_thrift_cc_message = '%sCompiling %s$SOURCE%s to cc source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_thrift_java_message = '%sCompiling %s$SOURCE%s to java source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_thrift_python_message = '%sCompiling %s$SOURCE%s to python source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_resource_header_message = '%sGenerating resource header %s$TARGET%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_resource_message = '%sCompiling %s$SOURCE%s as resource file%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_source_message = '%sCompiling %s$SOURCE%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

assembling_source_message = '%sAssembling %s$SOURCE%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

link_program_message = '%sLinking Program %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end'))

link_library_message = '%sCreating Static Library %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end'))

ranlib_library_message = '%sRanlib Library %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end')) \

link_shared_library_message = '%sLinking Shared Library %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end'))

compile_java_jar_message = '%sGenerating java jar %s$TARGET%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_python_binary_message = '%sGenerating python binary %s$TARGET%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_yacc_message = '%sYacc %s$SOURCE%s to $TARGET%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_swig_python_message = '%sCompiling %s$SOURCE%s to python source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_swig_java_message = '%sCompiling %s$SOURCE%s to java source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_swig_php_message = '%sCompiling %s$SOURCE%s to php source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))
""")

        if not getattr(self.options, 'verbose', False):
            self._add_rule(r"""
top_env.Append(
    CXXCOMSTR = compile_source_message,
    CCCOMSTR = compile_source_message,
    ASCOMSTR = assembling_source_message,
    SHCCCOMSTR = compile_source_message,
    SHCXXCOMSTR = compile_source_message,
    ARCOMSTR = link_library_message,
    RANLIBCOMSTR = ranlib_library_message,
    SHLINKCOMSTR = link_shared_library_message,
    LINKCOMSTR = link_program_message,
    JAVACCOMSTR = compile_source_message
)""")

    def _generate_fast_link_builders(self):
        """Generates fast link builders if it is specified in blade bash. """
        link_config = configparse.blade_config.get_config('link_config')
        enable_dccc = link_config['enable_dccc']
        if link_config['link_on_tmp']:
            if (not enable_dccc) or (
                    enable_dccc
                    and not self.build_environment.dccc_env_prepared):
                self._add_rule('create_fast_link_builders(top_env)')

    def generate_builders(self):
        """Generates common builders. """
        # Generates builders specified in blade bash at first
        self._generate_fast_link_builders()

        proto_config = configparse.blade_config.get_config(
            'proto_library_config')
        protoc_bin = proto_config['protoc']
        protobuf_path = proto_config['protobuf_path']

        protobuf_incs_str = _incs_list_to_string(proto_config['protobuf_incs'])
        protobuf_php_path = proto_config['protobuf_php_path']
        protoc_php_plugin = proto_config['protoc_php_plugin']
        # Genreates common builders now
        builder_list = []
        self._add_rule('time_value = Value("%s")' % time.asctime())
        self._add_rule(
            'proto_bld = Builder(action = MakeAction("%s --proto_path=. -I. %s'
            ' -I=`dirname $SOURCE` --cpp_out=%s $SOURCE", '
            'compile_proto_cc_message))' %
            (protoc_bin, protobuf_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"Proto" : proto_bld}')

        self._add_rule(
            'proto_java_bld = Builder(action = MakeAction("%s --proto_path=. '
            '--proto_path=%s --java_out=%s/`dirname $SOURCE` $SOURCE", '
            'compile_proto_java_message))' %
            (protoc_bin, protobuf_path, self.build_dir))
        builder_list.append('BUILDERS = {"ProtoJava" : proto_java_bld}')

        self._add_rule('proto_php_bld = Builder(action = MakeAction("%s '
                       '--proto_path=. --plugin=protoc-gen-php=%s '
                       '-I. %s -I%s -I=`dirname $SOURCE` '
                       '--php_out=%s/`dirname $SOURCE` '
                       '$SOURCE", compile_proto_php_message))' %
                       (protoc_bin, protoc_php_plugin, protobuf_incs_str,
                        protobuf_php_path, self.build_dir))
        builder_list.append('BUILDERS = {"ProtoPhp" : proto_php_bld}')

        self._add_rule('proto_python_bld = Builder(action = MakeAction("%s '
                       '--proto_path=. '
                       '-I. %s -I=`dirname $SOURCE` '
                       '--python_out=%s '
                       '$SOURCE", compile_proto_python_message))' %
                       (protoc_bin, protobuf_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"ProtoPython" : proto_python_bld}')

        # Generate thrift library builders.
        thrift_config = configparse.blade_config.get_config('thrift_config')
        thrift_incs_str = _incs_list_to_string(thrift_config['thrift_incs'])
        thrift_bin = thrift_config['thrift']
        if thrift_bin.startswith('//'):
            thrift_bin = thrift_bin.replace('//', self.build_dir + '/')
            thrift_bin = thrift_bin.replace(':', '/')

        # Genreates common builders now
        self._add_rule(
            'thrift_bld = Builder(action = MakeAction("%s '
            '--gen cpp:include_prefix,pure_enums -I . %s -I `dirname $SOURCE` '
            '-out %s/`dirname $SOURCE` $SOURCE", compile_thrift_cc_message))' %
            (thrift_bin, thrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"Thrift" : thrift_bld}')

        self._add_rule(
            'thrift_java_bld = Builder(action = MakeAction("%s '
            '--gen java -I . %s -I `dirname $SOURCE` -out %s/`dirname $SOURCE` '
            '$SOURCE", compile_thrift_java_message))' %
            (thrift_bin, thrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"ThriftJava" : thrift_java_bld}')

        self._add_rule(
            'thrift_python_bld = Builder(action = MakeAction("%s '
            '--gen py -I . %s -I `dirname $SOURCE` -out %s/`dirname $SOURCE` '
            '$SOURCE", compile_thrift_python_message))' %
            (thrift_bin, thrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"ThriftPython" : thrift_python_bld}')

        self._add_rule(r"""
blade_jar_bld = Builder(action = MakeAction('jar cf $TARGET -C `dirname $SOURCE` .',
    compile_java_jar_message))

yacc_bld = Builder(action = MakeAction('bison $YACCFLAGS -d -o $TARGET $SOURCE',
    compile_yacc_message))

resource_header_bld = Builder(action = MakeAction(generate_resource_header,
    compile_resource_header_message))

resource_file_bld = Builder(action = MakeAction(generate_resource_file,
    compile_resource_message))

python_binary_bld = Builder(action = MakeAction(generate_python_binary,
    compile_python_binary_message))
""")
        builder_list.append('BUILDERS = {"BladeJar" : blade_jar_bld}')
        builder_list.append('BUILDERS = {"Yacc" : yacc_bld}')
        builder_list.append(
            'BUILDERS = {"ResourceHeader" : resource_header_bld}')
        builder_list.append('BUILDERS = {"ResourceFile" : resource_file_bld}')
        builder_list.append('BUILDERS = {"PythonBinary" : python_binary_bld}')

        for builder in builder_list:
            self._add_rule('top_env.Append(%s)' % builder)

    def generate_compliation_flags(self):
        """Generates compliation flags. """
        toolchain_dir = os.environ.get('TOOLCHAIN_DIR', '')
        if toolchain_dir and not toolchain_dir.endswith('/'):
            toolchain_dir += '/'
        cpp_str = toolchain_dir + os.environ.get('CPP', 'cpp')
        cc_str = toolchain_dir + os.environ.get('CC', 'gcc')
        cxx_str = toolchain_dir + os.environ.get('CXX', 'g++')
        nvcc_str = toolchain_dir + os.environ.get('NVCC', 'nvcc')
        ld_str = toolchain_dir + os.environ.get('LD', 'g++')
        console.info('CPP=%s' % cpp_str)
        console.info('CC=%s' % cc_str)
        console.info('CXX=%s' % cxx_str)
        console.info('NVCC=%s' % nvcc_str)
        console.info('LD=%s' % ld_str)

        self.ccflags_manager.set_cpp_str(cpp_str)

        # To modify CC, CXX, LD according to the building environment and
        # project configuration
        build_with_distcc = (self.distcc_enabled
                             and self.build_environment.distcc_env_prepared)
        cc_str = self._append_prefix_to_building_var(
            prefix='distcc', building_var=cc_str, condition=build_with_distcc)

        cxx_str = self._append_prefix_to_building_var(
            prefix='distcc', building_var=cxx_str, condition=build_with_distcc)

        build_with_ccache = self.build_environment.ccache_installed
        cc_str = self._append_prefix_to_building_var(
            prefix='ccache', building_var=cc_str, condition=build_with_ccache)

        cxx_str = self._append_prefix_to_building_var(
            prefix='ccache', building_var=cxx_str, condition=build_with_ccache)

        build_with_dccc = (self.dccc_enabled
                           and self.build_environment.dccc_env_prepared)
        ld_str = self._append_prefix_to_building_var(prefix='dccc',
                                                     building_var=ld_str,
                                                     condition=build_with_dccc)

        cc_env_str = 'CC="%s", CXX="%s"' % (cc_str, cxx_str)
        ld_env_str = 'LINK="%s"' % ld_str
        nvcc_env_str = 'NVCC="%s"' % nvcc_str

        cc_config = configparse.blade_config.get_config('cc_config')
        extra_incs = cc_config['extra_incs']
        extra_incs_str = ', '.join(['"%s"' % inc for inc in extra_incs])
        if not extra_incs_str:
            extra_incs_str = '""'

        (cppflags_except_warning,
         linkflags) = self.ccflags_manager.get_flags_except_warning()

        builder_list = []
        cuda_incs_str = ' '.join(['-I%s' % inc for inc in self.cuda_inc])
        self._add_rule(
            'nvcc_object_bld = Builder(action = MakeAction("%s -ccbin g++ %s '
            '$NVCCFLAGS -o $TARGET -c $SOURCE", compile_source_message))' %
            (nvcc_str, cuda_incs_str))
        builder_list.append('BUILDERS = {"NvccObject" : nvcc_object_bld}')

        self._add_rule('nvcc_binary_bld = Builder(action = MakeAction("%s %s '
                       '$NVCCFLAGS -o $TARGET ", link_program_message))' %
                       (nvcc_str, cuda_incs_str))
        builder_list.append('BUILDERS = {"NvccBinary" : nvcc_binary_bld}')

        for builder in builder_list:
            self._add_rule('top_env.Append(%s)' % builder)

        self._add_rule(
            'top_env.Replace(%s, %s, '
            'CPPPATH=[%s, "%s", "%s"], '
            'CPPFLAGS=%s, CFLAGS=%s, CXXFLAGS=%s, '
            '%s, LINKFLAGS=%s)' %
            (cc_env_str, nvcc_env_str, extra_incs_str, self.build_dir,
             self.python_inc, cc_config['cppflags'] + cppflags_except_warning,
             cc_config['cflags'], cc_config['cxxflags'], ld_env_str,
             linkflags))

        self._setup_cache()

        if build_with_distcc:
            self.build_environment.setup_distcc_env()

        for rule in self.build_environment.get_rules():
            self._add_rule(rule)

        self._setup_warnings()

    def _setup_warnings(self):
        for env in self.env_list:
            self._add_rule('%s = top_env.Clone()' % env)

        (warnings, cxx_warnings,
         c_warnings) = self.ccflags_manager.get_warning_flags()
        self._add_rule('%s.Append(CPPFLAGS=%s, CFLAGS=%s, CXXFLAGS=%s)' %
                       (self.env_list[0], warnings, c_warnings, cxx_warnings))

    def _setup_cache(self):
        if self.build_environment.ccache_installed:
            self.build_environment.setup_ccache_env()
        else:
            cache_dir = os.path.expanduser('~/.bladescache')
            cache_size = 4 * 1024 * 1024 * 1024
            if hasattr(self.options, 'cache_dir'):
                if not self.options.cache_dir:
                    return
                cache_dir = self.options.cache_dir
            else:
                console.info('using default cache dir: %s' % cache_dir)

            if hasattr(self.options,
                       'cache_size') and (self.options.cache_size != -1):
                cache_size = self.options.cache_size

            self._add_rule('CacheDir("%s")' % cache_dir)
            self._add_rule(
                'scache_manager = ScacheManager("%s", cache_limit=%d)' %
                (cache_dir, cache_size))
            self._add_rule('Progress(scache_manager, interval=100)')

            self._add_rule('console.info("using cache directory %s")' %
                           cache_dir)
            self._add_rule('console.info("scache size %d")' % cache_size)

    def generate(self, blade_path):
        """Generates all rules. """
        self.generate_imports_functions(blade_path)
        self.generate_top_level_env()
        self.generate_compliation_verbose()
        self.generate_version_file()
        self.generate_builders()
        self.generate_compliation_flags()
        return self.rules_buf
Beispiel #8
0
    def __init__(self, command_targets, blade_path, working_dir, build_path,
                 current_source_path, blade_options, **kwargs):
        """init method.

        Mainly to hold the global data.
        The directory which changes during the runtime of blade, and
        contains BUILD file under current focus.
        current_source_dir = "."

        Given some targets specified in the command line, Blade will load
        BUILD files containing these command line targets; global target
        functions, i.e., cc_libarary, cc_binary and etc, in these BUILD
        files will register targets into target_database, which then becomes
        the input to dependency analyzer and SCons rules generator.  It is
        notable that not all targets in target_database are dependencies of
        command line targets.
        target_database = {}

        related targets after loading the build files and exec BUILD files
        as python script
        related_targets = {}

        The map used by build rules to ensure that a source file occurres in
        exactly one rule/target(only library target).
        target_srcs_map = {}

        The scons cache manager class string, which should be output to
        scons script if ccache is not installed
        scache_manager_class_str = ''

        The targets keys list after sorting by topological sorting method.
        sorted_targets_keys = []

        Inidcating that whether the deps list is expanded by expander or not
        False - not expanded
        True - expanded
        target_deps_expanded

        All targets after expanding their dependency
        all_targets = {}

        The scons target objects registered into blade manager
        scons_targets_map = {}

        The vars which are depended by python binary
        {key : 'python_files'}
        self.python_binary_dep_source_cmd = {}

        The files which are depended by python binary
        {key : 'python_files'}
        python_binary_dep_source_map = {}

        The files which are depended by java jar file
        {key : 'java_files'}
        java_jar_dep_source_map = {}

        The files which should be packed into java jar
        {key : 'packing_files'}
        java_jar_files_packing_map = {}

        The jar files map
        {key : 'jar_files_generated'}
        java_jars_map = {}

        The java compiling classpath parameter map
        java_classpath_map = {}
        {key : 'target_path'}

        The java_jar dep var map, which should be added to dependency chain
        java_jar_dep_vars = {}

        The cc objects pool, a map to hold all the objects name.
        cc_objects_pool = {}

        The gen rule files map, which is used to generate the explict dependency
        relationtion ship between gen_rule target and other targets
        gen_rule_files_map = {}

        The direct targets that are used for analyzing
        direct_targets = []

        All command targets, make sure that all targets specified with ...
        are all in the list now
        all_command_targets = []

        The class to get platform info
        SconsPlatform

        The class to manage the cc flags
        CcFlagsManager

        The sources files that are needed to perform explict dependency
        sources_explict_dependency_map = {}

        The prebuilt cc_library file map which is needed to establish
        symbolic links while testing
        prebuilt_cc_library_file_map = {}

        """
        self.command_targets = command_targets
        self.direct_targets = []
        self.all_command_targets = []
        self.blade_path = blade_path
        self.working_dir = working_dir
        self.build_path = build_path
        self.current_source_path = current_source_path
        self.target_database = {}
        self.related_targets = {}
        self.target_srcs_map = {}
        self.scache_manager_class_str = ''
        self.options = blade_options
        self.sorted_targets_keys = []
        self.target_deps_expanded = False
        self.all_targets_expanded = {}
        self.scons_targets_map = {}
        self.java_jar_dep_source_map = {}
        self.java_jar_files_packing_map = {}
        self.java_jars_map = {}
        self.java_classpath_map = {}
        self.java_jar_dep_vars = {}
        self.python_binary_dep_source_cmd = {}
        self.python_binary_dep_source_map = {}
        self.cc_objects_pool = {}

        self.deps_expander = None
        self.build_rules_generator = None

        self.gen_rule_files_map = {}

        self.scons_platform = SconsPlatform()
        self.ccflags_manager = CcFlagsManager(self.options)
        self.sources_explict_dependency_map = {}
        self.prebuilt_cc_library_file_map = {}

        self.distcc_enabled = configparse.blade_config.get_config(
            'distcc_config')['enabled']

        self.build_environment = BuildEnvironment(self.current_source_path)

        self.svn_root_dirs = []

        self.kwargs = kwargs
Beispiel #9
0
class SconsFileHeaderGenerator(object):
    """SconsFileHeaderGenerator class"""
    def __init__(self, options, build_dir, gcc_version, python_inc, cuda_inc,
                 build_environment, svn_roots):
        """Init method. """
        self.rules_buf = []
        self.options = options
        self.build_dir = build_dir
        self.gcc_version = gcc_version
        self.python_inc = python_inc
        self.cuda_inc = cuda_inc
        self.build_environment = build_environment
        self.ccflags_manager = CcFlagsManager(options, build_dir, gcc_version)
        self.env_list = ['env_with_error', 'env_no_warning']

        self.svn_roots = svn_roots

        self.blade_config = configparse.blade_config
        self.distcc_enabled = self.blade_config.get_config(
            'distcc_config').get('enabled', False)
        self.dccc_enabled = self.blade_config.get_config('link_config').get(
            'enable_dccc', False)

    def _add_rule(self, rule):
        """Append one rule to buffer. """
        self.rules_buf.append('%s\n' % rule)

    def _append_prefix_to_building_var(self,
                                       prefix='',
                                       building_var='',
                                       condition=False):
        """A helper method: append prefix to building var if condition is True."""
        if condition:
            return '%s %s' % (prefix, building_var)
        else:
            return building_var

    def generate_version_file(self):
        """Generate version information files. """
        blade_root_dir = self.build_environment.blade_root_dir
        self._add_rule(
            'version_obj = scons_helper.generate_version_file(top_env, '
            'blade_root_dir="%s", build_dir="%s", profile="%s", '
            'gcc_version="%s", svn_roots=%s)' %
            (blade_root_dir, self.build_dir, self.options.profile,
             self.gcc_version, sorted(self.svn_roots)))

    def generate_imports_functions(self, blade_path):
        """Generates imports and functions. """
        self._add_rule(r"""
import sys
sys.path.insert(0, '%s')
""" % blade_path)
        self._add_rule(r"""
import os
import subprocess
import glob

import blade_util
import build_environment
import console
import scons_helper

""")

        if getattr(self.options, 'verbose', False):
            self._add_rule('scons_helper.option_verbose = True')
            self._add_rule('console.set_verbose(True)')

        self._add_rule(("""if not os.path.exists('%s'):
    os.mkdir('%s')""") % (self.build_dir, self.build_dir))
        self._add_rule('console.set_log_file("%s")' %
                       os.path.join(self.build_dir, 'blade_scons.log'))

        # Add java_home/bin into PATH to make scons
        # construction variables of java work as expected
        # See http://scons.org/faq.html#SCons_Questions
        java_config = configparse.blade_config.get_config('java_config')
        java_home = java_config['java_home']
        if java_home:
            self._add_rule('blade_util.environ_add_path(os.environ, "PATH", '
                           'os.path.join("%s", "bin"))' % java_home)

    def generate_top_level_env(self):
        """generates top level environment. """
        self._add_rule('top_env = scons_helper.make_top_env("%s")' %
                       self.build_dir)

    def generate_compliation_verbose(self):
        """Generates color and verbose message. """
        self._add_rule(
            'scons_helper.setup_compliation_verbose(top_env, color_enabled=%s, verbose=%s)'
            % (console.color_enabled, getattr(self.options, 'verbose', False)))

    def _generate_fast_link_builders(self):
        """Generates fast link builders if it is specified in blade bash. """
        link_config = configparse.blade_config.get_config('link_config')
        enable_dccc = link_config['enable_dccc']
        if link_config['link_on_tmp']:
            if (not enable_dccc) or (
                    enable_dccc
                    and not self.build_environment.dccc_env_prepared):
                self._add_rule(
                    'scons_helper.setup_fast_link_builders(top_env)')

    def _generate_proto_builders(self):
        self._add_rule('time_value = Value("%s")' % time.asctime())
        proto_config = configparse.blade_config.get_config(
            'proto_library_config')
        protoc_bin = proto_config['protoc']
        protoc_java_bin = protoc_bin
        if proto_config['protoc_java']:
            protoc_java_bin = proto_config['protoc_java']
        protobuf_path = proto_config['protobuf_path']

        protobuf_incs_str = _incs_list_to_string(proto_config['protobuf_incs'])
        protobuf_php_path = proto_config['protobuf_php_path']
        protoc_php_plugin = proto_config['protoc_php_plugin']
        protoc_go_plugin = proto_config['protoc_go_plugin']
        self._add_rule(
            'scons_helper.setup_proto_builders(top_env, "%s", protoc_bin="%s", '
            'protoc_java_bin="%s", protobuf_path="%s", protobuf_incs_str="%s", '
            'protobuf_php_path="%s", protoc_php_plugin="%s", '
            'protoc_go_plugin="%s")' %
            (self.build_dir, protoc_bin, protoc_java_bin, protobuf_path,
             protobuf_incs_str, protobuf_php_path, protoc_php_plugin,
             protoc_go_plugin))

    def _generate_thrift_builders(self):
        # Generate thrift library builders.
        thrift_config = configparse.blade_config.get_config('thrift_config')
        thrift_incs_str = _incs_list_to_string(thrift_config['thrift_incs'])
        thrift_bin = thrift_config['thrift']
        if thrift_bin.startswith('//'):
            thrift_bin = thrift_bin.replace('//', self.build_dir + '/')
            thrift_bin = thrift_bin.replace(':', '/')
        self._add_rule(
            'scons_helper.setup_thrift_builders(top_env, build_dir="%s", thrift_bin="%s", thrift_incs_str="%s")'
            % (self.build_dir, thrift_bin, thrift_incs_str))

    def _generate_fbthrift_builders(self):
        fbthrift_config = configparse.blade_config.get_config(
            'fbthrift_config')
        fbthrift1_bin = fbthrift_config['fbthrift1']
        fbthrift2_bin = fbthrift_config['fbthrift2']
        fbthrift_incs_str = _incs_list_to_string(
            fbthrift_config['fbthrift_incs'])
        self._add_rule(
            'scons_helper.setup_fbthrift_builders(top_env, "%s", '
            'fbthrift1_bin="%s", fbthrift2_bin="%s", fbthrift_incs_str="%s")' %
            (self.build_dir, fbthrift1_bin, fbthrift2_bin, fbthrift_incs_str))

    def _generate_cuda_builders(self):
        nvcc_str = os.environ.get('NVCC', 'nvcc')
        cuda_incs_str = ' '.join(['-I%s' % inc for inc in self.cuda_inc])
        self._add_rule(
            'scons_helper.setup_cuda_builders(top_env, "%s", "%s")' %
            (nvcc_str, cuda_incs_str))

    def _generate_swig_builders(self):
        self._add_rule('scons_helper.setup_swig_builders(top_env, "%s")' %
                       self.build_dir)

    def _generate_java_builders(self):
        config = configparse.blade_config.get_config('java_config')
        bin_config = configparse.blade_config.get_config('java_binary_config')
        self._add_rule(
            'scons_helper.setup_java_builders(top_env, "%s", "%s")' %
            (config['java_home'], bin_config['one_jar_boot_jar']))

    def _generate_scala_builders(self):
        config = configparse.blade_config.get_config('scala_config')
        self._add_rule('scons_helper.setup_scala_builders(top_env, "%s")' %
                       config['scala_home'])

    def _generate_go_builders(self):
        config = configparse.blade_config.get_config('go_config')
        self._add_rule('scons_helper.setup_go_builders(top_env, "%s", "%s")' %
                       (config['go'], config['go_home']))

    def _generate_other_builders(self):
        self._add_rule('scons_helper.setup_other_builders(top_env)')

    def generate_builders(self):
        """Generates common builders. """
        # Generates builders specified in blade bash at first
        self._generate_fast_link_builders()
        self._generate_proto_builders()
        self._generate_thrift_builders()
        self._generate_fbthrift_builders()
        self._generate_cuda_builders()
        self._generate_swig_builders()
        self._generate_java_builders()
        self._generate_scala_builders()
        self._generate_go_builders()
        self._generate_other_builders()

    def generate_compliation_flags(self):
        """Generates compliation flags. """
        toolchain_dir = os.environ.get('TOOLCHAIN_DIR', '')
        if toolchain_dir and not toolchain_dir.endswith('/'):
            toolchain_dir += '/'
        cpp = toolchain_dir + os.environ.get('CPP', 'cpp')
        cc = toolchain_dir + os.environ.get('CC', 'gcc')
        cxx = toolchain_dir + os.environ.get('CXX', 'g++')
        ld = toolchain_dir + os.environ.get('LD', 'g++')
        console.info('CPP=%s' % cpp)
        console.info('CC=%s' % cc)
        console.info('CXX=%s' % cxx)
        console.info('LD=%s' % ld)

        self.ccflags_manager.set_cc(cc)

        # To modify CC, CXX, LD according to the building environment and
        # project configuration
        build_with_distcc = (self.distcc_enabled
                             and self.build_environment.distcc_env_prepared)
        cc_str = self._append_prefix_to_building_var(
            prefix='distcc', building_var=cc, condition=build_with_distcc)

        cxx_str = self._append_prefix_to_building_var(
            prefix='distcc', building_var=cxx, condition=build_with_distcc)

        build_with_ccache = self.build_environment.ccache_installed
        cc_str = self._append_prefix_to_building_var(
            prefix='ccache', building_var=cc_str, condition=build_with_ccache)

        cxx_str = self._append_prefix_to_building_var(
            prefix='ccache', building_var=cxx_str, condition=build_with_ccache)

        build_with_dccc = (self.dccc_enabled
                           and self.build_environment.dccc_env_prepared)
        ld_str = self._append_prefix_to_building_var(prefix='dccc',
                                                     building_var=ld,
                                                     condition=build_with_dccc)

        cc_config = configparse.blade_config.get_config('cc_config')
        cc_env_str = ('CC="%s", CXX="%s", SECURECXX="%s %s"' %
                      (cc_str, cxx_str, cc_config['securecc'], cxx))
        ld_env_str = 'LINK="%s"' % ld_str

        extra_incs = cc_config['extra_incs']
        extra_incs_str = ', '.join(['"%s"' % inc for inc in extra_incs])
        if not extra_incs_str:
            extra_incs_str = '""'

        (cppflags_except_warning,
         linkflags) = self.ccflags_manager.get_flags_except_warning()
        linkflags += cc_config['linkflags']

        self._add_rule('top_env.Replace(%s, '
                       'CPPPATH=[%s, "%s", "%s"], '
                       'CPPFLAGS=%s, CFLAGS=%s, CXXFLAGS=%s, '
                       '%s, LINKFLAGS=%s)' %
                       (cc_env_str, extra_incs_str, self.build_dir,
                        self.python_inc, cc_config['cppflags'] +
                        cppflags_except_warning, cc_config['cflags'],
                        cc_config['cxxflags'], ld_env_str, linkflags))

        cc_library_config = configparse.blade_config.get_config(
            'cc_library_config')
        # By default blade use 'ar rcs' and skip ranlib
        # to generate index for static library
        arflags = cc_library_config['arflags']
        if arflags:
            self._add_rule('top_env.Replace(ARFLAGS="%s")' % ''.join(arflags))
        else:
            self._add_rule('top_env.Replace(ARFLAGS="rcs")')
        ranlibflags = cc_library_config['ranlibflags']
        if ranlibflags:
            self._add_rule('top_env.Replace(RANLIBFLAGS="%s")' %
                           ''.join(ranlibflags))
        else:
            self._add_rule('top_env.Replace(RANLIBCOM="", RANLIBCOMSTR="")')

        # The default ASPPFLAGS of scons is same as ASFLAGS,
        # this is incorrect for gcc/gas
        options = self.options
        self._add_rule('top_env.Replace(ASFLAGS=["-g", "--%s"])' % options.m)
        self._add_rule('top_env.Replace(ASPPFLAGS="-Wa,--%s")' % options.m)

        self._setup_cache()

        if build_with_distcc:
            self.build_environment.setup_distcc_env()

        for rule in self.build_environment.get_rules():
            self._add_rule(rule)

        self._setup_warnings()

    def _setup_warnings(self):
        for env in self.env_list:
            self._add_rule('%s = top_env.Clone()' % env)

        (warnings, cxx_warnings,
         c_warnings) = self.ccflags_manager.get_warning_flags()
        self._add_rule('%s.Append(CPPFLAGS=%s, CFLAGS=%s, CXXFLAGS=%s)' %
                       (self.env_list[0], warnings, c_warnings, cxx_warnings))

    def _setup_cache(self):
        self.build_environment.setup_build_cache(self.options)

    def generate_extra_flags(self):
        config = configparse.blade_config.get_config('java_test_config')
        jacoco_home = config['jacoco_home']
        if jacoco_home:
            jacoco_agent = os.path.join(jacoco_home, 'lib', 'jacocoagent.jar')
            self._add_rule('top_env.Replace(JACOCOAGENT="%s")' % jacoco_agent)

    def generate(self, blade_path):
        """Generates all rules. """
        self.generate_imports_functions(blade_path)
        self.generate_top_level_env()
        self.generate_compliation_verbose()
        self.generate_builders()
        self.generate_compliation_flags()
        self.generate_extra_flags()
        self.generate_version_file()
        return self.rules_buf
Beispiel #10
0
class SconsFileHeaderGenerator(object):
    """SconsFileHeaderGenerator class"""
    def __init__(self, options, build_dir, gcc_version,
                 python_inc, cuda_inc, build_environment, svn_roots):
        """Init method. """
        self.rules_buf = []
        self.options = options
        self.build_dir = build_dir
        self.gcc_version = gcc_version
        self.python_inc = python_inc
        self.cuda_inc = cuda_inc
        self.build_environment = build_environment
        self.ccflags_manager = CcFlagsManager(options, build_dir, gcc_version)
        self.env_list = ['env_with_error', 'env_no_warning']

        self.svn_roots = svn_roots

        self.blade_config = configparse.blade_config
        self.distcc_enabled = self.blade_config.get_config(
                              'distcc_config').get('enabled', False)
        self.dccc_enabled = self.blade_config.get_config(
                              'link_config').get('enable_dccc', False)

    def _add_rule(self, rule):
        """Append one rule to buffer. """
        self.rules_buf.append('%s\n' % rule)

    def _append_prefix_to_building_var(
                self,
                prefix='',
                building_var='',
                condition=False):
        """A helper method: append prefix to building var if condition is True."""
        if condition:
            return '%s %s' % (prefix, building_var)
        else:
            return building_var

    def generate_version_file(self):
        """Generate version information files. """
        blade_root_dir = self.build_environment.blade_root_dir
        self._add_rule(
                'version_obj = scons_helper.generate_version_file(top_env, '
                'blade_root_dir="%s", build_dir="%s", profile="%s", '
                'gcc_version="%s", svn_roots=%s)' % (
                    blade_root_dir, self.build_dir, self.options.profile,
                    self.gcc_version, sorted(self.svn_roots)))

    def generate_imports_functions(self, blade_path):
        """Generates imports and functions. """
        self._add_rule(
            r"""
import sys
sys.path.insert(0, '%s')
""" % blade_path)
        self._add_rule(
            r"""
import os
import subprocess
import glob

import blade_util
import build_environment
import console
import scons_helper

""")

        if getattr(self.options, 'verbose', False):
            self._add_rule('scons_helper.option_verbose = True')
            self._add_rule('console.set_verbose(True)')

        self._add_rule((
                """if not os.path.exists('%s'):
    os.mkdir('%s')""") % (self.build_dir, self.build_dir))
        self._add_rule('console.set_log_file("%s")' % os.path.join(
                self.build_dir, 'blade_scons.log'))

        # Add java_home/bin into PATH to make scons
        # construction variables of java work as expected
        # See http://scons.org/faq.html#SCons_Questions
        java_config = configparse.blade_config.get_config('java_config')
        java_home = java_config['java_home']
        if java_home:
            self._add_rule('blade_util.environ_add_path(os.environ, "PATH", '
                           'os.path.join("%s", "bin"))' % java_home)

    def generate_top_level_env(self):
        """generates top level environment. """
        self._add_rule('top_env = scons_helper.make_top_env("%s")' % self.build_dir)

    def generate_compliation_verbose(self):
        """Generates color and verbose message. """
        self._add_rule('scons_helper.setup_compliation_verbose(top_env, color_enabled=%s, verbose=%s)' %
                (console.color_enabled, getattr(self.options, 'verbose', False)))

    def _generate_fast_link_builders(self):
        """Generates fast link builders if it is specified in blade bash. """
        link_config = configparse.blade_config.get_config('link_config')
        enable_dccc = link_config['enable_dccc']
        if link_config['link_on_tmp']:
            if (not enable_dccc) or (
                    enable_dccc and not self.build_environment.dccc_env_prepared):
                self._add_rule('scons_helper.setup_fast_link_builders(top_env)')

    def _generate_proto_builders(self):
        self._add_rule('time_value = Value("%s")' % time.asctime())
        proto_config = configparse.blade_config.get_config('proto_library_config')
        protoc_bin = proto_config['protoc']
        protoc_java_bin = protoc_bin
        if proto_config['protoc_java']:
            protoc_java_bin = proto_config['protoc_java']
        protobuf_path = proto_config['protobuf_path']

        protobuf_incs_str = _incs_list_to_string(proto_config['protobuf_incs'])
        protobuf_php_path = proto_config['protobuf_php_path']
        protoc_php_plugin = proto_config['protoc_php_plugin']
        protoc_go_plugin = proto_config['protoc_go_plugin']
        self._add_rule('scons_helper.setup_proto_builders(top_env, "%s", protoc_bin="%s", '
                       'protoc_java_bin="%s", protobuf_path="%s", protobuf_incs_str="%s", '
                       'protobuf_php_path="%s", protoc_php_plugin="%s", '
                       'protoc_go_plugin="%s")' % (
            self.build_dir, protoc_bin, protoc_java_bin, protobuf_path, protobuf_incs_str,
            protobuf_php_path, protoc_php_plugin, protoc_go_plugin))

    def _generate_thrift_builders(self):
        # Generate thrift library builders.
        thrift_config = configparse.blade_config.get_config('thrift_config')
        thrift_incs_str = _incs_list_to_string(thrift_config['thrift_incs'])
        thrift_bin = thrift_config['thrift']
        if thrift_bin.startswith('//'):
            thrift_bin = thrift_bin.replace('//', self.build_dir + '/')
            thrift_bin = thrift_bin.replace(':', '/')
        self._add_rule(
            'scons_helper.setup_thrift_builders(top_env, build_dir="%s", thrift_bin="%s", thrift_incs_str="%s")' % (
                    self.build_dir, thrift_bin, thrift_incs_str))

    def _generate_fbthrift_builders(self):
        fbthrift_config = configparse.blade_config.get_config('fbthrift_config')
        fbthrift1_bin = fbthrift_config['fbthrift1']
        fbthrift2_bin = fbthrift_config['fbthrift2']
        fbthrift_incs_str = _incs_list_to_string(fbthrift_config['fbthrift_incs'])
        self._add_rule('scons_helper.setup_fbthrift_builders(top_env, "%s", '
                'fbthrift1_bin="%s", fbthrift2_bin="%s", fbthrift_incs_str="%s")' % (
                    self.build_dir, fbthrift1_bin, fbthrift2_bin, fbthrift_incs_str))

    def _generate_cuda_builders(self):
        nvcc_str = os.environ.get('NVCC', 'nvcc')
        cuda_incs_str = ' '.join(['-I%s' % inc for inc in self.cuda_inc])
        self._add_rule('scons_helper.setup_cuda_builders(top_env, "%s", "%s")' % (
            nvcc_str, cuda_incs_str))

    def _generate_swig_builders(self):
        self._add_rule('scons_helper.setup_swig_builders(top_env, "%s")' % self.build_dir)

    def _generate_java_builders(self):
        config = configparse.blade_config.get_config('java_config')
        bin_config = configparse.blade_config.get_config('java_binary_config')
        self._add_rule('scons_helper.setup_java_builders(top_env, "%s", "%s")' % (
            config['java_home'], bin_config['one_jar_boot_jar']))

    def _generate_scala_builders(self):
        config = configparse.blade_config.get_config('scala_config')
        self._add_rule('scons_helper.setup_scala_builders(top_env, "%s")' % config['scala_home'])

    def _generate_go_builders(self):
        config = configparse.blade_config.get_config('go_config')
        self._add_rule('scons_helper.setup_go_builders(top_env, "%s", "%s")' %
                       (config['go'], config['go_home']))

    def _generate_other_builders(self):
        self._add_rule('scons_helper.setup_other_builders(top_env)')

    def generate_builders(self):
        """Generates common builders. """
        # Generates builders specified in blade bash at first
        self._generate_fast_link_builders()
        self._generate_proto_builders()
        self._generate_thrift_builders()
        self._generate_fbthrift_builders()
        self._generate_cuda_builders()
        self._generate_swig_builders()
        self._generate_java_builders()
        self._generate_scala_builders()
        self._generate_go_builders()
        self._generate_other_builders()

    def generate_compliation_flags(self):
        """Generates compliation flags. """
        toolchain_dir = os.environ.get('TOOLCHAIN_DIR', '')
        if toolchain_dir and not toolchain_dir.endswith('/'):
            toolchain_dir += '/'
        cpp = toolchain_dir + os.environ.get('CPP', 'cpp')
        cc = toolchain_dir + os.environ.get('CC', 'gcc')
        cxx = toolchain_dir + os.environ.get('CXX', 'g++')
        ld = toolchain_dir + os.environ.get('LD', 'g++')
        console.info('CPP=%s' % cpp)
        console.info('CC=%s' % cc)
        console.info('CXX=%s' % cxx)
        console.info('LD=%s' % ld)

        self.ccflags_manager.set_cc(cc)

        # To modify CC, CXX, LD according to the building environment and
        # project configuration
        build_with_distcc = (self.distcc_enabled and
                             self.build_environment.distcc_env_prepared)
        cc_str = self._append_prefix_to_building_var(
                         prefix='distcc',
                         building_var=cc,
                         condition=build_with_distcc)

        cxx_str = self._append_prefix_to_building_var(
                         prefix='distcc',
                         building_var=cxx,
                         condition=build_with_distcc)

        build_with_ccache = self.build_environment.ccache_installed
        cc_str = self._append_prefix_to_building_var(
                         prefix='ccache',
                         building_var=cc_str,
                         condition=build_with_ccache)

        cxx_str = self._append_prefix_to_building_var(
                         prefix='ccache',
                         building_var=cxx_str,
                         condition=build_with_ccache)

        build_with_dccc = (self.dccc_enabled and
                           self.build_environment.dccc_env_prepared)
        ld_str = self._append_prefix_to_building_var(
                        prefix='dccc',
                        building_var=ld,
                        condition=build_with_dccc)

        cc_config = configparse.blade_config.get_config('cc_config')
        cc_env_str = ('CC="%s", CXX="%s", SECURECXX="%s %s"' % (
                      cc_str, cxx_str, cc_config['securecc'], cxx))
        ld_env_str = 'LINK="%s"' % ld_str

        extra_incs = cc_config['extra_incs']
        extra_incs_str = ', '.join(['"%s"' % inc for inc in extra_incs])
        if not extra_incs_str:
            extra_incs_str = '""'

        (cppflags_except_warning, linkflags) = self.ccflags_manager.get_flags_except_warning()

        self._add_rule('top_env.Replace(%s, '
                       'CPPPATH=[%s, "%s", "%s"], '
                       'CPPFLAGS=%s, CFLAGS=%s, CXXFLAGS=%s, '
                       '%s, LINKFLAGS=%s)' %
                       (cc_env_str,
                        extra_incs_str, self.build_dir, self.python_inc,
                        cc_config['cppflags'] + cppflags_except_warning,
                        cc_config['cflags'],
                        cc_config['cxxflags'],
                        ld_env_str, linkflags))

        cc_library_config = configparse.blade_config.get_config('cc_library_config')
        # By default blade use 'ar rcs' and skip ranlib
        # to generate index for static library
        arflags = cc_library_config['arflags']
        if arflags:
            self._add_rule('top_env.Replace(ARFLAGS="%s")' % ''.join(arflags))
        else:
            self._add_rule('top_env.Replace(ARFLAGS="rcs")')
        ranlibflags = cc_library_config['ranlibflags']
        if ranlibflags:
            self._add_rule('top_env.Replace(RANLIBFLAGS="%s")' % ''.join(ranlibflags))
        else:
            self._add_rule('top_env.Replace(RANLIBCOM="", RANLIBCOMSTR="")')

        # The default ASPPFLAGS of scons is same as ASFLAGS,
        # this is incorrect for gcc/gas
        self._add_rule("top_env.Replace(ASPPFLAGS='')")

        self._setup_cache()

        if build_with_distcc:
            self.build_environment.setup_distcc_env()

        for rule in self.build_environment.get_rules():
            self._add_rule(rule)

        self._setup_warnings()

    def _setup_warnings(self):
        for env in self.env_list:
            self._add_rule('%s = top_env.Clone()' % env)

        (warnings, cxx_warnings, c_warnings) = self.ccflags_manager.get_warning_flags()
        self._add_rule('%s.Append(CPPFLAGS=%s, CFLAGS=%s, CXXFLAGS=%s)' % (
            self.env_list[0],
            warnings, c_warnings, cxx_warnings))

    def _setup_cache(self):
        self.build_environment.setup_build_cache(self.options)

    def generate_extra_flags(self):
        config = configparse.blade_config.get_config('java_test_config')
        jacoco_home = config['jacoco_home']
        if jacoco_home:
            jacoco_agent = os.path.join(jacoco_home, 'lib', 'jacocoagent.jar')
            self._add_rule('top_env.Replace(JACOCOAGENT="%s")' % jacoco_agent)

    def generate(self, blade_path):
        """Generates all rules. """
        self.generate_imports_functions(blade_path)
        self.generate_top_level_env()
        self.generate_compliation_verbose()
        self.generate_builders()
        self.generate_compliation_flags()
        self.generate_extra_flags()
        self.generate_version_file()
        return self.rules_buf
class SconsFileHeaderGenerator(object):
    """SconsFileHeaderGenerator class"""
    def __init__(self, options, build_dir, gcc_version, python_inc, cuda_inc,
                 build_environment, svn_roots):
        """Init method. """
        self.rules_buf = []
        self.options = options
        self.build_dir = build_dir
        self.gcc_version = gcc_version
        self.python_inc = python_inc
        self.cuda_inc = cuda_inc
        self.build_environment = build_environment
        self.ccflags_manager = CcFlagsManager(options)
        self.env_list = ['env_with_error', 'env_no_warning']

        self.svn_roots = svn_roots
        self.svn_info_map = {}

        self.version_cpp_compile_template = string.Template("""
env_version = Environment(ENV = os.environ)
env_version.Append(SHCXXCOMSTR = '%s$updateinfo%s' % (colors('cyan'), colors('end')))
env_version.Append(CPPFLAGS = '-m$m')
version_obj = env_version.SharedObject('$filename')
""")
        self.blade_config = configparse.blade_config
        self.distcc_enabled = self.blade_config.get_config(
            'distcc_config').get('enabled', False)
        self.dccc_enabled = self.blade_config.get_config('link_config').get(
            'enable_dccc', False)

    def _add_rule(self, rule):
        """Append one rule to buffer. """
        self.rules_buf.append('%s\n' % rule)

    def _append_prefix_to_building_var(self,
                                       prefix='',
                                       building_var='',
                                       condition=False):
        """A helper method: append prefix to building var if condition is True."""
        if condition:
            return '%s %s' % (prefix, building_var)
        else:
            return building_var

    def _exec_get_version_info(self, cmd, cwd, dirname):
        lc_all_env = os.environ
        lc_all_env['LC_ALL'] = 'POSIX'
        p = subprocess.Popen(cmd,
                             env=lc_all_env,
                             cwd=cwd,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             shell=True)
        std_out, std_err = p.communicate()
        if p.returncode:
            return False
        else:
            self.svn_info_map[dirname] = std_out.replace('\n', '\\n\\\n')
            return True

    def _get_version_info(self):
        """Gets svn root dir info. """

        blade_root_dir = self.build_environment.blade_root_dir
        if os.path.exists("%s/.git" % blade_root_dir):
            cmd = "git log -n 1"
            self._exec_get_version_info(cmd, None,
                                        os.path.dirname(blade_root_dir))
            return

        for root_dir in self.svn_roots:
            root_dir_realpath = os.path.realpath(root_dir)
            svn_working_dir = os.path.dirname(root_dir_realpath)
            svn_dir = os.path.basename(root_dir_realpath)

            cmd = 'svn info %s' % svn_dir
            cwd = svn_working_dir
            if not self._exec_get_version_info(cmd, cwd, root_dir):
                cmd = 'git ls-remote --get-url && git branch | grep "*" && git log -n 1'
                cwd = root_dir_realpath
                if not self._exec_get_version_info(cmd, cwd, root_dir):
                    console.warning(
                        'failed to get version control info in %s' % root_dir)

    def generate_version_file(self):
        """Generate version information files. """
        self._get_version_info()
        svn_info_len = len(self.svn_info_map)

        if not os.path.exists(self.build_dir):
            os.makedirs(self.build_dir)

        # get trunk svn info
        revision = 0
        trunk_svn_info = os.popen('svn info').readlines()
        for line in trunk_svn_info:
            if 0 == line.find("Revision"):
                revision = filter(str.isdigit, line)

        version_h = open('%s/pebble_version.inh' % self.build_dir, 'w')

        print >> version_h, '/* This file was generated by blade */'
        print >> version_h, '#ifndef _PEBBLE_VERSION_INH_'
        print >> version_h, '#define _PEBBLE_VERSION_INH_'
        print >> version_h, '#include <stdio.h>'
        print >> version_h, '#include <string>'
        print >> version_h, '#include "../version.inh"'
        print >> version_h, 'namespace pebble {'

        print >> version_h, 'class PebbleVersion {'
        print >> version_h, 'public:'
        print >> version_h, 'static std::string GetVersion() {'
        print >> version_h, '    std::string version(PEBBLE_VERSION);'
        print >> version_h, '    version.append(".");'
        print >> version_h, '    version.append("%s");' % revision
        print >> version_h, '    return version;'
        print >> version_h, '}'
        print >> version_h, '};'
        print >> version_h, '} // namespace pebble'
        print >> version_h, '#endif // _PEBBLE_VERSION_INH_'

        version_h.close()

        version_cpp = open('%s/version.cpp' % self.build_dir, 'w')
        print >> version_cpp, '// do noting'
        version_cpp.close()

        self._add_rule('VariantDir("%s", ".", duplicate=0)' % self.build_dir)
        self._add_rule(
            self.version_cpp_compile_template.substitute(
                updateinfo='Updating version information',
                m=self.options.m,
                filename='%s/version.cpp' % self.build_dir))

    def generate_imports_functions(self, blade_path):
        """Generates imports and functions. """
        self._add_rule(r"""
import sys
sys.path.insert(0, '%s')
""" % blade_path)
        self._add_rule(r"""
import os
import subprocess
import signal
import time
import socket
import glob

import blade_util
import console
import scons_helper

from build_environment import ScacheManager
from console import colors
from scons_helper import MakeAction
from scons_helper import create_fast_link_builders
from scons_helper import echospawn
from scons_helper import error_colorize
from scons_helper import generate_python_binary
from scons_helper import generate_resource_file
from scons_helper import generate_resource_index
""")

        if getattr(self.options, 'verbose', False):
            self._add_rule('scons_helper.option_verbose = True')

        self._add_rule(("""if not os.path.exists('%s'):
    os.mkdir('%s')""") % (self.build_dir, self.build_dir))

    def generate_top_level_env(self):
        """generates top level environment. """
        self._add_rule('os.environ["LC_ALL"] = "C"')
        self._add_rule('top_env = Environment(ENV=os.environ)')
        # Optimization options, see http://www.scons.org/wiki/GoFastButton
        self._add_rule('top_env.Decider("MD5-timestamp")')
        self._add_rule('top_env.SetOption("implicit_cache", 1)')
        self._add_rule('top_env.SetOption("max_drift", 1)')

    def generate_compliation_verbose(self):
        """Generates color and verbose message. """
        self._add_rule('console.color_enabled=%s' % console.color_enabled)

        if not getattr(self.options, 'verbose', False):
            self._add_rule('top_env["SPAWN"] = echospawn')

        self._add_rule("""
compile_proto_cc_message = '%sCompiling %s$SOURCE%s to cc source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_proto_java_message = '%sCompiling %s$SOURCE%s to java source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_proto_php_message = '%sCompiling %s$SOURCE%s to php source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_proto_python_message = '%sCompiling %s$SOURCE%s to python source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_thrift_cc_message = '%sCompiling %s$SOURCE%s to cc source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_thrift_java_message = '%sCompiling %s$SOURCE%s to java source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_thrift_python_message = '%sCompiling %s$SOURCE%s to python source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_fbthrift_cpp_message = '%sCompiling %s$SOURCE%s to cpp source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_fbthrift_cpp2_message = '%sCompiling %s$SOURCE%s to cpp2 source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_resource_index_message = '%sGenerating resource index for %s$SOURCE_PATH/$TARGET_NAME%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_resource_message = '%sCompiling %s$SOURCE%s as resource file%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_source_message = '%sCompiling %s$SOURCE%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

assembling_source_message = '%sAssembling %s$SOURCE%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

link_program_message = '%sLinking Program %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end'))

link_library_message = '%sCreating Static Library %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end'))

ranlib_library_message = '%sRanlib Library %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end')) \

link_shared_library_message = '%sLinking Shared Library %s$TARGET%s%s' % \
    (colors('green'), colors('purple'), colors('green'), colors('end'))

compile_java_jar_message = '%sGenerating java jar %s$TARGET%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_python_binary_message = '%sGenerating python binary %s$TARGET%s%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_yacc_message = '%sYacc %s$SOURCE%s to $TARGET%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_swig_python_message = '%sCompiling %s$SOURCE%s to python source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_swig_java_message = '%sCompiling %s$SOURCE%s to java source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))

compile_swig_php_message = '%sCompiling %s$SOURCE%s to php source%s' % \
    (colors('cyan'), colors('purple'), colors('cyan'), colors('end'))
""")

        if not getattr(self.options, 'verbose', False):
            self._add_rule(r"""
top_env.Append(
    CXXCOMSTR = compile_source_message,
    CCCOMSTR = compile_source_message,
    ASCOMSTR = assembling_source_message,
    SHCCCOMSTR = compile_source_message,
    SHCXXCOMSTR = compile_source_message,
    ARCOMSTR = link_library_message,
    RANLIBCOMSTR = ranlib_library_message,
    SHLINKCOMSTR = link_shared_library_message,
    LINKCOMSTR = link_program_message,
    JAVACCOMSTR = compile_source_message
)""")

    def _generate_fast_link_builders(self):
        """Generates fast link builders if it is specified in blade bash. """
        link_config = configparse.blade_config.get_config('link_config')
        enable_dccc = link_config['enable_dccc']
        if link_config['link_on_tmp']:
            if (not enable_dccc) or (
                    enable_dccc
                    and not self.build_environment.dccc_env_prepared):
                self._add_rule('create_fast_link_builders(top_env)')

    def generate_builders(self):
        """Generates common builders. """
        # Generates builders specified in blade bash at first
        self._generate_fast_link_builders()

        proto_config = configparse.blade_config.get_config(
            'proto_library_config')
        protoc_bin = proto_config['protoc']
        protobuf_path = proto_config['protobuf_path']

        protobuf_incs_str = _incs_list_to_string(proto_config['protobuf_incs'])
        protobuf_php_path = proto_config['protobuf_php_path']
        protoc_php_plugin = proto_config['protoc_php_plugin']
        # Genreates common builders now
        builder_list = []
        self._add_rule('time_value = Value("%s")' % time.asctime())
        self._add_rule(
            'proto_bld = Builder(action = MakeAction("%s --proto_path=. -I. %s'
            ' -I=`dirname $SOURCE` --cpp_out=%s $SOURCE", '
            'compile_proto_cc_message))' %
            (protoc_bin, protobuf_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"Proto" : proto_bld}')

        self._add_rule(
            'proto_java_bld = Builder(action = MakeAction("%s --proto_path=. '
            '--proto_path=%s --java_out=%s/`dirname $SOURCE` $SOURCE", '
            'compile_proto_java_message))' %
            (protoc_bin, protobuf_path, self.build_dir))
        builder_list.append('BUILDERS = {"ProtoJava" : proto_java_bld}')

        self._add_rule('proto_php_bld = Builder(action = MakeAction("%s '
                       '--proto_path=. --plugin=protoc-gen-php=%s '
                       '-I. %s -I%s -I=`dirname $SOURCE` '
                       '--php_out=%s/`dirname $SOURCE` '
                       '$SOURCE", compile_proto_php_message))' %
                       (protoc_bin, protoc_php_plugin, protobuf_incs_str,
                        protobuf_php_path, self.build_dir))
        builder_list.append('BUILDERS = {"ProtoPhp" : proto_php_bld}')

        self._add_rule('proto_python_bld = Builder(action = MakeAction("%s '
                       '--proto_path=. '
                       '-I. %s -I=`dirname $SOURCE` '
                       '--python_out=%s '
                       '$SOURCE", compile_proto_python_message))' %
                       (protoc_bin, protobuf_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"ProtoPython" : proto_python_bld}')

        # Generate thrift library builders.
        thrift_config = configparse.blade_config.get_config('thrift_config')
        thrift_incs_str = _incs_list_to_string(thrift_config['thrift_incs'])
        thrift_bin = thrift_config['thrift']
        if thrift_bin.startswith('//'):
            thrift_bin = thrift_bin.replace('//', self.build_dir + '/')
            thrift_bin = thrift_bin.replace(':', '/')

        # Genreates common builders now
        self._add_rule(
            'thrift_bld = Builder(action = MakeAction("%s '
            '--gen cpp:include_prefix,pure_enums -I . %s -I `dirname $SOURCE` '
            '-out %s/`dirname $SOURCE` $SOURCE", compile_thrift_cc_message))' %
            (thrift_bin, thrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"Thrift" : thrift_bld}')

        self._add_rule(
            'thrift_java_bld = Builder(action = MakeAction("%s '
            '--gen java -I . %s -I `dirname $SOURCE` -out %s/`dirname $SOURCE` '
            '$SOURCE", compile_thrift_java_message))' %
            (thrift_bin, thrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"ThriftJava" : thrift_java_bld}')

        self._add_rule(
            'thrift_python_bld = Builder(action = MakeAction("%s '
            '--gen py -I . %s -I `dirname $SOURCE` -out %s/`dirname $SOURCE` '
            '$SOURCE", compile_thrift_python_message))' %
            (thrift_bin, thrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"ThriftPython" : thrift_python_bld}')

        fbthrift_config = configparse.blade_config.get_config(
            'fbthrift_config')
        fbthrift1_bin = fbthrift_config['fbthrift1']
        fbthrift2_bin = fbthrift_config['fbthrift2']
        fbthrift_incs_str = _incs_list_to_string(
            fbthrift_config['fbthrift_incs'])

        self._add_rule(
            'fbthrift1_bld = Builder(action = MakeAction("%s '
            '--gen cpp:templates,cob_style,include_prefix,enum_strict -I . %s -I `dirname $SOURCE` '
            '-o %s/`dirname $SOURCE` $SOURCE", compile_fbthrift_cpp_message))'
            % (fbthrift1_bin, fbthrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"FBThrift1" : fbthrift1_bld}')

        self._add_rule(
            'fbthrift2_bld = Builder(action = MakeAction("%s '
            '--gen=cpp2:cob_style,include_prefix,future -I . %s -I `dirname $SOURCE` '
            '-o %s/`dirname $SOURCE` $SOURCE", compile_fbthrift_cpp2_message))'
            % (fbthrift2_bin, fbthrift_incs_str, self.build_dir))
        builder_list.append('BUILDERS = {"FBThrift2" : fbthrift2_bld}')

        self._add_rule(r"""
blade_jar_bld = Builder(action = MakeAction('jar cf $TARGET -C `dirname $SOURCE` .',
    compile_java_jar_message))

yacc_bld = Builder(action = MakeAction('bison $YACCFLAGS -d -o $TARGET $SOURCE',
    compile_yacc_message))

resource_index_bld = Builder(action = MakeAction(generate_resource_index,
    compile_resource_index_message))

resource_file_bld = Builder(action = MakeAction(generate_resource_file,
    compile_resource_message))

python_binary_bld = Builder(action = MakeAction(generate_python_binary,
    compile_python_binary_message))
""")
        builder_list.append('BUILDERS = {"BladeJar" : blade_jar_bld}')
        builder_list.append('BUILDERS = {"Yacc" : yacc_bld}')
        builder_list.append(
            'BUILDERS = {"ResourceIndex" : resource_index_bld}')
        builder_list.append('BUILDERS = {"ResourceFile" : resource_file_bld}')
        builder_list.append('BUILDERS = {"PythonBinary" : python_binary_bld}')

        for builder in builder_list:
            self._add_rule('top_env.Append(%s)' % builder)

    def generate_compliation_flags(self):
        """Generates compliation flags. """
        toolchain_dir = os.environ.get('TOOLCHAIN_DIR', '')
        if toolchain_dir and not toolchain_dir.endswith('/'):
            toolchain_dir += '/'
        cpp_str = toolchain_dir + os.environ.get('CPP', 'cpp')
        cc_str = toolchain_dir + os.environ.get('CC', 'gcc')
        cxx_str = toolchain_dir + os.environ.get('CXX', 'g++')
        nvcc_str = toolchain_dir + os.environ.get('NVCC', 'nvcc')
        ld_str = toolchain_dir + os.environ.get('LD', 'g++')
        console.info('CPP=%s' % cpp_str)
        console.info('CC=%s' % cc_str)
        console.info('CXX=%s' % cxx_str)
        console.info('NVCC=%s' % nvcc_str)
        console.info('LD=%s' % ld_str)

        self.ccflags_manager.set_cpp_str(cpp_str)

        # To modify CC, CXX, LD according to the building environment and
        # project configuration
        build_with_distcc = (self.distcc_enabled
                             and self.build_environment.distcc_env_prepared)
        cc_str = self._append_prefix_to_building_var(
            prefix='distcc', building_var=cc_str, condition=build_with_distcc)

        cxx_str = self._append_prefix_to_building_var(
            prefix='distcc', building_var=cxx_str, condition=build_with_distcc)

        build_with_ccache = self.build_environment.ccache_installed
        cc_str = self._append_prefix_to_building_var(
            prefix='ccache', building_var=cc_str, condition=build_with_ccache)

        cxx_str = self._append_prefix_to_building_var(
            prefix='ccache', building_var=cxx_str, condition=build_with_ccache)

        build_with_dccc = (self.dccc_enabled
                           and self.build_environment.dccc_env_prepared)
        ld_str = self._append_prefix_to_building_var(prefix='dccc',
                                                     building_var=ld_str,
                                                     condition=build_with_dccc)

        cc_env_str = 'CC="%s", CXX="%s"' % (cc_str, cxx_str)
        ld_env_str = 'LINK="%s"' % ld_str
        nvcc_env_str = 'NVCC="%s"' % nvcc_str

        cc_config = configparse.blade_config.get_config('cc_config')
        extra_incs = cc_config['extra_incs']
        extra_incs_str = ', '.join(['"%s"' % inc for inc in extra_incs])
        if not extra_incs_str:
            extra_incs_str = '""'

        (cppflags_except_warning,
         linkflags) = self.ccflags_manager.get_flags_except_warning()

        builder_list = []
        cuda_incs_str = ' '.join(['-I%s' % inc for inc in self.cuda_inc])
        self._add_rule(
            'nvcc_object_bld = Builder(action = MakeAction("%s -ccbin g++ %s '
            '$NVCCFLAGS -o $TARGET -c $SOURCE", compile_source_message))' %
            (nvcc_str, cuda_incs_str))
        builder_list.append('BUILDERS = {"NvccObject" : nvcc_object_bld}')

        self._add_rule('nvcc_binary_bld = Builder(action = MakeAction("%s %s '
                       '$NVCCFLAGS -o $TARGET ", link_program_message))' %
                       (nvcc_str, cuda_incs_str))
        builder_list.append('BUILDERS = {"NvccBinary" : nvcc_binary_bld}')

        for builder in builder_list:
            self._add_rule('top_env.Append(%s)' % builder)

        self._add_rule(
            'top_env.Replace(%s, %s, '
            'CPPPATH=[%s, "%s", "%s"], '
            'CPPFLAGS=%s, CFLAGS=%s, CXXFLAGS=%s, '
            '%s, LINKFLAGS=%s)' %
            (cc_env_str, nvcc_env_str, extra_incs_str, self.build_dir,
             self.python_inc, cc_config['cppflags'] + cppflags_except_warning,
             cc_config['cflags'], cc_config['cxxflags'], ld_env_str,
             linkflags))

        self._setup_cache()

        if build_with_distcc:
            self.build_environment.setup_distcc_env()

        for rule in self.build_environment.get_rules():
            self._add_rule(rule)

        self._setup_warnings()

    def _setup_warnings(self):
        for env in self.env_list:
            self._add_rule('%s = top_env.Clone()' % env)

        (warnings, cxx_warnings,
         c_warnings) = self.ccflags_manager.get_warning_flags()
        self._add_rule('%s.Append(CPPFLAGS=%s, CFLAGS=%s, CXXFLAGS=%s)' %
                       (self.env_list[0], warnings, c_warnings, cxx_warnings))

    def _setup_cache(self):
        if self.build_environment.ccache_installed:
            self.build_environment.setup_ccache_env()
        else:
            cache_dir = os.path.expanduser('~/.bladescache')
            cache_size = 4 * 1024 * 1024 * 1024
            if hasattr(self.options, 'cache_dir'):
                if not self.options.cache_dir:
                    return
                cache_dir = self.options.cache_dir
            else:
                console.info('using default cache dir: %s' % cache_dir)

            if hasattr(self.options,
                       'cache_size') and (self.options.cache_size != -1):
                cache_size = self.options.cache_size

            self._add_rule('CacheDir("%s")' % cache_dir)
            self._add_rule(
                'scache_manager = ScacheManager("%s", cache_limit=%d)' %
                (cache_dir, cache_size))
            self._add_rule('Progress(scache_manager, interval=100)')

            self._add_rule('console.info("using cache directory %s")' %
                           cache_dir)
            self._add_rule('console.info("scache size %d")' % cache_size)

    def generate(self, blade_path):
        """Generates all rules. """
        self.generate_imports_functions(blade_path)
        self.generate_top_level_env()
        self.generate_compliation_verbose()
        self.generate_version_file()
        self.generate_builders()
        self.generate_compliation_flags()
        return self.rules_buf