docs: def get_package_info(srcdir='.', exclude=()):
      """
      Collates all of the information for building all subpackages
      and returns a dictionary of keyword arguments that can
      be passed directly to `distutils.setup`.
  
      The purpose of this function is to allow subpackages to update the
      arguments to the package's ``setup()`` function in its setup.py
      script, rather than having to specify all extensions/package data
      directly in the ``setup.py``.  See Astropy's own
      ``setup.py`` for example usage and the Astropy development docs
      for more details.
  
      This function obtains that information by iterating through all
      packages in ``srcdir`` and locating a ``setup_package.py`` module.
      This module can contain the following functions:
      ``get_extensions()``, ``get_package_data()``,
      ``get_build_options()``, and ``get_external_libraries()``.
  
      Each of those functions take no arguments.
  
      - ``get_extensions`` returns a list of
        `distutils.extension.Extension` objects.
  
      - ``get_package_data()`` returns a dict formatted as required by
        the ``package_data`` argument to ``setup()``.
  
      - ``get_build_options()`` returns a list of tuples describing the
        extra build options to add.
  
      - ``get_external_libraries()`` returns
        a list of libraries that can optionally be built using external
        dependencies.
      """
      ext_modules = []
      packages = []
      package_dir = {}
  
      # Read in existing package data, and add to it below
      setup_cfg = os.path.join(srcdir, 'setup.cfg')
      if os.path.exists(setup_cfg):
          conf = read_configuration(setup_cfg)
          if 'options' in conf and 'package_data' in conf['options']:
              package_data = conf['options']['package_data']
          else:
              package_data = {}
      else:
          package_data = {}
  
      if exclude:
          warnings.warn(
              "Use of the exclude parameter is no longer supported since it does "
              "not work as expected. Use add_exclude_packages instead. Note that "
              "it must be called prior to any other calls from setup helpers.",
              AstropyDeprecationWarning)
  
      # Use the find_packages tool to locate all packages and modules
      packages = find_packages(srcdir, exclude=exclude)
  
      # Update package_dir if the package lies in a subdirectory
      if srcdir != '.':
          package_dir[''] = srcdir
  
      # For each of the setup_package.py modules, extract any
      # information that is needed to install them.  The build options
      # are extracted first, so that their values will be available in
      # subsequent calls to `get_extensions`, etc.
      for setuppkg in iter_setup_packages(srcdir, packages):
          if hasattr(setuppkg, 'get_build_options'):
              options = setuppkg.get_build_options()
              for option in options:
                  add_command_option('build', *option)
          if hasattr(setuppkg, 'get_external_libraries'):
              libraries = setuppkg.get_external_libraries()
              for library in libraries:
                  add_external_library(library)
  
      for setuppkg in iter_setup_packages(srcdir, packages):
          # get_extensions must include any Cython extensions by their .pyx
          # filename.
          if hasattr(setuppkg, 'get_extensions'):
              ext_modules.extend(setuppkg.get_extensions())
          if hasattr(setuppkg, 'get_package_data'):
              package_data.update(setuppkg.get_package_data())
  
      # Locate any .pyx files not already specified, and add their extensions in.
      # The default include dirs include numpy to facilitate numerical work.
      ext_modules.extend(get_cython_extensions(srcdir, packages, ext_modules,
                                               ['numpy']))
  
      # Now remove extensions that have the special name 'skip_cython', as they
      # exist Only to indicate that the cython extensions shouldn't be built
      for i, ext in reversed(list(enumerate(ext_modules))):
          if ext.name == 'skip_cython':
              del ext_modules[i]
  
      # On Microsoft compilers, we need to pass the '/MANIFEST'
      # commandline argument.  This was the default on MSVC 9.0, but is
      # now required on MSVC 10.0, but it doesn't seem to hurt to add
      # it unconditionally.
      if get_compiler_option() == 'msvc':
          for ext in ext_modules:
              ext.extra_link_args.append('/MANIFEST')
  
      return {
          'ext_modules': ext_modules,
          'packages': packages,
          'package_dir': package_dir,
          'package_data': package_data,
          }