| # 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/. |
| |
| # Combined with build/autoconf/config.status.m4, ConfigStatus is an almost |
| # drop-in replacement for autoconf 2.13's config.status, with features |
| # borrowed from autoconf > 2.5, and additional features. |
| |
| from __future__ import absolute_import, print_function |
| |
| import logging |
| import os |
| import sys |
| import time |
| |
| from argparse import ArgumentParser |
| |
| from mach.logging import LoggingManager |
| from mozbuild.backend.configenvironment import ConfigEnvironment |
| from mozbuild.backend.recursivemake import RecursiveMakeBackend |
| from mozbuild.base import MachCommandConditions |
| from mozbuild.frontend.emitter import TreeMetadataEmitter |
| from mozbuild.frontend.reader import BuildReader |
| from mozbuild.mozinfo import write_mozinfo |
| from itertools import chain |
| |
| |
| log_manager = LoggingManager() |
| |
| |
| ANDROID_IDE_ADVERTISEMENT = ''' |
| ============= |
| ADVERTISEMENT |
| |
| You are building Firefox for Android. After your build completes, you |
| should run `mach gradle-install` to prepare Gradle and IntelliJ/Android Studio |
| integration. Then import the Gradle project at $OBJDIR/mobile/android/gradle |
| into the IDE of your choice. |
| |
| PLEASE BE AWARE THAT GRADLE AND INTELLIJ/ANDROID STUDIO SUPPORT IS EXPERIMENTAL. |
| You should verify any changes using |mach build|. |
| ============= |
| '''.strip() |
| |
| VISUAL_STUDIO_ADVERTISEMENT = ''' |
| =============================== |
| Visual Studio Support Available |
| |
| You are building Firefox on Windows. Please help us test the experimental |
| Visual Studio project files (yes, IntelliSense works) by running the |
| following: |
| |
| mach build-backend --backend=VisualStudio |
| |
| =============================== |
| '''.strip() |
| |
| |
| def config_status(topobjdir='.', topsrcdir='.', |
| defines=[], non_global_defines=[], substs=[], source=None): |
| '''Main function, providing config.status functionality. |
| |
| Contrary to config.status, it doesn't use CONFIG_FILES or CONFIG_HEADERS |
| variables. |
| |
| Without the -n option, this program acts as config.status and considers |
| the current directory as the top object directory, even when config.status |
| is in a different directory. It will, however, treat the directory |
| containing config.status as the top object directory with the -n option. |
| |
| The --recheck option, like with the original config.status, runs configure |
| again, with the options given in the "ac_configure_args" subst. |
| |
| The options to this function are passed when creating the |
| ConfigEnvironment. These lists, as well as the actual wrapper script |
| around this function, are meant to be generated by configure. |
| See build/autoconf/config.status.m4. |
| ''' |
| |
| if 'CONFIG_FILES' in os.environ: |
| raise Exception('Using the CONFIG_FILES environment variable is not ' |
| 'supported.') |
| if 'CONFIG_HEADERS' in os.environ: |
| raise Exception('Using the CONFIG_HEADERS environment variable is not ' |
| 'supported.') |
| |
| if not os.path.isabs(topsrcdir): |
| raise Exception('topsrcdir must be defined as an absolute directory: ' |
| '%s' % topsrcdir) |
| |
| default_backends = ['RecursiveMake'] |
| # We have a chicken/egg problem, where we only have a dict for substs after |
| # creating the ConfigEnvironment, which requires argument parsing to have |
| # occurred. |
| for name, value in substs: |
| if name == 'BUILD_BACKENDS': |
| default_backends = value |
| break |
| |
| parser = ArgumentParser() |
| parser.add_argument('--recheck', dest='recheck', action='store_true', |
| help='update config.status by reconfiguring in the same conditions') |
| parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', |
| help='display verbose output') |
| parser.add_argument('-n', dest='not_topobjdir', action='store_true', |
| help='do not consider current directory as top object directory') |
| parser.add_argument('-d', '--diff', action='store_true', |
| help='print diffs of changed files.') |
| parser.add_argument('-b', '--backend', nargs='+', |
| choices=['RecursiveMake', 'AndroidEclipse', 'CppEclipse', |
| 'VisualStudio', 'FasterMake', 'CompileDB'], |
| default=default_backends, |
| help='what backend to build (default: %s).' % |
| ' '.join(default_backends)) |
| options = parser.parse_args() |
| |
| # Without -n, the current directory is meant to be the top object directory |
| if not options.not_topobjdir: |
| topobjdir = os.path.abspath('.') |
| |
| env = ConfigEnvironment(topsrcdir, topobjdir, defines=defines, |
| non_global_defines=non_global_defines, substs=substs, source=source) |
| |
| # mozinfo.json only needs written if configure changes and configure always |
| # passes this environment variable. |
| if 'WRITE_MOZINFO' in os.environ: |
| write_mozinfo(os.path.join(topobjdir, 'mozinfo.json'), env, os.environ) |
| |
| # Make an appropriate backend instance, defaulting to RecursiveMakeBackend. |
| backends_cls = [] |
| for backend in options.backend: |
| if backend == 'AndroidEclipse': |
| from mozbuild.backend.android_eclipse import AndroidEclipseBackend |
| if not MachCommandConditions.is_android(env): |
| raise Exception('The Android Eclipse backend is not available with this configuration.') |
| backends_cls.append(AndroidEclipseBackend) |
| elif backend == 'CppEclipse': |
| from mozbuild.backend.cpp_eclipse import CppEclipseBackend |
| backends_cls.append(CppEclipseBackend) |
| if os.name == 'nt': |
| raise Exception('Eclipse is not supported on Windows. Consider using Visual Studio instead.') |
| elif backend == 'VisualStudio': |
| from mozbuild.backend.visualstudio import VisualStudioBackend |
| backends_cls.append(VisualStudioBackend) |
| elif backend == 'FasterMake': |
| from mozbuild.backend.fastermake import FasterMakeBackend |
| backends_cls.append(FasterMakeBackend) |
| elif backend == 'CompileDB': |
| from mozbuild.compilation.database import CompileDBBackend |
| backends_cls.append(CompileDBBackend) |
| else: |
| backends_cls.append(RecursiveMakeBackend) |
| |
| cpu_start = time.clock() |
| time_start = time.time() |
| |
| backends = [cls(env) for cls in backends_cls] |
| |
| reader = BuildReader(env) |
| emitter = TreeMetadataEmitter(env) |
| # This won't actually do anything because of the magic of generators. |
| definitions = emitter.emit(reader.read_topsrcdir()) |
| |
| if options.recheck: |
| # Execute configure from the top object directory |
| os.chdir(topobjdir) |
| os.execlp('sh', 'sh', '-c', ' '.join([os.path.join(topsrcdir, 'configure'), env.substs['ac_configure_args'], '--no-create', '--no-recursion'])) |
| |
| log_level = logging.DEBUG if options.verbose else logging.INFO |
| log_manager.add_terminal_logging(level=log_level) |
| log_manager.enable_unstructured() |
| |
| print('Reticulating splines...', file=sys.stderr) |
| if len(backends) > 1: |
| definitions = list(definitions) |
| |
| for the_backend in backends: |
| the_backend.consume(definitions) |
| |
| execution_time = 0.0 |
| for obj in chain((reader, emitter), backends): |
| summary = obj.summary() |
| print(summary, file=sys.stderr) |
| execution_time += summary.execution_time |
| |
| cpu_time = time.clock() - cpu_start |
| wall_time = time.time() - time_start |
| efficiency = cpu_time / wall_time if wall_time else 100 |
| untracked = wall_time - execution_time |
| |
| print( |
| 'Total wall time: {:.2f}s; CPU time: {:.2f}s; Efficiency: ' |
| '{:.0%}; Untracked: {:.2f}s'.format( |
| wall_time, cpu_time, efficiency, untracked), |
| file=sys.stderr |
| ) |
| |
| if options.diff: |
| for the_backend in backends: |
| for path, diff in sorted(the_backend.file_diffs.items()): |
| print('\n'.join(diff)) |
| |
| # Advertise Visual Studio if appropriate. |
| if os.name == 'nt' and 'VisualStudio' not in options.backend: |
| print(VISUAL_STUDIO_ADVERTISEMENT) |
| |
| # Advertise Eclipse if it is appropriate. |
| if MachCommandConditions.is_android(env): |
| if 'AndroidEclipse' not in options.backend: |
| print(ANDROID_IDE_ADVERTISEMENT) |