mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-10-31 16:28:05 +02:00 
			
		
		
		
	 fcd16177c6
			
		
	
	
		fcd16177c6
		
	
	
	
	
		
			
			`mach configure` currently runs the equivalent to `make -f client.mk`. This is history, and essentially does the following: - Create `configure` and `js/src/configure` from `configure.in` and `js/src/configure.in` respectively. - Create the objdir. - Run `configure` from the objdir. The `configure` script is, nowadays, only really used as a means to set OLD_CONFIGURE (and also for people who want to run `configure`, literally, as in the `configure; make` workflow). `mach configure` actually doesn't need it. Neither does recursing into `js/src` require `js/src/configure`, since bug 1520340 (and now as of bug 1669633, we don't even recurse). Because configure.py can actually derive OLD_CONFIGURE on its own (except for `js/src/configure`, but `mach configure` doesn't run that), we don't really need `configure` for `mach configure`. So all in all, we're at a point in history where it's straightforward to just initiate configure.py from mach configure, so we just do that. And in the hypothetical case where the `mach configure` code is somehow running in python2, we get the mach virtualenv python3 and use it to execute `configure.py`. Differential Revision: https://phabricator.services.mozilla.com/D93741
		
			
				
	
	
		
			216 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			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/.
 | |
| 
 | |
| from __future__ import absolute_import, print_function, unicode_literals
 | |
| 
 | |
| import codecs
 | |
| import errno
 | |
| import io
 | |
| import itertools
 | |
| import logging
 | |
| import os
 | |
| import sys
 | |
| import textwrap
 | |
| 
 | |
| 
 | |
| try:
 | |
|     from collections.abc import Iterable
 | |
| except ImportError:
 | |
|     from collections import Iterable
 | |
| 
 | |
| 
 | |
| base_dir = os.path.abspath(os.path.dirname(__file__))
 | |
| sys.path.insert(0, os.path.join(base_dir, 'python', 'mozboot'))
 | |
| sys.path.insert(0, os.path.join(base_dir, 'python', 'mozbuild'))
 | |
| sys.path.insert(0, os.path.join(base_dir, 'third_party', 'python', 'six'))
 | |
| from mozbuild.configure import (
 | |
|     ConfigureSandbox,
 | |
|     TRACE,
 | |
| )
 | |
| from mozbuild.pythonutil import iter_modules_in_path
 | |
| from mozbuild.backend.configenvironment import PartialConfigEnvironment
 | |
| from mozbuild.util import (
 | |
|     write_indented_repr,
 | |
| )
 | |
| import mozpack.path as mozpath
 | |
| import six
 | |
| 
 | |
| 
 | |
| def main(argv):
 | |
|     config = {}
 | |
| 
 | |
|     if 'OLD_CONFIGURE' not in os.environ:
 | |
|         os.environ['OLD_CONFIGURE'] = os.path.join(base_dir, 'old-configure')
 | |
| 
 | |
|     sandbox = ConfigureSandbox(config, os.environ, argv)
 | |
| 
 | |
|     clobber_file = 'CLOBBER'
 | |
|     if not os.path.exists(clobber_file):
 | |
|         # Simply touch the file.
 | |
|         with open(clobber_file, 'a'):
 | |
|             pass
 | |
| 
 | |
|     if os.environ.get('MOZ_CONFIGURE_TRACE'):
 | |
|         sandbox._logger.setLevel(TRACE)
 | |
| 
 | |
|     sandbox.run(os.path.join(os.path.dirname(__file__), 'moz.configure'))
 | |
| 
 | |
|     if sandbox._help:
 | |
|         return 0
 | |
| 
 | |
|     logging.getLogger('moz.configure').info('Creating config.status')
 | |
| 
 | |
|     old_js_configure_substs = config.pop('OLD_JS_CONFIGURE_SUBSTS', None)
 | |
|     old_js_configure_defines = config.pop('OLD_JS_CONFIGURE_DEFINES', None)
 | |
|     if old_js_configure_substs or old_js_configure_defines:
 | |
|         js_config = config.copy()
 | |
|         pwd = os.getcwd()
 | |
|         try:
 | |
|             try:
 | |
|                 os.makedirs('js/src')
 | |
|             except OSError as e:
 | |
|                 if e.errno != errno.EEXIST:
 | |
|                     raise
 | |
| 
 | |
|             os.chdir('js/src')
 | |
|             js_config['OLD_CONFIGURE_SUBSTS'] = old_js_configure_substs
 | |
|             js_config['OLD_CONFIGURE_DEFINES'] = old_js_configure_defines
 | |
|             # The build system frontend expects $objdir/js/src/config.status
 | |
|             # to have $objdir/js/src as topobjdir.
 | |
|             # We want forward slashes on all platforms.
 | |
|             js_config['TOPOBJDIR'] += '/js/src'
 | |
|             config_status(js_config, execute=False)
 | |
|         finally:
 | |
|             os.chdir(pwd)
 | |
| 
 | |
|     return config_status(config)
 | |
| 
 | |
| 
 | |
| def check_unicode(obj):
 | |
|     '''Recursively check that all strings in the object are unicode strings.'''
 | |
|     if isinstance(obj, dict):
 | |
|         result = True
 | |
|         for k, v in six.iteritems(obj):
 | |
|             if not check_unicode(k):
 | |
|                 print("%s key is not unicode." % k, file=sys.stderr)
 | |
|                 result = False
 | |
|             elif not check_unicode(v):
 | |
|                 print("%s value is not unicode." % k, file=sys.stderr)
 | |
|                 result = False
 | |
|         return result
 | |
|     if isinstance(obj, bytes):
 | |
|         return False
 | |
|     if isinstance(obj, six.text_type):
 | |
|         return True
 | |
|     if isinstance(obj, Iterable):
 | |
|         return all(check_unicode(o) for o in obj)
 | |
|     return True
 | |
| 
 | |
| 
 | |
| def config_status(config, execute=True):
 | |
|     # Sanitize config data to feed config.status
 | |
|     # Ideally, all the backend and frontend code would handle the booleans, but
 | |
|     # there are so many things involved, that it's easier to keep config.status
 | |
|     # untouched for now.
 | |
|     def sanitize_config(v):
 | |
|         if v is True:
 | |
|             return '1'
 | |
|         if v is False:
 | |
|             return ''
 | |
|         # Serialize types that look like lists and tuples as lists.
 | |
|         if not isinstance(v, (bytes, six.text_type, dict)) and isinstance(v, Iterable):
 | |
|             return list(v)
 | |
|         return v
 | |
| 
 | |
|     sanitized_config = {}
 | |
|     sanitized_config['substs'] = {
 | |
|         k: sanitize_config(v) for k, v in six.iteritems(config)
 | |
|         if k not in ('DEFINES', 'TOPSRCDIR', 'TOPOBJDIR', 'CONFIG_STATUS_DEPS',
 | |
|                      'OLD_CONFIGURE_SUBSTS', 'OLD_CONFIGURE_DEFINES')
 | |
|     }
 | |
|     for k, v in config['OLD_CONFIGURE_SUBSTS']:
 | |
|         sanitized_config['substs'][k] = sanitize_config(v)
 | |
|     sanitized_config['defines'] = {
 | |
|         k: sanitize_config(v) for k, v in six.iteritems(config['DEFINES'])
 | |
|     }
 | |
|     for k, v in config['OLD_CONFIGURE_DEFINES']:
 | |
|         sanitized_config['defines'][k] = sanitize_config(v)
 | |
|     sanitized_config['topsrcdir'] = config['TOPSRCDIR']
 | |
|     sanitized_config['topobjdir'] = config['TOPOBJDIR']
 | |
|     sanitized_config['mozconfig'] = config.get('MOZCONFIG')
 | |
| 
 | |
|     if not check_unicode(sanitized_config):
 | |
|         print("Configuration should be all unicode.", file=sys.stderr)
 | |
|         print("Please file a bug for the above.", file=sys.stderr)
 | |
|         sys.exit(1)
 | |
| 
 | |
|     # Some values in sanitized_config also have more complex types, such as
 | |
|     # EnumString, which using when calling config_status would currently
 | |
|     # break the build, as well as making it inconsistent with re-running
 | |
|     # config.status, for which they are normalized to plain strings via
 | |
|     # indented_repr. Likewise for non-dict non-string iterables being
 | |
|     # converted to lists.
 | |
|     def normalize(obj):
 | |
|         if isinstance(obj, dict):
 | |
|             return {
 | |
|                 k: normalize(v)
 | |
|                 for k, v in six.iteritems(obj)
 | |
|             }
 | |
|         if isinstance(obj, six.text_type):
 | |
|             return six.text_type(obj)
 | |
|         if isinstance(obj, Iterable):
 | |
|             return [normalize(o) for o in obj]
 | |
|         return obj
 | |
| 
 | |
|     sanitized_config = normalize(sanitized_config)
 | |
| 
 | |
|     # Create config.status. Eventually, we'll want to just do the work it does
 | |
|     # here, when we're able to skip configure tests/use cached results/not rely
 | |
|     # on autoconf.
 | |
|     with codecs.open('config.status', 'w', 'utf-8') as fh:
 | |
|         fh.write(textwrap.dedent('''\
 | |
|             #!%(python)s
 | |
|             # coding=utf-8
 | |
|             from __future__ import unicode_literals
 | |
|         ''') % {'python': config['PYTHON3']})
 | |
|         for k, v in sorted(six.iteritems(sanitized_config)):
 | |
|             fh.write('%s = ' % k)
 | |
|             write_indented_repr(fh, v)
 | |
|         fh.write("__all__ = ['topobjdir', 'topsrcdir', 'defines', "
 | |
|                  "'substs', 'mozconfig']")
 | |
| 
 | |
|         if execute:
 | |
|             fh.write(textwrap.dedent('''
 | |
|                 if __name__ == '__main__':
 | |
|                     from mozbuild.util import patch_main
 | |
|                     patch_main()
 | |
|                     from mozbuild.config_status import config_status
 | |
|                     args = dict([(name, globals()[name]) for name in __all__])
 | |
|                     config_status(**args)
 | |
|             '''))
 | |
| 
 | |
|     partial_config = PartialConfigEnvironment(config['TOPOBJDIR'])
 | |
|     partial_config.write_vars(sanitized_config)
 | |
| 
 | |
|     # Write out a file so the build backend knows to re-run configure when
 | |
|     # relevant Python changes.
 | |
|     with io.open('config_status_deps.in', 'w', encoding='utf-8',
 | |
|                  newline='\n') as fh:
 | |
|         for f in sorted(
 | |
|                 itertools.chain(config['CONFIG_STATUS_DEPS'],
 | |
|                                 iter_modules_in_path(config['TOPOBJDIR'],
 | |
|                                                      config['TOPSRCDIR']))):
 | |
|             fh.write('%s\n' % mozpath.normpath(f))
 | |
| 
 | |
|     # Other things than us are going to run this file, so we need to give it
 | |
|     # executable permissions.
 | |
|     os.chmod('config.status', 0o755)
 | |
|     if execute:
 | |
|         from mozbuild.config_status import config_status
 | |
|         return config_status(args=[], **sanitized_config)
 | |
|     return 0
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     sys.exit(main(sys.argv))
 |