2 # Copyright 2008, Google Inc.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
15 # * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 sys
.path
.append("./common")
41 Dir('gtest').addRepository(Dir('../third_party/gtest/files'))
46 # ----------------------------------------------------------
47 # Base environment for both nacl and non-nacl variants.
48 pre_base_env
= Environment(
49 tools
= ['component_setup'],
50 # Makes SOURCE_ROOT independent of site_init.
51 SOURCE_ROOT
= Dir('#/../..').abspath
,
52 # Publish dlls as final products (to staging).
53 COMPONENT_LIBRARY_PUBLISH
= True,
55 pre_base_env
.Append(BUILD_GROUPS
=['most'])
58 # ----------------------------------------------------------
59 # Generic Test Wrapper
60 # all test suites know so far
61 TEST_SUITES
= {'all_tests': None}
63 def AddNodeToTestSuite(env
, node
, suite_name
, node_name
=None):
65 env
.Alias('all_tests', node
)
67 if s
not in TEST_SUITES
:
71 env
.ComponentTestOutput(node_name
, node
)
73 pre_base_env
.AddMethod(AddNodeToTestSuite
)
75 # ----------------------------------------------------------
76 # Small tests are usually unit tests
77 def AddNodeToSmallTestsSuite(env
, node
, node_name
=None):
78 env
.AddNodeToTestSuite(node
, ['small_tests'], node_name
)
80 pre_base_env
.AddMethod(AddNodeToSmallTestsSuite
)
82 # ----------------------------------------------------------
83 # Medium tests are usually larger than unit tests, but don't take as much time
85 def AddNodeToMediumTestsSuite(env
, node
, node_name
=None):
86 env
.AddNodeToTestSuite(node
, ['medium_tests'], node_name
)
88 pre_base_env
.AddMethod(AddNodeToMediumTestsSuite
)
90 # ----------------------------------------------------------
91 # Large tests are usually long tests
93 def AddNodeToLargeTestsSuite(env
, node
, node_name
=None):
94 env
.AddNodeToTestSuite(node
, ['large_tests'], node_name
)
96 pre_base_env
.AddMethod(AddNodeToLargeTestsSuite
)
98 # ----------------------------------------------------------
99 # Smoke tests run before any check-in
100 def AddNodeToSmokeTestSuite(env
, node
, node_name
=None):
101 env
.AddNodeToTestSuite(node
, ['smoke_tests'], node_name
)
103 pre_base_env
.AddMethod(AddNodeToSmokeTestSuite
)
105 # ----------------------------------------------------------
107 Alias('unit_tests', 'small_tests')
109 # ----------------------------------------------------------
115 pre_base_env
.AddMethod(Banner
)
118 def FindLikelySelLdr(directory
):
120 if (nacl_util
.GetSelLdr('opt')):
121 candidates
.append(nacl_util
.GetSelLdr('opt'))
122 if (nacl_util
.GetSelLdr('dbg')):
123 candidates
.append(nacl_util
.GetSelLdr('dbg'))
126 mtime
= os
.stat(c
)[stat
.ST_MTIME
]
127 if mtime
> latest
[1]:
132 def CommandSelLdrTestNacl(env
, name
, command
,
137 # TODO: we do not model a proper dependency to
140 sel_ldr
= FindLikelySelLdr(env
.subst('$DESTINATION_ROOT'))
141 # Bail out if sel_ldr can't be found.
143 Banner('could not find a sel_ldr binary, try running "scons sel_ldr"')
146 sel_ldr
= '$STAGING_DIR/${PROGPREFIX}sel_ldr${PROGSUFFIX}'
148 command
= [sel_ldr
, '-d', '-f'] + command
150 # NOTE: log handling is a little magical
151 # We do not pass these via flags because those are not usable for sel_ldr
152 # when testing via plugin, esp windows.
153 if 'log_golden' in extra
:
154 logout
= '${TARGET}.log'
155 extra
['logout'] = logout
156 extra
['osenv'] = 'NACLLOG=%s,NACLVERBOSITY=%d' % (logout
, log_verbosity
)
158 return CommandTestAgainstGoldenOuput(env
, name
, command
, **extra
)
160 pre_base_env
.AddMethod(CommandSelLdrTestNacl
)
162 # ----------------------------------------------------------
163 TEST_EXTRA_ARGS
= ['stdin', 'logout',
164 'stdout_golden', 'stderr_golden', 'log_golden',
165 'stdout_filter', 'stderr_filter', 'log_filter',
166 'osenv', 'exit_status']
168 TEST_SCRIPT
= '${SCONSTRUCT_DIR}/tools/command_tester.py'
170 def CommandTestAgainstGoldenOuput(env
, name
, command
, **extra
):
171 script_flags
= ['--name', name
]
174 # extract deps from command and rewrite
175 for n
, c
in enumerate(command
):
178 command
[n
] = '${SOURCES[%d].abspath}' % (len(deps
) - 1)
180 # extract deps from flags and rewrite
182 assert e
in TEST_EXTRA_ARGS
183 if type(extra
[e
]) != str:
184 deps
.append(extra
[e
])
185 extra
[e
] = '${SOURCES[%d].abspath}' % (len(deps
) - 1)
186 script_flags
.append('--' + e
)
187 script_flags
.append(extra
[e
])
189 # NOTE: "SOURCES[X]" references the scons object in deps[x]
190 command
= ['${PYTHON}',
191 '${SOURCES[0].abspath}',
192 ' '.join(script_flags
),
197 # TODO: consider redirecting output into tests/results
198 return env
.Command(name
, deps
, " ".join(command
))
200 pre_base_env
.AddMethod(CommandTestAgainstGoldenOuput
)
202 # ----------------------------------------------------------
203 if ARGUMENTS
.get('pp', 0):
204 def CommandPrettyPrinter(cmd
, targets
, source
, env
):
205 prefix
= env
.subst('$SOURCE_ROOT') + '/googleclient/'
207 cmd_tokens
= cmd
.split()
208 if "python" in cmd_tokens
[0]:
209 cmd_name
= cmd_tokens
[1]
211 cmd_name
= cmd_tokens
[0].split('(')[0]
212 if cmd_name
.startswith(prefix
):
213 cmd_name
= cmd_name
[len(prefix
):]
214 env_name
= env
.subst('${BUILD_TYPE}${BUILD_SUBTYPE}')
215 print '[%s] [%s] %s' % (cmd_name
, env_name
, target
.get_path())
216 pre_base_env
.Append(PRINT_CMD_LINE_FUNC
= CommandPrettyPrinter
)
218 # ----------------------------------------------------------
219 base_env
= pre_base_env
.Clone()
222 BUILD_SCONSCRIPTS
= [
223 # NOTE: this dir also has a nacl.scons
224 'tests/npapi_bridge/build.scons',
226 'platform_qual_test/build.scons',
227 'sandbox/build.scons',
228 'service_runtime/build.scons',
229 'service_runtime/nrd_xfer_lib/build.scons',
230 'tools/libsrpc/build.scons',
231 'tools/npapi_runtime/build.scons',
232 'intermodule_comm/build.scons',
233 'npapi_plugin/build.scons',
234 'npapi_plugin/install.scons',
236 'nonnacl_util/build.scons',
237 'tests/python_version/build.scons',
238 # 'nacl_ie_plugin/build.scons',
241 ['NACL_BLOCK_SHIFT', '5'],
242 ['NACL_BLOCK_SIZE', '32'],
244 CPPPATH
= ['$SOURCE_ROOT/googleclient'],
245 GEN2_FLAGS
= '-c -f "Video|Audio|Multimedia"',
246 # NOTE: the EXTRA_* mechanism does not fully work yet
252 CFLAGS
= ['${EXTRA_CFLAGS}'],
253 CCFLAGS
= ['${EXTRA_CCFLAGS}'],
254 CXXFLAGS
= ['${EXTRA_CXXFLAGS}'],
255 LIBS
= ['${EXTRA_LIBS}'],
258 SDL_HERMETIC_LINUX_DIR
='$MAIN_DIR/../third_party/sdl/linux/v1_2_13',
259 SDL_HERMETIC_MAC_DIR
='$MAIN_DIR/../third_party/sdl/osx/v1_2_13',
260 SDL_HERMETIC_WINDOWS_DIR
='$MAIN_DIR/../third_party/sdl/win/v1_2_13',
265 # Optionally ignore the build process.
266 DeclareBit('prebuilt', 'Disable all build steps, only support install steps')
267 base_env
.SetBitFromOption('prebuilt', False)
268 if base_env
.Bit('prebuilt'):
269 base_env
.Replace(BUILD_SCONSCRIPTS
= ['npapi_plugin/install.scons'])
271 # Add the sdk root path (without setting up the tools).
272 base_env
['NACL_SDK_ROOT_ONLY'] = True
273 base_env
.Tool('naclsdk')
277 ======================================================================
279 ======================================================================
286 * + nacl: scons -c MODE=most
287 * + doc and more: scons -c MODE=all
288 * just the doc: scons MODE=doc
289 * build mandel: scons MODE=most mandel.nexe
290 * some unittests: scons small_tests
291 * a smoke test: scons -k pp=1 smoke_tests
292 * 2nd smoke test: scons -k pp=1 MODE=nacl smoke_tests
293 * firefox plugin: scons MODE=opt-linux npGoogleNaClPlugin
294 * sel_ldr: scons MODE=opt-linux sel_ldr
295 * firefox install: scons firefox_install
296 * firefox install pre-built copy: scons firefox_install --prebuilt
300 pp=1 use command line pretty printing (more concise output)
301 sdl=<mode> where <mode>:
302 'none': don't use SDL (default)
303 'local': use locally installed SDL
304 'hermetic': use the hermetic SDL copy
305 naclsdk_mode=<mode> where <mode>:
306 'local': use locally installed sdk kit
307 'download': use the download copy (default)
308 'custom:<path>': use kit at <path>
310 --prebuilt Do not build things, just do install steps
312 Automagically generated help:
313 -----------------------------
316 # ---------------------------------------------------------
317 def GenerateOptimizationLevels(env
):
318 # Generate debug variant.
319 debug_env
= env
.Clone(tools
= ['target_debug'])
320 debug_env
['OPTIMIZATION_LEVEL'] = 'dbg'
321 debug_env
['BUILD_TYPE'] = debug_env
.subst('$BUILD_TYPE')
322 debug_env
['BUILD_DESCRIPTION'] = debug_env
.subst('$BUILD_DESCRIPTION')
323 # Add debug to the default group.
324 debug_env
.Append(BUILD_GROUPS
= ['default'])
325 # Add to the list of fully described environments.
326 environment_list
.append(debug_env
)
328 # Generate opt variant.
329 opt_env
= env
.Clone(tools
= ['target_optimized'])
330 opt_env
['OPTIMIZATION_LEVEL'] = 'opt'
331 opt_env
['BUILD_TYPE'] = opt_env
.subst('$BUILD_TYPE')
332 opt_env
['BUILD_DESCRIPTION'] = opt_env
.subst('$BUILD_DESCRIPTION')
333 # Add to the list of fully described environments.
334 environment_list
.append(opt_env
)
336 return (debug_env
, opt_env
)
339 # ----------------------------------------------------------
340 windows_env
= base_env
.Clone(
341 BUILD_TYPE
= '${OPTIMIZATION_LEVEL}-win',
342 BUILD_TYPE_DESCRIPTION
= 'Windows ${OPTIMIZATION_LEVEL} build',
343 tools
= ['target_platform_windows'],
344 ASCOM
= '$ASPPCOM /E | as -o $TARGET',
345 PDB
= '${TARGET.base}.pdb',
349 ['NACL_WINDOWS', '1'],
352 ['_WIN32_WINNT', '0x0501'],
353 ['__STDC_LIMIT_MACROS', '1'],
355 NACL_PLATFORM
= 'win',
356 LIBS
= ['wsock32', 'advapi32'],
357 CCFLAGS
= ['/EHsc', '/WX'],
361 windows_optimized_env
) = GenerateOptimizationLevels(windows_env
)
363 if ARGUMENTS
.get('sdl', 'hermetic') != 'none':
364 # These will only apply to sdl!=none builds!
365 windows_debug_env
.Append(CPPDEFINES
= ['_DLL', '_MT'])
366 windows_optimized_env
.Append(CPPDEFINES
= ['_DLL', '_MT'])
368 if '/MT' in windows_optimized_env
['CCFLAGS']:
369 windows_optimized_env
.FilterOut(CCFLAGS
=['/MT']);
370 windows_optimized_env
.Append(CCFLAGS
=['/MD']);
371 if '/MTd' in windows_debug_env
['CCFLAGS']:
372 windows_debug_env
.FilterOut(CCFLAGS
=['/MTd']);
373 windows_debug_env
.Append(CCFLAGS
=['/MDd']);
374 # this doesn't feel right, but fixes dbg-win
375 windows_debug_env
.Append(LINKFLAGS
= ['/NODEFAULTLIB:msvcrt'])
376 # make source level debugging a little easier
377 if '/Z7' not in windows_debug_env
['CCFLAGS']:
378 if '/Zi' not in windows_debug_env
['CCFLAGS']:
379 windows_debug_env
.Append(CCFLAGS
=['/Z7'])
381 # ----------------------------------------------------------
383 unix_like_env
= base_env
.Clone()
384 unix_like_env
.Append(
386 # TODO: explore adding stricter checking from
387 # as we do for the linux_env
392 # start pedantic flags for code extreme cleaning
399 '-fvisibility=hidden',
402 CFLAGS
= ['-std=gnu99' ],
403 LIBS
= ['pthread', 'ssl', 'crypto'],
406 # ----------------------------------------------------------
408 mac_env
= unix_like_env
.Clone(
409 BUILD_TYPE
= '${OPTIMIZATION_LEVEL}-mac',
410 BUILD_TYPE_DESCRIPTION
= 'MacOS ${OPTIMIZATION_LEVEL} build',
411 tools
= ['target_platform_mac'],
412 # TODO: this should really be able to live in unix_like_env
413 # but can't due to what the target_platform_x module is
416 PLUGIN_SUFFIX
= '.bundle',
419 CCFLAGS
= ['-mmacosx-version-min=10.4'],
420 CFLAGS
= ['-std=gnu99'],
421 # TODO: remove UNIX_LIKE_CFLAGS when scons bug is fixed
422 CPPDEFINES
= [['NACL_WINDOWS', '0'],
425 ['MAC_OS_X_VERSION_MIN_REQUIRED', 'MAC_OS_X_VERSION_10_4'],
426 ['_DARWIN_C_SOURCE', '1'],
427 ['__STDC_LIMIT_MACROS', '1'],
429 NACL_PLATFORM
= 'osx',
432 (mac_debug_env
, mac_optimized_env
) = GenerateOptimizationLevels(mac_env
)
434 # ----------------------------------------------------------
436 linux_env
= unix_like_env
.Clone(
437 BUILD_TYPE
= '${OPTIMIZATION_LEVEL}-linux',
438 BUILD_TYPE_DESCRIPTION
= 'Linux ${OPTIMIZATION_LEVEL} build',
439 tools
= ['target_platform_linux'],
440 # TODO: this should really be able to live in unix_like_env
441 # but can't due to what the target_platform_x module is
446 # -m32 and -L/usr/lib32 are needed to do 32-bit builds on 64-bit
447 # user-space machines; requires ia32-libs-dev to be installed; or,
448 # failing that, ia32-libs and symbolic links *manually* created for
449 # /usr/lib32/libssl.so and /usr/lib32/libcrypto.so to the current
450 # /usr/lib32/lib*.so.version (tested with ia32-libs 2.2ubuntu11; no
451 # ia32-libs-dev was available for testing).
452 # Additional symlinks of this sort are needed for gtk,
453 # see nonnacl_util/build.scons.
455 linux_env
.SetDefault(
456 # NOTE: look into http://www.scons.org/wiki/DoxygenBuilder
457 DOXYGEN
= ARGUMENTS
.get('DOXYGEN', '/usr/bin/doxygen'),
461 ASFLAGS
= ['-m32', ],
462 # TODO: move these flags up to unix_like_env.
463 # currently mac issues prevent us from doing that
466 # NOTE: not available with older gcc/g++ versions
467 # '-fdiagnostics-show-option',
469 CXXFLAGS
=['-std=c++98'],
470 CFLAGS
=['-std=gnu99'],
471 CPPDEFINES
= [['NACL_WINDOWS', '0'],
474 ['_BSD_SOURCE', '1'],
475 ['_POSIX_C_SOURCE', '199506'],
476 ['_XOPEN_SOURCE', '600'],
477 ['_GNU_SOURCE', '1'],
478 ['__STDC_LIMIT_MACROS', '1'],
481 LINKFLAGS
= ['-m32', '-L/usr/lib32'],
482 NACL_PLATFORM
= 'linux',
486 (linux_debug_env
, linux_optimized_env
) = GenerateOptimizationLevels(linux_env
)
489 # ----------------------------------------------------------
490 # The nacl_env is used to build native_client modules
491 # using a special tool chain which produces platform
492 # independent binaries
493 # ----------------------------------------------------------
494 nacl_env
= pre_base_env
.Clone(
497 BUILD_TYPE_DESCRIPTION
= 'NaCl module build',
500 # always optimize binaries
504 '-fomit-frame-pointer',
506 '-fdiagnostics-show-option',
509 CPPPATH
= ['$SOURCE_ROOT/googleclient'],
510 # from third_party/software_construction_toolkit/files/site_scons/site_tools/naclsdk.py
511 LIBPATH
= ['$NACL_SDK_LIB'],
514 Banner('Building nexe binaries using sdk at [%s]' %
515 nacl_env
.subst('$NACL_SDK_ROOT'))
519 BUILD_SCONSCRIPTS
= [
520 #### ALPHABETICALLY SORTED ####
522 'tests/app_lib/nacl.scons',
523 'tests/autoloader/nacl.scons',
524 'tests/contest_issues/nacl.scons',
525 'tests/cloudfs/nacl.scons',
526 'tests/earth/nacl.scons',
527 'tests/fib/nacl.scons',
528 'tests/file/nacl.scons',
529 'tests/hello_world/nacl.scons',
530 'tests/imc_shm_mmap/nacl.scons',
531 'tests/life/nacl.scons',
532 'tests/mandel/nacl.scons',
533 'tests/mandel_nav/nacl.scons',
534 'tests/many/nacl.scons',
535 'tests/mmap/nacl.scons',
536 'tests/noop/nacl.scons',
537 'tests/npapi_bridge/nacl.scons',
538 'tests/npapi_hw/nacl.scons',
539 'tests/npapi_pi/nacl.scons',
540 'tests/nrd_xfer/nacl.scons',
541 'tests/null/nacl.scons',
542 'tests/nullptr/nacl.scons',
543 'tests/srpc/nacl.scons',
544 'tests/srpc_hw/nacl.scons',
545 'tests/syscalls/nacl.scons',
546 'tests/threads/nacl.scons',
547 'tests/tone/nacl.scons',
548 'tests/voronoi/nacl.scons',
550 'tools/tests/nacl.scons',
551 #### ALPHABETICALLY SORTED ####
555 environment_list
.append(nacl_env
)
556 # ----------------------------------------------------------
557 # We force this into a separate env so that the tests in nacl_env
558 # have NO access to any libraries build here but need to link them
559 # from the sdk libdir
560 # ----------------------------------------------------------
561 nacl_extra_sdk_env
= pre_base_env
.Clone(
563 BUILD_TYPE
= 'nacl_extra_sdk',
564 BUILD_TYPE_DESCRIPTION
= 'NaCl SDK extra library build',
573 '-fno-stack-protector',
574 '-DNACL_BLOCK_SHIFT=5',
575 '-fdiagnostics-show-option',
578 CPPPATH
= ['$SOURCE_ROOT/googleclient'],
582 nacl_extra_sdk_env
.Append(
583 BUILD_SCONSCRIPTS
= [
584 #### ALPHABETICALLY SORTED ####
585 # TODO: maybe move this to tools/ as well
586 'intermodule_comm/nacl.scons',
588 'tools/stubs/nacl.scons',
589 'tools/libnacl/nacl.scons',
590 'tools/libsrpc/nacl.scons',
591 'tools/nc_threads/nacl.scons',
592 'tools/libav/nacl.scons',
593 'tools/libunimpl/nacl.scons',
594 'tools/npapi_runtime/nacl.scons',
595 #### ALPHABETICALLY SORTED ####
599 environment_list
.append(nacl_extra_sdk_env
)
601 nacl_extra_sdk_env
.FilterOut(BUILD_GROUPS
=['most', 'all'])
603 # ----------------------------------------------------------
604 # Targets for updating sdk headers and libraries
605 # NACL_SDK_ROOT is defined by
606 # third_party/software_construction_toolkit/files/site_scons/site_tools/naclsdk.py
608 def AddHeaderToSdk(env
, nodes
, path
=None):
610 path
= 'nacl/include/nacl/'
612 n
= env
.Replicate('${NACL_SDK_ROOT}/' + path
, nodes
)
613 env
.Alias('extra_sdk_update', n
)
616 nacl_extra_sdk_env
.AddMethod(AddHeaderToSdk
)
618 def AddLibraryToSdk(env
, nodes
, path
=None):
622 n
= env
.ReplicatePublished('${NACL_SDK_ROOT}/' + path
, nodes
, 'link')
623 env
.Alias('extra_sdk_update', n
)
626 nacl_extra_sdk_env
.AddMethod(AddLibraryToSdk
)
628 def AddObjectToSdk(env
, nodes
, path
=None):
632 n
= env
.Replicate('${NACL_SDK_ROOT}/' + path
, nodes
)
633 env
.Alias('extra_sdk_update', n
)
636 nacl_extra_sdk_env
.AddMethod(AddObjectToSdk
)
638 # NOTE: a helpful target to test the sdk_extra magic
639 # combine this with a 'MODE=nacl -c'
640 # TODO: find a way to cleanup the libs on top of the headers
641 nacl_extra_sdk_env
.Command('extra_sdk_clean', [],
642 ['rm -rf ${NACL_SDK_ROOT}/nacl/include/nacl*'])
644 # ----------------------------------------------------------
646 # ----------------------------------------------------------
647 # ----------------------------------------------------------
649 # ----------------------------------------------------------
651 doc_env
= pre_base_env
.Clone(
653 BUILD_TYPE_DESCRIPTION
= 'Documentation build',
654 HOST_PLATFORMS
= '*',
656 doc_env
.FilterOut(BUILD_GROUPS
=['most'])
657 environment_list
.append(doc_env
)
659 BUILD_SCONSCRIPTS
= [
665 # ----------------------------------------------------------
667 # Blank out defaults.
670 BuildComponents(environment_list
)
672 # Change default to build everything, but not run tests.
673 Default(['all_programs', 'all_bundles', 'all_test_programs', 'all_libraries'])
675 # ----------------------------------------------------------
678 # Generate a solution, defer to the end.
679 solution_env
= base_env
.Clone(tools
= ['visual_studio_solution'])
680 solution
= solution_env
.Solution(
681 'nacl', environment_list
,
682 exclude_pattern
= '.*third_party.*',
683 extra_build_targets
= {
684 'Firefox': 'c:/Program Files/Mozilla FireFox/firefox.exe',
687 solution_env
.Alias('solution', solution
)