Source code

Revision control

Other Tools

1
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
2
# vim: set filetype=python:
3
# This Source Code Form is subject to the terms of the Mozilla Public
4
# License, v. 2.0. If a copy of the MPL was not distributed with this
5
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7
include('util.configure')
8
include('checks.configure')
9
10
# Make `toolkit` available when toolkit/moz.configure is not included.
11
toolkit = dependable(None)
12
# Likewise with `bindgen_config_paths` when
13
# build/moz.configure/bindgen.configure is not included.
14
bindgen_config_paths = dependable(None)
15
16
option(env='DIST', nargs=1, help='DIST directory')
17
18
19
# Do not allow objdir == srcdir builds.
20
# ==============================================================
21
@depends('--help', 'DIST')
22
@imports(_from='__builtin__', _import='open')
23
@imports(_from='os.path', _import='exists')
24
@imports(_from='six', _import='ensure_text')
25
def check_build_environment(help, dist):
26
topobjdir = os.path.realpath(os.path.abspath('.'))
27
topsrcdir = os.path.realpath(os.path.abspath(
28
os.path.join(os.path.dirname(__file__), '..', '..')))
29
30
if dist:
31
dist = normsep(dist[0])
32
else:
33
dist = os.path.join(topobjdir, 'dist')
34
35
result = namespace(
36
topsrcdir=topsrcdir,
37
topobjdir=topobjdir,
38
dist=dist,
39
)
40
41
if help:
42
return result
43
44
# This limitation has mostly to do with GNU make. Since make can't represent
45
# variables with spaces without correct quoting and many paths are used
46
# without proper quoting, using paths with spaces commonly results in
47
# targets or dependencies being treated as multiple paths. This, of course,
48
# undermines the ability for make to perform up-to-date checks and makes
49
# the build system not work very efficiently. In theory, a non-make build
50
# backend will make this limitation go away. But there is likely a long tail
51
# of things that will need fixing due to e.g. lack of proper path quoting.
52
if len(topsrcdir.split()) > 1:
53
die('Source directory cannot be located in a path with spaces: %s' %
54
topsrcdir)
55
if len(topobjdir.split()) > 1:
56
die('Object directory cannot be located in a path with spaces: %s' %
57
topobjdir)
58
59
if topsrcdir == topobjdir:
60
die(' ***\n'
61
' * Building directly in the main source directory is not allowed.\n'
62
' *\n'
63
' * To build, you must run configure from a separate directory\n'
64
' * (referred to as an object directory).\n'
65
' *\n'
66
' * If you are building with a mozconfig, you will need to change your\n'
67
' * mozconfig to point to a different object directory.\n'
68
' ***'
69
)
70
71
# Check for CRLF line endings.
72
with open(os.path.join(topsrcdir, 'configure.py'), 'r') as fh:
73
data = ensure_text(fh.read())
74
if '\r' in data:
75
die('\n ***\n'
76
' * The source tree appears to have Windows-style line endings.\n'
77
' *\n'
78
' * If using Git, Git is likely configured to use Windows-style\n'
79
' * line endings.\n'
80
' *\n'
81
' * To convert the working copy to UNIX-style line endings, run\n'
82
' * the following:\n'
83
' *\n'
84
' * $ git config core.autocrlf false\n'
85
' * $ git config core.eof lf\n'
86
' * $ git rm --cached -r .\n'
87
' * $ git reset --hard\n'
88
' *\n'
89
' * If not using Git, the tool you used to obtain the source\n'
90
' * code likely converted files to Windows line endings. See\n'
91
' * usage information for that tool for more.\n'
92
' ***')
93
94
# Check for a couple representative files in the source tree
95
conflict_files = [
96
'* %s' % f for f in ('Makefile', 'config/autoconf.mk')
97
if exists(os.path.join(topsrcdir, f))
98
]
99
if conflict_files:
100
die(' ***\n'
101
' * Your source tree contains these files:\n'
102
' %s\n'
103
' * This indicates that you previously built in the source tree.\n'
104
' * A source tree build can confuse the separate objdir build.\n'
105
' *\n'
106
' * To clean up the source tree:\n'
107
' * 1. cd %s\n'
108
' * 2. gmake distclean\n'
109
' ***'
110
% ('\n '.join(conflict_files), topsrcdir)
111
)
112
113
return result
114
115
116
set_config('TOPSRCDIR', check_build_environment.topsrcdir)
117
set_config('TOPOBJDIR', check_build_environment.topobjdir)
118
set_config('MOZ_BUILD_ROOT', check_build_environment.topobjdir)
119
set_config('DIST', check_build_environment.dist)
120
121
add_old_configure_assignment(
122
'_topsrcdir', check_build_environment.topsrcdir)
123
add_old_configure_assignment(
124
'_objdir', check_build_environment.topobjdir)
125
add_old_configure_assignment(
126
'MOZ_BUILD_ROOT', check_build_environment.topobjdir)
127
add_old_configure_assignment(
128
'DIST', check_build_environment.dist)
129
130
option(env='MOZ_AUTOMATION', help='Enable options for automated builds')
131
set_config('MOZ_AUTOMATION', depends_if('MOZ_AUTOMATION')(lambda x: True))
132
133
134
option(env='OLD_CONFIGURE', nargs=1, help='Path to the old configure script')
135
136
option(env='MOZCONFIG', nargs=1, help='Mozconfig location')
137
138
option('--with-external-source-dir', env='EXTERNAL_SOURCE_DIR', nargs=1,
139
help='External directory containing additional build files')
140
141
142
@depends('--with-external-source-dir')
143
def external_source_dir(value):
144
if value:
145
return value[0]
146
147
148
set_config('EXTERNAL_SOURCE_DIR', external_source_dir)
149
add_old_configure_assignment('EXTERNAL_SOURCE_DIR', external_source_dir)
150
151
# Read user mozconfig
152
# ==============================================================
153
# Note: the dependency on --help is only there to always read the mozconfig,
154
# even when --help is passed. Without this dependency, the function wouldn't
155
# be called when --help is passed, and the mozconfig wouldn't be read.
156
157
158
@depends('MOZCONFIG', 'OLD_CONFIGURE',
159
check_build_environment, '--with-external-source-dir',
160
'--help')
161
@imports(_from='mozbuild.mozconfig', _import='MozconfigLoader')
162
def mozconfig(mozconfig, old_configure, build_env,
163
external_source_dir, help):
164
if not old_configure and not help:
165
die('The OLD_CONFIGURE environment variable must be set')
166
167
# Don't read the mozconfig for the js configure (yay backwards
168
# compatibility)
169
# While the long term goal is that js and top-level use the same configure
170
# and the same overall setup, including the possibility to use mozconfigs,
171
# figuring out what we want to do wrt mozconfig vs. command line and
172
# environment variable is not a clear-cut case, and it's more important to
173
# fix the immediate problem mozconfig causes to js developers by
174
# "temporarily" returning to the previous behavior of not loading the
175
# mozconfig for the js configure.
176
# Separately to the immediate problem for js developers, there is also the
177
# need to not load a mozconfig when running js configure as a subconfigure.
178
# Unfortunately, there is no direct way to tell whether the running
179
# configure is the js configure. The indirect way is to look at the
180
# OLD_CONFIGURE path, which points to js/src/old-configure.
181
# I expect we'll have figured things out for mozconfigs well before
182
# old-configure dies.
183
if old_configure and os.path.dirname(os.path.abspath(old_configure[0])).endswith('/js/src'):
184
return {'path': None}
185
186
topsrcdir = build_env.topsrcdir
187
if external_source_dir:
188
topsrcdir = external_source_dir[0]
189
loader = MozconfigLoader(topsrcdir)
190
mozconfig = mozconfig[0] if mozconfig else None
191
mozconfig = loader.find_mozconfig(env={'MOZCONFIG': mozconfig})
192
mozconfig = loader.read_mozconfig(mozconfig)
193
194
return mozconfig
195
196
197
set_config('MOZCONFIG', depends(mozconfig)(lambda m: m['path']))
198
199
200
# Mozilla-Build
201
# ==============================================================
202
option(env='MOZILLABUILD', nargs=1,
203
help='Path to Mozilla Build (Windows-only)')
204
205
option(env='CONFIG_SHELL', nargs=1, help='Path to a POSIX shell')
206
207
# It feels dirty replicating this from python/mozbuild/mozbuild/mozconfig.py,
208
# but the end goal being that the configure script would go away...
209
210
211
@depends('CONFIG_SHELL', 'MOZILLABUILD')
212
@checking('for a shell')
213
@imports('sys')
214
def shell(value, mozillabuild):
215
if value:
216
return find_program(value[0])
217
shell = 'sh'
218
if mozillabuild:
219
shell = mozillabuild[0] + '/msys/bin/sh'
220
if sys.platform == 'win32':
221
shell = shell + '.exe'
222
return find_program(shell)
223
224
225
# This defines a reasonable shell for when running with --help.
226
# If one was passed in the environment, though, fall back to that.
227
@depends('--help', 'CONFIG_SHELL')
228
def help_shell(help, shell):
229
if help and not shell:
230
return 'sh'
231
232
233
shell = help_shell | shell
234
235
236
# Python 2
237
# ========
238
239
option(env='PYTHON', nargs=1, help='Python 2.7 interpreter')
240
241
242
@depends('PYTHON', check_build_environment, 'MOZILLABUILD', mozconfig, '--help')
243
@imports(_from='__builtin__', _import='Exception')
244
@imports('os')
245
@imports('sys')
246
@imports('subprocess')
247
@imports('distutils.sysconfig')
248
@imports(_from='mozbuild.configure.util', _import='LineIO')
249
@imports(_from='mozbuild.virtualenv', _import='VirtualenvManager')
250
@imports(_from='mozbuild.virtualenv', _import='verify_python_version')
251
@imports(_from='mozbuild.virtualenv', _import='PY2')
252
@imports(_from='mozbuild.pythonutil', _import='find_python2_executable')
253
@imports(_from='mozbuild.pythonutil', _import='python_executable_version')
254
@imports(_from='six', _import='ensure_text')
255
def virtualenv_python2(env_python, build_env, mozillabuild, mozconfig, help):
256
if help:
257
return
258
259
# NOTE: We cannot assume the Python we are calling this code with is the
260
# Python we want to set up a virtualenv for.
261
#
262
# We also cannot assume that the Python the caller is configuring meets our
263
# build requirements.
264
#
265
# Because of this the code is written to re-execute itself with the correct
266
# interpreter if required.
267
268
log.debug("python2: running with pid %r" % os.getpid())
269
log.debug("python2: sys.executable: %r" % sys.executable)
270
271
python = env_python[0] if env_python else None
272
273
# Did our python come from mozconfig? Overrides environment setting.
274
# Ideally we'd rely on the mozconfig injection from mozconfig_options,
275
# but we'd rather avoid the verbosity when we need to reexecute with
276
# a different python.
277
if mozconfig['path']:
278
if 'PYTHON' in mozconfig['env']['added']:
279
python = mozconfig['env']['added']['PYTHON']
280
elif 'PYTHON' in mozconfig['env']['modified']:
281
python = mozconfig['env']['modified']['PYTHON'][1]
282
elif 'PYTHON' in mozconfig['vars']['added']:
283
python = mozconfig['vars']['added']['PYTHON']
284
elif 'PYTHON' in mozconfig['vars']['modified']:
285
python = mozconfig['vars']['modified']['PYTHON'][1]
286
287
log.debug("python2: executable from configuration: %r" % python)
288
289
with LineIO(lambda l: log.error(l)) as out:
290
verify_python_version(out)
291
topsrcdir, topobjdir = build_env.topsrcdir, build_env.topobjdir
292
if topobjdir.endswith('/js/src'):
293
topobjdir = topobjdir[:-7]
294
295
virtualenvs_root = os.path.join(topobjdir, '_virtualenvs')
296
with LineIO(lambda l: log.info(l), 'replace') as out:
297
manager = VirtualenvManager(
298
topsrcdir, topobjdir,
299
os.path.join(virtualenvs_root, 'init'), out,
300
os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'))
301
302
# If we're not in the virtualenv, we need the mozfile module for
303
# find_program.
304
if normsep(sys.executable) != normsep(manager.python_path):
305
sys.path.insert(
306
0, os.path.join(topsrcdir, 'testing', 'mozbase', 'mozfile'))
307
308
if python:
309
found_python = find_program(python)
310
if not found_python:
311
die('The PYTHON environment variable does not contain '
312
'a valid path. Cannot find %s', python)
313
python = found_python
314
elif mozillabuild:
315
# MozillaBuild provides a Python 2.
316
python = normsep('%s/python/python2.exe' % mozillabuild)
317
318
try:
319
version = python_executable_version(python).version
320
except Exception as e:
321
raise FatalCheckError('could not determine version of '
322
'MozillaBuild python: %s' % e)
323
else:
324
python, version = find_python2_executable()
325
if python:
326
python = ensure_text(python)
327
328
if not python:
329
raise FatalCheckError(
330
'Python 2.7 is required to build. Ensure a `python2.7` executable '
331
'is in your PATH or define PYTHON to point to a Python 2.7 '
332
'executable.')
333
334
if version < (2, 7, 0):
335
raise FatalCheckError(
336
'Python 2.7 is required to build; '
337
'%s is Python %d.%d' % (python, version[0], version[1]))
338
339
log.debug("python2: found executable: %r" % python)
340
341
if not manager.up_to_date(python):
342
log.info('Creating Python 2 environment')
343
manager.build(python)
344
else:
345
log.debug("python2: venv is up to date")
346
347
python = normsep(manager.python_path)
348
349
# The currently running interpreter could be Python 2 or Python 3. We make the
350
# part of the code that re-executes everything with the virtualenv's Python
351
# conditional on running the same major version as the current interpreter. If we
352
# don't do this then the configure code for the Py 2 and Py 3 virtualenvs could
353
# activate each other from inside the other's virtualenv. We can't guarantee
354
# how the virtualenvs would interact if that happens.
355
if PY2:
356
if not normsep(sys.executable).startswith(normsep(virtualenvs_root)):
357
log.debug("python2: executing as %s, should be running as %s" % (
358
sys.executable, manager.python_path))
359
log.info('Reexecuting in the virtualenv')
360
if env_python:
361
del os.environ['PYTHON']
362
# One would prefer to use os.execl, but that's completely borked on
363
# Windows.
364
sys.exit(subprocess.call([python] + sys.argv))
365
366
# We are now in the virtualenv
367
if not distutils.sysconfig.get_python_lib():
368
die('Could not determine python site packages directory')
369
370
return python
371
372
373
set_config('PYTHON', virtualenv_python2)
374
add_old_configure_assignment('PYTHON', virtualenv_python2)
375
376
377
# Inject mozconfig options
378
# ==============================================================
379
# All options defined above this point can't be injected in mozconfig_options
380
# below, so collect them.
381
382
383
@template
384
def early_options():
385
@dependable
386
@imports('__sandbox__')
387
def early_options():
388
return set(
389
option.env
390
for option in __sandbox__._options.itervalues()
391
if option.env
392
)
393
return early_options
394
395
396
early_options = early_options()
397
398
399
@depends(mozconfig, 'MOZ_AUTOMATION', '--help')
400
# This gives access to the sandbox. Don't copy this blindly.
401
@imports('__sandbox__')
402
@imports('os')
403
@imports('six')
404
def mozconfig_options(mozconfig, automation, help):
405
if mozconfig['path']:
406
if 'MOZ_AUTOMATION_MOZCONFIG' in mozconfig['env']['added']:
407
if not automation:
408
log.error('%s directly or indirectly includes an in-tree '
409
'mozconfig.', mozconfig['path'])
410
log.error('In-tree mozconfigs make strong assumptions about '
411
'and are only meant to be used by Mozilla '
412
'automation.')
413
die("Please don't use them.")
414
helper = __sandbox__._helper
415
log.info('Adding configure options from %s' % mozconfig['path'])
416
for arg in mozconfig['configure_args']:
417
log.info(' %s' % arg)
418
# We could be using imply_option() here, but it has other
419
# contraints that don't really apply to the command-line
420
# emulation that mozconfig provides.
421
helper.add(arg, origin='mozconfig', args=helper._args)
422
423
def add(key, value):
424
if key.isupper():
425
arg = '%s=%s' % (key, value)
426
log.info(' %s' % arg)
427
helper.add(arg, origin='mozconfig', args=helper._args)
428
429
for key, value in six.iteritems(mozconfig['env']['added']):
430
add(key, value)
431
os.environ[key] = value
432
for key, (_, value) in six.iteritems(mozconfig['env']['modified']):
433
add(key, value)
434
os.environ[key] = value
435
for key, value in six.iteritems(mozconfig['vars']['added']):
436
add(key, value)
437
for key, (_, value) in six.iteritems(mozconfig['vars']['modified']):
438
add(key, value)
439
440
441
# Python 3
442
# ========
443
444
option(env='PYTHON3', nargs=1, help='Python 3 interpreter (3.5 or later)')
445
446
447
@depends(
448
'PYTHON3', check_build_environment, 'MOZILLABUILD', mozconfig, '--help')
449
@checking('for Python 3',
450
callback=lambda x: '%s (%s)' % (x.path, x.str_version) if x else 'no')
451
@imports(_from='__builtin__', _import='Exception')
452
@imports('os')
453
@imports('sys')
454
@imports('subprocess')
455
@imports('distutils.sysconfig')
456
@imports(_from='mozbuild.configure.util', _import='LineIO')
457
@imports(_from='mozbuild.virtualenv', _import='VirtualenvManager')
458
@imports(_from='mozbuild.virtualenv', _import='verify_python_version')
459
@imports(_from='mozbuild.virtualenv', _import='PY3')
460
@imports(_from='mozbuild.pythonutil', _import='find_python3_executable')
461
@imports(_from='mozbuild.pythonutil', _import='python_executable_version')
462
@imports(_from='six', _import='ensure_text')
463
def virtualenv_python3(env_python, build_env, mozillabuild, mozconfig, help):
464
if help:
465
return
466
467
# NOTE: We cannot assume the Python we are calling this code with is the
468
# Python we want to set up a virtualenv for.
469
#
470
# We also cannot assume that the Python the caller is configuring meets our
471
# build requirements.
472
#
473
# Because of this the code is written to re-execute itself with the correct
474
# interpreter if required.
475
476
log.debug("python3: running with pid %r" % os.getpid())
477
log.debug("python3: sys.executable: %r" % sys.executable)
478
479
# Verify that the Python version we executed this code with is the minimum
480
# required version to handle all project code.
481
with LineIO(lambda l: log.error(l)) as out:
482
verify_python_version(out)
483
484
python = env_python[0] if env_python else None
485
486
# Ideally we'd rely on the mozconfig injection from mozconfig_options,
487
# but we'd rather avoid the verbosity when we need to reexecute with
488
# a different python.
489
if mozconfig['path']:
490
if 'PYTHON3' in mozconfig['env']['added']:
491
python = mozconfig['env']['added']['PYTHON3']
492
elif 'PYTHON3' in mozconfig['env']['modified']:
493
python = mozconfig['env']['modified']['PYTHON3'][1]
494
elif 'PYTHON3' in mozconfig['vars']['added']:
495
python = mozconfig['vars']['added']['PYTHON3']
496
elif 'PYTHON3' in mozconfig['vars']['modified']:
497
python = mozconfig['vars']['modified']['PYTHON3'][1]
498
499
log.debug("python3: executable from configuration: %r" % python)
500
501
# If this is a mozilla-central build, we'll find the virtualenv in the top
502
# source directory. If this is a SpiderMonkey build, we assume we're at
503
# js/src and try to find the virtualenv from the mozilla-central root.
504
# See mozilla-central changeset d2cce982a7c809815d86d5daecefe2e7a563ecca
505
# Bug 784841
506
topsrcdir, topobjdir = build_env.topsrcdir, build_env.topobjdir
507
if topobjdir.endswith('/js/src'):
508
topobjdir = topobjdir[:-7]
509
510
# If we know the Python executable the caller is asking for then verify its
511
# version. If the caller did not ask for a specific executable then find
512
# a reasonable default.
513
if python:
514
try:
515
version = python_executable_version(python).version
516
except Exception as e:
517
raise FatalCheckError('could not determine version of PYTHON '
518
'(%s): %s' % (python, e))
519
elif mozillabuild:
520
# MozillaBuild provides a Python 3.
521
python = normsep('%s/python3/python3.exe' % mozillabuild)
522
523
try:
524
version = python_executable_version(python).version
525
except Exception as e:
526
raise FatalCheckError('could not determine version of '
527
'MozillaBuild python: %s' % e)
528
else:
529
# Fall back to the search routine.
530
python, version = find_python3_executable(min_version='3.5.0')
531
532
# The API returns a bytes whereas everything in configure is unicode.
533
if python:
534
python = ensure_text(python)
535
536
if not python:
537
raise FatalCheckError('Python 3.5 or newer is required to build. '
538
'Ensure a `python3.x` executable is in your '
539
'PATH or define PYTHON3 to point to a Python '
540
'3.5 executable.')
541
542
if version < (3, 5, 0):
543
raise FatalCheckError('Python 3.5 or newer is required to build; '
544
'%s is Python %d.%d' % (python, version[0],
545
version[1]))
546
547
log.debug("python3: found executable: %r" % python)
548
549
virtualenvs_root = os.path.join(topobjdir, '_virtualenvs')
550
with LineIO(lambda l: log.info(l), 'replace') as out:
551
manager = VirtualenvManager(
552
topsrcdir, topobjdir,
553
os.path.join(virtualenvs_root, 'init_py3'), out,
554
os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'))
555
556
log.debug("python3: using venv: %r" % manager.virtualenv_root)
557
558
if not manager.up_to_date(python):
559
log.info('Creating Python 3 environment')
560
manager.build(python)
561
else:
562
log.debug("python3: venv is up to date")
563
564
python = normsep(manager.python_path)
565
566
# The currently running interpreter could be Python 2 or Python 3. We make the
567
# part of the code that re-executes everything with the virtualenv's Python
568
# conditional on running the same major version as the current interpreter. If we
569
# don't do this then the configure code for the Py 2 and Py 3 virtualenvs could
570
# activate each other from inside the other's virtualenv. We can't guarantee
571
# how the virtualenvs would interact if that happens.
572
if PY3:
573
if not normsep(sys.executable).startswith(normsep(virtualenvs_root)):
574
log.debug("python3: executing as %s, should be running as %s" % (
575
sys.executable, manager.python_path))
576
log.info('Re-executing in the virtualenv')
577
if env_python:
578
del os.environ['PYTHON3']
579
# One would prefer to use os.execl, but that's completely borked on
580
# Windows.
581
sys.exit(subprocess.call([python] + sys.argv))
582
583
# We are now in the virtualenv
584
if not distutils.sysconfig.get_python_lib():
585
die('Could not determine python site packages directory')
586
587
str_version = '.'.join(str(v) for v in version)
588
589
return namespace(
590
path=python,
591
version=version,
592
str_version=str_version,
593
)
594
595
596
set_config('PYTHON3', depends(virtualenv_python3)(lambda p: p.path))
597
set_config(
598
'PYTHON3_VERSION',
599
depends(virtualenv_python3)(lambda p: p.str_version))
600
601
602
# Source checkout and version control integration.
603
# ================================================
604
605
606
@depends(check_build_environment, 'MOZ_AUTOMATION', '--help')
607
@checking('for vcs source checkout')
608
@imports('os')
609
def vcs_checkout_type(build_env, automation, help):
610
if os.path.exists(os.path.join(build_env.topsrcdir, '.hg')):
611
return 'hg'
612
elif os.path.exists(os.path.join(build_env.topsrcdir, '.git')):
613
return 'git'
614
elif automation and not help:
615
raise FatalCheckError('unable to resolve VCS type; must run '
616
'from a source checkout when MOZ_AUTOMATION '
617
'is set')
618
619
# Resolve VCS binary for detected repository type.
620
621
622
# TODO remove hg.exe once bug 1382940 addresses ambiguous executables case.
623
hg = check_prog('HG', ('hg.exe', 'hg',), allow_missing=True,
624
when=depends(vcs_checkout_type)(lambda x: x == 'hg'))
625
git = check_prog('GIT', ('git',), allow_missing=True,
626
when=depends(vcs_checkout_type)(lambda x: x == 'git'))
627
628
629
@depends_if(hg)
630
@checking('for Mercurial version')
631
@imports('os')
632
@imports('re')
633
def hg_version(hg):
634
# HGPLAIN in Mercurial 1.5+ forces stable output, regardless of set
635
# locale or encoding.
636
env = dict(os.environ)
637
env['HGPLAIN'] = '1'
638
639
out = check_cmd_output(hg, '--version', env=env)
640
641
match = re.search(r'Mercurial Distributed SCM \(version ([^\)]+)', out)
642
643
if not match:
644
raise FatalCheckError(
645
'unable to determine Mercurial version: %s' % out)
646
647
# The version string may be "unknown" for Mercurial run out of its own
648
# source checkout or for bad builds. But LooseVersion handles it.
649
650
return Version(match.group(1))
651
652
# Resolve Mercurial config items so other checks have easy access.
653
# Do NOT set this in the config because it may contain sensitive data
654
# like API keys.
655
656
657
@depends_all(check_build_environment, hg, hg_version)
658
@imports('os')
659
def hg_config(build_env, hg, version):
660
env = dict(os.environ)
661
env['HGPLAIN'] = '1'
662
663
# Warnings may get sent to stderr. But check_cmd_output() ignores
664
# stderr if exit code is 0. And the command should always succeed if
665
# `hg version` worked.
666
out = check_cmd_output(hg, 'config', env=env, cwd=build_env.topsrcdir)
667
668
config = {}
669
670
for line in out.strip().splitlines():
671
key, value = [s.strip() for s in line.split('=', 1)]
672
config[key] = value
673
674
return config
675
676
677
@depends_if(git)
678
@checking('for Git version')
679
@imports('re')
680
def git_version(git):
681
out = check_cmd_output(git, '--version').rstrip()
682
683
match = re.search('git version (.*)$', out)
684
685
if not match:
686
raise FatalCheckError('unable to determine Git version: %s' % out)
687
688
return Version(match.group(1))
689
690
# Only set VCS_CHECKOUT_TYPE if we resolved the VCS binary.
691
# Require resolved VCS info when running in automation so automation's
692
# environment is more well-defined.
693
694
695
@depends(vcs_checkout_type, hg_version, git_version, 'MOZ_AUTOMATION')
696
def exposed_vcs_checkout_type(vcs_checkout_type, hg, git, automation):
697
if vcs_checkout_type == 'hg':
698
if hg:
699
return 'hg'
700
701
if automation:
702
raise FatalCheckError('could not resolve Mercurial binary info')
703
704
elif vcs_checkout_type == 'git':
705
if git:
706
return 'git'
707
708
if automation:
709
raise FatalCheckError('could not resolve Git binary info')
710
elif vcs_checkout_type:
711
raise FatalCheckError('unhandled VCS type: %s' % vcs_checkout_type)
712
713
714
set_config('VCS_CHECKOUT_TYPE', exposed_vcs_checkout_type)
715
716
# Obtain a Repository interface for the current VCS repository.
717
718
719
@depends(check_build_environment, exposed_vcs_checkout_type, hg, git)
720
@imports(_from='mozversioncontrol', _import='get_repository_object')
721
def vcs_repository(build_env, vcs_checkout_type, hg, git):
722
if vcs_checkout_type == 'hg':
723
return get_repository_object(build_env.topsrcdir, hg=hg)
724
elif vcs_checkout_type == 'git':
725
return get_repository_object(build_env.topsrcdir, git=git)
726
elif vcs_checkout_type:
727
raise FatalCheckError('unhandled VCS type: %s' % vcs_checkout_type)
728
729
730
@depends_if(vcs_repository)
731
@checking('for sparse checkout')
732
def vcs_sparse_checkout(repo):
733
return repo.sparse_checkout_present()
734
735
736
set_config('VCS_SPARSE_CHECKOUT', vcs_sparse_checkout)
737
738
# The application/project to build
739
# ==============================================================
740
option('--enable-application', nargs=1, env='MOZ_BUILD_APP',
741
help='Application to build. Same as --enable-project.')
742
743
744
@depends('--enable-application')
745
def application(app):
746
if app:
747
return app
748
749
750
imply_option('--enable-project', application)
751
752
753
@depends(check_build_environment)
754
def default_project(build_env):
755
if build_env.topobjdir.endswith('/js/src'):
756
return 'js'
757
return 'browser'
758
759
760
option('--enable-project', nargs=1, default=default_project,
761
help='Project to build')
762
763
764
# Host and target systems
765
# ==============================================================
766
option('--host', nargs=1, help='Define the system type performing the build')
767
768
option('--target', nargs=1,
769
help='Define the system type where the resulting executables will be '
770
'used')
771
772
773
@imports(_from='mozbuild.configure.constants', _import='CPU')
774
@imports(_from='mozbuild.configure.constants', _import='CPU_bitness')
775
@imports(_from='mozbuild.configure.constants', _import='Endianness')
776
@imports(_from='mozbuild.configure.constants', _import='Kernel')
777
@imports(_from='mozbuild.configure.constants', _import='OS')
778
@imports(_from='__builtin__', _import='ValueError')
779
def split_triplet(triplet):
780
# The standard triplet is defined as
781
# CPU_TYPE-VENDOR-OPERATING_SYSTEM
782
# There is also a quartet form:
783
# CPU_TYPE-VENDOR-KERNEL-OPERATING_SYSTEM
784
# But we can consider the "KERNEL-OPERATING_SYSTEM" as one.
785
# Additionally, some may omit "unknown" when the vendor
786
# is not specified and emit
787
# CPU_TYPE-OPERATING_SYSTEM
788
vendor = 'unknown'
789
parts = triplet.split('-', 2)
790
if len(parts) == 3:
791
cpu, vendor, os = parts
792
elif len(parts) == 2:
793
cpu, os = parts
794
else:
795
raise ValueError("Unexpected triplet string: %s" % triplet)
796
797
# Autoconf uses config.sub to validate and canonicalize those triplets,
798
# but the granularity of its results has never been satisfying to our
799
# use, so we've had our own, different, canonicalization. We've also
800
# historically not been very consistent with how we use the canonicalized
801
# values. Hopefully, this will help us make things better.
802
# The tests are inherited from our decades-old autoconf-based configure,
803
# which can probably be improved/cleaned up because they are based on a
804
# mix of uname and config.guess output, while we now only use the latter,
805
# which presumably has a cleaner and leaner output. Let's refine later.
806
os = os.replace('/', '_')
807
if 'android' in os:
808
canonical_os = 'Android'
809
canonical_kernel = 'Linux'
810
elif os.startswith('linux'):
811
canonical_os = 'GNU'
812
canonical_kernel = 'Linux'
813
elif os.startswith('kfreebsd') and os.endswith('-gnu'):
814
canonical_os = 'GNU'
815
canonical_kernel = 'kFreeBSD'
816
elif os.startswith('gnu'):
817
canonical_os = canonical_kernel = 'GNU'
818
elif os.startswith('mingw'):
819
canonical_os = canonical_kernel = 'WINNT'
820
elif os.startswith('darwin'):
821
canonical_kernel = 'Darwin'
822
canonical_os = 'OSX'
823
elif os.startswith('ios'):
824
canonical_kernel = 'Darwin'
825
canonical_os = 'iOS'
826
elif os.startswith('dragonfly'):
827
canonical_os = canonical_kernel = 'DragonFly'
828
elif os.startswith('freebsd'):
829
canonical_os = canonical_kernel = 'FreeBSD'
830
elif os.startswith('netbsd'):
831
canonical_os = canonical_kernel = 'NetBSD'
832
elif os.startswith('openbsd'):
833
canonical_os = canonical_kernel = 'OpenBSD'
834
elif os.startswith('solaris'):
835
canonical_os = canonical_kernel = 'SunOS'
836
else:
837
raise ValueError('Unknown OS: %s' % os)
838
839
# The CPU granularity is probably not enough. Moving more things from
840
# old-configure will tell us if we need more
841
if cpu.endswith('86') or (cpu.startswith('i') and '86' in cpu):
842
canonical_cpu = 'x86'
843
endianness = 'little'
844
elif cpu in ('x86_64', 'ia64'):
845
canonical_cpu = cpu
846
endianness = 'little'
847
elif cpu in ('s390', 's390x'):
848
canonical_cpu = cpu
849
endianness = 'big'
850
elif cpu in ('powerpc64', 'ppc64', 'powerpc64le', 'ppc64le'):
851
canonical_cpu = 'ppc64'
852
endianness = 'little' if 'le' in cpu else 'big'
853
elif cpu in ('powerpc', 'ppc', 'rs6000') or cpu.startswith('powerpc'):
854
canonical_cpu = 'ppc'
855
endianness = 'big'
856
elif cpu in ('Alpha', 'alpha', 'ALPHA'):
857
canonical_cpu = 'Alpha'
858
endianness = 'little'
859
elif cpu.startswith('hppa') or cpu == 'parisc':
860
canonical_cpu = 'hppa'
861
endianness = 'big'
862
elif cpu.startswith('sparc64') or cpu.startswith('sparcv9'):
863
canonical_cpu = 'sparc64'
864
endianness = 'big'
865
elif cpu.startswith('sparc') or cpu == 'sun4u':
866
canonical_cpu = 'sparc'
867
endianness = 'big'
868
elif cpu.startswith('arm'):
869
canonical_cpu = 'arm'
870
endianness = 'big' if cpu.startswith(('armeb', 'armbe')) else 'little'
871
elif cpu in ('mips', 'mipsel'):
872
canonical_cpu = 'mips32'
873
endianness = 'little' if 'el' in cpu else 'big'
874
elif cpu in ('mips64', 'mips64el'):
875
canonical_cpu = 'mips64'
876
endianness = 'little' if 'el' in cpu else 'big'
877
elif cpu.startswith('aarch64'):
878
canonical_cpu = 'aarch64'
879
endianness = 'little'
880
elif cpu == 'sh4':
881
canonical_cpu = 'sh4'
882
endianness = 'little'
883
else:
884
raise ValueError('Unknown CPU type: %s' % cpu)
885
886
# Toolchains, most notably for cross compilation may use cpu-os
887
# prefixes. We need to be more specific about the LLVM target on Mac
888
# so cross-language LTO will work correctly.
889
890
if os.startswith('darwin'):
891
toolchain = '%s-apple-%s' % (cpu, os)
892
elif canonical_cpu == 'aarch64' and canonical_os == 'WINNT':
893
toolchain = 'aarch64-windows-msvc'
894
else:
895
toolchain = '%s-%s' % (cpu, os)
896
897
return namespace(
898
alias=triplet,
899
cpu=CPU(canonical_cpu),
900
bitness=CPU_bitness[canonical_cpu],
901
kernel=Kernel(canonical_kernel),
902
os=OS(canonical_os),
903
endianness=Endianness(endianness),
904
raw_cpu=cpu,
905
raw_os=os,
906
toolchain=toolchain,
907
vendor=vendor,
908
)
909
910
911
# This defines a fake target/host namespace for when running with --help
912
# If either --host or --target is passed on the command line, then fall
913
# back to the real deal.
914
@depends('--help', '--host', '--target')
915
def help_host_target(help, host, target):
916
if help and not host and not target:
917
return namespace(
918
alias='unknown-unknown-unknown',
919
cpu='unknown',
920
bitness='unknown',
921
kernel='unknown',
922
os='unknown',
923
endianness='unknown',
924
raw_cpu='unknown',
925
raw_os='unknown',
926
toolchain='unknown-unknown',
927
)
928
929
930
def config_sub(shell, triplet):
931
config_sub = os.path.join(os.path.dirname(__file__), '..',
932
'autoconf', 'config.sub')
933
return check_cmd_output(shell, config_sub, triplet).strip()
934
935
936
@depends('--host', shell)
937
@checking('for host system type', lambda h: h.alias)
938
@imports('os')
939
@imports('sys')
940
@imports(_from='__builtin__', _import='ValueError')
941
def real_host(value, shell):
942
if not value and sys.platform == 'win32':
943
arch = (os.environ.get('PROCESSOR_ARCHITEW6432') or
944
os.environ.get('PROCESSOR_ARCHITECTURE'))
945
if arch == 'AMD64':
946
return split_triplet('x86_64-pc-mingw32')
947
elif arch == 'x86':
948
return split_triplet('i686-pc-mingw32')
949
950
if not value:
951
config_guess = os.path.join(os.path.dirname(__file__), '..',
952
'autoconf', 'config.guess')
953
host = check_cmd_output(shell, config_guess).strip()
954
try:
955
return split_triplet(host)
956
except ValueError:
957
pass
958
else:
959
host = value[0]
960
961
host = config_sub(shell, host)
962
963
try:
964
return split_triplet(host)
965
except ValueError as e:
966
die(e.message)
967
968
969
host = help_host_target | real_host
970
971
972
@depends('--target', real_host, shell, '--enable-project', '--enable-application')
973
@checking('for target system type', lambda t: t.alias)
974
@imports(_from='__builtin__', _import='ValueError')
975
def real_target(value, host, shell, project, application):
976
# Because --enable-project is implied by --enable-application, and
977
# implied options are not currently handled during --help, which is
978
# used get the build target in mozbuild.base, we manually check
979
# whether --enable-application was given, and fall back to
980
# --enable-project if not. Both can't be given contradictory values
981
# under normal circumstances, so it's fine.
982
if application:
983
project = application[0]
984
elif project:
985
project = project[0]
986
if not value:
987
if project == 'mobile/android':
988
return split_triplet('arm-unknown-linux-androideabi')
989
return host
990
# If --target was only given a cpu arch, expand it with the
991
# non-cpu part of the host. For mobile/android, expand it with
992
# unknown-linux-android.
993
target = value[0]
994
if '-' not in target:
995
if project == 'mobile/android':
996
rest = 'unknown-linux-android'
997
if target.startswith('arm'):
998
rest += 'eabi'
999
else:
1000
cpu, rest = host.alias.split('-', 1)
1001
target = '-'.join((target, rest))
1002
try:
1003
return split_triplet(target)
1004
except ValueError:
1005
pass
1006
1007
try:
1008
return split_triplet(config_sub(shell, target))
1009
except ValueError as e:
1010
die(e.message)
1011
1012
1013
target = help_host_target | real_target
1014
1015
1016
@depends(host, target)
1017
@checking('whether cross compiling')
1018
def cross_compiling(host, target):
1019
return host != target
1020
1021
1022
set_config('CROSS_COMPILE', cross_compiling)
1023
set_define('CROSS_COMPILE', cross_compiling)
1024
add_old_configure_assignment('CROSS_COMPILE', cross_compiling)
1025
1026
1027
@depends(target)
1028
def have_64_bit(target):
1029
if target.bitness == 64:
1030
return True
1031
1032
1033
set_config('HAVE_64BIT_BUILD', have_64_bit)
1034
set_define('HAVE_64BIT_BUILD', have_64_bit)
1035
add_old_configure_assignment('HAVE_64BIT_BUILD', have_64_bit)
1036
1037
1038
@depends(host)
1039
def host_os_kernel_major_version(host):
1040
versions = host.raw_os.split('.')
1041
version = ''.join(x for x in versions[0] if x.isdigit())
1042
return version
1043
1044
1045
set_config('HOST_MAJOR_VERSION', host_os_kernel_major_version)
1046
1047
# Autoconf needs these set
1048
1049
1050
@depends(host)
1051
def host_for_old_configure(host):
1052
return '--host=%s' % host.alias
1053
1054
1055
add_old_configure_arg(host_for_old_configure)
1056
1057
1058
@depends(target)
1059
def target_for_old_configure(target):
1060
target_alias = target.alias
1061
# old-configure does plenty of tests against $target and $target_os
1062
# and expects darwin for iOS, so make it happy.
1063
if target.os == 'iOS':
1064
target_alias = target_alias.replace('-ios', '-darwin')
1065
return '--target=%s' % target_alias
1066
1067
1068
add_old_configure_arg(target_for_old_configure)
1069
1070
1071
# These variables are for compatibility with the current moz.builds and
1072
# old-configure. Eventually, we'll want to canonicalize better.
1073
@depends(target)
1074
def target_variables(target):
1075
if target.kernel == 'kFreeBSD':
1076
os_target = 'GNU/kFreeBSD'
1077
os_arch = 'GNU_kFreeBSD'
1078
elif target.kernel == 'Darwin' or (target.kernel == 'Linux' and
1079
target.os == 'GNU'):
1080
os_target = target.kernel
1081
os_arch = target.kernel
1082
else:
1083
os_target = target.os
1084
os_arch = target.kernel
1085
1086
return namespace(
1087
OS_TARGET=os_target,
1088
OS_ARCH=os_arch,
1089
INTEL_ARCHITECTURE=target.cpu in ('x86', 'x86_64') or None,
1090
)
1091
1092
1093
set_config('OS_TARGET', target_variables.OS_TARGET)
1094
add_old_configure_assignment('OS_TARGET',
1095
target_variables.OS_TARGET)
1096
set_config('OS_ARCH', target_variables.OS_ARCH)
1097
add_old_configure_assignment('OS_ARCH',
1098
target_variables.OS_ARCH)
1099
set_config('CPU_ARCH', target.cpu)
1100
add_old_configure_assignment('CPU_ARCH', target.cpu)
1101
set_config('INTEL_ARCHITECTURE', target_variables.INTEL_ARCHITECTURE)
1102
set_config('TARGET_CPU', target.raw_cpu)
1103
set_config('TARGET_OS', target.raw_os)
1104
set_config('TARGET_ENDIANNESS', target.endianness)
1105
1106
1107
@depends(host)
1108
def host_variables(host):
1109
if host.kernel == 'kFreeBSD':
1110
os_arch = 'GNU_kFreeBSD'
1111
else:
1112
os_arch = host.kernel
1113
return namespace(
1114
HOST_OS_ARCH=os_arch,
1115
)
1116
1117
1118
set_config('HOST_CPU_ARCH', host.cpu)
1119
set_config('HOST_OS_ARCH', host_variables.HOST_OS_ARCH)
1120
add_old_configure_assignment('HOST_OS_ARCH',
1121
host_variables.HOST_OS_ARCH)
1122
1123
1124
@depends(target)
1125
def target_is_windows(target):
1126
if target.kernel == 'WINNT':
1127
return True
1128
1129
1130
set_define('_WINDOWS', target_is_windows)
1131
set_define('WIN32', target_is_windows)
1132
set_define('XP_WIN', target_is_windows)
1133
1134
1135
@depends(target)
1136
def target_is_unix(target):
1137
if target.kernel != 'WINNT':
1138
return True
1139
1140
1141
set_define('XP_UNIX', target_is_unix)
1142
1143
1144
@depends(target)
1145
def target_is_darwin(target):
1146
if target.kernel == 'Darwin':
1147
return True
1148
1149
1150
set_define('XP_DARWIN', target_is_darwin)
1151
1152
1153
@depends(target)
1154
def target_is_ios(target):
1155
if target.kernel == 'Darwin' and target.os == 'iOS':
1156
return True
1157
1158
1159
set_define('XP_IOS', target_is_ios)
1160
1161
1162
@depends(target)
1163
def target_is_osx(target):
1164
if target.kernel == 'Darwin' and target.os == 'OSX':
1165
return True
1166
1167
1168
set_define('XP_MACOSX', target_is_osx)
1169
1170
1171
@depends(target)
1172
def target_is_linux(target):
1173
if target.kernel == 'Linux':
1174
return True
1175
1176
1177
set_define('XP_LINUX', target_is_linux)
1178
1179
1180
@depends(target)
1181
def target_is_android(target):
1182
if target.os == 'Android':
1183
return True
1184
1185
1186
set_define('ANDROID', target_is_android)
1187
1188
1189
@depends(target)
1190
def target_is_openbsd(target):
1191
if target.kernel == 'OpenBSD':
1192
return True
1193
1194
1195
set_define('XP_OPENBSD', target_is_openbsd)
1196
1197
@depends(target)
1198
def target_is_netbsd(target):
1199
if target.kernel == 'NetBSD':
1200
return True
1201
1202
1203
set_define('XP_NETBSD', target_is_netbsd)
1204
1205
@depends(target)
1206
def target_is_freebsd(target):
1207
if target.kernel == 'FreeBSD':
1208
return True
1209
1210
1211
set_define('XP_FREEBSD', target_is_freebsd)
1212
1213
@depends(target)
1214
def target_is_solaris(target):
1215
if target.kernel == 'SunOS':
1216
return True
1217
1218
1219
set_define('XP_SOLARIS', target_is_solaris)
1220
1221
1222
@depends(target)
1223
def target_is_sparc(target):
1224
if target.cpu == 'sparc64':
1225
return True
1226
1227
set_define('SPARC64', target_is_sparc)
1228
1229
1230
@depends('--enable-project', '--with-external-source-dir',
1231
check_build_environment, '--help')
1232
@imports(_from='os.path', _import='exists')
1233
def include_project_configure(project, external_source_dir, build_env, help):
1234
if not project:
1235
die('--enable-project is required.')
1236
1237
base_dir = build_env.topsrcdir
1238
if external_source_dir:
1239
base_dir = os.path.join(base_dir, external_source_dir[0])
1240
1241
path = os.path.join(base_dir, project[0], 'moz.configure')
1242
if not exists(path):
1243
die('Cannot find project %s', project[0])
1244
return path
1245
1246
1247
@depends(include_project_configure, check_build_environment)
1248
def build_project(include_project_configure, build_env):
1249
ret = os.path.dirname(os.path.relpath(include_project_configure,
1250
build_env.topsrcdir))
1251
return ret
1252
1253
1254
set_config('MOZ_BUILD_APP', build_project)
1255
set_define('MOZ_BUILD_APP', build_project)
1256
add_old_configure_assignment('MOZ_BUILD_APP', build_project)
1257
1258
1259
# This is temporary until js/src/configure and configure are merged.
1260
# Use instead of option() in js/moz.configure and more generally, for
1261
# options that are shared between configure and js/src/configure.
1262
@template
1263
def js_option(*args, **kwargs):
1264
opt = option(*args, **kwargs)
1265
1266
@depends(opt.option, build_project, when=kwargs.get('when'))
1267
def js_option(value, build_project):
1268
if build_project != 'js':
1269
return value.format(opt.option)
1270
1271
add_old_configure_arg(js_option)
1272
1273
1274
js_option(env='MOZILLA_OFFICIAL',
1275
help='Build an official release')
1276
1277
1278
@depends('MOZILLA_OFFICIAL')
1279
def mozilla_official(official):
1280
if official:
1281
return True
1282
1283
1284
set_config('MOZILLA_OFFICIAL', mozilla_official)
1285
set_define('MOZILLA_OFFICIAL', mozilla_official)
1286
add_old_configure_assignment('MOZILLA_OFFICIAL', mozilla_official)
1287
1288
1289
# Allow specifying custom paths to the version files used by the milestone() function below.
1290
option('--with-version-file-path',
1291
nargs=1,
1292
help='Specify a custom path to app version files instead of auto-detecting',
1293
default=None)
1294
1295
@depends('--with-version-file-path')
1296
def version_path(path):
1297
return path
1298
1299
# set RELEASE_OR_BETA and NIGHTLY_BUILD variables depending on the cycle we're in
1300
# The logic works like this:
1301
# - if we have "a1" in GRE_MILESTONE, we're building Nightly (define NIGHTLY_BUILD)
1302
# - otherwise, if we have "a" in GRE_MILESTONE, we're building Nightly or Aurora
1303
# - otherwise, we're building Release/Beta (define RELEASE_OR_BETA)
1304
@depends(check_build_environment, build_project, version_path, '--help')
1305
@imports(_from='__builtin__', _import='open')
1306
@imports('os')
1307
@imports('re')
1308
def milestone(build_env, build_project, version_path, _):
1309
versions = []
1310
paths = ['config/milestone.txt']
1311
if build_project == 'js':
1312
paths = paths * 3
1313
else:
1314
paths += [
1315
'browser/config/version.txt',
1316
'browser/config/version_display.txt',
1317
]
1318
if version_path:
1319
version_path = version_path[0]
1320
else:
1321
version_path = os.path.join(build_project, 'config')
1322
for f in ('version.txt', 'version_display.txt'):
1323
f = os.path.join(version_path, f)
1324
if not os.path.exists(os.path.join(build_env.topsrcdir, f)):
1325
break
1326
paths.append(f)
1327
1328
for p in paths:
1329
with open(os.path.join(build_env.topsrcdir, p), 'r') as fh:
1330
content = fh.read().splitlines()
1331
if not content:
1332
die('Could not find a version number in {}'.format(p))
1333
versions.append(content[-1])
1334
1335
milestone, firefox_version, firefox_version_display = versions[:3]
1336
1337
# version.txt content from the project directory if there is one, otherwise
1338
# the firefox version.
1339
app_version = versions[3] if len(versions) > 3 else firefox_version
1340
# version_display.txt content from the project directory if there is one,
1341
# otherwise version.txt content from the project directory, otherwise the
1342
# firefox version for display.
1343
app_version_display = versions[-1] if len(versions) > 3 else firefox_version_display
1344
1345
is_nightly = is_release_or_beta = is_early_beta_or_earlier = None
1346
1347
if 'a1' in milestone:
1348
is_nightly = True
1349
elif 'a' not in milestone:
1350
is_release_or_beta = True
1351
1352
major_version = milestone.split('.')[0]
1353
m = re.search(r"([ab]\d+)", milestone)
1354
ab_patch = m.group(1) if m else ''
1355
1356
defines = os.path.join(build_env.topsrcdir, 'build', 'defines.sh')
1357
with open(defines, 'r') as fh:
1358
for line in fh.read().splitlines():
1359
line = line.strip()
1360
if not line or line.startswith('#'):
1361
continue
1362
name, _, value = line.partition('=')
1363
name = name.strip()
1364
value = value.strip()
1365
if name != 'EARLY_BETA_OR_EARLIER':
1366
die('Only the EARLY_BETA_OR_EARLIER variable can be set in build/defines.sh')
1367
if value:
1368
is_early_beta_or_earlier = True
1369
1370
# Only expose the major version milestone in the UA string and hide the
1371
# patch leve (bugs 572659 and 870868).
1372
#
1373
# Only expose major milestone and alpha version in the symbolversion
1374
# string; as the name suggests, we use it for symbol versioning on Linux.
1375
return namespace(version=milestone,
1376
uaversion='%s.0' % major_version,
1377
symbolversion='%s%s' % (major_version, ab_patch),
1378
is_nightly=is_nightly,
1379
is_release_or_beta=is_release_or_beta,
1380
is_early_beta_or_earlier=is_early_beta_or_earlier,
1381
app_version=app_version,
1382
app_version_display=app_version_display)
1383
1384
1385
set_config('GRE_MILESTONE', milestone.version)
1386
set_config('NIGHTLY_BUILD', milestone.is_nightly)
1387
set_define('NIGHTLY_BUILD', milestone.is_nightly)
1388
set_config('RELEASE_OR_BETA', milestone.is_release_or_beta)
1389
set_define('RELEASE_OR_BETA', milestone.is_release_or_beta)
1390
add_old_configure_assignment('RELEASE_OR_BETA',
1391
milestone.is_release_or_beta)
1392
set_config('EARLY_BETA_OR_EARLIER', milestone.is_early_beta_or_earlier)
1393
set_define('EARLY_BETA_OR_EARLIER', milestone.is_early_beta_or_earlier)
1394
add_old_configure_assignment('EARLY_BETA_OR_EARLIER',
1395
milestone.is_early_beta_or_earlier)
1396
set_define('MOZILLA_VERSION', depends(milestone)(lambda m: '"%s"' % m.version))
1397
set_config('MOZILLA_VERSION', milestone.version)
1398
set_define('MOZILLA_VERSION_U', milestone.version)
1399
set_define('MOZILLA_UAVERSION', depends(milestone)(lambda m: '"%s"' % m.uaversion))
1400
set_config('MOZILLA_SYMBOLVERSION', milestone.symbolversion)
1401
# JS configure still wants to look at these.
1402
add_old_configure_assignment('MOZILLA_VERSION', milestone.version)
1403
add_old_configure_assignment('MOZILLA_SYMBOLVERSION', milestone.symbolversion)
1404
1405
set_config('MOZ_APP_VERSION', milestone.app_version)
1406
set_config('MOZ_APP_VERSION_DISPLAY', milestone.app_version_display)
1407
add_old_configure_assignment('MOZ_APP_VERSION', milestone.app_version)
1408
1409
1410
# Dummy function for availability in toolkit/moz.configure. Overridden in
1411
# mobile/android/moz.configure.
1412
@depends(milestone.is_nightly)
1413
def fennec_nightly(is_nightly):
1414
return is_nightly
1415
1416
1417
# The app update channel is 'default' when not supplied. The value is used in
1418
# the application's confvars.sh (and is made available to a project specific
1419
# moz.configure).
1420
option('--enable-update-channel',
1421
nargs=1,
1422
help='Select application update channel',
1423
default='default')
1424
1425
1426
@depends('--enable-update-channel')
1427
def update_channel(channel):
1428
if not channel or channel[0] == '':
1429
return 'default'
1430
return channel[0].lower()
1431
1432
1433
set_config('MOZ_UPDATE_CHANNEL', update_channel)
1434
set_define('MOZ_UPDATE_CHANNEL', update_channel)
1435
add_old_configure_assignment('MOZ_UPDATE_CHANNEL', update_channel)
1436
1437
1438
js_option(env='MOZBUILD_STATE_PATH', nargs=1,
1439
help='Path to a persistent state directory for the build system '
1440
'and related tools')
1441
1442
1443
@depends('MOZBUILD_STATE_PATH', '--help')
1444
@imports('os')
1445
def mozbuild_state_path(path, _):
1446
if path:
1447
return path[0]
1448
return os.path.expanduser(os.path.join('~', '.mozbuild'))
1449
1450
1451
# A template providing a shorthand for setting a variable. The created
1452
# option will only be settable with imply_option.
1453
# It is expected that a project-specific moz.configure will call imply_option
1454
# to set a value other than the default.
1455
# If required, the set_as_define and set_for_old_configure arguments
1456
# will additionally cause the variable to be set using set_define and
1457
# add_old_configure_assignment. util.configure would be an appropriate place for
1458
# this, but it uses add_old_configure_assignment, which is defined in this file.
1459
@template
1460
def project_flag(env=None, set_for_old_configure=False,
1461
set_as_define=False, **kwargs):
1462
1463
if not env:
1464
configure_error(
1465
"A project_flag must be passed a variable name to set.")
1466
1467
opt = option(env=env, possible_origins=('implied',), **kwargs)
1468
1469
@depends(opt.option)
1470
def option_implementation(value):
1471
if value:
1472
if len(value):
1473
return value
1474
return bool(value)
1475
1476
set_config(env, option_implementation)
1477
if set_as_define:
1478
set_define(env, option_implementation)
1479
if set_for_old_configure:
1480
add_old_configure_assignment(env, option_implementation)
1481
1482
# milestone.is_nightly corresponds to cases NIGHTLY_BUILD is set.
1483
1484
1485
@depends(milestone)
1486
def enabled_in_nightly(milestone):
1487
return milestone.is_nightly