# Copyright (c) 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 utils Import('env') env = env.Clone() # TODO: move all these builders out to site_scons or somesuch. # TODO: all the other ports, including third-party libs # - SAFARI, android, symbian # - breakpad[_osx] # - glint # - growl # - spidermonkey # - libspeex # - libtremor # TODO: other targets # - installer (safari, android, ...) # Initialize our BROWSER_* input files. env.InitBrowserInputs() # Building .stab files, using M4FLAGS. env.Replace( STAB = 'python $OPEN_DIR/tools/parse_stab.py', I18N_INPUTS_BASEDIR = '$OPEN_DIR/ui/generated', STABCOM = \ '$STAB $M4FLAGS ${_M4INCFLAGS} $TARGET $SOURCE $I18N_INPUTS_BASEDIR', ) stab_builder = Builder(action = '$STABCOM', src_suffix = '.stab') env.Append(BUILDERS = {'Stab': stab_builder}) # Building .idl files. # This is a total mess. MIDL needs to be run from $OPEN_DIR because it's too # stupid to apply its include paths to a relative path like "ui/ie/bla.idl" # (it only looks in the current dir). So we have to jump through hoops to fix # up our relative include paths and output files. env.Tool('midl') if env['BROWSER'] == 'IE': env.Replace( SCONS_DIR = '..', # the scons dir relative to OPEN_DIR IDLINCPREFIX = '/I$SCONS_DIR/', IDLINCSUFFIX = '', _IDLINCFLAGS = ('${_concat(IDLINCPREFIX, CPPPATH, IDLINCSUFFIX, ' '__env__, RDirs, TARGET, SOURCE)}'), IDLDEFPREFIX = '/D', IDLDEFSUFFIX = '', _IDLDEFFLAGS = ('${_defines(IDLDEFPREFIX, CPPDEFINES, ' 'IDLDEFSUFFIX, __env__)}'), MIDLCOM = ( 'cd $OPEN_DIR && ' '$MIDL ${_IDLDEFFLAGS} ${_IDLINCFLAGS} -env win32 -Oicf ' '/tlb $SCONS_DIR/${TARGET.base}.tlb ' '/h $SCONS_DIR/${TARGET.base}.h ' '/iid $SCONS_DIR/${TARGET.base}_i.c ' '/proxy $SCONS_DIR/${TARGET.base}_p.c ' '/dlldata $SCONS_DIR/${TARGET.base}_data.c ' '$SCONS_DIR/$SOURCE' ), ) elif env['BROWSER'] in ['FF2', 'FF3']: env.Replace( GECKO_SDK = '$GECKO_BASE/$OS', GECKO_BIN = '$GECKO_SDK/gecko_sdk/bin', GECKO_LIB = '$GECKO_SDK/gecko_sdk/lib', MIDLCOM = ( 'xpidl -I $GECKO_SDK/gecko_sdk/idl -I $GECKO_BASE ' '-m header -o ${TARGET.base} $SOURCE && ' 'xpidl -I $GECKO_SDK/gecko_sdk/idl -I $GECKO_BASE ' '-m typelib -o ${TARGET.base} $SOURCE' ), ) if env['BROWSER'] == 'FF2': env['GECKO_BASE'] = '$THIRD_PARTY_DIR/gecko_1.8' else: env['GECKO_BASE'] = '$THIRD_PARTY_DIR/gecko_1.9' env.PrependENVPath('PATH', env.Dir('#/$GECKO_BIN').abspath) def MyIdlEmitter(target, source, env): """Produce the list of outputs generated by our IDL compiler. Outputs differ depending on whether we're using xpidl (Firefox) or midl (IE).""" base = os.path.splitext(str(target[0]))[0] if 'xpidl' in env['MIDLCOM']: # Firefox's IDL compiler only generates .h and .xpt files. target = [base + '.h', base + '.xpt'] else: # MIDL generates the following. Depending on the IDL, a .tlb is # generated, but since we can't know, we'll just ignore that. target = [base + '.h', base + '_i.c', base + '_p.c', base + '_data.c'] return (target, source) # Copy the builder object so we don't overwrite everyone's # emitter with ours. import copy env['BUILDERS']['TypeLibrary'] = copy.copy(env['BUILDERS']['TypeLibrary']) env['BUILDERS']['TypeLibrary'].emitter = MyIdlEmitter # Building .xpt files. if env['BROWSER'] in ['FF2', 'FF3']: env.Replace( XPTLINK = 'xpt_link', XPTLINKCOM = '$XPTLINK $TARGET $SOURCES', ) xpt_builder = Builder(action = '$XPTLINKCOM', src_suffix = '.xpt') env.Append(BUILDERS = {'XptLink': xpt_builder}) # C++ defines env.Prepend( CPPDEFINES = [ 'BROWSER_${BROWSER}=1', ], ) if env['BROWSER'] in ['FF2', 'FF3']: if env['OS'] == 'osx': env.Prepend( CPPDEFINES = [ 'LINUX' ] ) env.Prepend( CPPDEFINES = [ # TODO(cprince): Update source files so we don't need this compatibility define? 'BROWSER_FF=1', 'MOZILLA_STRICT_API', # SpiderMonkey (the Firefox JS engine)'s JS_GET_CLASS macro in jsapi.h needs # this defined to work with the gecko SDK that we've built. # The definition of JS_THREADSAFE must be kept in sync with MOZJS_CPPFLAGS. 'JS_THREADSAFE', ], CPPPATH = [ '$GECKO_BASE', '$GECKO_SDK', '$GECKO_SDK/gecko_sdk/include', ], ) elif env['BROWSER'] == 'NPAPI' and env['OS'] == 'win32': env.Prepend( CPPDEFINES = [ 'BROWSER_CHROME=1', ], ) elif env['BROWSER'] == 'SF': env.Replace( # Enable breakpad for Safari on MacOSX. USING_BREAKPAD_OSX = '1') env.Append( CPPDEFINES = [ # Remove these - During development, it was convenient to have these defined in # the Safari port. Before release we want to clean this up, and replace these # with a single BROWSER_SF symbol. # We also want to consolidate the include paths, so we don't have to add these # paths here. 'BROWSER_NPAPI', 'BROWSER_WEBKIT', 'BROWSER_SAFARI' ], CCFLAGS = [ # These flags are needed so that instead of exporting all symbols defined in # the code, we just export those specifically marked, this reduces the output # size. '-fvisibility=hidden' ], CPPPATH = ['$THIRD_PARTY/spidermonkey/nspr/pr/include'] ) env.Append( LIBS = [ 'googleurl-gears', 'png-gears', 'sqlite-gears', 'zlib-gears', ], ) if env['OS'] == 'osx': env.Append( LIBS = [ 'mozjs-gears', 'curl', 'crypto', 'leopard_support', 'breakpad_osx-gears' ], LIBPATH = [ '$OPEN_DIR/tools/osx' ], ) # Add in libraries for in-development APIs for non-official builds. if not env['OFFICIAL_BUILD']: env.Append(LIBS = [ 'jpeg-gears', 'gd', ]) # Except on these platforms. if env['OS'] == 'wince': env.FilterOut(LIBS = [ 'gd', 'jpeg-gears', ]) if env['OS'] == 'android': env.Append(LIBS = [ 'mozjs-gears', ]) env.FilterOut(LIBS = [ 'googleurl-gears', 'sqlite-gears', 'png-gears', 'zlib-gears', 'jpeg-gears', 'gd', ]) if env['BROWSER'] == 'IE': if env['OS'] == 'win32': env.Append( LIBS = [ 'kernel32.lib', 'user32.lib', 'gdi32.lib', 'uuid.lib', 'sensapi.lib', 'shlwapi.lib', 'shell32.lib', 'advapi32.lib', 'wininet.lib', 'comdlg32.lib', 'user32.lib', ], ) else: # OS=wince env.Append( LIBS = [ 'wininet.lib', 'ceshell.lib', 'coredll.lib', 'corelibc.lib', 'ole32.lib', 'oleaut32.lib', 'uuid.lib', 'commctrl.lib', 'atlosapis.lib', 'piedocvw.lib', 'cellcore.lib', 'htmlview.lib', 'imaging.lib', 'toolhelp.lib', 'aygshell.lib', 'iphlpapi.lib', 'gpsapi.lib', ], ) elif env['BROWSER'] in ['FF2', 'FF3']: env.Append(LIBPATH = '$GECKO_LIB') if env['BROWSER'] == 'FF2': env.Append(LIBS = '$FF2_LIBS') else: env.Append(LIBS = '$FF3_LIBS') if env['OS'] == 'win32': env.Append( LIBS = [ 'xpcom', 'xpcomglue_s', 'nspr4.lib', 'js3250.lib', 'ole32.lib', 'shell32.lib', 'shlwapi.lib', 'advapi32.lib', 'wininet.lib', 'comdlg32.lib', 'user32.lib', ], ) elif env['OS'] == 'linux': env.Append( LIBS = [ 'xpcom', 'xpcomglue_s', ], # Although the 1.9 SDK contains libnspr4, it is better to link against # libxul, which in turn depends on libnspr4. In Ubuntu 8.04, libnspr4 was # not listed in /usr/lib, only libxul was. FF2_LIBS = ['nspr4'], FF3_LIBS = ['xul'], ) elif env['OS'] == 'osx': env.Append( LIBS = [ 'xpcom', 'mozjs', 'nspr4', 'plds4', 'plc4', ], FF2_LIBS = ['xpcom_core'], # TODO(mpcomplete): the Makefiles specify many more libs, but we link fine with # just this. Why? FF3_LIBS = ['xpcomglue_s'], ) elif env['BROWSER'] == 'NPAPI': if env['OS'] == 'win32': env.Append( LIBS = [ 'delayimp.lib', 'comdlg32.lib', ], SHLINKFLAGS = [ '/DELAYLOAD:"comdlg32.dll"', ], ) # Building resources. if env['OS'] in ['win32', 'wince']: env_res = env.Clone() env_res.Replace( CPPDEFINES = [ '_UNICODE', 'UNICODE', '$EXTRA_DEFINES', ], EXTRA_DEFINES = [ 'BROWSER_${BROWSER}=1', ], CPPPATH = [ '$COMMON_GENFILES_DIR/..', '$GENFILES_DIR/..', '$OPEN_DIR', '$VC80_CPPPATH', ], ) if env['MODE'] == 'dbg': env_res.Append(CPPDEFINES = 'DEBUG=1') else: env_res.Append(CPPDEFINES = 'NDEBUG=1') env_res.Append(RCFLAGS = [('/l', '0x409')]) if env['OS'] == 'win32': env_res.Append( CPPPATH = [ '$PRIVATE_THIRD_PARTY_DIR/atlmfc_vc80/files/include', ], ) elif env['OS'] == 'wince': env_res.Append( CPPDEFINES = [ 'OS_WINCE', '_WIN32', '_WIN32_WCE', 'UNDER_CE', ], CPPPATH = [ '$OPEN_DIR/..', '$PRIVATE_THIRD_PARTY_DIR/atlmfc_vc80ce/files/include', ], RCFLAGS = [ '-N', ] ) else: env_res = None if env['OS'] == 'win32': # TODO: move to breakpad env.Append(CPPFLAGS = ['/wd4018']) # TODO(playmobil): Create builder to generate required header files. # browser_specific_objects += \ # env.SharedObject('$OPEN_DIR/base/safari/resource_archive.cc') #----------------------------------------------------------------------------- # Generate the dependency tree. def PatternRule(t, s): return utils.PatternRule(t, s, env) def GetInputs(var): return utils.GetInputs(var, env) outputs = {} # genfiles/%: %.m4 m4s = [env.M4(*PatternRule('$GENFILES_DIR/${SOURCE.filebase}', src)) for src in GetInputs('$BROWSER_M4SRCS')] outputs['M4S'] = m4s # genfiles/%.html: %.html_m4 html_m4s = [env.M4( *PatternRule('$GENFILES_DIR/${SOURCE.filebase}.html', src)) for src in GetInputs('$BROWSER_HTML_M4SRCS')] # genfiles/i18n/%: %.m4 # This magic grabs the last *2* components from the path ("en-US/foo.m4") def PathEnd(path, n): """Returns the last n components of the given path. Example: PathEnd('/foo/bar/baz', 2) == 'bar/baz'""" split_path = os.path.normpath(path).split(os.sep) return os.sep.join(split_path[-n:]) env['PathEnd'] = PathEnd tmp_pattern = '$GENFILES_DIR/i18n/${PathEnd(str(SOURCE.base), 2)}' i18n_m4s = [env.M4(*PatternRule(tmp_pattern, src)) for src in GetInputs('$BROWSER_I18N_M4SRCS')] # genfiles/%.js: %.js.stab stabs = [env.Stab( *PatternRule('$GENFILES_DIR/${SOURCE.filebase}', src)) for src in GetInputs('$BROWSER_STABSRCS')] # genfiles/%.html: %.js for stab in stabs: env.Depends(*PatternRule('${SOURCE.base}.html', stab)) # genfiles/%.tlb: %.idl xptsrcs = [] for src in GetInputs('$BROWSER_IDLSRCS'): idl = env.TypeLibrary( *PatternRule('$GENFILES_DIR/${SOURCE.filebase}.tlb', src)) env.Append(BROWSER_CPPSRCS = [x for x in idl if str(x).endswith('_i.c')]) if env['BROWSER'] in ['FF2', 'FF3']: xptsrcs += [x for x in idl if str(x).endswith('.xpt')] if env['BROWSER'] in ['FF2', 'FF3']: outputs['MODULE_TYPELIB'] = env.XptLink('gears.xpt', xptsrcs) if env_res: # genfiles/%.res: %.rc env.Append(BROWSER_SHLINKSRCS = [ [env_res.RES( *PatternRule('$GENFILES_DIR/${SOURCE.filebase}.res', src)) for src in GetInputs('$BROWSER_RESSRCS')] ]) # TODO: figure out why the .rc scanner doesn't notice these dependencies. if env['OS'] in ['win32', 'wince'] and env['BROWSER'] in ['NPAPI', 'IE']: env.Depends('$GENFILES_DIR/ui_resources.rc', html_m4s) env.Depends('$OPEN_DIR/base/npapi/module.rc', m4s) # Safari resources if env['BROWSER'] == 'SF': env.Replace( WEBARCHIVER = '$OPEN_DIR/tools/osx/webarchiver/webarchiver', GEN_RESOURCE_LIST = 'python $OPEN_DIR/tools/osx/gen_resource_list.py', GEN_RESOURCES = ['$GENFILES_DIR/resource_list.h'], ) def WebArchiver(src): src_basename = os.path.basename(os.path.splitext(src)[0]) return ('$WEBARCHIVER "$GENFILES_DIR/%s.webarchive" "%s" ' ' $COMMON_RESOURCES' % (src_basename, src)) def XXD(src): src_basename = os.path.basename(os.path.splitext(src)[0]) env.Append(GEN_RESOURCES = ['$GENFILES_DIR/%s.h' % src_basename]) return 'xxd -i "%s" > "$GENFILES_DIR/%s.h"' % (src, src_basename) resource_list_h = env.Command( '$GENFILES_DIR/resource_list.h', GetInputs('$COMMON_RESOURCES') + html_m4s, [WebArchiver('$GENFILES_DIR/permissions_dialog.html'), WebArchiver('$GENFILES_DIR/shortcuts_dialog.html'), WebArchiver('$GENFILES_DIR/settings_dialog.html'), XXD('$GENFILES_DIR/permissions_dialog.webarchive'), XXD('$GENFILES_DIR/shortcuts_dialog.webarchive'), XXD('$GENFILES_DIR/settings_dialog.webarchive'), XXD('$OPEN_DIR/ui/common/location_data.png'), XXD('$OPEN_DIR/ui/common/local_data.png'), '$GEN_RESOURCE_LIST $GEN_RESOURCES'], ) resource_obj = env.SharedObject( '$GENFILES_DIR/resources', '$OPEN_DIR/base/safari/resource_archive.cc') env.Depends(resource_obj, resource_list_h) env.Append(BROWSER_LINKSRCS = resource_obj) # HACK: gears, vista_broker, and wince_setup share some inputs, but the # Chrome* helpers muck with the environment, so SCons complains if we try to # compile those inputs differently. So we try to precompile them before # passing them to those methods first. So far, only *_CPPSRCS inputs # are shared. module = env.ChromeSharedLibrary('gears-$OS-$ARCH-$MODE-${BROWSER}', env.SharedObject(GetInputs('$BROWSER_CPPSRCS')) + GetInputs('$BROWSER_LINKSRCS $BROWSER_SHLINKSRCS')) outputs['MODULE'] = env.InstallAs('${SHLIBPREFIX}gears${SHLIBSUFFIX}', module) if env['OS'] in ['win32', 'wince'] and env['MODE'] == 'dbg': outputs['MODULE_PDB'] = env.InstallAs('gears.pdb', 'gears-$OS-$ARCH-$MODE-${BROWSER}.pdb') if env['GEARS_STATIC_LIB']: if env['OS'] == 'win32' and env['BROWSER'] == 'NPAPI': lib = env.ChromeLibrary('gears-static', env.SharedObject(GetInputs('$BROWSER_CPPSRCS')) + GetInputs('$BROWSER_LINKSRCS')) env.Alias('gears', lib) else: env.Alias('gears', outputs['MODULE']) if 'MODULE_PDB' in outputs: env.Alias('gears', outputs['MODULE_PDB']) if env['OS'] == 'wince': env.Append(WINCE_SETUP_LINKSRCS = [ [env_res.RES(*PatternRule('$GENFILES_DIR/${SOURCE.filebase}.res', src)) for src in GetInputs('$WINCE_SETUP_RESSRCS')] ]) outputs['WINCE_SETUP_DLL'] = env.ChromeSharedLibrary('setup', env.SharedObject(GetInputs('$WINCE_SETUP_CPPSRCS')) + GetInputs('$WINCE_SETUP_LINKSRCS')) if env['OS'] == 'win32' and env['BROWSER'] == 'IE': # Note: We use IE_OUTDIR so that relative path from gears.dll is same in # development environment as deployment environment. # Note: vista_broker.exe needs to stay in sync with name used in # desktop_win32.cc. # TODO(aa): This can move to common_outdir like crash_sender.exe env.Append(VISTA_BROKER_LINKSRCS = [ [env_res.RES('$GENFILES_DIR/vista_broker_${SOURCE.filebase}.res', env_res.File(src), EXTRA_DEFINES = 'VISTA_BROKER=1') for src in GetInputs('$VISTA_BROKER_RESSRCS')] ]) outputs['VISTA_BROKER_EXE'] = env.ChromeProgram('vista_broker', env.SharedObject(GetInputs('$VISTA_BROKER_CPPSRCS')) + GetInputs('$VISTA_BROKER_LINKSRCS')) env.Alias('gears', outputs['VISTA_BROKER_EXE']) if env['BROWSER'] == 'SF': outputs['PROXY_DLL'] = env.ChromeSharedLibrary('gears_proxy', GetInputs('$SF_PROXY_DLL_CPPSRCS')) outputs['INPUTMANAGER_EXE'] = env.ChromeProgram('GearsEnabler', GetInputs('$SF_INPUTMANAGER_CPPSRCS'), FRAMEWORKS = env['FRAMEWORKS'] + Split('Foundation AppKit')) # See main SConscript for how 'outputs' is used. Return('outputs')