summaryrefslogtreecommitdiffstats
path: root/site_scons/site_tools/component_builders.py
diff options
context:
space:
mode:
Diffstat (limited to 'site_scons/site_tools/component_builders.py')
-rw-r--r--site_scons/site_tools/component_builders.py618
1 files changed, 0 insertions, 618 deletions
diff --git a/site_scons/site_tools/component_builders.py b/site_scons/site_tools/component_builders.py
deleted file mode 100644
index 1fe638c..0000000
--- a/site_scons/site_tools/component_builders.py
+++ /dev/null
@@ -1,618 +0,0 @@
-#!/usr/bin/python2.4
-# Copyright 2008, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Software construction toolkit builders for SCons."""
-
-
-import SCons
-
-
-__component_list = {}
-
-
-def _InitializeComponentBuilders(env):
- """Re-initializes component builders module.
-
- Args:
- env: Environment context
- """
- env = env # Silence gpylint
-
- __component_list.clear()
-
-
-def _RetrieveComponents(component_name, filter_components=None):
- """Get the list of all components required by the specified component.
-
- Args:
- component_name: Name of the base component.
- filter_components: List of components NOT to include.
-
- Returns:
- A list of the transitive closure of all components required by the base
- component. That is, if A requires B and B requires C, this returns [B, C].
-
- """
- if filter_components:
- filter_components = set(filter_components)
- else:
- filter_components = set()
-
- components = set([component_name]) # Components always require themselves
- new_components = set(components)
- while new_components:
- # Take next new component and add it to the list we've already scanned.
- c = new_components.pop()
- components.add(c)
- # Add to the list of new components any of c's components that we haven't
- # seen before.
- new_components.update(__component_list.get(c, set())
- - components - filter_components)
-
- return list(components)
-
-
-def _StoreComponents(self, component_name):
- """Stores the list of child components for the specified component.
-
- Args:
- self: Environment containing component.
- component_name: Name of the component.
-
- Adds component references based on the LIBS and COMPONENTS variables in the
- current environment. Should be called at primary SConscript execution time;
- use _RetrieveComponents() to get the final components lists in a Defer()'d
- function.
- """
-
- components = set()
- for clist in ('LIBS', 'COMPONENTS'):
- components.update(map(self.subst, self.Flatten(self[clist])))
-
- if component_name not in __component_list:
- __component_list[component_name] = set()
- __component_list[component_name].update(components)
-
-
-def _ComponentPlatformSetup(env, builder_name, **kwargs):
- """Modify an environment to work with a component builder.
-
- Args:
- env: Environment to clone.
- builder_name: Name of the builder.
- kwargs: Keyword arguments.
-
- Returns:
- A modified clone of the environment.
- """
- # Clone environment so we can modify it
- env = env.Clone()
-
- # Add all keyword arguments to the environment
- for k, v in kwargs.items():
- env[k] = v
-
- # Add compiler flags for included headers, if any
- env['INCLUDES'] = env.Flatten(env.subst_list(['$INCLUDES']))
- for h in env['INCLUDES']:
- env.Append(CCFLAGS = ['${CCFLAG_INCLUDE}%s' % h])
-
- # Call platform-specific component setup function, if any
- if env.get('COMPONENT_PLATFORM_SETUP'):
- env['COMPONENT_PLATFORM_SETUP'](env, builder_name)
-
- # Return the modified environment
- return env
-
-#------------------------------------------------------------------------------
-
-# TODO(rspangler): Should be possible to refactor programs, test programs,
-# libs to all publish as packages, for simplicity and code reuse.
-
-
-def ComponentPackageDeferred(env):
- """Deferred build steps for component package.
-
- Args:
- env: Environment from ComponentPackage().
-
- Sets up the aliases to build the package.
- """
- package_name = env['PACKAGE_NAME']
-
- # Install program and resources
- all_outputs = []
- filter = env.Flatten(env.subst_list('$COMPONENT_PACKAGE_FILTER'))
- components = _RetrieveComponents(package_name, filter)
- for resource, dest_dir in env.get('COMPONENT_PACKAGE_RESOURCES').items():
- all_outputs += env.ReplicatePublished(dest_dir, components, resource)
-
- # Add installed program and resources to the alias
- env.Alias(package_name, all_outputs)
-
-
-def ComponentPackage(self, package_name, dest_dir, **kwargs):
- """Pseudo-builder for package containing other components.
-
- Args:
- self: Environment in which we were called.
- package_name: Name of package.
- dest_dir: Destination directory for package.
- args: Positional arguments.
- kwargs: Keyword arguments.
-
- Returns:
- The alias node for the package.
- """
- # Clone and modify environment
- env = _ComponentPlatformSetup(self, 'ComponentPackage', **kwargs)
-
- env.Replace(
- PACKAGE_NAME=package_name,
- PACKAGE_DIR=dest_dir,
- )
-
- # Add an empty alias for the package and add it to the right groups
- a = env.Alias(package_name, [])
- for group in env['COMPONENT_PACKAGE_GROUPS']:
- SCons.Script.Alias(group, a)
-
- # Store list of components for this program
- env._StoreComponents(package_name)
-
- # Let component_targets know this target is available in the current mode
- env.SetTargetProperty(package_name, TARGET_PATH=dest_dir)
-
- # Set up deferred call to replicate resources
- env.Defer(ComponentPackageDeferred)
-
- # Return the alias, since it's the only node we have
- return a
-
-#------------------------------------------------------------------------------
-
-
-def ComponentObject(self, *args, **kwargs):
- """Pseudo-builder for object to handle platform-dependent type.
-
- Args:
- self: Environment in which we were called.
- args: Positional arguments.
- kwargs: Keyword arguments.
-
- Returns:
- Passthrough return code from env.StaticLibrary() or env.SharedLibrary().
-
- TODO(rspangler): Perhaps this should be a generator builder, so it can take
- a list of inputs and return a list of outputs?
- """
- # Clone and modify environment
- env = _ComponentPlatformSetup(self, 'ComponentObject', **kwargs)
-
- # Make appropriate object type
- if env.get('COMPONENT_STATIC'):
- o = env.StaticObject(*args, **kwargs)
- else:
- o = env.SharedObject(*args, **kwargs)
-
- # Add dependencies on includes
- env.Depends(o, env['INCLUDES'])
-
- return o
-
-#------------------------------------------------------------------------------
-
-
-def ComponentLibrary(self, lib_name, *args, **kwargs):
- """Pseudo-builder for library to handle platform-dependent type.
-
- Args:
- self: Environment in which we were called.
- lib_name: Library name.
- args: Positional arguments.
- kwargs: Keyword arguments.
-
- Returns:
- Passthrough return code from env.StaticLibrary() or env.SharedLibrary().
- """
- # Clone and modify environment
- env = _ComponentPlatformSetup(self, 'ComponentLibrary', **kwargs)
-
- # Make appropriate library type
- if env.get('COMPONENT_STATIC'):
- lib_outputs = env.StaticLibrary(lib_name, *args, **kwargs)
- else:
- lib_outputs = env.SharedLibrary(lib_name, *args, **kwargs)
-
- # Add dependencies on includes
- env.Depends(lib_outputs, env['INCLUDES'])
-
- # Scan library outputs for files we need to link against this library, and
- # files we need to run executables linked against this library.
- need_for_link = []
- need_for_debug = []
- need_for_run = []
- for o in lib_outputs:
- if o.suffix in env['COMPONENT_LIBRARY_LINK_SUFFIXES']:
- need_for_link.append(o)
- if o.suffix in env['COMPONENT_LIBRARY_DEBUG_SUFFIXES']:
- need_for_debug.append(o)
- if o.suffix == env['SHLIBSUFFIX']:
- need_for_run.append(o)
- all_outputs = lib_outputs
-
- # Install library in intermediate directory, so other libs and programs can
- # link against it
- all_outputs += env.Replicate('$LIB_DIR', need_for_link)
-
- # Publish output
- env.Publish(lib_name, 'run', need_for_run)
- env.Publish(lib_name, 'debug', need_for_debug)
-
- # Add an alias to build and copy the library, and add it to the right groups
- a = self.Alias(lib_name, all_outputs)
- for group in env['COMPONENT_LIBRARY_GROUPS']:
- SCons.Script.Alias(group, a)
-
- # Store list of components for this library
- env._StoreComponents(lib_name)
-
- # Let component_targets know this target is available in the current mode.
- env.SetTargetProperty(lib_name, TARGET_PATH=lib_outputs[0])
-
- # If library should publish itself, publish as if it was a program
- if env.get('COMPONENT_LIBRARY_PUBLISH'):
- env['PROGRAM_BASENAME'] = lib_name
- env.Defer(ComponentProgramDeferred)
-
- # Return the library outputs
- return lib_outputs
-
-#------------------------------------------------------------------------------
-
-
-def ComponentTestProgramDeferred(env):
- """Deferred build steps for test program.
-
- Args:
- env: Environment from ComponentTestProgram().
-
- Sets up the aliases to compile and run the test program.
- """
- prog_name = env['PROGRAM_BASENAME']
-
- # Install program and resources
- all_outputs = []
- components = _RetrieveComponents(prog_name)
- for resource, dest_dir in env.get('COMPONENT_TEST_RESOURCES').items():
- all_outputs += env.ReplicatePublished(dest_dir, components, resource)
-
- # Add installed program and resources to the alias
- env.Alias(prog_name, all_outputs)
-
- # Add target properties
- env.SetTargetProperty(
- prog_name,
- # The copy of the program we care about is the one in the tests dir
- EXE='$TESTS_DIR/$PROGRAM_NAME',
- RUN_CMDLINE='$COMPONENT_TEST_CMDLINE',
- RUN_DIR='$TESTS_DIR',
- TARGET_PATH='$TESTS_DIR/$PROGRAM_NAME',
- )
-
- # Add an alias for running the test in the test directory, if the test is
- # runnable and has a test command line.
- if env.get('COMPONENT_TEST_RUNNABLE') and env.get('COMPONENT_TEST_CMDLINE'):
- env.Replace(
- COMMAND_OUTPUT_CMDLINE=env['COMPONENT_TEST_CMDLINE'],
- COMMAND_OUTPUT_RUN_DIR='$TESTS_DIR',
- )
- test_out_name = '$TEST_OUTPUT_DIR/${PROGRAM_BASENAME}.out.txt'
- if (env.GetOption('component_test_retest')
- and env.File(test_out_name).exists()):
- # Delete old test results, so test will rerun.
- env.Execute(SCons.Script.Delete(test_out_name))
-
- # Set timeout based on test size
- timeout = env.get('COMPONENT_TEST_TIMEOUT')
- if type(timeout) is dict:
- timeout = timeout.get(env.get('COMPONENT_TEST_SIZE'))
- if timeout:
- env['COMMAND_OUTPUT_TIMEOUT'] = timeout
-
- # Test program is the first run resource we replicated. (Duplicate
- # replicate is not harmful, and is a handy way to pick out the correct
- # file from all those we replicated above.)
- test_program = env.ReplicatePublished('$TESTS_DIR', prog_name, 'run')
-
- # Run the test. Note that we need to refer to the file by name, so that
- # SCons will recreate the file node after we've deleted it; if we used the
- # env.File() we created in the if statement above, SCons would still think
- # it exists and not rerun the test.
- test_out = env.CommandOutput(test_out_name, test_program)
-
- # Running the test requires the test and its libs copied to the tests dir
- env.Depends(test_out, all_outputs)
- env.ComponentTestOutput('run_' + prog_name, test_out)
-
- # Add target properties
- env.SetTargetProperty(prog_name, RUN_TARGET='run_' + prog_name)
-
-def ComponentTestProgram(self, prog_name, *args, **kwargs):
- """Pseudo-builder for test program to handle platform-dependent type.
-
- Args:
- self: Environment in which we were called.
- prog_name: Test program name.
- args: Positional arguments.
- kwargs: Keyword arguments.
-
- Returns:
- Output node list from env.Program().
-
- TODO(rspangler): Should have some sort of support for S/M/L categorization
- """
- # Clone and modify environment
- env = _ComponentPlatformSetup(self, 'ComponentTestProgram', **kwargs)
-
- env['PROGRAM_BASENAME'] = prog_name
- env['PROGRAM_NAME'] = '$PROGPREFIX$PROGRAM_BASENAME$PROGSUFFIX'
-
- # Call env.Program()
- out_nodes = env.Program(prog_name, *args, **kwargs)
-
- # Add dependencies on includes
- env.Depends(out_nodes, env['INCLUDES'])
-
- # Publish output
- env.Publish(prog_name, 'run', out_nodes[0])
- env.Publish(prog_name, 'debug', out_nodes[1:])
-
- # Add an alias to build the program to the right groups
- a = env.Alias(prog_name, out_nodes)
- for group in env['COMPONENT_TEST_PROGRAM_GROUPS']:
- SCons.Script.Alias(group, a)
-
- # Store list of components for this program
- env._StoreComponents(prog_name)
-
- # Let component_targets know this target is available in the current mode
- env.SetTargetProperty(prog_name, TARGET_PATH=out_nodes[0])
-
- # Set up deferred call to replicate resources and run test
- env.Defer(ComponentTestProgramDeferred)
-
- # Return the output node
- return out_nodes
-
-#------------------------------------------------------------------------------
-
-
-def ComponentProgramDeferred(env):
- """Deferred build steps for program.
-
- Args:
- env: Environment from ComponentProgram().
-
- Sets up the aliases to compile the program.
- """
- prog_name = env['PROGRAM_BASENAME']
-
- # Install program and resources
- all_outputs = []
- components = _RetrieveComponents(prog_name)
- for resource, dest_dir in env.get('COMPONENT_PROGRAM_RESOURCES').items():
- all_outputs += env.ReplicatePublished(dest_dir, components, resource)
-
- # Add installed program and resources to the alias
- env.Alias(prog_name, all_outputs)
-
-
-def ComponentProgram(self, prog_name, *args, **kwargs):
- """Pseudo-builder for program to handle platform-dependent type.
-
- Args:
- self: Environment in which we were called.
- prog_name: Test program name.
- args: Positional arguments.
- kwargs: Keyword arguments.
-
- Returns:
- Output node list from env.Program().
- """
- # Clone and modify environment
- env = _ComponentPlatformSetup(self, 'ComponentProgram', **kwargs)
-
- env['PROGRAM_BASENAME'] = prog_name
-
- # Call env.Program()
- out_nodes = env.Program(prog_name, *args, **kwargs)
-
- # Add dependencies on includes
- env.Depends(out_nodes, env['INCLUDES'])
-
- # Publish output
- env.Publish(prog_name, 'run', out_nodes[0])
- env.Publish(prog_name, 'debug', out_nodes[1:])
-
- # Add an alias to build the program to the right groups
- a = env.Alias(prog_name, out_nodes)
- for group in env['COMPONENT_PROGRAM_GROUPS']:
- SCons.Script.Alias(group, a)
-
- # Store list of components for this program
- env._StoreComponents(prog_name)
-
- # Let component_targets know this target is available in the current mode
- env.SetTargetProperty(prog_name)
-
- # Set up deferred call to replicate resources
- env.Defer(ComponentProgramDeferred)
-
- # Return the output nodes
- return out_nodes
-
-#------------------------------------------------------------------------------
-
-
-def ComponentTestOutput(self, test_name, nodes):
- """Pseudo-builder for test output.
-
- Args:
- self: Environment in which we were called.
- test_name: Test name.
- nodes: List of files/Nodes output by the test.
-
- Returns:
- Passthrough return code from env.Alias().
- """
-
- # Add an alias for the test output
- a = self.Alias(test_name, nodes)
-
- groups = self.get('COMPONENT_TEST_OUTPUT_GROUPS')
- if not groups:
- # Output group not explicitly specified, so automatically add to groups
- if self.get('COMPONENT_TEST_ENABLED'):
- # Enabled tests go in all tests, and their size category
- groups = ['run_all_tests']
- if self.get('COMPONENT_TEST_SIZE'):
- groups.append(self.subst('run_${COMPONENT_TEST_SIZE}_tests'))
- else:
- # Disabled tests only go in their group
- groups = ['run_disabled_tests']
-
- for group in groups:
- SCons.Script.Alias(group, a)
-
- # Let component_targets know this target is available in the current mode
- self.SetTargetProperty(test_name, TARGET_PATH=nodes[0])
-
- # Return the output node
- return a
-
-#------------------------------------------------------------------------------
-
-
-def generate(env):
- # NOTE: SCons requires the use of this name, which fails gpylint.
- """SCons entry point for this tool."""
-
- env.Replace(
- LIB_DIR='$TARGET_ROOT/lib',
- # TODO(rspangler): Remove legacy COMPONENT_LIBRARY_DIR, once all users
- # have transitioned to LIB_DIR
- COMPONENT_LIBRARY_DIR='$LIB_DIR',
- STAGING_DIR='$TARGET_ROOT/staging',
- TESTS_DIR='$TARGET_ROOT/tests',
- TEST_OUTPUT_DIR='$TARGET_ROOT/test_output',
- # Default command line for a test is just the name of the file.
- # TODO(rspangler): Why doesn't the following work:
- # COMPONENT_TEST_CMDLINE='${SOURCE.abspath}',
- # (it generates a SCons error)
- COMPONENT_TEST_CMDLINE='${PROGRAM_NAME}',
- # Component tests are runnable by default.
- COMPONENT_TEST_RUNNABLE=True,
- # Default test size is large
- COMPONENT_TEST_SIZE='large',
- # Default timeouts for component tests
- COMPONENT_TEST_TIMEOUT={'large': 900, 'medium': 450, 'small': 180},
- # Tests are enabled by default
- COMPONENT_TEST_ENABLED=True,
- # Static linking is a sensible default
- COMPONENT_STATIC=True,
- # Don't publish libraries to the staging dir by themselves by default.
- COMPONENT_LIBRARY_PUBLISH=False,
- )
- env.Append(
- LIBPATH=['$LIB_DIR'],
- RPATH=['$LIB_DIR'],
-
- # Default alias groups for component builders
- COMPONENT_PACKAGE_GROUPS=['all_packages'],
- COMPONENT_LIBRARY_GROUPS=['all_libraries'],
- COMPONENT_PROGRAM_GROUPS=['all_programs'],
- COMPONENT_TEST_PROGRAM_GROUPS=['all_test_programs'],
-
- # Additional components whose resources should be copied into program
- # directories, in addition to those from LIBS and the program itself.
- LIBS=[],
- COMPONENTS=[],
-
- # Dicts of what resources should go in each destination directory for
- # programs and test programs.
- COMPONENT_PACKAGE_RESOURCES={
- 'run': '$PACKAGE_DIR',
- 'debug': '$PACKAGE_DIR',
- },
- COMPONENT_PROGRAM_RESOURCES={
- 'run': '$STAGING_DIR',
- 'debug': '$STAGING_DIR',
- },
- COMPONENT_TEST_RESOURCES={
- 'run': '$TESTS_DIR',
- 'debug': '$TESTS_DIR',
- 'test_input': '$TESTS_DIR',
- },
- )
-
- # Add command line option for retest
- SCons.Script.AddOption(
- '--retest',
- dest='component_test_retest',
- action='store_true',
- help='force all tests to rerun')
- SCons.Script.Help(' --retest '
- 'Rerun specified tests, ignoring cached results.\n')
-
- # Defer per-environment initialization, but do before building SConscripts
- env.Defer(_InitializeComponentBuilders)
- env.Defer('BuildEnvironmentSConscripts', after=_InitializeComponentBuilders)
-
- # Add our pseudo-builder methods
- env.AddMethod(_StoreComponents)
- env.AddMethod(ComponentPackage)
- env.AddMethod(ComponentObject)
- env.AddMethod(ComponentLibrary)
- env.AddMethod(ComponentProgram)
- env.AddMethod(ComponentTestProgram)
- env.AddMethod(ComponentTestOutput)
-
- # Add our target groups
- AddTargetGroup('all_libraries', 'libraries can be built')
- AddTargetGroup('all_programs', 'programs can be built')
- AddTargetGroup('all_test_programs', 'tests can be built')
- AddTargetGroup('all_packages', 'packages can be built')
- AddTargetGroup('run_all_tests', 'tests can be run')
- AddTargetGroup('run_disabled_tests', 'tests are disabled')
- AddTargetGroup('run_small_tests', 'small tests can be run')
- AddTargetGroup('run_medium_tests', 'medium tests can be run')
- AddTargetGroup('run_large_tests', 'large tests can be run')
-