triumvirate的setup.py

```

import os
import platform
import sys
from copy import deepcopy
from distutils.log import _global_log as distutils_logger
from multiprocessing import cpu_count
from setuptools import setup
from setuptools.command.build_clib import build_clib

import numpy
from Cython.Build import cythonize
from Cython.Distutils import build_ext, Extension
from extension_helpers._openmp_helpers import check_openmp_support
from extension_helpers._setup_helpers import pkg_config


# ========================================================================
# Package
# ========================================================================

PROJECT_NAME = 'Triumvirate'


def get_pkg_name():
    """Get package name in lower-case format.

    Returns
    -------
    str
        Package name.

    """
    return PROJECT_NAME.lower()


def get_pkg_dir(topdir="src"):
    """Get package directory.

    Parameters
    ----------
    topdir : str, optional
        Top-level (sub-)directory containing the package at the
        repository root.

    Returns
    -------
    str
        Package directory.

    """
    return os.path.join(topdir, get_pkg_name())


def get_pkg_include_dir(subdir="include"):
    """Get package C++ header directory.

    Parameters
    ----------
    subdir : str, optional
        Subdirectory containing C++ headers in the package directory.

    Returns
    -------
    str
        C++ header directory.

    """
    return os.path.join(get_pkg_dir(), subdir)


def get_pkg_src_dir(subdir="src"):
    """Get package C++ source directory.

    Parameters
    ----------
    subdir : str, optional
        Subdirectory containing C++ sources in the package directory.

    Returns
    -------
    str
        C++ source directory.

    """
    return os.path.join(get_pkg_dir(), subdir)


def get_pkg_version_scheme(default_ver_scheme='no-guess-dev',
                           default_loc_scheme='node-and-date'):
    """Get package version scheme from the environment.

    Parameters
    ----------
    default_ver_scheme : str, optional
        Fallback default version scheme for the package
        (default is 'no-guess-dev').
    default_loc_scheme : str, optional
        Fallback default local scheme for the package
        (default is 'node-and-date').

    Returns
    -------
    dict
        Package version scheme(s).

    See Also
    --------
    :pkg:`setuptools_scm`
        For available version schemes.

    """
    ver_scheme = os.environ.get('PY_SCM_VER_SCHEME', '').strip() \
        or default_ver_scheme
    loc_scheme = os.environ.get('PY_SCM_LOC_SCHEME', '').strip() \
        or default_loc_scheme

    scheme = {
        'version_scheme': ver_scheme,
        'local_scheme': loc_scheme,
    }

    prioprint(f"Versioning scheme: {scheme}")

    return scheme


# ========================================================================
# Build
# ========================================================================

class BuildExt(build_ext):
    """Modified :class:`Cython.Distutils.build_ext`.

    """

    def finalize_options(self):
        """Modify parallelisation option in
        :meth:`Cython.Distutils.build_ext.finalize_options`.

        """
        super().finalize_options()

        _num_procs = get_build_num_procs()
        if getattr(self, 'parallel', None) is None and _num_procs is not None:
            self.parallel = _num_procs

    def build_extensions(self):
        """Modify compiler and compilation configuration in
        :meth:`Cython.Distutils.build_ext.build_extensions`.

        """
        OPTS_TO_REMOVE = ['-Wstrict-prototypes', '-Wl,-pie',]  # noqa: E231
        for opt in OPTS_TO_REMOVE:
            try:
                self.compiler.compiler_so.remove(opt)
            except ValueError:
                pass

        try:
            _num_procs = max(int(self.parallel), 1)
        except TypeError:
            _num_procs = 1

        distutils_logger.info(
            "running build_ext on %d process(es) with %s compiler",
            _num_procs, self.compiler.compiler_so[0],
        )

        super().build_extensions()


class BuildClib(build_clib):
    """Modified :class:`setuptools.command.build_clib.build_clib`.

    """

    def build_libraries(self, libraries):
        """Modify compiler and compilation configuration for libraries.

        See also
        --------
        :meth:`setuptools.command.build_clib.build_clib.build_libraries`
            For the original method this overrides.

        """  # numpydoc ignore=PR01
        OPTS_TO_REMOVE = ['-Wstrict-prototypes', '-Wl,-pie',]  # noqa: E231
        for opt in OPTS_TO_REMOVE:
            try:
                self.compiler.compiler_so.remove(opt)
            except ValueError:
                pass

        distutils_logger.info(
            "running build_clib with %s compiler",
            self.compiler.compiler_so[0],
        )

        super().build_libraries(libraries)


def get_build_num_procs():
    """Get the number of build parallel processes.

    Returns
    -------
    int or None
        Number of parallel processes, which may be `None` in the case
        of no parallelisation.

    """
    flag_parallel = os.environ.get('PY_BUILD_PARALLEL', '').strip()
    if '-j' == flag_parallel:
        num_procs = cpu_count()
    elif '-j' in flag_parallel:
        try:
            num_procs = int(flag_parallel.lstrip('-j'))
        except ValueError:
            num_procs = None
    else:
        num_procs = None

    return num_procs


def prioprint(*args, **kwargs):
    """`print` with high priority.

    Parameters
    ----------
    *args
        Positional arguments passed to :func:`print`.
    **kwargs
        Keyword arguments passed to :func:`print`.

    """
    print(*args, file=sys.stderr, **kwargs)


def display_py_environs():
    """Display customised environment variables passed to setup.

    """
    PY_ENV_VARS = [
        'PY_CXX',
        'PY_INCLUDES',  # typically included in 'CPPFLAGS'
        'PY_CXXFLAGS',  # atypically includes macros in 'CPPFLAGS'
        'PY_LDFLAGS',  # atypically includes 'LDLIBS'
        'PY_NO_OMP',  # disable OpenMP explicitly
        'PY_OMP',  # enable OpenMP explicitly unless overridden by `PY_NO_OMP`
        'PY_CXXFLAGS_OMP',
        'PY_LDFLAGS_OMP',
        'PY_BUILD_PARALLEL',
        'PY_SCM_VER_SCHEME',
        'PY_SCM_LOC_SCHEME',
    ]
    for env_var in PY_ENV_VARS:
        prioprint("{}={}".format(env_var, os.environ.get(env_var)))


def display_py_options():
    """Display customised compilation options used in build.

    """
    PY_OPT_TYPES = [
        'macros',
        'cflags',
        'ldflags',
        'libs',
        'include_dirs',
        'lib_dirs',
    ]
    for opt_type in PY_OPT_TYPES:
        prioprint("{}={}".format(opt_type, globals().get(opt_type)))


# ========================================================================
# Compilation
# ========================================================================

EXT_LANG = 'c++'


# -- OS ------------------------------------------------------------------

def get_platform():
    """Get the build platform.

    Returns
    -------
    {'linux', 'darwin', 'default'}
        Build platform.

    """
    build_platform = platform.system().lower()
    if build_platform not in ['linux', 'darwin']:
        build_platform = 'default'

    return build_platform


# -- Compiler ------------------------------------------------------------

# List default compilers (GCC assumed).
COMPILERS = {
    'default': 'g++',
    'linux': 'g++',
    'darwin': 'g++',
}


def get_compiler():
    """Get the build compiler.

    Returns
    -------
    str
        Build compiler.

    """
    compiler = os.environ.get('PY_CXX', COMPILERS[get_platform()])

    return compiler


def set_cli_compiler(compiler=None):
    """Set command-line compiler through the ``CC``and ``CXX``
    environmental variables.

    Parameters
    ----------
    compiler : str, optional
        Compiler to use.  If `None` (default), :func:`get_compiler` is
        used to determine the compiler.

    """
    _compiler = compiler or get_compiler()

    os.environ['CC'] = _compiler
    os.environ['CXX'] = _compiler


# -- Dependencies --------------------------------------------------------

PKG_LIB_NAME = 'trv'

LIBS_CORE = ['gsl', 'fftw3',]  # noqa: E231
LIBS_FULL = ['gsl', 'gslcblas', 'm', 'fftw3',]  # noqa: E231

# Default to GCC OpenMP implementation.
OPENMP_LIBS = {
    'default': 'gomp',  # or LLVM 'omp'
    'linux': '',  # set by ``-fopenmp`` or environment
    'darwin': '',  # set by ``-fopenmp`` or environment
}


# -- Options -------------------------------------------------------------

# List default compilation options.
CFLAGS = ['-std=c++17',]


def convert_macro(macro):
    """Convert a macro flag to a tuple.

    Parameters
    ----------
    macro : str
        Macro as a flag with '-D' prefix.

    Returns
    -------
    tuple[str, Union[str, None]]
        Macro as a 2-tuple.

    """
    macro_ = macro.lstrip('-D').split('=')
    if len(macro_) == 1:
        return (macro_.pop(), None)
    if len(macro_) == 2:
        return tuple(macro_)
    raise ValueError(f"Invalid macro to convert: {macro_}.")


def parse_cli_cflags():
    """Parse command-line ``PY_CXXFLAGS`` components for extension
    keyword arguments.

    Returns
    -------
    list of str, list of str
        Parsed `macros` and `cflags`.

    """
    cli_cflags = os.environ.get('PY_CXXFLAGS', '').split()

    parsed_macros, parsed_cflags = [], CFLAGS.copy()
    for cflag_ in cli_cflags:
        if cflag_.startswith('-D'):
            macro_ = convert_macro(cflag_)
            parsed_macros.append(macro_)
        else:
            parsed_cflags.append(cflag_)

    return parsed_macros, parsed_cflags


def parse_cli_ldflags():
    """Parse command-line ``PY_LDFLAGS`` components for extension
    keyword arguments.

    Returns
    -------
    list of str, list of str, list of str
        Parsed `ldflags`, `libs` and `lib_dirs`.

    """
    cli_ldflags = os.environ.get('PY_LDFLAGS', '').split()

    parsed_ldflags, parsed_libs, parsed_lib_dirs = [], [], []
    for ldflag_ in cli_ldflags:
        if ldflag_.startswith('-l'):
            lib_ = ldflag_.lstrip('-l')
            parsed_libs.append(lib_)
        elif ldflag_.startswith('-L'):
            ldflag_L = ldflag_.lstrip('-L')
            parsed_lib_dirs.append(ldflag_L)
        else:
            parsed_ldflags.append(ldflag_)

    return parsed_ldflags, parsed_libs, parsed_lib_dirs


def parse_cli_includes():
    """Parse command-line ``PY_INCLUDES`` components for extension
    keyword arguments.

    Returns
    -------
    list of str
        Parsed `include_dirs`.

    """
    parsed_include_dirs = \
        os.environ.get('PY_INCLUDES', '').replace('-I', '').split()

    return parsed_include_dirs


def parse_cli_cflags_omp():
    """Parse command-line ``PY_CXXFLAGS_OMP`` components for extension
    keyword arguments.

    Returns
    -------
    list of str, list of str
        Parsed `macros` and `include_dirs` for OpenMP.

    """
    cli_cflags_omp = os.environ.get('PY_CXXFLAGS_OMP', '').split()
    if not cli_cflags_omp:
        return None

    parsed_macros_omp, parsed_cflags_omp = [], []
    for cflag_ in cli_cflags_omp:
        if cflag_.startswith('-D'):
            macro_ = cflag_.lstrip('-D').split('=')
            if len(macro_) == 1:
                parsed_macros_omp.append((macro_.pop(), None))
            elif len(macro_) == 2:
                parsed_macros_omp.append(tuple(macro_))
            else:
                raise ValueError(f"Invalid macro in CXXFLAG_OMP: {cflag_}.")
        else:
            parsed_cflags_omp.append(cflag_)

    return parsed_macros_omp, parsed_cflags_omp


def parse_cli_ldflags_omp():
    """Parse command-line ``PY_LDFLAGS_OMP`` components for extension
    keyword arguments.

    Returns
    -------
    list of str, list of str
        Parsed `ldflags`, `libs` and `lib_dirs` for OpenMP.

    """
    cli_ldflags_omp = os.environ.get('PY_LDFLAGS_OMP', '').split()
    if not cli_ldflags_omp:
        return None

    parsed_ldflags_omp, parsed_libs_omp, parsed_lib_dirs_omp = [], [], []
    for ldflag_ in cli_ldflags_omp:
        if ldflag_.startswith('-l'):
            parsed_libs_omp.append(ldflag_.lstrip('-l'))
        elif ldflag_.startswith('-L'):
            parsed_lib_dirs_omp.append(ldflag_.lstrip('-L'))
        else:
            parsed_ldflags_omp.append(ldflag_)

    return parsed_ldflags_omp, parsed_libs_omp, parsed_lib_dirs_omp


def add_options_nonomp(macros, cflags, ldflags, libs, lib_dirs, include_dirs):
    """Add non-OpenMP compilation options.

    Parameters
    ----------
    macros : list of tuple[str, Union[str, None]]
        Macros without the '-D' prefix.
    cflags : list of str
        ``CXXFLAGS`` components with non-'-D' and non-'-I' prefixes.
    ldflags : list of str
        ``LDFLAGS`` components with non-'-l' and non-'-L' prefixes.
    libs : list of str
        Libraries without the '-l' prefix.
    lib_dirs : list of str
        Library directories without the '-L' prefix.
    include_dirs : list of str
        ``INCLUDES`` directories without the '-I' prefix.

    Returns
    -------
    macros : list of tuple[str, Union[str, None]]
        Extended macros without the '-D' prefix.
    cflags : list of str
        Extended ``CXXFLAGS`` components with non-'-D' and
        non-'-I' prefixes.
    ldflags : list of str
        Extended ``LDFLAGS`` components with non-'-l' and
        non-'-L' prefixes.
    libs : list of str
        Extended libraries without the '-l' prefix.
    lib_dirs : list of str
        Extended library directories without the '-L' prefix.
    include_dirs :list of str
        Extended ``INCLUDES`` directories without the '-I' prefix.

    """
    libs_core = deepcopy(LIBS_CORE)
    libs_full = deepcopy(LIBS_FULL)

    for lib_ in libs:
        if lib_ not in libs_full:
            libs_core.append(lib_)
            libs_full.append(lib_)

    checked_options = pkg_config(libs_core, default_libraries=libs_full)

    libs = checked_options['libraries']

    for macro_ in checked_options['define_macros']:
        if macro_ not in macros:
            macros.append(macro_)
    for flag in checked_options['extra_compile_args']:
        if flag not in cflags + ldflags:
            cflags.append(flag)
    for lib_dir_ in checked_options['library_dirs']:
        if lib_dir_ not in lib_dirs:
            lib_dirs.append(lib_dir_)
    for include_dir_ in checked_options['include_dirs']:
        if include_dir_ not in include_dirs:
            include_dirs.append(include_dir_)

    return macros, cflags, ldflags, libs, lib_dirs, include_dirs


def add_options_omp(macros, cflags, ldflags, libs, lib_dirs, include_dirs):
    """Add OpenMP options, if enabled.

    By default, GCC OpenMP is assumed.

    Parameters
    ----------
    macros : list of tuple[str, Union[str, None]]
        Macros without the '-D' prefix.
    cflags : list of str
        ``CXXFLAGS`` components with non-'-D' and non-'-I' prefixes.
    ldflags : list of str
        ``LDFLAGS`` components with non-'-l' and non-'-L' prefixes.
    libs : list of str
        Libraries without the '-l' prefix.
    lib_dirs : list of str
        Library directories without the '-L' prefix.
    include_dirs : list of str
        ``INCLUDES`` directories without the '-I' prefix.

    Returns
    -------
    macros : list of tuple[str, Union[str, None]]
        Extended macros without the '-D' prefix.
    cflags : list of str
        Extended ``CXXFLAGS`` components with non-'-D' and
        non-'-I' prefixes.
    ldflags : list of str
        Extended ``LDFLAGS`` components with non-'-l' and
        non-'-L' prefixes.
    libs : list of str
        Extended libraries without the '-l' prefix.
    lib_dirs : list of str
        Extended library directories without the '-L' prefix.
    include_dirs :list of str
        Extended ``INCLUDES`` directories without the '-I' prefix.

    """
    # Check if OpenMP is explicitly disabled.
    if os.environ.get('PY_NO_OMP') is not None:
        prioprint("OpenMP is disabled explicitly.")
        return macros, cflags, ldflags, libs, lib_dirs, include_dirs

    # Check if OpenMP is unsupported.
    if os.environ.get('PY_OMP') is None and not check_openmp_support():
        prioprint(
            "OpenMP is disabled as "
            "it is not supported in this build environment."
        )
        return macros, cflags, ldflags, libs, lib_dirs, include_dirs

    # Enable OpenMP by default otherwise.
    prioprint("OpenMP is enabled.")

    # Adapt `macros` and `cflags`.
    MACROS_OMP_RELATED = [
        ('TRV_USE_OMP', None),
        ('TRV_USE_FFTWOMP', None),
    ]
    for macro_ in MACROS_OMP_RELATED:
        if macro_ not in macros:
            macros.append(macro_)

    try:
        macros_omp, cflags_omp = parse_cli_cflags_omp()
    except TypeError:
        macros_omp = []
        cflags_omp = ['-fopenmp',]  # noqa: E231

    for macro_ in macros_omp:
        macro_ = convert_macro(macro_)
        if macro_ not in macros:
            macros.append(macro_)
    for cflag_ in cflags_omp:
        if cflag_ not in cflags:
            cflags.append(cflag_)

    # Adapt `ldflags`, `libs` and `lib_dirs`.
    LIBS_OMP_BASED = [
        'fftw3_omp',
    ]  # noqa: E231
    for lib_ in LIBS_OMP_BASED:
        if lib_ and lib_ not in libs:
            libs.append(lib_)

    try:
        ldflags_omp, libs_omp, lib_dirs_omp = parse_cli_ldflags_omp()
    except TypeError:
        ldflags_omp = ['-fopenmp',]  # noqa: E231
        libs_omp = [OPENMP_LIBS[get_platform()],]  # noqa: E231
        lib_dirs_omp = []  # noqa: E231

    for ldflag_ in ldflags_omp:
        if ldflag_ not in ldflags:
            ldflags.append(ldflag_)
    for lib_ in libs_omp:
        if lib_ and lib_ not in libs:
            libs.append(lib_)
    for lib_dir_ in lib_dirs_omp:
        if lib_dir_ not in lib_dirs:
            lib_dirs.append(lib_dir_)

    return macros, cflags, ldflags, libs, lib_dirs, include_dirs


def add_options_pkgs(macros, cflags, ldflags, libs, lib_dirs, include_dirs):
    """Add options required by this package and external packages.

    Parameters
    ----------
    macros : list of tuple[str, Union[str, None]]
        Macros without the '-D' prefix.
    cflags : list of str
        ``CXXFLAGS`` components with non-'-D' and non-'-I' prefixes.
    ldflags : list of str
        ``LDFLAGS`` components with non-'-l' and non-'-L' prefixes.
    libs : list of str
        Libraries without the '-l' prefix.
    lib_dirs : list of str
        Library directories without the '-L' prefix.
    include_dirs : list of str
        ``INCLUDES`` directories without the '-I' prefix.

    Returns
    -------
    macros : list of tuple[str, Union[str, None]]
        Extended macros without the '-D' prefix.
    cflags : list of str
        Extended ``CXXFLAGS`` components with non-'-D' and
        non-'-I' prefixes.
    ldflags : list of str
        Extended ``LDFLAGS`` components with non-'-l' and
        non-'-L' prefixes.
    libs : list of str
        Extended libraries without the '-l' prefix.
    lib_dirs : list of str
        Extended library directories without the '-L' prefix.
    include_dirs : list of str
        Extended ``INCLUDES`` directories without the '-I' prefix.

    """
    # Adapt `macros`.
    MACROS_PKG = [
        ('TRV_EXTCALL', None),
        # ('TRV_USE_LEGACY_CODE', None),
        # ('DBG_MODE', None),
        # ('DBG_FLAG_NOAC', None),
    ]
    MACROS_EXT = [
        ('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION'),
    ]

    for macro_ in MACROS_PKG + MACROS_EXT:
        macros.append(macro_)

    # Adapt `ldflags`. Note the `rpath` option is added.
    for lib_dir_ in lib_dirs:
        ldflags.append(f'-Wl,-rpath,{lib_dir_}')

    # Adapt `libs`. Note the linking order matters.
    libs = [PKG_LIB_NAME,] + libs  # noqa: E231

    # Adapt `include_dirs`.
    include_dirs_pkg = [
        os.path.abspath(get_pkg_include_dir()),
    ]
    include_dirs_ext = [
        numpy.get_include(),
    ]

    for include_dir_ in include_dirs_pkg + include_dirs_ext:
        if include_dir_ not in include_dirs:
            include_dirs.append(include_dir_)

    return macros, cflags, ldflags, libs, lib_dirs, include_dirs


def cleanup_options(*args):
    """Clean up compilation options by removing duplicates.

    Parameters
    ----------
    *args : list of list of str
        List of compilation options.

    Returns
    -------
    list of list of str
        Cleaned-up compilation options.

    """
    ret_args = []
    for arg in args:
        ret_args.append(list(dict.fromkeys(arg)))

    return ret_args


# ========================================================================
# Targets
# ========================================================================

CYTHON_DIRECTIVES = {
    'language_level': '3',
    'c_string_encoding': 'utf-8',
    'embedsignature': True,
}

EXT_CONFIGS = {
    'parameters': {},
    'dataobjs': {},
    '_particles': {},
    '_field': {},
    '_twopt': {},
    '_threept': {},
    '_fftlog': {},
}


def define_pkg_library(lib_name=PKG_LIB_NAME):
    """Define package library to be built and linked against.

    Parameters
    ----------
    lib_name : str
        Package libaray name.

    Returns
    -------
    tuple[str, dict]
        Package library and corresponding configurations.

    """
    pkg_src_dir = get_pkg_src_dir()

    pkg_sources = [
        os.path.join(pkg_src_dir, _cpp_source)
        for _cpp_source in os.listdir(pkg_src_dir)
    ]

    pkg_cfg = {
        cfg_opt: globals()[cfg_opt]
        for cfg_opt in ['macros', 'cflags', 'include_dirs',]  # noqa: E231
    }

    pkg_library = (lib_name, dict(sources=pkg_sources, **pkg_cfg))

    return pkg_library


def define_pkg_extension(ext_name,
                         auto_cpp_source=False, extra_cpp_sources=None,
                         **ext_kwargs):
    """Define package extension from given source files and options.

    Parameters
    ----------
    ext_name : str
        Extension module name in the form ``<pkg_name>.<ext_name>``.
        This sets the .pyx source file to ``<pkg_dir>/<ext_name>.pyx``.
    auto_cpp_source : bool, optional
        If `True` (default is `False`), add
        ``<pkg_src_dir>/<ext_name>.cpp`` to the list of source files
        with any prefix underscores removed from ``<ext_name>``.
    extra_cpp_sources : list of str, optional
        Additional .cpp source files under ``<pkg_src_dir>``
        (default is `None`).
    **ext_kwargs
        Options to pass to :class:`Cython.Distutils.Extension`.

    Returns
    -------
    :class:`Cython.Distutils.Extension`
        Cython extension.

    """
    EXT_CFG_MAPPING = [
        ('define_macros', 'macros'),
        ('extra_compile_args', 'cflags'),
        ('extra_link_args', 'ldflags'),
        ('include_dirs', 'include_dirs'),
        ('library_dirs', 'lib_dirs'),
        ('libraries', 'libs'),
    ]

    # Define Cython sources.
    pkg_dir = get_pkg_dir()

    sources = [os.path.join(pkg_dir, f"{ext_name}.pyx"),]  # noqa: E231

    # Add C++ sources.
    pkg_src_dir = get_pkg_src_dir()

    if auto_cpp_source:
        sources.append(
            os.path.join(pkg_src_dir, f"{ext_name}.cpp".lstrip('_'))
        )

    if extra_cpp_sources is None:
        extra_cpp_sources = []
    for _cpp_source in extra_cpp_sources:
        sources.append(os.path.join(pkg_src_dir, _cpp_source))

    # Determine extension configurations.
    ext_module_kwargs = {
        cfg: globals()[cfg_var]
        for (cfg, cfg_var) in EXT_CFG_MAPPING
    }

    if ext_kwargs:
        ext_module_kwargs.update(ext_kwargs)

    return Extension(
        '{}.{}'.format(get_pkg_name(), ext_name),
        sources=sources, language=EXT_LANG, **ext_module_kwargs
    )


# ========================================================================
# Set-up
# ========================================================================

if __name__ == '__main__':

    # Check build environment.
    display_py_environs()

    # Parse compilation options.
    set_cli_compiler()

    macros, cflags = parse_cli_cflags()
    ldflags, libs, lib_dirs = parse_cli_ldflags()
    include_dirs = parse_cli_includes()

    # Adapt compilation options.
    macros, cflags, ldflags, libs, lib_dirs, include_dirs = add_options_nonomp(
        macros, cflags, ldflags, libs, lib_dirs, include_dirs
    )
    macros, cflags, ldflags, libs, lib_dirs, include_dirs = add_options_omp(
        macros, cflags, ldflags, libs, lib_dirs, include_dirs
    )
    macros, cflags, ldflags, libs, lib_dirs, include_dirs = add_options_pkgs(
        macros, cflags, ldflags, libs, lib_dirs, include_dirs
    )
    macros, cflags, ldflags, libs, lib_dirs, include_dirs = cleanup_options(
        macros, cflags, ldflags, libs, lib_dirs, include_dirs
    )

    # Check compilation options.
    display_py_options()

    # Define build targets.
    pkg_libraries = [define_pkg_library(),]  # noqa: E231

    pkg_extensions = [
        define_pkg_extension(ext, **cfg)
        for ext, cfg in EXT_CONFIGS.items()
    ]

    # Run build commands.
    cython_ext_modules = cythonize(
        pkg_extensions,
        compiler_directives=CYTHON_DIRECTIVES,
        nthreads=get_build_num_procs(),
    )

    setup_commands = {
        'build_clib': BuildClib,
        'build_ext': BuildExt,
    }

    setup(
        use_scm_version=get_pkg_version_scheme(),
        cmdclass=setup_commands,
        ext_modules=cython_ext_modules,
        libraries=pkg_libraries,
    )

```

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值