| # 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. |
| |
| import os |
| import shutil |
| import sys |
| |
| |
| p = ARGUMENTS.get('PROGRESS') |
| if p == 'spinner': |
| Progress(['/\r', '|\r', '\\\r', '-\r'], interval=5, file=open('con', 'w')) |
| elif p == 'name': |
| Progress('$TARGET\r', overwrite=True, file=open('con', 'w')) |
| |
| |
| SetOption('warn', ['no-missing-sconscript'] + GetOption('warn')) |
| |
| |
| load = ARGUMENTS.get('LOAD') |
| if load: |
| load = load.split(',') |
| else: |
| load = [] |
| |
| |
| env = Environment( |
| BUILD_TYPE = ARGUMENTS.get('BUILD_TYPE', 'Hammer'), |
| TARGET_ROOT = '#/$BUILD_TYPE', |
| OBJ_ROOT = '$TARGET_ROOT', |
| |
| LIBS_DIR = '#/$BUILD_TYPE/Libs', |
| |
| BASE_DIR = '#/$BUILD_TYPE/base', |
| BREAKPAD_DIR = '#/$BUILD_TYPE/breakpad', |
| CHROME_DIR = '#/$BUILD_TYPE/chrome', |
| GEARS_DIR = '#/$BUILD_TYPE/gears', |
| GOOGLE_UPDATE_DIR = '#/$BUILD_TYPE/google_update', |
| |
| # Work around a limitation (bug?) in SCons in that, when we build |
| # from a different directory, it forces the build targets defined |
| # the SConscript.googleurl file to be relative to that file (i.e., |
| # here in the build/ directory with us), not relative to the |
| # the SConstruct directory from which SCons was launched. When |
| # we roll forward to a version of SCons that fixes this, we'll |
| # need to revert to the $BUILD_TYPE definition of GOOGLEURL_DIR. |
| #GOOGLEURL_DIR = '#/$BUILD_TYPE/googleurl', |
| GOOGLEURL_DIR = '#/../build/googleurl', |
| |
| NET_DIR = '#/$BUILD_TYPE/net', |
| RLZ_DIR = '#/$BUILD_TYPE/rlz', |
| SANDBOX_DIR = '#/$BUILD_TYPE/sandbox', |
| SKIA_DIR = '#/$BUILD_TYPE/skia', |
| TESTING_DIR = '#/$BUILD_TYPE/testing', |
| THIRD_PARTY_DIR = '#/$BUILD_TYPE/third_party', |
| V8_DIR = '#/$BUILD_TYPE/v8', |
| WEBKIT_DIR = '#/$BUILD_TYPE/webkit', |
| |
| GTEST_DIR = '$TESTING_DIR/gtest', |
| |
| BSDIFF_DIR = '$THIRD_PARTY_DIR/bsdiff', |
| BSPATCH_DIR = '$THIRD_PARTY_DIR/bspatch', |
| BZIP2_DIR = '$THIRD_PARTY_DIR/bzip2', |
| ICU38_DIR = '$THIRD_PARTY_DIR/icu38', |
| LIBJPEG_DIR = '$THIRD_PARTY_DIR/libjpeg', |
| LIBPNG_DIR = '$THIRD_PARTY_DIR/libpng', |
| LIBXML_DIR = '$THIRD_PARTY_DIR/libxml', |
| LIBXSLT_DIR = '$THIRD_PARTY_DIR/libxslt', |
| LZMA_SDK_DIR = '$THIRD_PARTY_DIR/lzma_sdk', |
| MODP_B64_DIR = '$THIRD_PARTY_DIR/modp_b64', |
| NPAPI_DIR = '$THIRD_PARTY_DIR/npapi', |
| ZLIB_DIR = '$THIRD_PARTY_DIR/zlib', |
| |
| THIRD_PARTY_WEBKIT_DIR = '$THIRD_PARTY_DIR/WebKit', |
| |
| PYTHON=sys.executable, |
| |
| LIBPATH = ['$LIBS_DIR'], |
| ) |
| |
| def AddPdbToTarget(args): |
| """Add the windows pdb file to the build target. |
| |
| Arguments: |
| args is a tuple passed to ChromeProgram or ChromeTestProgram |
| Returns: |
| A tuple to pass on to Environment.Program.""" |
| # Only add .pdb to the target if the target was only a string. We can't |
| # blindly add foo.pdb because chrome.exe and chrome.dll use chrome_exe.pdb |
| # and chrome_dll.pdb. |
| if not isinstance(args[0], str): |
| return args |
| |
| mutable_args = list(args) |
| mutable_args[0] = [args[0], args[0] + '.pdb'] |
| return tuple(mutable_args) |
| |
| def ChromeProgram(env, *args, **kw): |
| if env['PLATFORM'] == 'win32': |
| # TODO(tc): We should handle kw['target'] too. |
| args = AddPdbToTarget(args) |
| return env.Program(*args, **kw) |
| env.AddMethod(ChromeProgram, "ChromeProgram") |
| |
| def ChromeTestProgram(env, *args, **kw): |
| if env['PLATFORM'] == 'win32': |
| # TODO(tc): We should handle kw['target'] too. |
| args = AddPdbToTarget(args) |
| return env.Program(*args, **kw) |
| env.AddMethod(ChromeTestProgram, "ChromeTestProgram") |
| |
| def ChromeStaticLibrary(env, *args, **kw): |
| result = env.StaticLibrary(*args, **kw) |
| if env['PLATFORM'] == 'win32': |
| # TODO(sgk): |
| # We'd like to do this with env.Install() like we do on other systems, |
| # but this causes problems on Windows when the Python copy of the file |
| # in one thread prevents a linker spawned by another thread from |
| # opening the copied .lib, despite the fact that the copy has |
| # successfully concluded before the spawn occurs. Work around the |
| # underlying problem (whatever it is) by calling the external Windows |
| # xcopy utility. |
| env.Command('$LIBS_DIR/${RESULT.name}', '$RESULT', |
| "xcopy /q /y $SOURCE ${TARGET.dir}", |
| RESULT=result[0]) |
| else: |
| env.Install('$LIBS_DIR', result) |
| return result |
| env.AddMethod(ChromeStaticLibrary, "ChromeStaticLibrary") |
| |
| def ChromeSharedLibrary(env, *args, **kw): |
| return env.SharedLibrary(*args, **kw) |
| env.AddMethod(ChromeSharedLibrary, "ChromeSharedLibrary") |
| |
| |
| if env['PLATFORM'] == 'win32': |
| |
| processors = int(os.environ.get('NUMBER_OF_PROCESSORS', 1)) |
| SetOption('num_jobs', processors + 1) |
| |
| msvs_env = Environment(tools=['msvc', 'mslink', 'msvs'])['ENV'] |
| |
| # Use the absolute path for MSVC because it might not be on the same drive |
| # as our source checkout. |
| visual_studio_path = (msvs_env['PATH'][0] + |
| ':/Program Files/Microsoft Visual Studio 8') |
| |
| env.Replace( |
| CSCRIPT = 'c:\\Windows\\System32\\cscript', |
| |
| PLATFORMSDK_VISTA_REL = '../third_party/platformsdk_vista_6_0', |
| PLATFORMSDK_VISTA = '#/$PLATFORMSDK_VISTA_REL', |
| VISUAL_STUDIO = visual_studio_path, |
| |
| CYGWIN_DIR = Dir('#../third_party/cygwin'), |
| CYGWIN_BIN_DIR = '$CYGWIN_DIR/bin', |
| |
| PERL = '$CYGWIN_BIN_DIR/perl.exe', |
| PERL_INCLUDE_FLAG = '-I ', |
| PERL_INCLUDE_SUFFIX = '', |
| _PERL_INCLUDE_FLAGS = ('${_concat(PERL_INCLUDE_FLAG, ' |
| 'PERL_INCLUDE_PATH, ' |
| 'PERL_INCLUDE_SUFFIX,' |
| '__env__, RDirs, TARGET, SOURCE)}'), |
| |
| MSVS_ENV = msvs_env, |
| |
| YACC = '$CYGWIN_BIN_DIR/bison.exe', |
| |
| ARFLAGS = [ |
| '/nologo', |
| ], |
| |
| CCFLAGS = [ |
| '/nologo', |
| |
| '/Od', # no optimization |
| |
| '/RTC1', |
| '/MTd', # static link to crt, and debug version |
| '/Gy', |
| '/GR-', |
| |
| '/W3', |
| |
| '/Z7', |
| |
| '/errorReport:prompt', |
| |
| '/wd4503', |
| '/wd4819', |
| ], |
| |
| CPPDEFINES = [ |
| '_CRT_SECURE_NO_DEPRECATE', |
| '_CRT_NONSTDC_NO_WARNINGS', |
| '_CRT_NONSTDC_NO_DEPRECATE', |
| '_SCL_SECURE_NO_DEPRECATE', |
| |
| '_DEBUG', |
| |
| '_CRT_RAND_S', |
| ('_WIN32_WINNT', '0x0600'), |
| ('WINVER', '0x0600'), |
| 'WIN32', |
| '_WINDOWS', |
| ('_HAS_EXCEPTIONS', 0), |
| 'NOMINMAX', |
| '_UNICODE', |
| 'UNICODE', |
| |
| 'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS', |
| 'WIN32_LEAN_AND_MEAN', |
| ], |
| |
| CPPPATH = [ |
| '$PLATFORMSDK_VISTA/files/Include', |
| '$PLATFORMSDK_VISTA/files/VC/INCLUDE', |
| '$VISUAL_STUDIO/VC/atlmfc/include', |
| ], |
| |
| LIBS = [ |
| 'advapi32.lib', |
| 'comdlg32.lib', |
| 'gdi32.lib', |
| 'kernel32.lib', |
| 'msimg32.lib', |
| 'odbc32.lib', |
| 'odbccp32.lib', |
| 'ole32.lib', |
| 'oleaut32.lib', |
| 'psapi.lib', |
| 'shell32.lib', |
| 'user32.lib', |
| 'usp10.lib', |
| 'uuid.lib', |
| 'version.lib', |
| 'wininet.lib', |
| 'winspool.lib', |
| 'ws2_32.lib', |
| |
| 'DelayImp.lib', |
| ], |
| |
| LINKFLAGS = [ |
| '/nologo', |
| '/DEBUG', |
| ], |
| ) |
| |
| env.Append( |
| LIBPATH = [ |
| '$PLATFORMSDK_VISTA/files/Lib', |
| '$PLATFORMSDK_VISTA/files/VC/LIB', |
| '$VISUAL_STUDIO/VC/atlmfc/lib', |
| ], |
| ) |
| |
| # TODO(sgk): remove once we upgrade to SCons 0.98.4 |
| for var in ['INCLUDE', 'LIB', 'PATH']: |
| msvs_env[var] = msvs_env[var].split('|', 1)[0] |
| env['ENV'][var] = env['ENV'][var].split('|', 1)[0] |
| |
| # Force scons to handle long include lines correctly. |
| pchcom_fixed = env['PCHCOM'] |
| pchcom_fixed = pchcom_fixed.replace('${TARGETS[0]}', '$TARGET') |
| pchcom_fixed = pchcom_fixed.replace('${TARGETS[1]}', '$TARGETS1') |
| |
| env.Replace( |
| CCCOM = "${TEMPFILE('%s')}" % env['CCCOM'], |
| CXXCOM = "${TEMPFILE('%s')}" % env['CXXCOM'], |
| SHCCCOM = "${TEMPFILE('%s')}" % env['SHCCCOM'], |
| SHCXXCOM = "${TEMPFILE('%s')}" % env['SHCXXCOM'], |
| PCHCOM = "${TEMPFILE('%s')}" % pchcom_fixed, |
| TARGETS1 = '${TARGETS[1]}', |
| ) |
| |
| env['ENV']['PROGRAMFILES'] = os.environ['PROGRAMFILES'] |
| env['ENV']['SystemDrive'] = os.environ['SystemDrive'] |
| env['ENV']['USERPROFILE'] = os.environ['USERPROFILE'] |
| |
| env.AppendENVPath('PATH', ';C:\\WINDOWS\\system32') |
| |
| elif env['PLATFORM'] == 'posix': |
| |
| # Copy some environment variables from the outer environment if they exist. |
| for envvar in ['CC', 'CXX']: |
| if envvar in os.environ: |
| env[envvar] = os.environ[envvar] |
| # Provide $HOME when compiling so distcc can find its lock file. |
| env['ENV']['HOME'] = os.environ['HOME'] |
| if 'DISTCC_HOSTS' in os.environ: |
| env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS'] |
| |
| # TODO(evanm): this is Linux-specific, not posix. |
| # Parse /proc/cpuinfo for processor count. |
| cpus = len([l for l in open('/proc/cpuinfo') if l.startswith('processor\t')]) |
| SetOption('num_jobs', cpus + 1) |
| |
| # For now, linux only loads the components we know work on Linux, by default. |
| load = [ |
| 'base', |
| 'breakpad', |
| 'googleurl', |
| 'net', |
| 'skia', |
| 'testing', |
| 'third_party', |
| 'webkit', |
| ] |
| |
| # TODO: fix code that triggers these warnings. |
| excluded_warnings = [ |
| '-Wno-unknown-pragmas', # TODO: remove all the Windows-specific #pragmas. |
| '-Wno-unused-function', # TODO: there's just one Skia function. |
| '-Wno-switch', # TODO: this is likely masking real bugs. |
| '-Wno-sign-compare', # TODO: this is likely masking real bugs. |
| '-Wno-missing-braces', # TODO: just a file in net. |
| |
| # Not TODO: This is technically nonstandard, but a lot of the image |
| # decoding code depends on it and osx wants this. |
| '-Wno-multichar', |
| ] |
| env.Replace( |
| CCFLAGS = ['-m32', '-g', '-pthread', '-Wall', '-Werror'] + excluded_warnings, |
| LINKFLAGS = ['-m32', '-pthread'], |
| # We need rt for clock_gettime. |
| LIBS = ['rt'], |
| |
| PERL = '/usr/bin/perl', |
| PERL_INCLUDE_FLAG = '-I ', |
| PERL_INCLUDE_SUFFIX = '', |
| _PERL_INCLUDE_FLAGS = ('${_concat(PERL_INCLUDE_FLAG, ' |
| 'PERL_INCLUDE_PATH, ' |
| 'PERL_INCLUDE_SUFFIX,' |
| '__env__, RDirs, TARGET, SOURCE)}'), |
| ) |
| # Build with support for gcov when COVERAGE=1. |
| if ARGUMENTS.get('COVERAGE') == '1': |
| env.Append(CCFLAGS=['-fprofile-arcs', '-ftest-coverage']) |
| env.Append(LINKFLAGS=['-fprofile-arcs']) |
| |
| # Build with system-provided NSS |
| env.ParseConfig('pkg-config --cflags --libs nss') |
| else: |
| |
| print "Unsupported SCons $PLATFORM value %s" % repr(env['PLATFORM']) |
| Exit(1) |
| |
| |
| if ARGUMENTS.get('VERBOSE') in (None, '0'): |
| env['CCCOMSTR'] = 'Compiling $TARGET ...' |
| env['CXXCOMSTR'] = 'Compiling $TARGET ...' |
| env['ARCOMSTR'] = 'Archiving $TARGET ...' |
| env['LINKCOMSTR'] = 'Linking $TARGET ...' |
| env['BINDINGSCOMSTR'] = 'Building bindings in $TARGET ...' |
| |
| |
| # Place the .sconsign.dblite in the build directory. |
| target_dir = env.Dir('$TARGET_ROOT') |
| if not os.path.exists(target_dir.abspath): |
| Execute(Mkdir(target_dir)) |
| SConsignFile(target_dir.File('.sconsign').abspath) |
| |
| |
| # Add --clobber (for the buildbot). |
| # NOTE: seems to be crucial to do this before any builders are invoked. |
| AddOption('--clobber', action='store_true', dest='clobber', default=False, |
| help='Delete build directory before building.') |
| if GetOption('clobber'): |
| shutil.rmtree(env.Dir('$TARGET_ROOT').abspath, True) |
| |
| # Use timestamps change, followed by MD5 for speed |
| env.Decider('MD5-timestamp') |
| |
| |
| # Overlay things from a layer below. |
| env.Dir('$TARGET_ROOT').addRepository(Dir('..')) |
| |
| |
| included = [c for c in load if not c.startswith('-')] |
| excluded = [c[1:] for c in load if c.startswith('-')] |
| if not included: |
| included = ['all'] |
| |
| components = ['all'] |
| |
| def LoadComponent(c): |
| components.append(c) |
| return (not GetOption('help') and |
| c in included or |
| ('all' in included and not c in excluded)) |
| |
| sconscripts = [] |
| |
| if LoadComponent('base'): |
| sconscripts.append('$BASE_DIR/SConscript') |
| |
| if LoadComponent('breakpad'): |
| sconscripts.append('$BREAKPAD_DIR/SConscript') |
| |
| if LoadComponent('chrome'): |
| sconscripts.append('$CHROME_DIR/SConscript') |
| |
| if LoadComponent('google_update'): |
| sconscripts.append('$GOOGLE_UPDATE_DIR/SConscript') |
| |
| if LoadComponent('googleurl'): |
| env.SConscript('SConscript.googleurl', |
| duplicate=0, |
| variant_dir='$GOOGLEURL_DIR', |
| src_dir='../googleurl', |
| exports=['env']) |
| |
| if LoadComponent('net'): |
| sconscripts.append('$NET_DIR/SConscript') |
| |
| if LoadComponent('rlz'): |
| sconscripts.append('$RLZ_DIR/SConscript') |
| |
| if LoadComponent('sandbox'): |
| sconscripts.append('$SANDBOX_DIR/src/SConscript') |
| |
| if LoadComponent('skia'): |
| sconscripts.append('$SKIA_DIR/SConscript') |
| |
| if LoadComponent('testing'): |
| sconscripts.append('$TESTING_DIR/SConscript.gtest') |
| |
| if LoadComponent('third_party'): |
| sconscripts.extend([ |
| '$BSDIFF_DIR/SConscript', |
| '$BSPATCH_DIR/SConscript', |
| '$BZIP2_DIR/SConscript', |
| '$ICU38_DIR/SConscript', |
| '$LIBJPEG_DIR/SConscript', |
| '$LIBPNG_DIR/SConscript', |
| '$LIBXML_DIR/SConscript', |
| '$LIBXSLT_DIR/SConscript', |
| '$LZMA_SDK_DIR/SConscript', |
| '$MODP_B64_DIR/SConscript', |
| '$ZLIB_DIR/SConscript', |
| ]) |
| |
| if LoadComponent('v8') and env.Dir('#/../v8').exists(): |
| env.SConscript('SConscript.v8', |
| exports=['env']) |
| |
| if LoadComponent('webkit'): |
| sconscripts.append('$WEBKIT_DIR/SConscript') |
| |
| env.SConscript(sconscripts, exports=['env']) |
| |
| |
| help_fmt = """ |
| Usage: hammer [SCONS_OPTIONS] [VARIABLES] [TARGET] ... |
| |
| Supported build variables: |
| |
| BUILD_TYPE=type Build type. Also used as the subdirectory name |
| in which the build occurs. |
| LOAD=[module,...] Comma-separated list of components to load in the |
| dependency graph ('-' prefix excludes): |
| %s |
| PROGRESS=type Display a progress indicator: |
| name: print each evaluated target name |
| spinner: print a spinner every 5 targets |
| VERBOSE=1 Display full command lines |
| """ |
| |
| if GetOption('help'): |
| import textwrap |
| tw = textwrap.TextWrapper( |
| width = 78, |
| initial_indent = ' '*32, |
| subsequent_indent = ' '*32, |
| ) |
| components = tw.fill(', '.join(components)) |
| |
| Help(help_fmt % components) |
| |
| |
| Import('build_component') |
| Default(build_component) |