| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- # ------------------------------------------------------------------
- # Copyright (c) 2024 PyInstaller Development Team.
- #
- # This file is distributed under the terms of the GNU General Public
- # License (version 2.0 or later).
- #
- # The full license is available in LICENSE, distributed with
- # this software.
- #
- # SPDX-License-Identifier: GPL-2.0-or-later
- # ------------------------------------------------------------------
- import os
- import pathlib
- from PyInstaller import isolated
- from PyInstaller.utils.hooks import collect_data_files, logger
- # Collect the headers (eccodes.h, gribapi.h) that are bundled with the package.
- datas = collect_data_files('gribapi')
- # Collect the eccodes shared library. Starting with eccodes 2.37.0, binary wheels with bundled shared library are
- # provided for linux and macOS, and since 2.39.0, also for Windows.
- # NOTE: custom isolated function is used here instead of `get_module_attribute('gribapi.bindings', 'library_path')`
- # hook utility function because with eccodes 2.37.0, `eccodes` needs to be imported before `gribapi` to avoid circular
- # imports... Also, this way, we can obtain the root directory of eccodes package at the same time.
- @isolated.decorate
- def get_eccodes_library_path():
- import eccodes
- import gribapi.bindings
- return (
- # Path to eccodes shared library used by the gribapi bindings.
- str(gribapi.bindings.library_path),
- # Path to eccodes package (implicitly assumed to be next to the gribapi package, since they are part of the
- # same eccodes dist).
- str(eccodes.__path__[0]),
- )
- binaries = []
- hiddenimports = []
- try:
- library_path, package_path = get_eccodes_library_path()
- except Exception:
- logger.warning("hook-gribapi: failed to query gribapi.bindings.library_path!", exc_info=True)
- library_path = None
- if library_path:
- if not os.path.isabs(library_path):
- from PyInstaller.depend.utils import _resolveCtypesImports
- resolved_binary = _resolveCtypesImports([os.path.basename(library_path)])
- if resolved_binary:
- library_path = resolved_binary[0][1]
- else:
- logger.warning("hook-gribapi: failed to resolve shared library name %r!", library_path)
- library_path = None
- else:
- logger.warning("hook-gribapi: could not determine path to eccodes shared library!")
- if library_path:
- # If we are collecting eccodes shared library that is bundled with eccodes >= 2.37.0 binary wheel, attempt to
- # preserve its parent directory layout. This ensures that the library is found at run-time, but implicitly requires
- # PyInstaller 6.x, whose binary dependency analysis (that might also pick up this shared library) also preserves the
- # parent directory layout of discovered shared libraries. With PyInstaller 5.x, this will result in duplication
- # because binary dependency analysis collects into top-level application directory, but that copy will not be
- # discovered at run-time, so duplication is unavoidable.
- library_parent_path = pathlib.PurePath(library_path).parent
- package_parent_path = pathlib.PurePath(package_path).parent
- if package_parent_path in library_parent_path.parents:
- # Should end up being `eccodes.libs` on Linux, `eccodes/.dylib` on macOS, and `eccodes` on Windows.
- dest_dir = str(library_parent_path.relative_to(package_parent_path))
- else:
- # External copy; collect into top-level application directory.
- dest_dir = '.'
- logger.info(
- "hook-gribapi: collecting eccodes shared library %r to destination directory %r", library_path, dest_dir
- )
- binaries.append((library_path, dest_dir))
- # If the shared library is available in the stand-alone `eccodeslib` package, add this package to to hidden imports,
- # so that `findlibs.find()` can import it and query its `__file__` attribute.
- if 'eccodeslib' in library_parent_path.parts:
- hiddenimports += ['eccodeslib']
|