1 # Copyright (c) 2008 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
17 if env['OS'] in ['win32', 'wince']:
18 env.Append(DATE = 'echo %DATE%.%TIME%')
20 env.Append(DATE = 'date')
22 def GetInputs(var): return utils.GetInputs(var, env)
25 """Execute a shell command and return the output."""
26 cmd[0] = env.Entry(cmd[0]).abspath
28 return subprocess.Popen(
29 cmd, shell=True, stdout=subprocess.PIPE).communicate()[0]
31 if env['OS'] == 'win32':
33 """Generate a GGUID for the given value."""
34 return Shell(['$GGUIDGEN', '$NAMESPACE_GUID', value + '-$VERSION'])
36 GGUIDGEN = '#/$OPEN_DIR/tools/gguidgen.exe',
37 NAMESPACE_GUID = '36F65206-5D4E-4752-9D52-27708E10DA79',
38 # MSI version numbers must have the form <major>.<minor>.<build>. To meet this,
39 # we combine our build and patch version numbers like so:
40 # MSI_VERSION = <major>.<minor>.<BUILD * 100 + PATCH>.
41 # Note: This assumes that the BUILD and PATCH variables adhere to the range
42 # requirements in version.mk. See comments in version.mk for more details.
43 MSI_BUILD = eval(env.subst('$BUILD * 100 + $PATCH')),
44 MSI_VERSION = '${MAJOR}.${MINOR}.${MSI_BUILD}',
47 # Building wxiobjs with candle
49 CANDLEDEFPREFIX = '-d',
51 _CANDLEDEFFLAGS = ('${_defines(CANDLEDEFPREFIX, CANDLEDEFINES, '
52 'CANDLEDEFSUFFIX, __env__)}'),
53 CANDLECOM = 'candle.exe -out $TARGET $SOURCE ${_CANDLEDEFFLAGS}',
56 # Note: Since light.exe is run from $OPEN_DIR, candle.exe must generate
57 # output with paths relative to that dir.
58 SCONS_DIR = '..', # the scons dir relative to OPEN_DIR
59 # You can change the names of ProductId vars, but NEVER change their values!
62 GGUIDGen('OUR_PRODUCT_ID')),
63 ('OurComponentGUID_FFComponentsDirFiles',
64 GGUIDGen('OUR_COMPONENT_GUID_FF_COMPONENTS_DIR_FILES')),
65 ('OurComponentGUID_FFContentDirFiles',
66 GGUIDGen('OUR_COMPONENT_GUID_FF_CONTENT_DIR_FILES')),
67 ('OurComponentGUID_FFDirFiles',
68 GGUIDGen('OUR_COMPONENT_GUID_FF_DIR_FILES')),
69 ('OurComponentGUID_FFLibDirFiles',
70 GGUIDGen('OUR_COMPONENT_GUID_FF_LIB_DIR_FILES')),
71 ('OurComponentGUID_FFRegistry',
72 GGUIDGen('OUR_COMPONENT_GUID_FF_REGISTRY')),
73 ('OurComponentGUID_IEFiles',
74 GGUIDGen('OUR_COMPONENT_GUID_IE_FILES')),
75 ('OurComponentGUID_IERegistry',
76 GGUIDGen('OUR_COMPONENT_GUID_IE_REGISTRY')),
77 ('OurComponentGUID_SharedFiles',
78 GGUIDGen('OUR_COMPONENT_GUID_SHARED_FILES')),
79 ('OurComponentGUID_SharedVersionedFiles',
80 GGUIDGen('OUR_COMPONENT_GUID_SHARED_VERSIONED_FILES')),
81 ('OurComponentGUID_SharedRegistry',
82 GGUIDGen('OUR_COMPONENT_GUID_SHARED_REGISTRY')),
84 GGUIDGen('OUR_2ND_PRODUCT_ID')),
85 ('OurComponentGUID_NpapiFiles',
86 GGUIDGen('OUR_COMPONENT_GUID_NPAPI_FILES')),
87 ('OurComponentGUID_NpapiRegistry',
88 GGUIDGen('OUR_COMPONENT_GUID_NPAPI_REGISTRY')),
89 ('OurMsiVersion', '$MSI_VERSION'),
90 ('OurCommonPath', '$COMMON_OUTDIR'),
91 ('OurIEPath', '$IE_OUTDIR'),
92 ('OurIpcTestPath', '$COMMON_OUTDIR'),
93 ('OurFFPath', '$INSTALLER_OUTDIR/$INSTALLER_BASENAME'),
94 ('OurNpapiPath', '$NPAPI_OUTDIR'),
97 wix_langs = [re.sub('-', '_', lang) for lang in env['I18N_LANGS']]
100 [('OurComponentGUID_FFLang' + lang + 'DirFiles',
101 GGUIDGen('OUR_COMPONENT_GUID_FF_' + lang + '_DIR_FILES'))
102 for lang in wix_langs],
106 """Like the builtin Mkdir, but doesn't fail if the dir exists."""
107 def Func(target, source, env):
108 dir_subst = env.subst(dir, target=target)
109 if not os.path.exists(dir_subst):
110 os.makedirs(dir_subst)
112 return Action(Func, 'SafeMkdir("' + dir + '")')
114 def RecursiveDelete(pattern):
115 """Recursively deletes directories matching a pattern."""
116 def Func(target, source, env):
117 # strip off '.dir' suffix
118 target_dir = env.subst('${TARGET.base}', target=target)
119 for root, dirs, files in os.walk(target_dir):
120 if fnmatch.fnmatch(os.path.normpath(root), pattern):
121 print 'Deleting', root
124 return Action(Func, 'RecursiveDelete("' + pattern + '")')
126 def ToUnixPath(path):
127 """Converts windows-style \ to unix-style /."""
128 return re.sub(r'\\', r'/', path)
130 def DirBuilder(env, dirtarget, dirsrcs):
131 """Builder that makes a directory tree by copying source files to
132 corresponding locations inside 'dirtarget'. 'dirsrcs' specifies the list of
133 mappings from source file/directory to the target location. It's formatted
135 (<target file or dir>, <list of source files>)
137 Note: source files that come from an output directory must be explicitly
138 specified relative to the toplevel dir '#'.
139 Note: as shorthand, if the target ends with a '/', then the sources will
140 be placed into that dir. Otherwise, source is renamed into the target.
144 actions = [Delete('${TARGET.base}')]
145 for target, sources in dirsrcs:
146 target_is_dir = target.endswith('/')
148 actions.append(SafeMkdir('${TARGET.base}/' + target))
150 actions.append(SafeMkdir('${TARGET.base}/' + os.path.dirname(target)))
151 for source in env.Flatten(sources):
152 source = env.subst(source, conv=lambda x:x)
155 # Special-case for Nodes and Node lists: use their absolute paths for
156 # the Copy() action, otherwise it will be relative to our variant dir
157 # (not what Copy expects).
158 if isinstance(source, list): source = source[0]
159 if isinstance(source, SCons.Node.Node): source = source.abspath
161 # HACK: Compensate for the workaround below. We want the .dir file
162 # to be the dependency to the Command() builder, but we want to copy
163 # the actual directory - so strip the extension here.
164 if source.endswith('.dir'):
169 Copy('${TARGET.base}/' + target + os.path.basename(source),
172 actions.append(Copy('${TARGET.base}/' + target, source))
174 # Remove any .svn directories that were copied.
175 actions.append(RecursiveDelete('*/.svn'))
177 # HACK: Workaround for bug in scons where directories aren't checked for
178 # dependency changes. Instead, we make a temp file the target, and ensure
179 # that that file changes everytime we execute these actions.
180 # See http://scons.tigris.org/issues/show_bug.cgi?id=2261
181 actions += ['$DATE > ${TARGET}']
182 return env.Command(env.subst(dirtarget) + '.dir', srcs, actions)
183 env.AddMethod(DirBuilder)
185 def FirefoxInstaller():
187 ('/', ['$FF3_OUTDIR/genfiles/install.rdf',
188 '$FF3_OUTDIR/genfiles/chrome.manifest']),
189 ('lib/', ['$OPEN_DIR/base/firefox/static_files/lib/updater.js']),
190 ('chrome/chromeFiles/content/',
191 GetInputs('$FF3_RESOURCES $COMMON_RESOURCES')),
192 ('chrome/chromeFiles/locale', ['$FF3_OUTDIR/genfiles/i18n']),
194 ['$FF3_MODULE_TYPELIB',
195 '$OPEN_DIR/base/firefox/static_files/components/bootstrap.js']),
196 ('components/${SHLIBPREFIX}gears${SHLIBSUFFIX}', ['$FF2_MODULE']),
197 ('components/${SHLIBPREFIX}gears_ff2${SHLIBSUFFIX}', ['$FF3_MODULE']),
200 if env['USING_CCTESTS']:
202 ('components/', ['$IPC_TEST_EXE']),
204 if env['OS'] != 'win32':
205 # TODO(playmobil): Inspector should be located in extensions dir on win32.
207 ('resources/inspector', [env.Dir('#/$OPEN_DIR/inspector')]),
208 ('resources/inspector/common/', ['$OPEN_DIR/sdk/gears_init.js',
209 '$OPEN_DIR/sdk/samples/sample.js']),
211 if env['MODE'] == 'dbg' and env['OS'] in ['win32', 'wince']:
213 ('components/gears_ff2.pdb', ['$FF2_MODULE_PDB']),
214 ('components/gears.pdb', ['$FF3_MODULE_PDB']),
216 if env['OS'] == 'osx':
218 ('resources/', ['$OSX_LAUNCHURL_EXE']),
221 dir = env.DirBuilder('$INSTALLER_OUTDIR/$INSTALLER_BASENAME', dirsrcs)
223 # Mark files writeable to allow .xpi rebuilds
224 'chmod -R 777 ${SOURCE.base}',
225 '(cd ${SOURCE.base} && zip -r ../${TARGET.file} .)'
228 return env.Command('$FF_XPI', dir, actions)
229 firefox_installer = FirefoxInstaller()
231 def Win32Installer():
232 wxiobj = env.Command(
233 '$COMMON_GENFILES_DIR/win32_msi.wxiobj',
234 '$COMMON_GENFILES_DIR/win32_msi.wxs',
236 # TODO(mpcomplete): remove this if/when the notifier goes away. This
237 # creates fake targets to satisfy the installer build.
238 notifier = env.Command(
240 '$COMMON_OUTDIR/notifier.exe',
241 '$COMMON_OUTDIR/notifier.dll',
242 '$COMMON_OUTDIR/notifier_test.exe'
245 # light.exe must be run from $OPEN_DIR
247 '$WIN32_INSTALLER_MSI',
248 [wxiobj, notifier, firefox_installer, '$IE_MODULE', '$NPAPI_MODULE'],
249 'cd $OPEN_DIR && light.exe -out ${TARGET.abspath} ${SOURCES[0].abspath}')
251 win32_installer = Win32Installer()
253 def WinCEInstaller():
254 env['ToUnixPath'] = ToUnixPath
255 inf_outdir = ToUnixPath(env.subst('$IE_OUTDIR'))
257 '$COMMON_GENFILES_DIR/wince_cab_fixed.inf',
258 '$COMMON_GENFILES_DIR/wince_cab_ie.inf',
259 'sed -e "s#bin-....wince-arm.ie.#' + inf_outdir + '#g" $SOURCE > $TARGET')
261 '$WINCE_INSTALLER_CAB',
262 [inf, '$IE_MODULE', '$IE_WINCE_SETUP_DLL'],
263 ['cabwiz ${ToUnixPath(str(SOURCE))} /compress'
264 ' /err ${SOURCES[0].base}.log',
265 Copy('$TARGET', '${SOURCE.base}.CAB')])
267 wince_installer = WinCEInstaller()
269 def SafariPluginBundle():
270 """This is the actual gears plugin bundle for Safari."""
272 ('Contents/', ['$SF_OUTDIR/genfiles/Info.plist']),
273 ('Contents/Resources/English.lproj/InfoPlist.strings',
274 ['$OPEN_DIR/tools/osx/English.lproj/InfoPlist.strings']),
275 ('Contents/Resources/', env.Glob('#/$OPEN_DIR/ui/safari/*.nib')),
276 ('Contents/Resources/', ['$CRASH_SENDER_EXE']),
277 ('Contents/Resources/', ['$OSX_CRASH_INSPECTOR_EXE']),
278 ('Contents/Resources/', ['$OSX_LAUNCHURL_EXE']),
279 ('Contents/MacOS/', ['$SF_MODULE']),
282 if env['USING_CCTESTS']:
284 ('Contents/Resources/', ['$IPC_TEST_EXE']),
287 return env.DirBuilder('$SF_PLUGIN_BUNDLE', dirsrcs)
288 safari_plugin_bundle = SafariPluginBundle()
290 def SafariPluginProxyBundle():
291 """This is a proxy plugin which simply loads gears into Safari and keeps
292 it in memory. It exists so that gears doesn't unload when Safari wants us
293 to, since that causes crashes."""
295 ('Contents/', ['$SF_OUTDIR/genfiles/Info.plist']),
296 ('Contents/MacOS/${SHLIBPREFIX}gears${SHLIBSUFFIX}', ['$SF_PROXY_DLL']),
297 ('Contents/Resources/', [safari_plugin_bundle]),
298 ('Contents/Resources/', ['$OPEN_DIR/tools/osx/uninstall.command']),
301 return env.DirBuilder('$SF_PLUGIN_PROXY_BUNDLE', dirsrcs)
302 safari_plugin_proxy_bundle = SafariPluginProxyBundle()
304 def SafariInstallerPluginBundle():
306 ('Contents/Info.plist',
307 ['$OPEN_DIR/base/safari/advanced_stats_sheet.plist']),
308 ('Contents/MacOS/InstallerPlugin', ['$SF_INSTALLER_PLUGIN_EXE']),
309 ('Contents/Resources/AdvancedStatsSheet.nib',
310 [env.Dir('#/$OPEN_DIR/base/safari/advanced_stats_sheet.nib')]),
313 return env.DirBuilder('$SF_INSTALLER_PLUGIN_BUNDLE', dirsrcs)
314 safari_installer_plugin_bundle = SafariInstallerPluginBundle()
316 def SafariInputManagerBundle():
317 info = env.Command('$SF_OUTDIR/genfiles/Enabler-Info.plist',
318 '$OPEN_DIR/tools/osx/Enabler-Info.plist',
320 'sed \'s/$${EXECUTABLE_NAME}/GearsEnabler/\' |'
321 'sed \'s/$${PRODUCT_NAME}/GearsEnabler/\' > $TARGET')
323 ('GearsEnabler.bundle/Contents/Info.plist', [info]),
324 ('GearsEnabler.bundle/Contents/MacOS/', ['$SF_INPUTMANAGER_EXE']),
325 ('GearsEnabler.bundle/Contents/Resources/English.lproj/',
326 ['$OPEN_DIR/tools/osx/English.lproj/InfoPlist.strings']),
327 ('Info', ['$OPEN_DIR/tools/osx/Info']),
330 return env.DirBuilder('$SF_INPUTMANAGER_BUNDLE', dirsrcs)
331 safari_input_manager_bundle = SafariInputManagerBundle()
333 def SafariInstallerPackage():
334 pkg = env.Iceberg(env.Dir('${SF_INSTALLER_PKG}'),
336 '$SF_OUTDIR/genfiles/installer.packproj',
337 safari_plugin_proxy_bundle,
338 safari_input_manager_bundle,
341 safari_installer_package = SafariInstallerPackage()
343 def SafariKeystoneInstaller():
344 if not os.path.exists(env.Dir('#/$PRIVATE_DIR').abspath):
345 print 'Skipping Safari Keystone installer. Required sources are not public.'
348 env.Append(CREATE_DISK_IMAGE =
349 "/usr/bin/hdiutil create -ov -imagekey zlib-level=9 -fs HFS+"
350 " -format UDZO -volname '$FRIENDLY_NAME ${VERSION}'"
351 " -srcfolder '${INSTALLER_OUTDIR}/Safari/dmg/' -scrub"
352 " -nocrossdev '${SF_KEYSTONE_INSTALLER_DMG}'"
355 pkg = env.Iceberg(env.Dir('${SF_KEYSTONE_INSTALLER_MPKG}'),
356 ['$SF_OUTDIR/genfiles/keystone_installer.packproj'])
357 env.Depends(pkg, GetInputs('$SF_M4S'))
358 env.Depends(pkg, safari_installer_package)
362 ('/.keystone_install',
363 ['$PRIVATE_DIR/tools/osx/installer/keystone_install']),
365 dmg = env.DirBuilder('$INSTALLER_OUTDIR/Safari/dmg', dirsrcs)
366 env.AddPostAction(dmg, 'chmod +x ${TARGET.base}/.keystone_install')
367 # hdiutil is crashy under leopard, so try twice.
368 env.AddPostAction(dmg, '$CREATE_DISK_IMAGE || $CREATE_DISK_IMAGE')
371 safari_keystone_installer = SafariKeystoneInstaller()
374 if 'FF3' in env['VALID_BROWSERS']:
375 installers += firefox_installer
376 if 'SF' in env['VALID_BROWSERS']:
378 safari_input_manager_bundle,
379 safari_plugin_bundle,
380 safari_plugin_proxy_bundle,
381 safari_installer_plugin_bundle,
382 safari_installer_package,
383 safari_input_manager_bundle,
384 safari_keystone_installer,
386 if env['OS'] == 'win32':
387 installers += win32_installer
388 if env['OS'] == 'wince':
389 installers += wince_installer
391 env.Alias('gears-installers', installers)