| # Copyright 2021 The Emscripten Authors. All rights reserved. |
| # Emscripten is available under two separate licenses, the MIT license and the |
| # University of Illinois/NCSA Open Source License. Both these licenses can be |
| # found in the LICENSE file. |
| |
| import difflib |
| import os |
| import re |
| |
| from .utils import path_from_root, exit_with_error |
| from . import diagnostics |
| |
| |
| class SettingsManager: |
| attrs = {} |
| legacy_settings = {} |
| alt_names = {} |
| internal_settings = set() |
| |
| def __init__(self): |
| self.attrs.clear() |
| self.legacy_settings.clear() |
| self.alt_names.clear() |
| self.internal_settings.clear() |
| |
| # Load the JS defaults into python. |
| settings = open(path_from_root('src', 'settings.js')).read().replace('//', '#') |
| settings = re.sub(r'var ([\w\d]+)', r'attrs["\1"]', settings) |
| # Variable TARGET_NOT_SUPPORTED is referenced by value settings.js (also beyond declaring it), |
| # so must pass it there explicitly. |
| exec(settings, {'attrs': self.attrs}) |
| |
| settings = open(path_from_root('src', 'settings_internal.js')).read().replace('//', '#') |
| settings = re.sub(r'var ([\w\d]+)', r'attrs["\1"]', settings) |
| internal_attrs = {} |
| exec(settings, {'attrs': internal_attrs}) |
| self.attrs.update(internal_attrs) |
| |
| if 'EMCC_STRICT' in os.environ: |
| self.attrs['STRICT'] = int(os.environ.get('EMCC_STRICT')) |
| |
| # Special handling for LEGACY_SETTINGS. See src/setting.js for more |
| # details |
| for legacy in self.attrs['LEGACY_SETTINGS']: |
| if len(legacy) == 2: |
| name, new_name = legacy |
| self.legacy_settings[name] = (None, 'setting renamed to ' + new_name) |
| self.alt_names[name] = new_name |
| self.alt_names[new_name] = name |
| default_value = self.attrs[new_name] |
| else: |
| name, fixed_values, err = legacy |
| self.legacy_settings[name] = (fixed_values, err) |
| default_value = fixed_values[0] |
| assert name not in self.attrs, 'legacy setting (%s) cannot also be a regular setting' % name |
| if not self.attrs['STRICT']: |
| self.attrs[name] = default_value |
| |
| self.internal_settings.update(internal_attrs.keys()) |
| |
| def dict(self): |
| return self.attrs |
| |
| def keys(self): |
| return self.attrs.keys() |
| |
| def __getattr__(self, attr): |
| if attr in self.attrs: |
| return self.attrs[attr] |
| else: |
| raise AttributeError("no such setting: '%s'" % attr) |
| |
| def __setattr__(self, name, value): |
| if name == 'STRICT' and value: |
| for a in self.legacy_settings: |
| self.attrs.pop(a, None) |
| |
| if name in self.legacy_settings: |
| # TODO(sbc): Rather then special case this we should have STRICT turn on the |
| # legacy-settings warning below |
| if self.attrs['STRICT']: |
| exit_with_error('legacy setting used in strict mode: %s', name) |
| fixed_values, error_message = self.legacy_settings[name] |
| if fixed_values and value not in fixed_values: |
| exit_with_error('Invalid command line option -s ' + name + '=' + str(value) + ': ' + error_message) |
| diagnostics.warning('legacy-settings', 'use of legacy setting: %s (%s)', name, error_message) |
| |
| if name in self.alt_names: |
| alt_name = self.alt_names[name] |
| self.attrs[alt_name] = value |
| |
| if name not in self.attrs: |
| msg = "Attempt to set a non-existent setting: '%s'\n" % name |
| suggestions = difflib.get_close_matches(name, list(self.attrs.keys())) |
| suggestions = [s for s in suggestions if s not in self.legacy_settings] |
| suggestions = ', '.join(suggestions) |
| if suggestions: |
| msg += ' - did you mean one of %s?\n' % suggestions |
| msg += " - perhaps a typo in emcc's -s X=Y notation?\n" |
| msg += ' - (see src/settings.js for valid values)' |
| exit_with_error(msg) |
| |
| self.attrs[name] = value |
| |
| def __getitem__(self, key): |
| return self.attrs[key] |
| |
| def __setitem__(self, key, value): |
| self.attrs[key] = value |
| |
| |
| settings = SettingsManager() |