From 5f842337e5979512f2b2405899b1967708f0a71d Mon Sep 17 00:00:00 2001 From: serge-sans-paille Date: Tue, 9 Jan 2024 13:28:42 +0100 Subject: [PATCH] Provide support for '--ignore-pythranrc' This should help reproducible builds. Related to #2170 --- docs/CLI.rst | 1 + docs/MANUAL.rst | 5 ++- pythran/config.py | 81 ++++++++++++++++++++++++++++++++--------------- pythran/run.py | 7 ++++ 4 files changed, 68 insertions(+), 26 deletions(-) diff --git a/docs/CLI.rst b/docs/CLI.rst index 4a4e811f7..b4b312a62 100644 --- a/docs/CLI.rst +++ b/docs/CLI.rst @@ -102,6 +102,7 @@ To know more options about Pythran, you can check:: compiler -U macro_definition any macro undef relevant to the underlying C++ compiler --config config config additional params + --ignore-pythranrc ignore .pythranrc content -ftime-report report time spent in each optimization/transformation It's a megablast! diff --git a/docs/MANUAL.rst b/docs/MANUAL.rst index 2aeeacea4..d7bb27181 100644 --- a/docs/MANUAL.rst +++ b/docs/MANUAL.rst @@ -559,7 +559,10 @@ For example:: would specify that pythran-openblas is the blas library to use. -Options specified using command-line arguments override the options found in the ``.pythranrc`` file +Options specified using command-line arguments override the options found in the ``.pythranrc`` file. + +``--ignore-pythranrc`` can be passed down to ``pythran`` and ``pythran-config`` +to ignore this file, which helps for reproducible builds. ``[compiler]`` diff --git a/pythran/config.py b/pythran/config.py index 8d1a44fbb..3fcfc6bb7 100644 --- a/pythran/config.py +++ b/pythran/config.py @@ -55,31 +55,55 @@ def get_paths_cfg( platform_config_path = os.path.join(sys_config_dir, "pythran-default.cfg") - user_config_path = os.environ.get('PYTHRANRC', None) - if not user_config_path: - user_config_dir = os.environ.get('XDG_CONFIG_HOME', None) - if not user_config_dir: - user_config_dir = os.environ.get('HOME', None) - if not user_config_dir: - user_config_dir = '~' - user_config_path = os.path.expanduser( - os.path.join(user_config_dir, user_file)) - return {"sys": sys_config_path, - "platform": platform_config_path, - "user": user_config_path} - - -def init_cfg(sys_file, platform_file, user_file, config_args=None): + paths = {"sys": sys_config_path, + "platform": platform_config_path} + + if user_file: + user_config_path = os.environ.get('PYTHRANRC', None) + if not user_config_path: + user_config_dir = os.environ.get('XDG_CONFIG_HOME', None) + if not user_config_dir: + user_config_dir = os.environ.get('HOME', None) + if not user_config_dir: + user_config_dir = '~' + user_config_path = os.path.expanduser( + os.path.join(user_config_dir, user_file)) + paths["user"] = user_config_path + + return paths + + +class UninitializedConfig: + pass + + +cfg = UninitializedConfig + + +def init_cfg(ignore_userfile=False): + global cfg + if cfg is not UninitializedConfig: + return cfg + + # load platform specific configuration then user configuration + cfg = _init_cfg('pythran.cfg', + 'pythran-{}.cfg'.format(sys.platform), + None if ignore_userfile else '.pythranrc') + return cfg + +def _init_cfg(sys_file, platform_file, user_file, config_args=None): paths = get_paths_cfg(sys_file, platform_file, user_file) sys_config_path = paths["sys"] platform_config_path = paths["platform"] - user_config_path = paths["user"] + user_config_path = paths.get("user") cfgp = ConfigParser() for required in (sys_config_path, platform_config_path): cfgp.read([required]) - cfgp.read([user_config_path]) + + if user_config_path: + cfgp.read([user_config_path]) if config_args is not None: update_cfg(cfgp, config_args) @@ -111,6 +135,8 @@ def lint_cfg(cfgp, **paths): # Check if pythran configuration files exists for loc, path in paths.items(): + if path is None: + continue exists = os.path.exists(path) msg = " ".join([ @@ -120,6 +146,10 @@ def lint_cfg(cfgp, **paths): ]) logger.info(msg) if exists else logger.warning(msg) + user_config_path = paths.get("user") + if user_config_path: + cfgp_ref.read(user_config_path) + for section in cfgp.sections(): # Check if section in the current configuration exists in the # reference configuration @@ -150,10 +180,10 @@ def lint_cfg(cfgp, **paths): def make_extension(python, **extra): # load platform specific configuration then user configuration - cfg = init_cfg('pythran.cfg', - 'pythran-{}.cfg'.format(sys.platform), - '.pythranrc', - extra.get('config', None)) + cfg = _init_cfg('pythran.cfg', + 'pythran-{}.cfg'.format(sys.platform), + None if extra.get('ignore_pythranrc') else '.pythranrc', + extra.get('config', None)) if 'config' in extra: extra.pop('config') @@ -279,16 +309,13 @@ def compiler(): Returns None if none is set or if it's set to the empty string """ + init_cfg() cfg_cxx = str(cfg.get('compiler', 'CXX')) if not cfg_cxx: cfg_cxx = None return os.environ.get('CXX', cfg_cxx) or None -# load platform specific configuration then user configuration -cfg = init_cfg('pythran.cfg', - 'pythran-{}.cfg'.format(sys.platform), - '.pythranrc') def run(): @@ -319,6 +346,10 @@ def run(): parser.add_argument('--no-python', action='store_true', help='do not include Python-related flags') + parser.add_argument('--ignore-pythranrc', dest='ignore_pythranrc', + action='store_true', + help='ignore .pythranrc content') + parser.add_argument('--verbose', '-v', action='count', default=0, help=( 'verbose mode: [-v] prints warnings if pythranrc ' diff --git a/pythran/run.py b/pythran/run.py index 4b669cb4d..1bbc52f8c 100644 --- a/pythran/run.py +++ b/pythran/run.py @@ -123,6 +123,10 @@ def run(): help='config additional params', default=list()) + parser.add_argument('--ignore-pythranrc', dest='ignore_pythranrc', + action='store_true', + help='ignore .pythranrc content') + parser.add_argument('-ftime-report', dest='report_times', action='store_true', help='report time spent in each optimization/transformation') @@ -146,6 +150,9 @@ def run(): if args.warn_off: logger.setLevel(logging.ERROR) + + pythran.config.init_cfg(args.ignore_pythranrc) + if args.config: pythran.config.update_cfg(pythran.config.cfg, args.config)