зеркало из https://github.com/mozilla/gecko-dev.git
461 строка
16 KiB
Python
461 строка
16 KiB
Python
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
|
# vim: set filetype=python:
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
option(env='AUTOCONF', nargs=1, help='Path to autoconf 2.13')
|
|
|
|
|
|
@depends(mozconfig, 'AUTOCONF')
|
|
@checking('for autoconf')
|
|
@imports(_from='os.path', _import='exists')
|
|
@imports('re')
|
|
def autoconf(mozconfig, autoconf):
|
|
mozconfig_autoconf = None
|
|
if mozconfig['path']:
|
|
make_extra = mozconfig['make_extra']
|
|
if make_extra:
|
|
for assignment in make_extra:
|
|
m = re.match('(?:export\s+)?AUTOCONF\s*:?=\s*(.+)$',
|
|
assignment)
|
|
if m:
|
|
mozconfig_autoconf = m.group(1)
|
|
# Check whether we've exported any known-broken variables.
|
|
m = re.match('(?:export\s+)?(?:CC|CXX)\s*:?=\s*(?:.+)$',
|
|
assignment)
|
|
if m:
|
|
die('Setting the value of CC or CXX with "mk_add_options" '
|
|
'can cause the build to fail unexpectedly. Please '
|
|
'change your mozconfig to instead use '
|
|
'"ac_add_options", e.g. ac_add_options '
|
|
'CC=my-custom-cc".')
|
|
|
|
autoconf = autoconf[0] if autoconf else None
|
|
|
|
for ac in (mozconfig_autoconf, autoconf, 'autoconf-2.13', 'autoconf2.13',
|
|
'autoconf213'):
|
|
if ac:
|
|
autoconf = find_program(ac)
|
|
if autoconf:
|
|
break
|
|
else:
|
|
fink = find_program('fink')
|
|
if fink:
|
|
autoconf = os.path.normpath(os.path.join(
|
|
fink, '..', '..', 'lib', 'autoconf2.13', 'bin', 'autoconf'))
|
|
else:
|
|
brew = find_program('brew')
|
|
if brew:
|
|
autoconf = os.path.normpath(os.path.join(
|
|
brew, '..', '..', 'Cellar', 'autoconf213', '2.13', 'bin',
|
|
'autoconf213'))
|
|
|
|
if not autoconf:
|
|
die('Could not find autoconf 2.13')
|
|
|
|
if not exists(autoconf):
|
|
die('Could not find autoconf 2.13 at %s', autoconf)
|
|
|
|
return autoconf
|
|
|
|
|
|
set_config('AUTOCONF', autoconf)
|
|
|
|
|
|
@depends(mozconfig)
|
|
def prepare_mozconfig(mozconfig):
|
|
if mozconfig['path']:
|
|
items = {}
|
|
for key, value in mozconfig['vars']['added'].items():
|
|
items[key] = (value, 'added')
|
|
for key, (old, value) in mozconfig['vars']['modified'].items():
|
|
items[key] = (value, 'modified')
|
|
for t in ('env', 'vars'):
|
|
for key in mozconfig[t]['removed'].keys():
|
|
items[key] = (None, 'removed ' + t)
|
|
return items
|
|
|
|
|
|
@depends('OLD_CONFIGURE', 'MOZILLABUILD', prepare_mozconfig, autoconf, check_build_environment,
|
|
shell, old_configure_assignments, build_project)
|
|
@imports(_from='__builtin__', _import='open')
|
|
@imports(_from='__builtin__', _import='print')
|
|
@imports(_from='__builtin__', _import='sorted')
|
|
@imports('glob')
|
|
@imports('itertools')
|
|
@imports('subprocess')
|
|
# Import getmtime without overwriting the sandbox os.path.
|
|
@imports(_from='os.path', _import='getmtime')
|
|
@imports(_from='os.path', _import='exists')
|
|
@imports(_from='mozbuild.shellutil', _import='quote')
|
|
@imports(_from='tempfile', _import='NamedTemporaryFile')
|
|
@imports(_from='os', _import='environ')
|
|
@imports(_from='os', _import='remove')
|
|
@imports(_from='os', _import='rename')
|
|
@imports(_from='subprocess', _import='CalledProcessError')
|
|
@imports(_from='__builtin__', _import='OSError')
|
|
def prepare_configure(old_configure, mozillabuild, mozconfig, autoconf, build_env, shell,
|
|
old_configure_assignments, build_project):
|
|
# os.path.abspath in the sandbox will ensure forward slashes on Windows,
|
|
# which is actually necessary because this path actually ends up literally
|
|
# as $0, and backslashes there breaks autoconf's detection of the source
|
|
# directory.
|
|
old_configure = os.path.abspath(old_configure[0])
|
|
if build_project == 'js':
|
|
old_configure_dir = os.path.dirname(old_configure)
|
|
if not old_configure_dir.endswith('/js/src'):
|
|
old_configure = os.path.join(old_configure_dir, 'js', 'src',
|
|
os.path.basename(old_configure))
|
|
|
|
refresh = True
|
|
if exists(old_configure):
|
|
mtime = getmtime(old_configure)
|
|
aclocal = os.path.join(build_env.topsrcdir, 'build', 'autoconf',
|
|
'*.m4')
|
|
for input in itertools.chain(
|
|
(old_configure + '.in',
|
|
os.path.join(os.path.dirname(old_configure), 'aclocal.m4')),
|
|
glob.iglob(aclocal),
|
|
):
|
|
if getmtime(input) > mtime:
|
|
break
|
|
else:
|
|
refresh = False
|
|
|
|
if refresh:
|
|
log.info('Refreshing %s with %s', old_configure, autoconf)
|
|
|
|
try:
|
|
script = subprocess.check_output([
|
|
shell, autoconf,
|
|
'--localdir=%s' % os.path.dirname(old_configure),
|
|
old_configure + '.in'])
|
|
except CalledProcessError as exc:
|
|
# Autoconf on win32 may break due to a bad $PATH. Let the user know
|
|
# their $PATH is suspect.
|
|
if mozillabuild:
|
|
mozillabuild_path = normsep(mozillabuild[0])
|
|
sh_path = normsep(find_program('sh'))
|
|
if mozillabuild_path not in sh_path:
|
|
log.warning("The '{}msys/bin' directory is not first in $PATH. "
|
|
"This may cause autoconf to fail. ($PATH is currently "
|
|
"set to: {})".format(mozillabuild_path, environ[
|
|
'PATH']))
|
|
die('autoconf exited with return code {}'.format(exc.returncode))
|
|
|
|
if not script:
|
|
die('Generated old-configure is empty! Check that your autoconf 2.13 program works!')
|
|
|
|
# Make old-configure append to config.log, where we put our own log.
|
|
# This could be done with a m4 macro, but it's way easier this way
|
|
script = script.replace('>./config.log', '>>${CONFIG_LOG=./config.log}')
|
|
|
|
with NamedTemporaryFile(mode='wb', prefix=os.path.basename(old_configure),
|
|
dir=os.path.dirname(old_configure), delete=False) as fh:
|
|
fh.write(script)
|
|
|
|
try:
|
|
rename(fh.name, old_configure)
|
|
except OSError:
|
|
try:
|
|
# Likely the file already existed (on Windows). Retry after removing it.
|
|
remove(old_configure)
|
|
rename(fh.name, old_configure)
|
|
except OSError as e:
|
|
die('Failed re-creating old-configure: %s' % e.message)
|
|
|
|
cmd = [shell, old_configure]
|
|
with open('old-configure.vars', 'w') as out:
|
|
log.debug('Injecting the following to old-configure:')
|
|
|
|
def inject(command):
|
|
print(command, file=out) # noqa Python 2vs3
|
|
log.debug('| %s', command)
|
|
|
|
if mozconfig:
|
|
inject('# start of mozconfig values')
|
|
for key, (value, action) in sorted(mozconfig.items()):
|
|
if action.startswith('removed '):
|
|
inject("unset %s # from %s" % (
|
|
key, action[len('removed '):]))
|
|
else:
|
|
inject("%s=%s # %s" % (key, quote(value), action))
|
|
|
|
inject('# end of mozconfig values')
|
|
|
|
# Autoconf is special, because it might be passed from
|
|
# mozconfig['make_extra'], which we don't pass automatically above.
|
|
inject('export AUTOCONF=%s' % quote(autoconf))
|
|
|
|
for k, v in old_configure_assignments:
|
|
inject('%s=%s' % (k, quote(v)))
|
|
|
|
return cmd
|
|
|
|
|
|
@template
|
|
def old_configure_options(*options):
|
|
for opt in options:
|
|
option(opt, nargs='*', help='Help missing for old configure options')
|
|
|
|
@dependable
|
|
def all_options():
|
|
return list(options)
|
|
|
|
return depends(extra_old_configure_args, all_options, *options)
|
|
|
|
|
|
@old_configure_options(
|
|
'--cache-file',
|
|
'--datadir',
|
|
'--enable-cookies',
|
|
'--enable-cpp-rtti',
|
|
'--enable-crashreporter',
|
|
'--enable-dbus',
|
|
'--enable-debug-js-modules',
|
|
'--enable-directshow',
|
|
'--enable-dtrace',
|
|
'--enable-dump-painting',
|
|
'--enable-extensions',
|
|
'--enable-feeds',
|
|
'--enable-gconf',
|
|
'--enable-icf',
|
|
'--enable-install-strip',
|
|
'--enable-ios-target',
|
|
'--enable-libjpeg-turbo',
|
|
'--enable-libproxy',
|
|
'--enable-llvm-hacks',
|
|
'--enable-logrefcnt',
|
|
'--enable-mobile-optimize',
|
|
'--enable-necko-wifi',
|
|
'--enable-negotiateauth',
|
|
'--enable-nfc',
|
|
'--enable-nspr-build',
|
|
'--enable-official-branding',
|
|
'--enable-parental-controls',
|
|
'--enable-pref-extensions',
|
|
'--enable-readline',
|
|
'--enable-sandbox',
|
|
'--enable-startup-notification',
|
|
'--enable-startupcache',
|
|
'--enable-strip',
|
|
'--enable-synth-pico',
|
|
'--enable-system-cairo',
|
|
'--enable-system-extension-dirs',
|
|
'--enable-system-pixman',
|
|
'--enable-universalchardet',
|
|
'--enable-updater',
|
|
'--enable-xul',
|
|
'--enable-zipwriter',
|
|
'--includedir',
|
|
'--libdir',
|
|
'--prefix',
|
|
'--with-android-distribution-directory',
|
|
'--with-android-max-sdk',
|
|
'--with-android-min-sdk',
|
|
'--with-app-basename',
|
|
'--with-app-name',
|
|
'--with-branding',
|
|
'--with-cross-lib',
|
|
'--with-debug-label',
|
|
'--with-distribution-id',
|
|
'--with-doc-include-dirs',
|
|
'--with-doc-input-dirs',
|
|
'--with-doc-output-dir',
|
|
'--with-intl-api',
|
|
'--with-ios-sdk',
|
|
'--with-jitreport-granularity',
|
|
'--with-macbundlename-prefix',
|
|
'--with-nspr-cflags',
|
|
'--with-nspr-exec-prefix',
|
|
'--with-nspr-libs',
|
|
'--with-nspr-prefix',
|
|
'--with-nss-exec-prefix',
|
|
'--with-nss-prefix',
|
|
'--with-qemu-exe',
|
|
'--with-sixgill',
|
|
'--with-system-bz2',
|
|
'--with-system-icu',
|
|
'--with-system-libevent',
|
|
'--with-system-nspr',
|
|
'--with-system-nss',
|
|
'--with-system-png',
|
|
'--with-system-zlib',
|
|
'--with-unify-dist',
|
|
'--with-user-appdir',
|
|
'--x-includes',
|
|
'--x-libraries',
|
|
)
|
|
def prepare_configure_options(extra_old_configure_args, all_options, *options):
|
|
# old-configure only supports the options listed in @old_configure_options
|
|
# so we don't need to pass it every single option we've been passed. Only
|
|
# the ones that are not supported by python configure need to.
|
|
options = [
|
|
value.format(name)
|
|
for name, value in zip(all_options, options)
|
|
if value.origin != 'default'
|
|
]
|
|
|
|
extra_env = {}
|
|
|
|
# We also pass it the options from js/moz.configure so that it can pass
|
|
# them down to js/src/configure. Note this list is empty when running
|
|
# js/src/configure, in which case we don't need to pass those options
|
|
# to old-configure since old-configure doesn't handle them anyways.
|
|
if extra_old_configure_args:
|
|
for arg in extra_old_configure_args:
|
|
if arg.startswith('-'):
|
|
options.append(arg)
|
|
else:
|
|
k, v = arg.split('=', 1)
|
|
extra_env[k] = v
|
|
|
|
return namespace(options=options, extra_env=extra_env, all_options=all_options)
|
|
|
|
|
|
@depends(prepare_configure, prepare_configure_options, altered_path)
|
|
@imports(_from='__builtin__', _import='compile')
|
|
@imports(_from='__builtin__', _import='open')
|
|
@imports('logging')
|
|
@imports('os')
|
|
@imports('subprocess')
|
|
@imports('sys')
|
|
@imports(_from='mozbuild.shellutil', _import='quote')
|
|
@imports(_from='mozbuild.shellutil', _import='split')
|
|
@imports(_from='six', _import='exec_')
|
|
@imports(_from='six', _import='string_types')
|
|
def old_configure(prepare_configure, prepare_configure_options, altered_path):
|
|
cmd = prepare_configure + prepare_configure_options.options
|
|
extra_env = prepare_configure_options.extra_env
|
|
|
|
env = dict(os.environ)
|
|
if extra_env:
|
|
env.update(extra_env)
|
|
|
|
# For debugging purpose, in case it's not what we'd expect.
|
|
log.debug('Running %s', quote(*cmd))
|
|
if extra_env:
|
|
log.debug('with extra environment: %s',
|
|
' '.join('%s=%s' % pair for pair in extra_env.iteritems()))
|
|
|
|
# Our logging goes to config.log, the same file old.configure uses.
|
|
# We can't share the handle on the file, so close it.
|
|
logger = logging.getLogger('moz.configure')
|
|
config_log = None
|
|
for handler in logger.handlers:
|
|
if isinstance(handler, logging.FileHandler):
|
|
config_log = handler
|
|
config_log.close()
|
|
logger.removeHandler(config_log)
|
|
env['CONFIG_LOG'] = config_log.baseFilename
|
|
log_size = os.path.getsize(config_log.baseFilename)
|
|
break
|
|
|
|
if altered_path:
|
|
env['PATH'] = altered_path
|
|
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
|
env=env)
|
|
while True:
|
|
line = proc.stdout.readline()
|
|
if not line:
|
|
break
|
|
log.info(line.rstrip())
|
|
|
|
ret = proc.wait()
|
|
if ret:
|
|
with log.queue_debug():
|
|
if config_log:
|
|
with open(config_log.baseFilename, 'r') as fh:
|
|
fh.seek(log_size)
|
|
for line in fh:
|
|
log.debug(line.rstrip())
|
|
log.error('old-configure failed')
|
|
sys.exit(ret)
|
|
|
|
if config_log:
|
|
# Create a new handler in append mode
|
|
handler = logging.FileHandler(config_log.baseFilename, mode='a', delay=True)
|
|
handler.setFormatter(config_log.formatter)
|
|
logger.addHandler(handler)
|
|
|
|
raw_config = {
|
|
'split': split,
|
|
'unique_list': unique_list,
|
|
}
|
|
with open('config.data', 'r') as fh:
|
|
code = compile(fh.read(), 'config.data', 'exec')
|
|
exec_(code, raw_config)
|
|
|
|
# Ensure all the flags known to old-configure appear in the
|
|
# @old_configure_options above.
|
|
all_options = set(prepare_configure_options.all_options)
|
|
for flag in raw_config['flags']:
|
|
if flag not in all_options:
|
|
die('Missing option in `@old_configure_options` in %s: %s',
|
|
__file__, flag)
|
|
|
|
# If the code execution above fails, we want to keep the file around for
|
|
# debugging.
|
|
os.remove('config.data')
|
|
|
|
for c in ('substs', 'defines'):
|
|
raw_config[c] = [
|
|
(k[1:-1], v[1:-1] if isinstance(v, string_types) else v)
|
|
for k, v in raw_config[c]
|
|
]
|
|
|
|
return raw_config
|
|
|
|
|
|
# set_config is only available in the global namespace, not directly in
|
|
# @depends functions, but we do need to enumerate the result of
|
|
# old_configure, so we cheat.
|
|
@imports('__sandbox__')
|
|
def set_old_configure_config(name, value):
|
|
__sandbox__.set_config_impl(name, value)
|
|
|
|
# Same as set_old_configure_config, but for set_define.
|
|
|
|
|
|
@imports('__sandbox__')
|
|
def set_old_configure_define(name, value):
|
|
__sandbox__.set_define_impl(name, value)
|
|
|
|
|
|
@depends(old_configure)
|
|
@imports(_from='six', _import='iteritems')
|
|
def post_old_configure(raw_config):
|
|
for k, v in raw_config['substs']:
|
|
set_old_configure_config(k, v)
|
|
|
|
for k, v in iteritems(dict(raw_config['defines'])):
|
|
set_old_configure_define(k, v)
|
|
|
|
set_old_configure_config('non_global_defines',
|
|
raw_config['non_global_defines'])
|
|
|
|
|
|
# Assuming no other option is declared after this function, handle the
|
|
# env options that were injected by mozconfig_options by creating dummy
|
|
# Option instances and having the sandbox's CommandLineHelper handle
|
|
# them. We only do so for options that haven't been declared so far,
|
|
# which should be a proxy for the options that old-configure handles
|
|
# and that we don't know anything about.
|
|
@depends('--help')
|
|
@imports('__sandbox__')
|
|
@imports(_from='mozbuild.configure.options', _import='Option')
|
|
def remaining_mozconfig_options(_):
|
|
helper = __sandbox__._helper
|
|
for arg in helper:
|
|
if helper._origins[arg] != 'mozconfig':
|
|
continue
|
|
name = arg.split('=', 1)[0]
|
|
if name.isupper() and name not in __sandbox__._options:
|
|
option = Option(env=name, nargs='*', help=name)
|
|
helper.handle(option)
|
|
|
|
# Please do not add anything after remaining_mozconfig_options()
|