blob: 51fd58fcc5d14d1391d13a927530de2a286b174c [file] [log] [blame]
#!/usr/bin/python2.4
# Copyright 2009, 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.
"""Build tool setup for MacOS.
This module is a SCons tool which should be include in the topmost mac
environment.
It is used as follows:
env = base_env.Clone(tools = ['component_setup'])
mac_env = base_env.Clone(tools = ['target_platform_mac'])
"""
import SCons.Script
def ComponentPlatformSetup(env, builder_name):
"""Hook to allow platform to modify environment inside a component builder.
Args:
env: Environment to modify
builder_name: Name of the builder
"""
if env.get('ENABLE_EXCEPTIONS'):
env.FilterOut(CCFLAGS=['-fno-exceptions'])
env.Append(CCFLAGS=['-fexceptions'])
#------------------------------------------------------------------------------
# TODO: This bundle builder here needs refactoring to use ComponentPackage().
# Until that refactoring, consider this code very experimental (i.e., don't use
# it unless you're ok with it changing out from underneath you).
def BundlePseudoBuilder(env, target, **kwargs):
"""MacOS Bundle PseudoBuilder.
Args:
env: Environment in which to build
target: Name of the bundle to build
kwargs: Additional parameters to set in the environment
Returns:
The target is returned.
"""
# Don't change the environment passed into the pseudo-builder
env = env.Clone()
# Bring keywords args into the environment.
for k, v in kwargs.items():
env[k] = v
# Make sure BUNDLE_RESOURCES is set and not empty; force it to be a list
bundle_resources = env.Flatten(env.get('BUNDLE_RESOURCES', []))
if not bundle_resources:
raise ValueError('BUNDLE_RESOURCES must be set and non-empty')
# Make each resource into a directory node.
# TODO: this seems a little too restrictive.
# bundle_resources = [env.Dir(i) for i in bundle_resources]
bundle_resources = [i for i in bundle_resources]
# Create a PkgInfo file only if BUNDLE_PKGINFO_FILENAME is useful.
# (NPAPI bundles are unhappy with PkgInfo files.)
if env.get('BUNDLE_PKGINFO_FILENAME'):
pkginfo_create_command = ('$BUNDLE_GENERATE_PKGINFO '
'>$TARGET/$BUNDLE_PKGINFO_FILENAME')
else:
pkginfo_create_command = '/bin/echo no PkgInfo will be created' # noop
# Add the build step for the bundle.
p = env.Command(env.Dir(target),
[env.File('$BUNDLE_EXE'),
env.File('$BUNDLE_INFO_PLIST')] +
bundle_resources,
[SCons.Script.Delete('$TARGET'),
SCons.Script.Mkdir('$TARGET/Contents'),
SCons.Script.Mkdir('$TARGET/Contents/MacOS'),
SCons.Script.Mkdir('$TARGET/Contents/Resources'),
'cp -f $SOURCE $TARGET/Contents/MacOS',
'cp -f ${SOURCES[1]} $TARGET/Contents',
pkginfo_create_command,
'cp -rf ${SOURCES[2:]} $TARGET/Contents/Resources'])
# Add an alias for this target.
# This also allows the 'all_bundles' target to build me.
a = env.Alias(target, p)
for group in env['COMPONENT_BUNDLE_GROUPS']:
SCons.Script.Alias(group, a)
return env.Dir(target)
#------------------------------------------------------------------------------
def generate(env):
# NOTE: SCons requires the use of this name, which fails gpylint.
"""SCons entry point for this tool."""
# Preserve some variables that get blown away by the tools.
saved = dict()
for k in ['CFLAGS', 'CCFLAGS', 'CXXFLAGS', 'LINKFLAGS', 'LIBS']:
saved[k] = env.get(k, [])
env[k] = []
# Use g++
env.Tool('g++')
env.Tool('gcc')
env.Tool('gnulink')
env.Tool('ar')
env.Tool('as')
env.Tool('applelink')
# Set target platform bits
env.SetBits('mac', 'posix')
env.Replace(
TARGET_PLATFORM='MAC',
COMPONENT_PLATFORM_SETUP=ComponentPlatformSetup,
CCFLAG_INCLUDE='-include', # Command line option to include a header
# Code coverage related.
COVERAGE_CCFLAGS=['-ftest-coverage', '-fprofile-arcs'],
COVERAGE_LIBS='gcov',
COVERAGE_STOP_CMD=[
'$COVERAGE_MCOV --directory "$TARGET_ROOT" --output "$TARGET"',
('$COVERAGE_GENHTML --output-directory $COVERAGE_HTML_DIR '
'$COVERAGE_OUTPUT_FILE'),
],
# Libraries expect to be in the same directory as their executables.
# This is correct for unit tests, and for libraries which are published
# in Contents/MacOS next to their executables.
DYLIB_INSTALL_NAME_FLAGS=[
'-install_name',
'@loader_path/${TARGET.file}'
],
)
env.Append(
HOST_PLATFORMS=['MAC'],
CPPDEFINES=['OS_MACOSX=OS_MACOSX'],
# Mac apps and dylibs have a more strict relationship about where they
# expect to find each other. When an app is linked, it stores the
# relative path from itself to any dylibs it links against. Override
# this so that it will store the relative path from $LIB_DIR instead.
# This is similar to RPATH on Linux.
LINKFLAGS = [
'-Xlinker', '-executable_path',
'-Xlinker', '$LIB_DIR',
],
# Similarly, tell the library where it expects to find itself once it's
# installed.
SHLINKFLAGS = ['$DYLIB_INSTALL_NAME_FLAGS'],
# Settings for debug
CCFLAGS_DEBUG=['-g'],
LINKFLAGS_DEBUG=['-g'],
# Settings for optimized
# Optimized for space by default, which is what Xcode does
CCFLAGS_OPTIMIZED=['-Os'],
# Settings for component_builders
COMPONENT_LIBRARY_LINK_SUFFIXES=['.dylib', '.a'],
COMPONENT_LIBRARY_DEBUG_SUFFIXES=[],
# New 'all' target. Helpful: "hammer -h" now lists it!
COMPONENT_BUNDLE_GROUPS=['all_bundles'],
)
# Set default values used by the Bundle pseudobuilder.
env.Replace(
BUNDLE_TYPE='APPL',
BUNDLE_STRING='${BUNDLE_TYPE}????',
BUNDLE_GENERATE_PKGINFO='echo "${BUNDLE_STRING}"',
BUNDLE_PKGINFO_FILENAME='PkgInfo',
BUNDLE_INFO_PLIST='Info.plist',
)
# Add the Bundle pseudobuilder.
env.AddMethod(BundlePseudoBuilder, 'Bundle')
# Add our target groups
AddTargetGroup('all_bundles', 'bundles can be built')
# Restore saved flags.
env.Append(**saved)