# Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. 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')) default_warnings = ['no-missing-sconscript', 'no-no-parallel-support'] default_warnings = ['no-no-parallel-support'] SetOption('warn', default_warnings + GetOption('warn')) load = ARGUMENTS.get('LOAD') if load: load = load.split(',') else: load = [] root_env = Environment( tools = ['component_setup'], CHROME_SRC_DIR = '$MAIN_DIR/..', DESTINATION_ROOT = '$MAIN_DIR/Hammer', TARGET_ROOT = '$DESTINATION_ROOT', # Where ComponentTestProgram() will build test executables. TESTS_DIR = '$TARGET_ROOT', # Where ComponentProgram() will build program executables. STAGING_DIR = '$TARGET_ROOT', # Where ComponentLibrary() will build libraries. LIBS_DIR = '$COMPONENT_LIBRARY_DIR', # TODO(hammer): when Hammer supports this... # Have Hammer prefix all Library aliases with lib_ (to avoid # collisions with the component names themselves). #COMPONENT_LIBRARY_ALIAS = 'lib_$LIBNAME', # Disable running of tests thru scons for now. COMPONENT_TEST_CMDLINE = '', BASE_DIR = '$OBJ_ROOT/base', BREAKPAD_DIR = '$OBJ_ROOT/breakpad', CHROME_DIR = '$OBJ_ROOT/chrome', GEARS_DIR = '$OBJ_ROOT/gears', GOOGLE_UPDATE_DIR = '$OBJ_ROOT/google_update', GOOGLEURL_DIR = '$OBJ_ROOT/googleurl', NET_DIR = '$OBJ_ROOT/net', RLZ_DIR = '$OBJ_ROOT/rlz', SANDBOX_DIR = '$OBJ_ROOT/sandbox', SDCH_DIR = '$OBJ_ROOT/sdch', SKIA_DIR = '$OBJ_ROOT/skia', TESTING_DIR = '$OBJ_ROOT/testing', THIRD_PARTY_DIR = '$OBJ_ROOT/third_party', V8_DIR = '$OBJ_ROOT/v8', WEBKIT_DIR = '$OBJ_ROOT/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', LIBEVENT_DIR = '$THIRD_PARTY_DIR/libevent', 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, PERL = '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)}'), ) root_env.Append(LIBPATH = ['$V8_DIR']) # Declare a bit to gate solution generation. # The actual generation must be at the end. DeclareBit('solution', 'Generate a solution file') root_env.SetBitFromOption('solution', False) def ChromeProgram(env, *args, **kw): return env.ComponentProgram(*args, **kw) root_env.AddMethod(ChromeProgram) def ChromeTestProgram(env, *args, **kw): return env.ComponentTestProgram(*args, **kw) root_env.AddMethod(ChromeTestProgram) def ChromeStaticLibrary(env, *args, **kw): kw['COMPONENT_STATIC'] = True return env.ComponentLibrary(*args, **kw) root_env.AddMethod(ChromeStaticLibrary) def ChromeSharedLibrary(env, *args, **kw): kw['COMPONENT_STATIC'] = False return [env.ComponentLibrary(*args, **kw)[0]] root_env.AddMethod(ChromeSharedLibrary, "ChromeSharedLibrary") def ChromeObject(env, *args, **kw): return env.ComponentObject(*args, **kw) root_env.AddMethod(ChromeObject) # TODO(bradnelson): pull this functionality into hammer. # Auto select the number of processors if root_env['PLATFORM'] in ['win32', 'cygwin']: cpus = int(os.environ.get('NUMBER_OF_PROCESSORS', 1)) elif root_env['PLATFORM'] in ['linux', 'linux2', 'posix']: # 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) if ARGUMENTS.get('VERBOSE') in (None, '0'): root_env['CCCOMSTR'] = 'Compiling $TARGET ...' root_env['CXXCOMSTR'] = 'Compiling $TARGET ...' root_env['SHCCCOMSTR'] = 'Compiling $TARGET ...' root_env['SHCXXCOMSTR'] = 'Compiling $TARGET ...' root_env['ARCOMSTR'] = 'Archiving $TARGET ...' root_env['LINKCOMSTR'] = 'Linking $TARGET ...' root_env['BINDINGSCOMSTR'] = 'Building bindings in $TARGET ...' # Use timestamps change, followed by MD5 for speed root_env.Decider('MD5-timestamp') # The list of all leaf (fully described) environments. environment_list = [] # -------------------------------------------------------------------------- # Decide which things to load. # Don't put anything platform depended here, this is just to gate things # in or out for speed. 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/base.scons') if LoadComponent('breakpad'): sconscripts.append('$BREAKPAD_DIR/SConscript') if LoadComponent('chrome'): sconscripts.append('$CHROME_DIR/chrome.scons') if LoadComponent('gears'): sconscripts.append('$GEARS_DIR/SConscript') if LoadComponent('google_update'): sconscripts.append('$GOOGLE_UPDATE_DIR/SConscript') if LoadComponent('googleurl'): # googleurl comes from a different repository so we provide the SConscript # file. sconscripts.append('$GOOGLEURL_DIR/googleurl.scons') if LoadComponent('net'): sconscripts.append('$NET_DIR/net.scons') if LoadComponent('rlz'): sconscripts.append('$RLZ_DIR/SConscript') # TODO(bradnelson): fix solution generation for sandbox. # The solution generator blows up on some of the tests in sandbox. # For now, disable sandbox for solution generation. if LoadComponent('sandbox') and not root_env.Bit('solution'): sconscripts.append('$SANDBOX_DIR/sandbox.scons') if LoadComponent('sdch'): sconscripts.append('$SDCH_DIR/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', '$BZIP2_DIR/bzip2.scons', '$ICU38_DIR/icu38.scons', '$LIBPNG_DIR/libpng.scons', '$LZMA_SDK_DIR/SConscript', '$MODP_B64_DIR/modp_b64.scons', '$ZLIB_DIR/zlib.scons', '$LIBJPEG_DIR/SConscript', '$LIBXML_DIR/SConscript', '$LIBXSLT_DIR/SConscript', '$BSPATCH_DIR/SConscript', ]) if LoadComponent('v8') and root_env.Dir('$CHROME_SRC_DIR/v8').exists(): sconscripts.append('$OBJ_ROOT/build/SConscript.v8') if LoadComponent('webkit'): sconscripts.append('$WEBKIT_DIR/SConscript') # Add the final list into the root environment to be build in BuildComponents. root_env.Append(BUILD_SCONSCRIPTS = sconscripts) # -------------------------------------------------------------------------- # Windows specific windows_env = root_env.Clone() environment_list.append(windows_env) windows_env.Tool('target_platform_windows') windows_env.Tool('target_debug') windows_env.Tool('component_targets_msvs') # Per target project support. windows_env.Tool('midl') windows_env.Replace( BUILD_TYPE = 'debug-windows', BUILD_TYPE_DESCRIPTION = 'Windows debug build', ) windows_env.Append(BUILD_GROUPS = ['default']) # TODO(bradnelson): this is needed for now because target_platform_windows # has OS_WINDOWS defined in a weird way. windows_env.FilterOut(CPPDEFINES = ['OS_WINDOWS=OS_WINDOWS']) windows_env['PDB'] = '${TARGET.base}.pdb' # TODO(bradnelson): this should not need to be gated on host platform. if root_env['PLATFORM'] in ['win32', 'cygwin']: msvs_env = Environment(tools=['msvc', 'mslink', 'msvs'])['ENV'] msvs_drive = msvs_env['PATH'][0] else: msvs_env = {'PATH': '', 'INCLUDE': '', 'LIB': ''} msvs_drive = 'C' # Use the absolute path for MSVC because it might not be on the same drive # as our source checkout. visual_studio_path = msvs_drive + ':/Program Files/Microsoft Visual Studio 8' windows_env.Replace( CSCRIPT = 'c:\\Windows\\System32\\cscript', PLATFORMSDK_VISTA_REL = '../third_party/platformsdk_vista_6_0', PLATFORMSDK_VISTA = '$CHROME_SRC_DIR/third_party/platformsdk_vista_6_0', VISUAL_STUDIO = visual_studio_path, CYGWIN_DIR = windows_env.Dir('$CHROME_SRC_DIR/third_party/cygwin'), CYGWIN_BIN_DIR = '$CYGWIN_DIR/bin', PERL = '$CYGWIN_BIN_DIR/perl.exe', MSVS_ENV = msvs_env, YACC = '$CYGWIN_BIN_DIR/bison.exe', ) windows_env.Append( 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', ], ICU_LIBS = ['icu'], ) windows_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] windows_env['ENV'][var] = windows_env['ENV'][var].split('|', 1)[0] # Force scons to handle long include lines correctly. pchcom_fixed = windows_env['PCHCOM'] pchcom_fixed = pchcom_fixed.replace('${TARGETS[0]}', '$TARGET') pchcom_fixed = pchcom_fixed.replace('${TARGETS[1]}', '$TARGETS1') windows_env.Replace( CCCOM = "${TEMPFILE('%s')}" % windows_env['CCCOM'], CXXCOM = "${TEMPFILE('%s')}" % windows_env['CXXCOM'], SHCCCOM = "${TEMPFILE('%s')}" % windows_env['SHCCCOM'], SHCXXCOM = "${TEMPFILE('%s')}" % windows_env['SHCXXCOM'], PCHCOM = "${TEMPFILE('%s')}" % pchcom_fixed, TARGETS1 = '${TARGETS[1]}', ) windows_env['ENV']['PROGRAMFILES'] = os.environ.get('PROGRAMFILES', '') windows_env['ENV']['SystemDrive'] = os.environ.get('SystemDrive', '') windows_env['ENV']['USERPROFILE'] = os.environ.get('USERPROFILE', '') windows_env.AppendENVPath('PATH', ';C:\\WINDOWS\\system32') # -------------------------------------------------------------------------- # Linux specific linux_env = root_env.Clone() environment_list.append(linux_env) linux_env.Tool('target_platform_linux') linux_env.Tool('target_debug') linux_env.Tool('yacc') linux_env.Replace( BUILD_TYPE = 'debug-linux', BUILD_TYPE_DESCRIPTION = 'Linux debug build', ) linux_env.Append(BUILD_GROUPS = ['default']) # TODO(bradnelson): this is needed for now because target_platform_linux has # OS_LINUX defined in a weird way. linux_env.FilterOut(CPPDEFINES = ['OS_LINUX=OS_LINUX']) # Copy some environment variables from the outer environment to the # SCons.Environment if they exist. for envvar in ('CC', 'CXX'): if envvar in os.environ: linux_env[envvar] = os.environ[envvar] # Copy these environment variables from the outer environment to the # environment that the build commands run in. # $HOME is needed by distcc so it can find its lock file. for envvar in ('HOME', 'DISTCC_HOSTS', 'CCACHE_DIR'): if envvar in os.environ: linux_env['ENV'][envvar] = os.environ[envvar] excluded_warnings = [ # TODO: Clean up uses of ext/hash_map and remove this. # (see unordered_map and base/hash_tables.h) '-Wno-deprecated', # Needed for using ext/hash_map on GCC 4.3 '-Wno-unknown-pragmas', # In wtf's ref counting system ] linux_env.Append( BUILD_SCONSCRIPTS = [ '$LIBEVENT_DIR/libevent.scons', ], CCFLAGS = ['-m32', '-g', '-pthread'], CXXFLAGS = ['-Wall', '-Werror'] + excluded_warnings, LINKFLAGS = ['-m32', '-pthread'], ) linux_env.Replace( # We have several cases where archives depend on each other in a cyclic # fashion. (V8Bindings, libport and WebCore being the most significant # example.) Since the GNU linker does only a single pass over the archives # we need some extra trickery to deal with these unavoidable cycles. That # trickery is --start-group and --end-group (aka -( and -) ). That causes ld # to loop over the group until no more undefined symbols are found. In an # ideal world we would only make groups from those libraries which we knew # to be in cycles. However, that's tough with SCons, so we bodge it by # making all the archives a group by redefining the linking command here. SHLINKCOM = ('$SHLINK -shared -o $TARGET $SHLINKFLAGS $SOURCES ' '$_LIBDIRFLAGS ' '-Wl,--start-group $_LIBFLAGS -Wl,--end-group'), LINKCOM = ('$LINK -o $TARGET $LINKFLAGS $SOURCES ' '$_LIBDIRFLAGS ' '-Wl,--start-group $_LIBFLAGS -Wl,--end-group'), ) linux_env.Replace( 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)}'), ) linux_env.FilterOut( BUILD_SCONSCRIPTS = [ '$BSPATCH_DIR/SConscript', '$BSDIFF_DIR/SConscript', '$GEARS_DIR/SConscript', '$GOOGLE_UPDATE_DIR/SConscript', '$RLZ_DIR/SConscript', '$SANDBOX_DIR/sandbox.scons', ], ) linux_env.Append( # We need rt for clock_gettime. LIBS = ['rt'], ICU_LIBS = ['icu'], ) # Build with support for gcov when COVERAGE=1. if ARGUMENTS.get('COVERAGE') == '1': linux_env.Append(CCFLAGS=['-fprofile-arcs', '-ftest-coverage']) linux_env.Append(LINKFLAGS=['-fprofile-arcs']) # Build with system-provided NSS and GTK. if root_env['PLATFORM'] in ['linux', 'linux2', 'posix']: try: linux_env.ParseConfig('pkg-config --cflags --libs nss') linux_env.ParseConfig('pkg-config --cflags --libs gtk+-2.0') linux_env.ParseConfig('pkg-config --cflags --libs pangoft2') except OSError, e: print ('\n' 'Failed to find a package dependency. Please install all the\n' 'packages listed at\n' 'http://code.google.com/p/chromium/wiki/LinuxBuildInstructions' '#Software_Requirements') sys.exit(1) # -------------------------------------------------------------------------- # Mac specific mac_env = root_env.Clone() environment_list.append(mac_env) mac_env.Tool('target_platform_mac') mac_env.Tool('target_debug') mac_env.Replace( BUILD_TYPE = 'debug-mac', BUILD_TYPE_DESCRIPTION = 'Mac debug build', ) mac_env.Append(BUILD_GROUPS = ['default']) mac_env.Replace( # Reproduce XCode's behavior of using gcc even to link C++, # and distinguishing it the -x c++ option. CC = 'gcc-4.2', CXX = 'g++-4.2', LINK = '$CXX', ) mac_env.FilterOut( BUILD_SCONSCRIPTS = [ '$BSPATCH_DIR/SConscript', '$BSDIFF_DIR/SConscript', '$LIBJPEG_DIR/SConscript', '$LIBXML_DIR/SConscript', '$LIBXSLT_DIR/SConscript', '$BREAKPAD_DIR/SConscript', '$CHROME_DIR/SConscript', '$GEARS_DIR/SConscript', '$GOOGLE_UPDATE_DIR/SConscript', '$RLZ_DIR/SConscript', '$SANDBOX_DIR/sandbox.scons', 'build/SConscript.v8', '$WEBKIT_DIR/SConscript', ], ) mac_env.Append( BUILD_SCONSCRIPTS = [ '$LIBEVENT_DIR/libevent.scons', ], CFLAGS = [ '-std=c99', ], CXXFLAGS = [ '-fvisibility-inlines-hidden', '${str(SOURCE).endswith(".mm") and "-fobjc-gc" or ""}', ], CCFLAGS = [ '-fmessage-length=0', '-pipe', '-O0', '-mdynamic-no-pic', '-Werror', '-Wnewline-eof', '-fvisibility=hidden', '-gdwarf-2', '-Wall', '-Wendif-labels', '-fstack-protector', '-fstack-protector-all', ], CPPDEFINES = [ 'DEBUG', ], FRAMEWORKPATH = [ mac_env.Dir('${TARGET_ROOT}'), '/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks', ], FRAMEWORKS = [ 'AppKit', 'ApplicationServices', 'Foundation', ], ICU_LIBS = ['icui18n', 'icuuc', 'icudata'], ) # 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(root_env.Dir('$DESTINATION_ROOT').abspath, True) # sconsign file gets put here at the moment. shutil.rmtree(root_env.Dir('$MAIN_DIR/scons-out').abspath, True) # ------------------------------------------------------------------------- # Overlay things from a layer below. for env in environment_list: env.Dir('$OBJ_ROOT').addRepository(env.Dir('$CHROME_SRC_DIR')) env.Dir('$OBJ_ROOT/googleurl').addRepository(env.Dir('$CHROME_SRC_DIR/build')) # We pre-resolve some common targets. We end up spending lots of time # resolving these over and over again. env.Replace( CHROME_SRC_DIR = str(env.Dir('$CHROME_SRC_DIR')), DESTINATION_ROOT = str(env.Dir('$DESTINATION_ROOT')), TARGET_ROOT = str(env.Dir('$TARGET_ROOT')), OBJ_ROOT = str(env.Dir('$OBJ_ROOT')), WEBKIT_DIR = str(env.Dir('$WEBKIT_DIR')), ) help_fmt = """ Usage: hammer [SCONS_OPTIONS] [VARIABLES] [TARGET] ... Supported build variables: 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(None) # Reset default target to empty. Default(Alias(build_component)) # Set default target based on where built. # ------------------------------------------------------------------------- # Invoke all the SConscripts in each of the environments that make sense on # this host-platform. BuildComponents(environment_list) # ------------------------------------------------------------------------- # This must occur after BuildComponents so that the dependency graph # will be populated. if root_env.Bit('solution'): solution_env = root_env.Clone(tools = ['visual_studio_solution']) src_solution = solution_env.Solution( '$MAIN_DIR/chrome_scons_src', [windows_env], exclude_pattern = '.*(Program Files|platformsdk_vista_6_0|cygwin).*', ) solution = windows_env.ComponentVSSolution('chrome_scons', [ 'all_libraries', 'all_programs', 'all_test_programs', ], projects = [windows_env.File('$MAIN_DIR/chrome_scons_src.vcproj')], COMPONENT_VS_SOLUTION_DIR='$MAIN_DIR', COMPONENT_VS_PROJECT_DIR='$MAIN_DIR/projects', COMPONENT_VS_PROJECT_SCRIPT_PATH=( 'cd $$(ProjectDir)/$VS_PROJECT_TO_MAIN_DIR && hammer.bat'), ) Default(None) # Delete all other default targets. Default([src_solution, solution]) # Build just the solution. # -------------------------------------------------------------------------