PKlCM uuskbuild/exceptions.py""" This module defines exceptions commonly used in scikit-build. """ class SKBuildError(RuntimeError): """Exception raised when an error occurs while configuring or building a project. """ pass class SKBuildGeneratorNotFoundError(SKBuildError): """Exception raised when no suitable generator is found for the current platform. """ pass PKlCMYQiYLLskbuild/setuptools_wrap.py"""This module provides functionality for wrapping key infrastructure components from distutils and setuptools. """ from __future__ import print_function import copy import os import os.path import sys import argparse import json import platform import stat from contextlib import contextmanager from distutils.errors import (DistutilsArgError, DistutilsError, DistutilsGetoptError) from glob import glob from shutil import copyfile, copymode from packaging.requirements import Requirement from packaging.version import parse as parse_version # XXX If 'six' becomes a dependency, use 'six.StringIO' instead. try: from StringIO import StringIO except ImportError: from io import StringIO try: from shutil import which except ImportError: from .compat import which from setuptools import setup as upstream_setup from setuptools.dist import Distribution as upstream_Distribution from . import cmaker from .command import (build, build_py, clean, install, install_lib, install_scripts, bdist, bdist_wheel, egg_info, sdist, generate_source_manifest, test) from .constants import (CMAKE_DEFAULT_EXECUTABLE, CMAKE_INSTALL_DIR, CMAKE_SPEC_FILE) from .exceptions import SKBuildError, SKBuildGeneratorNotFoundError from .utils import (mkdir_p, parse_manifestin, PythonModuleFinder, to_platform_path, to_unix_path) def create_skbuild_argparser(): """Create and return a scikit-build argument parser. """ parser = argparse.ArgumentParser(add_help=False) parser.add_argument( '--build-type', default='Release', metavar='', help='specify the CMake build type (e.g. Debug or Release)') parser.add_argument( '-G', '--generator', metavar='', help='specify the CMake build system generator') parser.add_argument( '-j', metavar='N', type=int, dest='jobs', help='allow N build jobs at once') parser.add_argument( '--cmake-executable', default=None, metavar='', help='specify the path to the cmake executable' ) parser.add_argument( '--skip-generator-test', action='store_true', help='skip generator test when a generator is explicitly selected using --generator' ) return parser def parse_skbuild_args(args, cmake_args, build_tool_args): """ Parse arguments in the scikit-build argument set. Convert specified arguments to proper format and append to cmake_args and build_tool_args. Returns the tuple ``(remaining arguments, cmake executable, skip_generator_test)``. """ parser = create_skbuild_argparser() namespace, remaining_args = parser.parse_known_args(args) # Construct CMake argument list cmake_args.append('-DCMAKE_BUILD_TYPE:STRING=' + namespace.build_type) if namespace.generator is not None: cmake_args.extend(['-G', namespace.generator]) # Construct build tool argument list build_tool_args.extend(['--config', namespace.build_type]) if namespace.jobs is not None: build_tool_args.extend(['-j', str(namespace.jobs)]) if namespace.generator is None and namespace.skip_generator_test is True: sys.exit("ERROR: Specifying --skip-generator-test requires --generator to also be specified.") return remaining_args, namespace.cmake_executable, namespace.skip_generator_test def parse_args(): """This function parses the command-line arguments ``sys.argv`` and returns the tuple ``(setuptools_args, cmake_executable, skip_generator_test, cmake_args, build_tool_args)`` where each ``*_args`` element corresponds to a set of arguments separated by ``--``.""" dutils = [] cmake = [] make = [] argsets = [dutils, cmake, make] i = 0 separator = '--' for arg in sys.argv: if arg == separator: i += 1 if i >= len(argsets): sys.exit( "ERROR: Too many \"{}\" separators provided " "(expected at most {}).".format(separator, len(argsets) - 1)) else: argsets[i].append(arg) dutils, cmake_executable, skip_generator_test = parse_skbuild_args(dutils, cmake, make) return dutils, cmake_executable, skip_generator_test, cmake, make @contextmanager def _capture_output(): oldout, olderr = sys.stdout, sys.stderr try: out = [StringIO(), StringIO()] sys.stdout, sys.stderr = out yield out finally: sys.stdout, sys.stderr = oldout, olderr out[0] = out[0].getvalue() out[1] = out[1].getvalue() def _parse_setuptools_arguments(setup_attrs): """This function instantiates a Distribution object and parses the command line arguments. It returns the tuple ``(display_only, help_commands, commands, hide_listing, force_cmake, skip_cmake, plat_name)`` where - display_only is a boolean indicating if an argument like '--help', '--help-commands' or '--author' was passed. - help_commands is a boolean indicating if argument '--help-commands' was passed. - commands contains the list of commands that were passed. - hide_listing is a boolean indicating if the list of files being included in the distribution is displayed or not. - force_cmake a boolean indicating that CMake should always be executed. - skip_cmake is a boolean indicating if the execution of CMake should explicitly be skipped. - plat_name is a string identifying the platform name to embed in generated filenames. It defaults to ``distutils.util.get_platform()``. Otherwise it raises DistutilsArgError exception if there are any error on the command-line, and it raises DistutilsGetoptError if there any error in the command 'options' attribute. The code has been adapted from the setup() function available in distutils/core.py. """ setup_attrs = dict(setup_attrs) setup_attrs['script_name'] = os.path.basename(sys.argv[0]) dist = upstream_Distribution(setup_attrs) # Update class attribute to also ensure the argument is processed # when ``upstream_setup`` is called. # pylint:disable=no-member upstream_Distribution.global_options.append( ('hide-listing', None, "do not display list of files being " "included in the distribution") ) # pylint:disable=no-member upstream_Distribution.global_options.append( ('force-cmake', None, "always run CMake") ) # pylint:disable=no-member upstream_Distribution.global_options.append( ('skip-cmake', None, "do not run CMake") ) # Find and parse the config file(s): they will override options from # the setup script, but be overridden by the command line. dist.parse_config_files() # Parse the command line and override config files; any # command-line errors are the end user's fault, so turn them into # SystemExit to suppress tracebacks. with _capture_output(): result = dist.parse_command_line() display_only = not result if not hasattr(dist, 'hide_listing'): dist.hide_listing = False if not hasattr(dist, 'force_cmake'): dist.force_cmake = False if not hasattr(dist, 'skip_cmake'): dist.skip_cmake = False plat_names = set() for cmd in [dist.get_command_obj(command) for command in dist.commands]: if getattr(cmd, 'plat_name', None) is not None: plat_names.add(cmd.plat_name) if not plat_names: plat_names.add(None) elif len(plat_names) > 1: raise SKBuildError( "--plat-name is ambiguous: %s" % ", ".join(plat_names)) plat_name = list(plat_names)[0] return (display_only, dist.help_commands, dist.commands, dist.hide_listing, dist.force_cmake, dist.skip_cmake, plat_name) def _check_skbuild_parameters(skbuild_kw): cmake_install_dir = skbuild_kw['cmake_install_dir'] if os.path.isabs(cmake_install_dir): raise SKBuildError(( "\n setup parameter 'cmake_install_dir' is set to " "an absolute path. A relative path is expected.\n" " Project Root : {}\n" " CMake Install Directory: {}\n").format( os.getcwd(), cmake_install_dir )) cmake_source_dir = skbuild_kw['cmake_source_dir'] if not os.path.exists(os.path.abspath(cmake_source_dir)): raise SKBuildError(( "\n setup parameter 'cmake_source_dir' set to " "a nonexistent directory.\n" " Project Root : {}\n" " CMake Source Directory: {}\n").format( os.getcwd(), cmake_source_dir )) def strip_package(package_parts, module_file): """Given ``package_parts`` (e.g. ``['foo', 'bar']``) and a ``module_file`` (e.g. ``foo/bar/jaz/rock/roll.py``), starting from the left, this function will strip the parts of the path matching the package parts and return a new string (e.g ``jaz/rock/roll.py``). The function will work as expected for either Windows or Unix-style ``module_file`` and this independently of the platform. """ if not package_parts or os.path.isabs(module_file): return module_file package = "/".join(package_parts) module_dir = os.path.dirname(module_file.replace("\\", "/")) module_dir = module_dir[:len(package)] return (module_file[len(package) + 1:] if package != "" and module_dir.startswith(package) else module_file) def _package_data_contain_module(module, package_data): """Return True if the ``module`` is contained in the ``package_data``. ``module`` is a tuple of the form ``(package, modulename, module_file)``. """ (package, _, module_file) = module if package not in package_data: return False # We need to strip the package because a module entry # usually looks like this: # # ('foo.bar', 'module', 'foo/bar/module.py') # # and the entry in package_data would look like this: # # {'foo.bar' : ['module.py']} if (strip_package(package.split("."), module_file) in package_data[package]): return True return False def _should_run_cmake(commands, cmake_with_sdist): """Return True if at least one command requiring ``cmake`` to run is found in ``commands``.""" for expected_command in [ "build", "develop", "install", "install_lib", "bdist", "bdist_dumb", "bdist_egg" "bdist_rpm", "bdist_wininst", "bdist_wheel", "test", ]: if expected_command in commands: return True if "sdist" in commands and cmake_with_sdist: return True return False def _save_cmake_spec(args): """Save the CMake spec to disk""" # We use JSON here because readability is more important than performance try: os.makedirs(os.path.dirname(CMAKE_SPEC_FILE)) except OSError: pass with open(CMAKE_SPEC_FILE, 'w+') as fp: json.dump(args, fp) def _load_cmake_spec(): """Load and return the CMake spec from disk""" try: with open(CMAKE_SPEC_FILE) as fp: return json.load(fp) except (OSError, IOError, ValueError): return None # pylint:disable=too-many-locals, too-many-branches def setup(*args, **kw): # noqa: C901 """This function wraps setup() so that we can run cmake, make, CMake build, then proceed as usual with setuptools, appending the CMake-generated output as necessary. The CMake project is re-configured only if needed. This is achieved by (1) retrieving the environment mapping associated with the generator set in the ``CMakeCache.txt`` file, (2) saving the CMake configure arguments and version in :const:`skbuild.constants.CMAKE_SPEC_FILE`: and (3) re-configuring only if either the generator or the CMake specs change. """ sys.argv, cmake_executable, skip_generator_test, cmake_args, make_args = parse_args() # work around https://bugs.python.org/issue1011113 # (patches provided, but no updates since 2014) cmdclass = kw.get('cmdclass', {}) cmdclass['build'] = cmdclass.get('build', build.build) cmdclass['build_py'] = cmdclass.get('build_py', build_py.build_py) cmdclass['install'] = cmdclass.get('install', install.install) cmdclass['install_lib'] = cmdclass.get('install_lib', install_lib.install_lib) cmdclass['install_scripts'] = cmdclass.get('install_scripts', install_scripts.install_scripts) cmdclass['clean'] = cmdclass.get('clean', clean.clean) cmdclass['sdist'] = cmdclass.get('sdist', sdist.sdist) cmdclass['bdist'] = cmdclass.get('bdist', bdist.bdist) cmdclass['bdist_wheel'] = cmdclass.get( 'bdist_wheel', bdist_wheel.bdist_wheel) cmdclass['egg_info'] = cmdclass.get('egg_info', egg_info.egg_info) cmdclass['generate_source_manifest'] = cmdclass.get( 'generate_source_manifest', generate_source_manifest.generate_source_manifest) cmdclass['test'] = cmdclass.get('test', test.test) kw['cmdclass'] = cmdclass # Extract setup keywords specific to scikit-build and remove them from kw. # Removing the keyword from kw need to be done here otherwise, the # following call to _parse_setuptools_arguments would complain about # unknown setup options. parameters = { 'cmake_args': [], 'cmake_install_dir': '', 'cmake_source_dir': '', 'cmake_with_sdist': False, 'cmake_languages': ('C', 'CXX'), 'cmake_minimum_required_version': None } skbuild_kw = {param: kw.pop(param, parameters[param]) for param in parameters} # ... and validate them try: _check_skbuild_parameters(skbuild_kw) except SKBuildError as ex: import traceback print("Traceback (most recent call last):") traceback.print_tb(sys.exc_info()[2]) print('') sys.exit(ex) # Convert source dir to a path relative to the root # of the project cmake_source_dir = skbuild_kw['cmake_source_dir'] if cmake_source_dir == ".": cmake_source_dir = "" if os.path.isabs(cmake_source_dir): cmake_source_dir = os.path.relpath(cmake_source_dir) # Skip running CMake in the following cases: # * flag "--skip-cmake" is provided # * "display only" argument is provided (e.g '--help', '--author', ...) # * no command-line arguments or invalid ones are provided # * no command requiring cmake is provided # * no CMakeLists.txt if found display_only = has_invalid_arguments = help_commands = False force_cmake = skip_cmake = False commands = [] try: (display_only, help_commands, commands, hide_listing, force_cmake, skip_cmake, plat_name) = \ _parse_setuptools_arguments(kw) except (DistutilsArgError, DistutilsGetoptError): has_invalid_arguments = True has_cmakelists = os.path.exists( os.path.join(cmake_source_dir, "CMakeLists.txt")) if not has_cmakelists: print('skipping skbuild (no CMakeLists.txt found)') skip_skbuild = (display_only or has_invalid_arguments or not _should_run_cmake(commands, skbuild_kw["cmake_with_sdist"]) or not has_cmakelists) if skip_skbuild and not force_cmake: if help_commands: # Prepend scikit-build help. Generate option descriptions using # argparse. skbuild_parser = create_skbuild_argparser() arg_descriptions = [ line for line in skbuild_parser.format_help().split('\n') if line.startswith(' ') ] print('scikit-build options:') print('\n'.join(arg_descriptions)) print('') print('Arguments following a "--" are passed directly to CMake ' '(e.g. -DMY_VAR:BOOL=TRUE).') print('Arguments following a second "--" are passed directly to ' ' the build tool.') print('') return upstream_setup(*args, **kw) developer_mode = "develop" in commands or "test" in commands packages = kw.get('packages', []) package_dir = kw.get('package_dir', {}) package_data = copy.deepcopy(kw.get('package_data', {})) py_modules = kw.get('py_modules', []) new_py_modules = {py_module: False for py_module in py_modules} scripts = kw.get('scripts', []) new_scripts = {script: False for script in scripts} data_files = { (parent_dir or '.'): set(file_list) for parent_dir, file_list in kw.get('data_files', []) } # Since CMake arguments provided through the command line have more # weight and when CMake is given multiple times a argument, only the last # one is considered, let's prepend the one provided in the setup call. cmake_args = skbuild_kw['cmake_args'] + cmake_args # Set CMAKE_OSX_DEPLOYMENT_TARGET and CMAKE_OSX_ARCHITECTURES if not already # specified if sys.platform == 'darwin': if plat_name is None: # The following code is duplicated in bdist_wheel.finalize_options() plat_name = "macosx-10.6-x86_64" (_, version, machine) = plat_name.split('-') if not cmaker.has_cmake_cache_arg( cmake_args, 'CMAKE_OSX_DEPLOYMENT_TARGET'): cmake_args.append( '-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=%s' % version ) if not cmaker.has_cmake_cache_arg( cmake_args, 'CMAKE_OSX_ARCHITECTURES'): cmake_args.append( '-DCMAKE_OSX_ARCHITECTURES:STRING=%s' % machine ) # Install cmake if listed in `setup_requires` for package in kw.get('setup_requires', []): if Requirement(package).name == 'cmake': setup_requires = [package] dist = upstream_Distribution({'setup_requires': setup_requires}) dist.fetch_build_eggs(setup_requires) # Considering packages associated with "setup_requires" keyword are # installed in .eggs subdirectory without honoring setuptools "console_scripts" # entry_points and without settings the expected executable permissions, we are # taking care of it below. import cmake for executable in ['cmake', 'cpack', 'ctest']: executable = os.path.join(cmake.CMAKE_BIN_DIR, executable) if platform.system().lower() == 'windows': executable += '.exe' st = os.stat(executable) permissions = ( st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH ) os.chmod(executable, permissions) cmake_executable = os.path.join(cmake.CMAKE_BIN_DIR, 'cmake') break # Languages are used to determine a working generator cmake_languages = skbuild_kw['cmake_languages'] try: if cmake_executable is None: cmake_executable = CMAKE_DEFAULT_EXECUTABLE cmkr = cmaker.CMaker(cmake_executable) if not skip_cmake: cmake_minimum_required_version = skbuild_kw['cmake_minimum_required_version'] if cmake_minimum_required_version is not None: if parse_version(cmkr.cmake_version) < parse_version(cmake_minimum_required_version): raise SKBuildError( "CMake version %s or higher is required. CMake version %s is being used" % ( cmake_minimum_required_version, cmkr.cmake_version)) # Used to confirm that the cmake executable is the same, and that the environment # didn't change cmake_spec = { 'args': [which(CMAKE_DEFAULT_EXECUTABLE)] + cmake_args, 'version': cmkr.cmake_version, 'environment': { 'PYTHONNOUSERSITE': os.environ.get("PYTHONNOUSERSITE"), 'PYTHONPATH': os.environ.get("PYTHONPATH") } } # skip the configure step for a cached build env = cmkr.get_cached_generator_env() if env is None or cmake_spec != _load_cmake_spec(): env = cmkr.configure(cmake_args, skip_generator_test=skip_generator_test, cmake_source_dir=cmake_source_dir, cmake_install_dir=skbuild_kw['cmake_install_dir'], languages=cmake_languages ) _save_cmake_spec(cmake_spec) cmkr.make(make_args, env=env) except SKBuildGeneratorNotFoundError as ex: sys.exit(ex) except SKBuildError as ex: import traceback print("Traceback (most recent call last):") traceback.print_tb(sys.exc_info()[2]) print('') sys.exit(ex) # If any, strip ending slash from each package directory package_dir = {package: prefix[:-1] if prefix[-1] == "/" else prefix for package, prefix in package_dir.items()} # If needed, set reasonable defaults for package_dir for package in packages: if package not in package_dir: package_dir[package] = package.replace(".", "/") if '' in package_dir: package_dir[package] = to_unix_path(os.path.join(package_dir[''], package_dir[package])) package_prefixes = _collect_package_prefixes(package_dir, packages) _classify_installed_files(cmkr.install(), package_data, package_prefixes, py_modules, new_py_modules, scripts, new_scripts, data_files, cmake_source_dir, skbuild_kw['cmake_install_dir']) original_manifestin_data_files = [] if kw.get("include_package_data", False): original_manifestin_data_files = parse_manifestin(os.path.join(os.getcwd(), "MANIFEST.in")) for path in original_manifestin_data_files: _classify_file(path, package_data, package_prefixes, py_modules, new_py_modules, scripts, new_scripts, data_files) if developer_mode: # Copy packages for package, package_file_list in package_data.items(): for package_file in package_file_list: package_file = os.path.join(package_dir[package], package_file) cmake_file = os.path.join(CMAKE_INSTALL_DIR, package_file) if os.path.exists(cmake_file): _copy_file(cmake_file, package_file, hide_listing) # Copy modules for py_module in py_modules: package_file = py_module + ".py" cmake_file = os.path.join(CMAKE_INSTALL_DIR, package_file) if os.path.exists(cmake_file): _copy_file(cmake_file, package_file, hide_listing) else: _consolidate_package_modules( cmake_source_dir, packages, package_dir, py_modules, package_data, hide_listing) original_package_data = kw.get('package_data', {}).copy() _consolidate_package_data_files(original_package_data, package_prefixes, hide_listing) for data_file in original_manifestin_data_files: dest_data_file = os.path.join(CMAKE_INSTALL_DIR, data_file) _copy_file(data_file, dest_data_file, hide_listing) kw['package_data'] = package_data kw['package_dir'] = { package: ( os.path.join(CMAKE_INSTALL_DIR, prefix) if os.path.exists(os.path.join(CMAKE_INSTALL_DIR, prefix)) else prefix) for prefix, package in package_prefixes } kw['scripts'] = [ os.path.join(CMAKE_INSTALL_DIR, script) if mask else script for script, mask in new_scripts.items() ] kw['data_files'] = [ (parent_dir, list(file_set)) for parent_dir, file_set in data_files.items() ] if 'zip_safe' not in kw: kw['zip_safe'] = False # Adapted from espdev/ITKPythonInstaller/setup.py.in # pylint: disable=missing-docstring class BinaryDistribution(upstream_Distribution): def has_ext_modules(self): # pylint: disable=no-self-use return has_cmakelists kw['distclass'] = BinaryDistribution print("") return upstream_setup(*args, **kw) def _collect_package_prefixes(package_dir, packages): """ Collect the list of prefixes for all packages The list is used to match paths in the install manifest to packages specified in the setup.py script. The list is sorted in decreasing order of prefix length so that paths are matched with their immediate parent package, instead of any of that package's ancestors. For example, consider the project structure below. Assume that the setup call was made with a package list featuring "top" and "top.bar", but not "top.not_a_subpackage". top/ -> top/ __init__.py -> top/__init__.py (parent: top) foo.py -> top/foo.py (parent: top) bar/ -> top/bar/ (parent: top) __init__.py -> top/bar/__init__.py (parent: top.bar) not_a_subpackage/ -> top/not_a_subpackage/ (parent: top) data_0.txt -> top/not_a_subpackage/data_0.txt (parent: top) data_1.txt -> top/not_a_subpackage/data_1.txt (parent: top) The paths in the generated install manifest are matched to packages according to the parents indicated on the right. Only packages that are specified in the setup() call are considered. Because of the sort order, the data files on the bottom would have been mapped to "top.not_a_subpackage" instead of "top", proper -- had such a package been specified. """ return list(sorted( ( (package_dir[package].replace('.', '/'), package) for package in packages ), key=lambda tup: len(tup[0]), reverse=True )) def _classify_installed_files(install_paths, package_data, package_prefixes, py_modules, new_py_modules, scripts, new_scripts, data_files, cmake_source_dir, cmake_install_dir): assert not os.path.isabs(cmake_source_dir) assert cmake_source_dir != "." install_root = os.path.join(os.getcwd(), CMAKE_INSTALL_DIR) for path in install_paths: # if this installed file is not within the project root, complain and # exit if not to_platform_path(path).startswith(CMAKE_INSTALL_DIR): raise SKBuildError(( "\n CMake-installed files must be within the project root.\n" " Project Root : {}\n" " Violating File: {}\n").format( install_root, to_platform_path(path))) # peel off the 'skbuild' prefix path = to_unix_path(os.path.relpath(path, CMAKE_INSTALL_DIR)) _classify_file(path, package_data, package_prefixes, py_modules, new_py_modules, scripts, new_scripts, data_files) def _classify_file(path, package_data, package_prefixes, py_modules, new_py_modules, scripts, new_scripts, data_files): found_package = False found_module = False found_script = False path = to_unix_path(path) # check to see if path is part of a package for prefix, package in package_prefixes: if path.startswith(prefix + "/"): # peel off the package prefix path = to_unix_path(os.path.relpath(path, prefix)) package_file_list = package_data.get(package, []) package_file_list.append(path) package_data[package] = package_file_list found_package = True break if found_package: return # If control reaches this point, then this installed file is not part of # a package. # check if path is a module for module in py_modules: if path.replace("/", ".") == ".".join((module, "py")): new_py_modules[module] = True found_module = True break if found_module: return # If control reaches this point, then this installed file is not a # module # if the file is a script, mark the corresponding script for script in scripts: if path == script: new_scripts[script] = True found_script = True break if found_script: return # If control reaches this point, then this installed file is not a # script # If control reaches this point, then we have installed files that are # not part of a package, not a module, nor a script. Without any other # information, we can only treat it as a generic data file. parent_dir = os.path.dirname(path) file_set = data_files.get(parent_dir) if file_set is None: file_set = set() data_files[parent_dir] = file_set file_set.add(os.path.join(CMAKE_INSTALL_DIR, path)) def _copy_file(src_file, dest_file, hide_listing=True): """Copy ``src_file`` to ``dest_file`` ensuring parent directory exists. By default, message like `creating directory /path/to/package` and `copying directory /src/path/to/package -> path/to/package` are displayed on standard output. Setting ``hide_listing`` to False avoids message from being displayed. """ # Create directory if needed dest_dir = os.path.dirname(dest_file) if dest_dir != "" and not os.path.exists(dest_dir): if not hide_listing: print("creating directory {}".format(dest_dir)) mkdir_p(dest_dir) # Copy file if not hide_listing: print("copying {} -> {}".format(src_file, dest_file)) copyfile(src_file, dest_file) copymode(src_file, dest_file) def _consolidate_package_modules( cmake_source_dir, packages, package_dir, py_modules, package_data, hide_listing ): """This function consolidates packages having modules located in both the source tree and the CMake install tree into one location. The one location is the CMake install tree (see data::`.constants.CMAKE_INSTALL_DIR`). Why ? This is a necessary evil because ``Setuptools`` keeps track of packages and modules files to install using a dictionary of lists where the key are package names (e.g ``foo.bar``) and the values are lists of module files (e.g ``['__init__.py', 'baz.py']``. Since this doesn't allow to "split" files associated with a given module in multiple location, one location is selected, and files are copied over. How? It currently searches for modules across both locations using the :class:`.utils.PythonModuleFinder`. then with the help of :func:`_package_data_contain_module`, it identifies which one are either already included or missing from the distribution. Once a module has been identified as ``missing``, it is both copied into the data::`.constants.CMAKE_INSTALL_DIR` and added to the ``package_data`` dictionary so that it can be considered by the upstream setup function. """ try: # Search for python modules in both the current directory # and cmake install tree. modules = PythonModuleFinder( packages, package_dir, py_modules, alternative_build_base=CMAKE_INSTALL_DIR ).find_all_modules() except DistutilsError as msg: raise SystemExit("error: {}".format(str(msg))) print("") for entry in modules: # Check if module file should be copied into the CMake install tree. if _package_data_contain_module(entry, package_data): continue (package, _, src_module_file) = entry # Copy missing module file if os.path.exists(src_module_file): dest_module_file = os.path.join(CMAKE_INSTALL_DIR, src_module_file) _copy_file(src_module_file, dest_module_file, hide_listing) # Since the mapping in package_data expects the package to be associated # with a list of files relative to the directory containing the package, # the following section makes sure to strip the redundant part of the # module file path. # The redundant part should be stripped for both cmake_source_dir and # the package. package_parts = [] if cmake_source_dir: package_parts = cmake_source_dir.split(os.path.sep) package_parts += package.split(".") stripped_module_file = strip_package(package_parts, src_module_file) # Update list of files associated with the corresponding package try: package_data[package].append(stripped_module_file) except KeyError: package_data[package] = [stripped_module_file] def _consolidate_package_data_files(original_package_data, package_prefixes, hide_listing): """This function copies package data files specified using the ``package_data`` keyword into data::`.constants.CMAKE_INSTALL_DIR`. :: setup(..., packages=['mypkg'], package_dir={'mypkg': 'src/mypkg'}, package_data={'mypkg': ['data/*.dat']}, ) Considering that (1) the packages associated with modules located in both the source tree and the CMake install tree are consolidated into the CMake install tree, and (2) the consolidated package path set in the ``package_dir`` dictionary and later used by setuptools to package (or install) modules and data files is data::`.constants.CMAKE_INSTALL_DIR`, copying the data files is required to ensure setuptools can find them when it uses the package directory. """ project_root = os.getcwd() for prefix, package in package_prefixes: if package not in original_package_data: continue raw_patterns = original_package_data[package] for pattern in raw_patterns: expanded_package_dir = os.path.join(project_root, prefix, pattern) for src_data_file in glob(expanded_package_dir): full_prefix_length = len(os.path.join(project_root, prefix)) + 1 data_file = src_data_file[full_prefix_length:] dest_data_file = os.path.join(CMAKE_INSTALL_DIR, prefix, data_file) _copy_file(src_data_file, dest_data_file, hide_listing) PKmCMskbuild/_version.py # This file was generated by 'versioneer.py' (0.18) from # revision-control system data, or from the parent directory name of an # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. import json version_json = ''' { "date": "2018-10-03T09:43:52-0400", "dirty": false, "error": null, "full-revisionid": "be0c3254234f68f3c04d55a03e88a1223e63b533", "version": "0.8.1" } ''' # END VERSION_JSON def get_versions(): return json.loads(version_json) PKlCMڪ2JJskbuild/cmaker.py""" This module provides an interface for invoking CMake executable. """ import argparse import distutils.sysconfig as du_sysconfig import glob import io import itertools import os import os.path import platform import re import subprocess import shlex import sys import sysconfig from .constants import (CMAKE_BUILD_DIR, CMAKE_DEFAULT_EXECUTABLE, CMAKE_INSTALL_DIR, SETUPTOOLS_INSTALL_DIR) from .platform_specifics import get_platform from .exceptions import SKBuildError RE_FILE_INSTALL = re.compile( r"""[ \t]*file\(INSTALL DESTINATION "([^"]+)".*"([^"]+)"\).*""") def pop_arg(arg, args, default=None): """Pops an argument ``arg`` from an argument list ``args`` and returns the new list and the value of the argument if present and a default otherwise. """ parser = argparse.ArgumentParser(add_help=False) parser.add_argument(arg) namespace, args = parser.parse_known_args(args) namespace = tuple(vars(namespace).items()) if namespace and namespace[0][1] is not None: val = namespace[0][1] else: val = default return args, val def _remove_cwd_prefix(path): cwd = os.getcwd() result = path.replace("/", os.sep) if result.startswith(cwd): result = os.path.relpath(result, cwd) if platform.system() == "Windows": result = result.replace("\\\\", os.sep) result = result.replace("\n", "") return result def has_cmake_cache_arg(cmake_args, arg_name, arg_value=None): """Return True if ``-D:TYPE=`` is found in ``cmake_args``. If ``arg_value`` is None, return True only if ``-D:`` is found in the list.""" for arg in reversed(cmake_args): if arg.startswith("-D%s:" % arg_name): if arg_value is None: return True elif "=" in arg: return arg.split("=")[1] == arg_value return False def get_cmake_version(cmake_executable=CMAKE_DEFAULT_EXECUTABLE): """Runs CMake and extracts associated version information. Raises :class:`skbuild.exceptions.SKBuildError` if it failed to execute CMake. """ try: version_string = subprocess.check_output([cmake_executable, '--version']) except (OSError, subprocess.CalledProcessError): raise SKBuildError( "Problem with the CMake installation, aborting build. CMake executable is %s" % cmake_executable) if sys.version_info > (3, 0): version_string = version_string.decode() return version_string.splitlines()[0].split(' ')[-1] class CMaker(object): """Interface to CMake executable.""" def __init__(self, cmake_executable=CMAKE_DEFAULT_EXECUTABLE): self.cmake_executable = cmake_executable self.cmake_version = get_cmake_version(self.cmake_executable) self.platform = get_platform() def get_cached_generator_name(self): """Reads and returns the cached generator from the :const:`skbuild.constants.CMAKE_BUILD_DIR`:. Returns None if not found. """ try: cmake_generator = 'CMAKE_GENERATOR:INTERNAL=' with open(os.path.join(CMAKE_BUILD_DIR, 'CMakeCache.txt')) as fp: for line in fp: if line.startswith(cmake_generator): return line[len(cmake_generator):].strip() except (OSError, IOError): pass return None def get_cached_generator_env(self): """If any, return a mapping of environment associated with the cached generator. """ generator_name = self.get_cached_generator_name() if generator_name is not None: return self.platform.get_generator(generator_name).env return None def configure(self, clargs=(), generator_name=None, skip_generator_test=False, cmake_source_dir='.', cmake_install_dir='', languages=('C', 'CXX'), cleanup=True): """Calls cmake to generate the Makefile/VS Solution/XCode project. clargs: tuple List of command line arguments to pass to cmake executable. generator_name: string The string representing the CMake generator to use. If None, uses defaults for your platform. skip_generator_test: bool If set to True and if a generator name is specified (either as a keyword argument or as `clargs` using `-G `), the generator test is skipped. cmake_source_dir: string Path to source tree containing a ``CMakeLists.txt`` cmake_install_dir: string Relative directory to append to :const:`skbuild.constants.CMAKE_INSTALL_DIR`. languages: tuple List of languages required to configure the project and expected to be supported by the compiler. The language identifier that can be specified in the list corresponds to the one recognized by CMake. cleanup: bool If True, cleans up temporary folder used to test generators. Set to False for debugging to see CMake's output files. Return a mapping of the environment associated with the selected :class:`skbuild.platform_specifics.abstract.CMakeGenerator`. Mapping of the environment can also be later retrieved using :meth:`.get_cached_generator_env`. """ # if no provided default generator_name, check environment if generator_name is None: generator_name = os.environ.get("CMAKE_GENERATOR") # if generator_name is provided on command line, use it clargs, cli_generator_name = pop_arg('-G', clargs) if cli_generator_name is not None: generator_name = cli_generator_name # use the generator returned from the platform, with the current # generator_name as a suggestion generator = self.platform.get_best_generator( generator_name, skip_generator_test=skip_generator_test, cmake_executable=self.cmake_executable, cmake_args=clargs, languages=languages, cleanup=cleanup) if not os.path.exists(CMAKE_BUILD_DIR): os.makedirs(CMAKE_BUILD_DIR) if not os.path.exists(CMAKE_INSTALL_DIR): os.makedirs(CMAKE_INSTALL_DIR) if not os.path.exists(SETUPTOOLS_INSTALL_DIR): os.makedirs(SETUPTOOLS_INSTALL_DIR) python_version = CMaker.get_python_version() python_include_dir = CMaker.get_python_include_dir(python_version) python_library = CMaker.get_python_library(python_version) cmake_source_dir = os.path.abspath(cmake_source_dir) cmd = [ self.cmake_executable, cmake_source_dir, '-G', generator.name, ("-DCMAKE_INSTALL_PREFIX:PATH=" + os.path.abspath( os.path.join(CMAKE_INSTALL_DIR, cmake_install_dir))), ("-DPYTHON_EXECUTABLE:FILEPATH=" + sys.executable), ("-DPYTHON_VERSION_STRING:STRING=" + sys.version.split(' ')[0]), ("-DPYTHON_INCLUDE_DIR:PATH=" + python_include_dir), ("-DPYTHON_LIBRARY:FILEPATH=" + python_library), ("-DSKBUILD:BOOL=" + "TRUE"), ("-DCMAKE_MODULE_PATH:PATH=" + os.path.join(os.path.dirname(__file__), "resources", "cmake")) ] cmd.extend(clargs) cmd.extend( filter(bool, shlex.split(os.environ.get("SKBUILD_CONFIGURE_OPTIONS", ""))) ) # changes dir to cmake_build and calls cmake's configure step # to generate makefile rtn = subprocess.call(cmd, cwd=CMAKE_BUILD_DIR, env=generator.env) if rtn != 0: raise SKBuildError( "An error occurred while configuring with CMake.\n" " Command:\n" " {}\n" " Source directory:\n" " {}\n" " Working directory:\n" " {}\n" "Please see CMake's output for more information.".format( self._formatArgsForDisplay(cmd), os.path.abspath(cmake_source_dir), os.path.abspath(CMAKE_BUILD_DIR))) CMaker.check_for_bad_installs() return generator.env @staticmethod def get_python_version(): """Get version associated with the current python interpreter.""" python_version = sysconfig.get_config_var('VERSION') if not python_version: python_version = sysconfig.get_config_var('py_version_short') if not python_version: python_version = ".".join(map(str, sys.version_info[:2])) return python_version # NOTE(opadron): The try-excepts raise the cyclomatic complexity, but we # need them for this function. @staticmethod # noqa: C901 def get_python_include_dir(python_version): """Get include directory associated with the current python interpreter.""" # determine python include dir python_include_dir = sysconfig.get_config_var('INCLUDEPY') # if Python.h not found (or python_include_dir is None), try to find a # suitable include dir found_python_h = ( python_include_dir is not None or os.path.exists(os.path.join(python_include_dir, 'Python.h')) ) if not found_python_h: # NOTE(opadron): these possible prefixes must be guarded against # AttributeErrors and KeyErrors because they each can throw on # different platforms or even different builds on the same platform. include_py = sysconfig.get_config_var('INCLUDEPY') include_dir = sysconfig.get_config_var('INCLUDEDIR') include = None plat_include = None python_inc = None python_inc2 = None try: include = sysconfig.get_path('include') except (AttributeError, KeyError): pass try: plat_include = sysconfig.get_path('platinclude') except (AttributeError, KeyError): pass try: python_inc = sysconfig.get_python_inc() except AttributeError: pass if include_py is not None: include_py = os.path.dirname(include_py) if include is not None: include = os.path.dirname(include) if plat_include is not None: plat_include = os.path.dirname(plat_include) if python_inc is not None: python_inc2 = os.path.join( python_inc, ".".join(map(str, sys.version_info[:2]))) candidate_prefixes = list(filter(bool, ( include_py, include_dir, include, plat_include, python_inc, python_inc2, ))) candidate_versions = (python_version,) if python_version: candidate_versions += ('',) candidates = ( os.path.join(prefix, ''.join(('python', ver))) for (prefix, ver) in itertools.product( candidate_prefixes, candidate_versions ) ) for candidate in candidates: if os.path.exists(os.path.join(candidate, 'Python.h')): # we found an include directory python_include_dir = candidate break # TODO(opadron): what happens if we don't find an include directory? # Throw SKBuildError? return python_include_dir @staticmethod def get_python_library(python_version): """Get path to the python library associated with the current python interpreter.""" # determine direct path to libpython python_library = sysconfig.get_config_var('LIBRARY') # if static (or nonexistent), try to find a suitable dynamic libpython if (python_library is None or os.path.splitext(python_library)[1][-2:] == '.a'): candidate_lib_prefixes = ['', 'lib'] candidate_extensions = ['.lib', '.so', '.a'] if sysconfig.get_config_var('WITH_DYLD'): candidate_extensions.insert(0, '.dylib') candidate_versions = [python_version] if python_version: candidate_versions.append('') candidate_versions.insert( 0, "".join(python_version.split(".")[:2])) abiflags = getattr(sys, 'abiflags', '') candidate_abiflags = [abiflags] if abiflags: candidate_abiflags.append('') # Ensure the value injected by virtualenv is # returned on windows. # Because calling `sysconfig.get_config_var('multiarchsubdir')` # returns an empty string on Linux, `du_sysconfig` is only used to # get the value of `LIBDIR`. libdir = du_sysconfig.get_config_var('LIBDIR') if sysconfig.get_config_var('MULTIARCH'): masd = sysconfig.get_config_var('multiarchsubdir') if masd: if masd.startswith(os.sep): masd = masd[len(os.sep):] libdir = os.path.join(libdir, masd) if libdir is None: libdir = os.path.abspath(os.path.join( sysconfig.get_config_var('LIBDEST'), "..", "libs")) candidates = ( os.path.join( libdir, ''.join((pre, 'python', ver, abi, ext)) ) for (pre, ext, ver, abi) in itertools.product( candidate_lib_prefixes, candidate_extensions, candidate_versions, candidate_abiflags ) ) for candidate in candidates: if os.path.exists(candidate): # we found a (likely alternate) libpython python_library = candidate break # TODO(opadron): what happens if we don't find a libpython? return python_library @staticmethod def check_for_bad_installs(): """This function tries to catch files that are meant to be installed outside the project root before they are actually installed. Indeed, we can not wait for the manifest, so we try to extract the information (install destination) from the CMake build files ``*.cmake`` found in :const:`skbuild.constants.CMAKE_BUILD_DIR`. It raises :class:`skbuild.exceptions.SKBuildError` if it found install destination outside of :const:`skbuild.constants.CMAKE_INSTALL_DIR`. """ bad_installs = [] install_dir = os.path.join(os.getcwd(), CMAKE_INSTALL_DIR) for root, _, file_list in os.walk(CMAKE_BUILD_DIR): for filename in file_list: if os.path.splitext(filename)[1] != ".cmake": continue for line in io.open(os.path.join(root, filename), encoding="utf-8"): match = RE_FILE_INSTALL.match(line) if match is None: continue destination = os.path.normpath( match.group(1).replace("${CMAKE_INSTALL_PREFIX}", install_dir)) if not destination.startswith(install_dir): bad_installs.append( os.path.join( destination, os.path.basename(match.group(2)) ) ) if bad_installs: raise SKBuildError("\n".join(( " CMake-installed files must be within the project root.", " Project Root:", " " + install_dir, " Violating Files:", "\n".join( (" " + _install) for _install in bad_installs) ))) def make(self, clargs=(), config="Release", source_dir=".", env=None): """Calls the system-specific make program to compile code. """ clargs, config = pop_arg('--config', clargs, config) if not os.path.exists(CMAKE_BUILD_DIR): raise SKBuildError(("CMake build folder ({}) does not exist. " "Did you forget to run configure before " "make?").format(CMAKE_BUILD_DIR)) cmd = [self.cmake_executable, "--build", source_dir, "--target", "install", "--config", config, "--"] cmd.extend(clargs) cmd.extend( filter(bool, shlex.split(os.environ.get("SKBUILD_BUILD_OPTIONS", ""))) ) rtn = subprocess.call(cmd, cwd=CMAKE_BUILD_DIR, env=env) if rtn != 0: raise SKBuildError( "An error occurred while building with CMake.\n" " Command:\n" " {}\n" " Source directory:\n" " {}\n" " Working directory:\n" " {}\n" "Please see CMake's output for more information.".format( self._formatArgsForDisplay(cmd), os.path.abspath(source_dir), os.path.abspath(CMAKE_BUILD_DIR))) def install(self): """Returns a list of file paths to install via setuptools that is compatible with the data_files keyword argument. """ return self._parse_manifests() def _parse_manifests(self): paths = \ glob.glob(os.path.join(CMAKE_BUILD_DIR, "install_manifest*.txt")) try: return [self._parse_manifest(path) for path in paths][0] except IndexError: return [] @staticmethod def _parse_manifest(install_manifest_path): with open(install_manifest_path, "r") as manifest: return [_remove_cwd_prefix(path) for path in manifest] return [] @staticmethod def _formatArgsForDisplay(args): """Format a list of arguments appropriately for display. When formatting a command and its arguments, the user should be able to execute the command by copying and pasting the output directly into a shell. Currently, the only formatting is naively surrounding each argument with quotation marks. """ return ' '.join("\"{}\"".format(arg) for arg in args) PKlCMuƳskbuild/constants.py""" This module defines constants commonly used in scikit-build. """ import os import sys from distutils.util import get_platform SKBUILD_DIR = os.path.join( "_skbuild", "{}-{}".format(get_platform(), '.'.join(map(str, sys.version_info[:2]))), ) """Top-level directory where setuptools and CMake directories are generated.""" CMAKE_DEFAULT_EXECUTABLE = "cmake" """Default path to CMake executable.""" CMAKE_BUILD_DIR = os.path.join(SKBUILD_DIR, "cmake-build") """CMake build directory.""" CMAKE_INSTALL_DIR = os.path.join(SKBUILD_DIR, "cmake-install") """CMake install directory.""" CMAKE_SPEC_FILE = os.path.join(CMAKE_BUILD_DIR, "CMakeSpec.json") """CMake specification file storing CMake version, CMake configuration arguments and environment variables ``PYTHONNOUSERSITE`` and ``PYTHONPATH``. """ SETUPTOOLS_INSTALL_DIR = os.path.join(SKBUILD_DIR, "setuptools") """Setuptools install directory.""" PKlCMQ  skbuild/compat.pyimport os def which(name, flags=os.X_OK): """Analogue of unix 'which'. Borrowed from the Twisted project, see their licence here: https://twistedmatrix.com/trac/browser/trunk/LICENSE Copied from ``pytest_shutil.cmdline.which`` to allow testing on conda-forge where ``pytest-shutil`` is not available. """ result = [] exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep)) path = os.environ.get('PATH', None) if path is None: return [] for p in os.environ.get('PATH', '').split(os.pathsep): p = os.path.join(p, name) if os.access(p, flags): result.append(p) for e in exts: pext = p + e if os.access(pext, flags): result.append(pext) return result PKlCMѹ3skbuild/__init__.py# -*- coding: utf-8 -*- """ scikit-build is an improved build system generator for CPython C extensions. This module provides the *glue* between the setuptools Python module and CMake. """ from ._version import get_versions from .setuptools_wrap import setup # noqa: F401 __author__ = 'The scikit-build team' __email__ = 'scikit-build@googlegroups.com' __version__ = '0.7.1' __version__ = get_versions()['version'] __all__ = ["setup"] del get_versions PKlCMR"skbuild/platform_specifics/unix.py"""This module defines object specific to Unix platform.""" from .abstract import CMakeGenerator from . import abstract # pylint:disable=abstract-method class UnixPlatform(abstract.CMakePlatform): """Unix implementation of :class:`.abstract.CMakePlatform`.""" def __init__(self): super(UnixPlatform, self).__init__() self.default_generators = [ CMakeGenerator("Ninja"), CMakeGenerator("Unix Makefiles") ] PKlCMl;!skbuild/platform_specifics/bsd.py"""This module defines object specific to BSD platform.""" from . import unix # pylint:disable=abstract-method class BSDPlatform(unix.UnixPlatform): """BSD implementation of :class:`.abstract.CMakePlatform`.""" pass PKlCMz;;.skbuild/platform_specifics/platform_factory.py"""This modules implements the logic allowing to instantiate the expected :class:`.abstract.CMakePlatform`.""" import platform from . import bsd from . import linux from . import osx from . import windows def get_platform(): """Return an instance of :class:`.abstract.CMakePlatform` corresponding to the current platform.""" this_platform = platform.system().lower() if this_platform == "windows": return windows.WindowsPlatform() if this_platform == "linux": return linux.LinuxPlatform() elif this_platform == "freebsd": return bsd.BSDPlatform() elif this_platform == "darwin": return osx.OSXPlatform() else: raise RuntimeError("Unsupported platform: {:s}. Please contact " "the scikit-build team.".format(this_platform)) PKlCM//&skbuild/platform_specifics/__init__.py"""This package provides :func:`get_platform()` allowing to get an instance of :class:`.abstract.CMakePlatform` matching the current platform. """ from .abstract import CMakeGenerator # noqa: F401 from .platform_factory import get_platform # noqa: F401 __all__ = ["CMakeGenerator", "get_platform"] PKlCM oo!skbuild/platform_specifics/osx.py"""This module defines object specific to OSX platform.""" import sys import textwrap from . import unix class OSXPlatform(unix.UnixPlatform): """OSX implementation of :class:`.abstract.CMakePlatform`.""" @property def generator_installation_help(self): """Return message guiding the user for installing a valid toolchain.""" return textwrap.dedent( """ Building MacOSX wheels for Python {pyver} requires XCode. Get it here: https://developer.apple.com/xcode/ """ ).format(pyver="%s.%s" % sys.version_info[:2]).strip() PKlCM3W W #skbuild/platform_specifics/linux.py"""This module defines object specific to Linux platform.""" import platform import sys import textwrap from . import unix class LinuxPlatform(unix.UnixPlatform): """Linux implementation of :class:`.abstract.CMakePlatform`""" @staticmethod def build_essential_install_cmd(): """Return a tuple of the form ``(distribution_name, cmd)``. ``cmd`` is the command allowing to install the build tools in the current Linux distribution. It set to an empty string if the command is not known. ``distribution_name`` is the name of the current distribution. It is set to an empty string if the distribution could not be determined. """ # gentoo, slackware: Compiler is available by default. distribution_name = platform.linux_distribution()[0] cmd = "" if distribution_name in [ 'debian', 'Ubuntu', 'mandrake', 'mandriva']: cmd = "sudo apt-get install build-essential" elif distribution_name in [ 'centos', 'fedora', 'redhat', 'turbolinux', 'yellowdog', 'rocks']: # http://unix.stackexchange.com/questions/16422/cant-install-build-essential-on-centos#32439 cmd = "sudo yum groupinstall 'Development Tools'" elif distribution_name in ['SuSE']: # http://serverfault.com/questions/437680/equivalent-development-build-tools-for-suse-professional-11#437681 cmd = "zypper install -t pattern devel_C_C++" return distribution_name, cmd @property def generator_installation_help(self): """Return message guiding the user for installing a valid toolchain.""" distribution_name, cmd = self.build_essential_install_cmd() install_help = "" if distribution_name: install_help = ( "But scikit-build does *NOT* know how to install it on %s\n" % distribution_name ) if distribution_name and cmd: install_help = ( "It can be installed using %s package manager:\n" "\n" " %s\n" % (distribution_name, cmd) ) arch = "x64" if platform.architecture()[0] == "64bit" else "x86" return textwrap.dedent( """ Building Linux wheels for Python %s requires a compiler (e.g gcc). %s To build compliant wheels, consider using the manylinux system described in PEP-513. Get it with "dockcross/manylinux-%s" docker image: https://github.com/dockcross/dockcross#readme For more details, please refer to scikit-build documentation: http://scikit-build.readthedocs.io/en/latest/generators.html#linux """ # noqa: E501 ).strip() % ("%s.%s" % sys.version_info[:2], install_help, arch) PKlCM)!!!&skbuild/platform_specifics/abstract.py"""This module defines objects useful to discover which CMake generator is supported on the current platform.""" from __future__ import print_function import os import shutil import subprocess import textwrap from ..constants import CMAKE_DEFAULT_EXECUTABLE from ..exceptions import SKBuildGeneratorNotFoundError from ..utils import push_dir test_folder = "_cmake_test_compile" class CMakePlatform(object): """This class encapsulates the logic allowing to get the identifier of a working CMake generator. Derived class should at least set :attr:`default_generators`. """ def __init__(self): self._default_generators = list() @property def default_generators(self): """List of generators considered by :func:`get_best_generator()`.""" return self._default_generators @default_generators.setter def default_generators(self, generators): self._default_generators = generators @property def generator_installation_help(self): """Return message guiding the user for installing a valid toolchain.""" raise NotImplementedError # pragma: no cover @staticmethod def write_test_cmakelist(languages): """Write a minimal ``CMakeLists.txt`` useful to check if the requested ``languages`` are supported.""" if not os.path.exists(test_folder): os.makedirs(test_folder) with open("{:s}/{:s}".format(test_folder, "CMakeLists.txt"), "w") as f: f.write("cmake_minimum_required(VERSION 2.8)\n") f.write("PROJECT(compiler_test NONE)\n") for language in languages: f.write("ENABLE_LANGUAGE({:s})\n".format(language)) @staticmethod def cleanup_test(): """Delete test project directory.""" if os.path.exists(test_folder): shutil.rmtree(test_folder) def get_generator(self, generator_name): """Loop over generators and return the first that matches the given name. """ for default_generator in self.default_generators: if default_generator.name == generator_name: return default_generator return CMakeGenerator(generator_name) # TODO: this method name is not great. Does anyone have a better idea for # renaming it? def get_best_generator( self, generator_name=None, skip_generator_test=False, languages=("CXX", "C"), cleanup=True, cmake_executable=CMAKE_DEFAULT_EXECUTABLE, cmake_args=()): """Loop over generators to find one that works by configuring and compiling a test project. :param generator_name: If provided, uses only provided generator, \ instead of trying :attr:`default_generators`. :type generator_name: string or None :param skip_generator_test: If set to True and if a generator name is \ specified, the generator test is skipped. If no generator_name is specified \ and the option is set to True, the first available generator is used. :type skip_generator_test: bool :param languages: The languages you'll need for your project, in terms \ that CMake recognizes. :type languages: tuple :param cleanup: If True, cleans up temporary folder used to test \ generators. Set to False for debugging to see CMake's output files. :type cleanup: bool :param cmake_executable: Path to CMake executable used to configure \ and build the test project used to evaluate if a generator is working. :type cmake_executable: string :param cmake_args: List of CMake arguments to use when configuring \ the test project. Only arguments starting with ``-DCMAKE_`` are \ used. :type cmake_args: tuple :return: CMake Generator object :rtype: :class:`CMakeGenerator` or None :raises skbuild.exceptions.SKBuildGeneratorNotFoundError: """ candidate_generators = [] if generator_name is None: candidate_generators = self.default_generators else: # Lookup CMakeGenerator by name. Doing this allow to get a # generator object with its ``env`` property appropriately # initialized. for default_generator in self.default_generators: if default_generator.name == generator_name: candidate_generators = [default_generator] break if not candidate_generators: candidate_generators = [CMakeGenerator(generator_name)] self.write_test_cmakelist(languages) if skip_generator_test: working_generator = candidate_generators[0] else: working_generator = self.compile_test_cmakelist( cmake_executable, candidate_generators, cmake_args) if working_generator is None: raise SKBuildGeneratorNotFoundError(textwrap.dedent( """ {line} scikit-build could not get a working generator for your system. Aborting build. {installation_help} {line} """).strip().format( # noqa: E501 line="*"*80, installation_help=self.generator_installation_help) ) if cleanup: CMakePlatform.cleanup_test() return working_generator @staticmethod @push_dir(directory=test_folder) def compile_test_cmakelist( cmake_exe_path, candidate_generators, cmake_args=()): """Attempt to configure the test project with each :class:`CMakeGenerator` from ``candidate_generators``. Only cmake arguments starting with ``-DCMAKE_`` are used to configure the test project. The function returns the first generator allowing to successfully configure the test project using ``cmake_exe_path``.""" # working generator is the first generator we find that works. working_generator = None # Include only -DCMAKE_* arguments cmake_args = [arg for arg in cmake_args if arg.startswith("-DCMAKE_")] # Do not complain about unused CMake arguments cmake_args.insert(0, "--no-warn-unused-cli") cmake_args_as_str = " ".join( ['"{:s}"'.format(arg) for arg in cmake_args]) def _generator_discovery_status_msg(_generator, suffix=""): outer = "-" * 80 inner = ["-" * ((idx * 5) - 3) for idx in range(1, 8)] print(outer if suffix == "" else "\n".join(inner)) print("-- Trying \"%s\" generator%s" % (_generator.name, suffix)) print(outer if suffix != "" else "\n".join(inner[::-1])) for generator in candidate_generators: print("\n") _generator_discovery_status_msg(generator) # clear the cache for each attempted generator type if os.path.isdir('build'): shutil.rmtree('build') with push_dir('build', make_directory=True): # call cmake to see if the compiler specified by this # generator works for the specified languages cmake_execution_string = '{:s} ../ -G "{:s}" {:s}'.format( cmake_exe_path, generator.name, cmake_args_as_str) status = subprocess.call( cmake_execution_string, shell=True, env=generator.env) _generator_discovery_status_msg( generator, " - %s" % ("success" if status == 0 else "failure")) print("") # cmake succeeded, this generator should work if status == 0: # we have a working generator, don't bother looking for more working_generator = generator break return working_generator class CMakeGenerator(object): """Represents a CMake generator. .. automethod:: __init__ """ def __init__(self, name, env=None): """Instantiate a generator object with the given ``name``. By default, ``os.environ`` is associated with the generator. Dictionary passed as ``env`` parameter will be merged with ``os.environ``. If an environment variable is set in both ``os.environ`` and ``env``, the variable in ``env`` is used. """ self._generator_name = name self.env = dict( list(os.environ.items()) + list(env.items() if env else [])) @property def name(self): """Name of CMake generator.""" return self._generator_name PKlCM;-ŸRR%skbuild/platform_specifics/windows.py"""This module defines object specific to Windows platform.""" from __future__ import print_function import sys import platform import textwrap from .abstract import CMakeGenerator from . import abstract class WindowsPlatform(abstract.CMakePlatform): """Windows implementation of :class:`.abstract.CMakePlatform`.""" def __init__(self): super(WindowsPlatform, self).__init__() version = sys.version_info self._vs_help = "" vs_help_template = textwrap.dedent( """ Building windows wheels for Python {pyver} requires Microsoft Visual Studio %s. Get it with "%s": %s """ # noqa: E501 ).strip().format(pyver="%s.%s" % sys.version_info[:2]) # For Python 2.7 to Python 3.2: VS2008 if ( (version.major == 2 and version.minor >= 7) or (version.major == 3 and version.minor <= 2) ): official_vs_year = "2008" self._vs_help = vs_help_template % ( official_vs_year, "Microsoft Visual C++ Compiler for Python 2.7", "http://aka.ms/vcpython27" ) # For Python 3.3 to Python 3.4: VS2010 elif ( version.major == 3 and ( version.minor >= 3 and version.minor <= 4 ) ): official_vs_year = "2010" self._vs_help = vs_help_template % ( official_vs_year, "Windows SDK for Windows 7 and .NET 4.0", "https://www.microsoft.com/download/details.aspx?id=8279" ) # # For Python 3.5 and above: VS2015 elif version.major == 3 and version.minor >= 5: official_vs_year = "2015" self._vs_help = vs_help_template % ( official_vs_year, "Microsoft Visual C++ Build Tools", "http://landinghub.visualstudio.com/visual-cpp-build-tools" ) self._vs_help += "\n\n" + textwrap.dedent( """ Or with "Visual Studio 2015": https://visualstudio.com/ """ ).strip() else: raise RuntimeError("Only Python >= 2.7 is supported on Windows.") assert official_vs_year is not None supported_vs_years = [official_vs_year] for vs_year in supported_vs_years: self.default_generators.extend([ CMakeVisualStudioCommandLineGenerator("Ninja", vs_year), CMakeVisualStudioIDEGenerator(vs_year), CMakeVisualStudioCommandLineGenerator( "NMake Makefiles", vs_year), CMakeVisualStudioCommandLineGenerator( "NMake Makefiles JOM", vs_year) ]) @property def generator_installation_help(self): """Return message guiding the user for installing a valid toolchain.""" return self._vs_help VS_YEAR_TO_VERSION = { "2008": 9, "2010": 10, "2015": 14 } """Describes the version of `Visual Studio` supported by :class:`CMakeVisualStudioIDEGenerator` and :class:`CMakeVisualStudioCommandLineGenerator`. The different version are identified by their year. """ class CMakeVisualStudioIDEGenerator(CMakeGenerator): """ Represents a Visual Studio CMake generator. .. automethod:: __init__ """ def __init__(self, year): """Instantiate a generator object with its name set to the `Visual Studio` generator associated with the given ``year`` (see :data:`VS_YEAR_TO_VERSION`) and the current platform (32-bit or 64-bit). """ vs_version = VS_YEAR_TO_VERSION[year] vs_base = "Visual Studio %s %s" % (vs_version, year) # Python is Win64, build a Win64 module if platform.architecture()[0] == "64bit": vs_base += " Win64" super(CMakeVisualStudioIDEGenerator, self).__init__(vs_base) # To avoid multiple slow calls to ``query_vcvarsall`` or ``_get_vc_env``, results # of previous calls are cached. __get_msvc_compiler_env_cache = dict() def _get_msvc_compiler_env(vs_version): # pylint:disable=global-statement global __get_msvc_compiler_env_cache from setuptools import monkey monkey.patch_for_msvc_specialized_compiler() arch = "x86" if vs_version < 14: if platform.architecture()[0] == "64bit": arch = "amd64" # If any, return cached version cache_key = ",".join([str(vs_version), arch]) if cache_key in __get_msvc_compiler_env_cache: return __get_msvc_compiler_env_cache[cache_key] try: import distutils.msvc9compiler cached_env = distutils.msvc9compiler.query_vcvarsall(vs_version, arch) __get_msvc_compiler_env_cache[cache_key] = cached_env return cached_env except ImportError: print("failed to import 'distutils.msvc9compiler'") else: if platform.architecture()[0] == "64bit": arch = "x86_amd64" # If any, return cached version cache_key = ",".join([str(vs_version), arch]) if cache_key in __get_msvc_compiler_env_cache: return __get_msvc_compiler_env_cache[cache_key] try: import distutils._msvccompiler from distutils.errors import DistutilsPlatformError # pylint:disable=protected-access vc_env = distutils._msvccompiler._get_vc_env(arch) cached_env = { 'PATH': vc_env.get('path', ''), 'INCLUDE': vc_env.get('include', ''), 'LIB': vc_env.get('lib', '') } __get_msvc_compiler_env_cache[cache_key] = cached_env return cached_env except ImportError: print("failed to import 'distutils._msvccompiler'") except DistutilsPlatformError: pass return {} class CMakeVisualStudioCommandLineGenerator(CMakeGenerator): """ Represents a command-line CMake generator initialized with a specific `Visual Studio` environment. .. automethod:: __init__ """ def __init__(self, name, year): """Instantiate CMake command-line generator. The generator ``name`` can be values like `Ninja`, `NMake Makefiles` or `NMake Makefiles JOM`. The ``year`` defines the `Visual Studio` environment associated with the generator. See :data:`VS_YEAR_TO_VERSION`. The platform (32-bit or 64-bit) is automatically selected based on the value of ``platform.architecture()[0]``. """ vc_env = _get_msvc_compiler_env(VS_YEAR_TO_VERSION[year]) env = {str(key.upper()): str(value) for key, value in vc_env.items()} super(CMakeVisualStudioCommandLineGenerator, self).__init__(name, env) PKlCMߔ(b b +skbuild/command/generate_source_manifest.py"""This module defines custom ``generate_source_manifest`` setuptools command.""" import os import subprocess import sys from distutils.cmd import Command from . import set_build_base_mixin from ..constants import SKBUILD_DIR from ..utils import new_style SKBUILD_MARKER_FILE = os.path.join(SKBUILD_DIR, "_skbuild_MANIFEST") class generate_source_manifest(set_build_base_mixin, new_style(Command)): """Custom setuptools command generating a `MANIFEST` file if not already provided.""" description = "generate source MANIFEST" # pylint:disable=no-self-use def initialize_options(self): """Set default values for all the options that this command supports.""" pass def run(self): """ If neither a `MANIFEST`, nor a `MANIFEST.in` file is provided, and we are in a git repo, try to create a `MANIFEST` file from the output of `git ls-tree --name-only -r HEAD`. We need a reliable way to tell if an existing `MANIFEST` file is one we've generated. distutils already uses a first-line comment to tell if the `MANIFEST` file was generated from `MANIFEST.in`, so we use a dummy file, `_skbuild_MANIFEST`, to avoid confusing distutils. """ do_generate = ( # If there's a MANIFEST.in file, we assume that we had nothing to do # with the project's manifest. not os.path.exists('MANIFEST.in') # otherwise, we check to see that there is no MANIFEST, ... and not os.path.exists('MANIFEST') # ... or ... # ... (if there is one,) that we created it or os.path.exists(SKBUILD_MARKER_FILE) ) if do_generate: try: with open('MANIFEST', 'wb') as manifest_file: # Since Git < 2.11 does not support --recurse-submodules option, fallback to # regular listing. try: manifest_file.write( subprocess.check_output(['git', 'ls-files', '--recurse-submodules']) ) except subprocess.CalledProcessError: manifest_file.write( subprocess.check_output(['git', 'ls-files']) ) except subprocess.CalledProcessError: sys.stderr.write( '\n\n' 'Since scikit-build could not find MANIFEST.in or ' 'MANIFEST, it tried to generate a MANIFEST file ' 'automatically, but could not because it could not ' 'determine which source files to include.\n\n' 'The command used was "git ls-files"\n' '\n\n' ) raise if not os.path.exists(SKBUILD_DIR): os.makedirs(SKBUILD_DIR) with open(SKBUILD_MARKER_FILE, 'w'): # touch pass def finalize_options(self, *args, **kwargs): """Set final values for all the options that this command supports.""" pass PKlCMugskbuild/command/build_py.py"""This module defines custom implementation of ``build_py`` setuptools command.""" import os from distutils import log as distutils_log from setuptools.command.build_py import build_py as _build_py from . import set_build_base_mixin from ..constants import CMAKE_INSTALL_DIR from ..utils import distribution_hide_listing, new_style class build_py(set_build_base_mixin, new_style(_build_py)): """Custom implementation of ``build_py`` setuptools command.""" def initialize_options(self): """Handle --hide-listing option. Initializes ``outfiles_count``. """ super(build_py, self).initialize_options() # pylint:disable=attribute-defined-outside-init self.outfiles_count = 0 def build_module(self, module, module_file, package): """Handle --hide-listing option. Increments ``outfiles_count``. """ super(build_py, self).build_module(module, module_file, package) self.outfiles_count += 1 def run(self, *args, **kwargs): """Handle --hide-listing option. Display number of copied files. It corresponds to the value of ``outfiles_count``. """ with distribution_hide_listing(self.distribution): super(build_py, self).run(*args, **kwargs) distutils_log.info("copied %d files" % self.outfiles_count) def find_modules(self): """Finds individually-specified Python modules, ie. those listed by module name in 'self.py_modules'. Returns a list of tuples (package, module_base, filename): 'package' is a tuple of the path through package-space to the module; 'module_base' is the bare (no packages, no dots) module name, and 'filename' is the path to the ".py" file (relative to the distribution root) that implements the module. """ # Map package names to tuples of useful info about the package: # (package_dir, checked) # package_dir - the directory where we'll find source files for # this package # checked - true if we have checked that the package directory # is valid (exists, contains __init__.py, ... ?) packages = {} # List of (package, module, filename) tuples to return modules = [] # We treat modules-in-packages almost the same as toplevel modules, # just the "package" for a toplevel is empty (either an empty # string or empty list, depending on context). Differences: # - don't check for __init__.py in directory for empty package for module in self.py_modules: path = module.split('.') package = '.'.join(path[0:-1]) module_base = path[-1] try: (package_dir, checked) = packages[package] except KeyError: package_dir = self.get_package_dir(package) checked = 0 if not checked: init_py = self.check_package(package, package_dir) packages[package] = (package_dir, 1) if init_py: modules.append((package, "__init__", init_py)) # XXX perhaps we should also check for just .pyc files # (so greedy closed-source bastards can distribute Python # modules too) module_file = os.path.join(package_dir, module_base + ".py") # skbuild: prepend CMAKE_INSTALL_DIR if file exists in the # CMake install tree. if os.path.exists(os.path.join(CMAKE_INSTALL_DIR, module_file)): module_file = os.path.join(CMAKE_INSTALL_DIR, module_file) if not self.check_module(module, module_file): continue modules.append((package, module_base, module_file)) return modules PKlCMskbuild/command/install.py"""This module defines custom implementation of ``install`` setuptools command.""" from setuptools.command.install import install as _install from . import set_build_base_mixin from ..utils import new_style class install(set_build_base_mixin, new_style(_install)): """Custom implementation of ``install`` setuptools command.""" def finalize_options(self, *args, **kwargs): """Ensure that if the distribution is non-pure, all modules are installed in ``self.install_platlib``. .. note:: `setuptools.dist.Distribution.has_ext_modules()` is overridden in :func:`..setuptools_wrap.setup()`. """ # pylint:disable=access-member-before-definition if self.install_lib is None and self.distribution.has_ext_modules(): # pylint:disable=attribute-defined-outside-init self.install_lib = self.install_platlib super(install, self).finalize_options(*args, **kwargs) PKlCMYԺǴ skbuild/command/bdist_wheel.py"""This module defines custom implementation of ``bdist_wheel`` setuptools command.""" import sys try: from wheel.wheelfile import WheelFile _USE_WHEELFILE = True except ImportError: from wheel import archive as _wheel_archive # Not available with wheel >= 0.32.0 _USE_WHEELFILE = False from wheel.bdist_wheel import bdist_wheel as _bdist_wheel from . import set_build_base_mixin from ..utils import distribution_hide_listing, new_style class bdist_wheel(set_build_base_mixin, new_style(_bdist_wheel)): """Custom implementation of ``bdist_wheel`` setuptools command.""" def run(self, *args, **kwargs): """Handle --hide-listing option.""" if _USE_WHEELFILE: old_write_files = WheelFile.write_files def update_write_files(wheelfile_self, base_dir): with distribution_hide_listing(self.distribution) as hide_listing: if hide_listing: zip_filename = wheelfile_self.filename print("creating '%s' and adding '%s' to it" % (zip_filename, base_dir)) old_write_files(wheelfile_self, base_dir) WheelFile.distribution = self.distribution WheelFile.write_files = update_write_files try: super(bdist_wheel, self).run(*args, **kwargs) finally: WheelFile.write_files = old_write_files del WheelFile.distribution else: old_make_wheelfile_inner = _wheel_archive.make_wheelfile_inner def _make_wheelfile_inner(base_name, base_dir='.'): with distribution_hide_listing(self.distribution) as hide_listing: if hide_listing: zip_filename = base_name + ".whl" print("creating '%s' and adding '%s' to it" % (zip_filename, base_dir)) old_make_wheelfile_inner(base_name, base_dir) _wheel_archive.make_wheelfile_inner = _make_wheelfile_inner try: super(bdist_wheel, self).run(*args, **kwargs) finally: _wheel_archive.make_wheelfile_inner = old_make_wheelfile_inner def finalize_options(self, *args, **kwargs): """Ensure MacOSX wheels include ``x86_64`` instead of ``intel``.""" # pylint:disable=attribute-defined-outside-init,access-member-before-definition if sys.platform == 'darwin' and self.plat_name is None and self.distribution.has_ext_modules(): # The following code is duplicated in setuptools_wrap # pylint:disable=access-member-before-definition self.plat_name = "macosx-10.6-x86_64" super(bdist_wheel, self).finalize_options(*args, **kwargs) def write_wheelfile(self, wheelfile_base, _=None): """Write ``skbuild `` as a wheel generator. See `PEP-0427 `_ for more details. """ from .. import __version__ as skbuild_version generator = "skbuild %s" % skbuild_version super(bdist_wheel, self).write_wheelfile(wheelfile_base, generator) PKlCMR@))skbuild/command/clean.py"""This module defines custom implementation of ``clean`` setuptools command.""" import os try: from setuptools.command.clean import clean as _clean except ImportError: from distutils.command.clean import clean as _clean from distutils import log from shutil import rmtree from . import set_build_base_mixin from ..constants import (CMAKE_BUILD_DIR, CMAKE_INSTALL_DIR, SKBUILD_DIR) from ..utils import new_style class clean(set_build_base_mixin, new_style(_clean)): """Custom implementation of ``clean`` setuptools command.""" def run(self): """After calling the super class implementation, this function removes the directories specific to scikit-build.""" super(clean, self).run() for dir_ in (CMAKE_INSTALL_DIR, CMAKE_BUILD_DIR, SKBUILD_DIR): if os.path.exists(dir_): log.info("removing '%s'", dir_) if not self.dry_run and os.path.exists(dir_): rmtree(dir_) PKlCM,skbuild/command/install_lib.py"""This module defines custom implementation of ``install_lib`` setuptools command.""" from distutils import log as distutils_log from setuptools.command.install_lib import install_lib as _install_lib from . import set_build_base_mixin from ..utils import distribution_hide_listing, new_style class install_lib(set_build_base_mixin, new_style(_install_lib)): """Custom implementation of ``install_lib`` setuptools command.""" def install(self): """Handle --hide-listing option.""" with distribution_hide_listing(self.distribution): outfiles = super(install_lib, self).install() if outfiles is not None: distutils_log.info("copied %d files" % len(outfiles)) PKlCM>bZskbuild/command/bdist.py"""This module defines custom implementation of ``bdist`` setuptools command.""" try: from setuptools.command.bdist import bdist as _bdist except ImportError: from distutils.command.bdist import bdist as _bdist from . import set_build_base_mixin from ..utils import new_style class bdist(set_build_base_mixin, new_style(_bdist)): """Custom implementation of ``bdist`` setuptools command.""" pass PKlCM%skbuild/command/sdist.py"""This module defines custom implementation of ``sdist`` setuptools command.""" import os from distutils import log as distutils_log from distutils.command.sdist import sdist as _sdist from . import set_build_base_mixin from ..utils import distribution_hide_listing, new_style class sdist(set_build_base_mixin, new_style(_sdist)): """Custom implementation of ``sdist`` setuptools command.""" def make_release_tree(self, base_dir, files): """Handle --hide-listing option.""" with distribution_hide_listing(self.distribution): super(sdist, self).make_release_tree(base_dir, files) distutils_log.info("%s %d files" % ( "hard-linked" if hasattr(os, 'link') else "copied", len(files))) # pylint:disable=too-many-arguments, unused-argument def make_archive(self, base_name, _format, root_dir=None, base_dir=None, owner=None, group=None): """Handle --hide-listing option.""" distutils_log.info("creating '%s' %s archive and adding '%s' to it", base_name, _format, base_dir) with distribution_hide_listing(self.distribution): super(sdist, self).make_archive( base_name, _format, root_dir, base_dir) def run(self, *args, **kwargs): """Force :class:`.egg_info.egg_info` command to run.""" self.run_command('generate_source_manifest') super(sdist, self).run(*args, **kwargs) PKlCM='Sskbuild/command/__init__.py"""Collection of objects allowing to customize behavior of standard distutils and setuptools commands. """ from .. import cmaker class set_build_base_mixin(object): """Mixin allowing to override distutils and setuptools commands. """ def finalize_options(self, *args, **kwargs): """Override built-in function and set a new `build_base`. """ try: if not self.build_base or self.build_base == 'build': self.build_base = cmaker.SETUPTOOLS_INSTALL_DIR except AttributeError: pass super(set_build_base_mixin, self).finalize_options(*args, **kwargs) PKlCMa||skbuild/command/egg_info.py"""This module defines custom implementation of ``egg_info`` setuptools command.""" import os import os.path from setuptools.command.egg_info import egg_info as _egg_info from . import set_build_base_mixin from ..constants import CMAKE_INSTALL_DIR from ..utils import new_style, to_unix_path class egg_info(set_build_base_mixin, new_style(_egg_info)): """Custom implementation of ``egg_info`` setuptools command.""" def finalize_options(self, *args, **kwargs): # pylint:disable=access-member-before-definition if self.egg_base is None: if self.distribution.package_dir is not None and len(self.distribution.package_dir) == 1: # Recover directory specified in setup() function # using `package_dir={'':}` # This is required to successfully update the python path when # running the test command. package_name = list(self.distribution.package_dir.keys())[0] egg_base = to_unix_path(list(self.distribution.package_dir.values())[0]) cmake_install_dir = to_unix_path(CMAKE_INSTALL_DIR) if egg_base.startswith(cmake_install_dir): egg_base = egg_base[len(cmake_install_dir) + 1:] if package_name and egg_base.endswith(package_name): egg_base = egg_base[:-len(package_name) - 1] if egg_base == "": egg_base = "." # pylint:disable=attribute-defined-outside-init self.egg_base = egg_base else: script_path = os.path.abspath(self.distribution.script_name) script_dir = os.path.dirname(script_path) # pylint:disable=attribute-defined-outside-init self.egg_base = os.path.join(script_dir, self.egg_base) super(egg_info, self).finalize_options(*args, **kwargs) PKlCM)"tskbuild/command/test.py"""This module defines custom implementation of ``test`` setuptools command.""" from setuptools.command.test import test as _test from . import set_build_base_mixin from ..utils import new_style class test(set_build_base_mixin, new_style(_test)): """Custom implementation of ``test`` setuptools command.""" def run(self, *args, **kwargs): """Force ``develop`` command to run.""" self.run_command('develop') super(test, self).run(*args, **kwargs) PKlCMg"skbuild/command/install_scripts.py"""This module defines custom implementation of ``install_scripts`` setuptools command.""" from distutils import log as distutils_log from setuptools.command.install_scripts import ( install_scripts as _install_scripts) from . import set_build_base_mixin from ..utils import distribution_hide_listing, new_style class install_scripts(set_build_base_mixin, new_style(_install_scripts)): """Custom implementation of ``install_scripts`` setuptools command.""" def run(self, *args, **kwargs): """Handle --hide-listing option.""" with distribution_hide_listing(self.distribution): super(install_scripts, self).run(*args, **kwargs) distutils_log.info("copied %d files" % len(self.outfiles)) PKlCM)]skbuild/command/build.py"""This module defines custom implementation of ``build`` setuptools command.""" try: from setuptools.command.build import build as _build except ImportError: from distutils.command.build import build as _build from . import set_build_base_mixin from ..utils import new_style class build(set_build_base_mixin, new_style(_build)): """Custom implementation of ``build`` setuptools command.""" pass PKlCMossskbuild/utils/__init__.py"""This module defines functions generally useful in scikit-build.""" import errno import os from collections import namedtuple from contextlib import contextmanager from distutils import log as distutils_log from distutils.command.build_py import build_py as distutils_build_py from distutils.errors import DistutilsTemplateError from distutils.filelist import FileList from distutils.text_file import TextFile from functools import wraps class ContextDecorator(object): """A base class or mixin that enables context managers to work as decorators.""" def __init__(self, **kwargs): self.__dict__.update(kwargs) def __enter__(self): # Note: Returning self means that in "with ... as x", x will be self return self def __exit__(self, typ, val, traceback): pass def __call__(self, func): @wraps(func) def inner(*args, **kwds): # pylint:disable=missing-docstring with self: return func(*args, **kwds) return inner def mkdir_p(path): """Ensure directory ``path`` exists. If needed, parent directories are created. Adapted from http://stackoverflow.com/a/600612/1539918 """ try: os.makedirs(path) except OSError as exc: # Python >2.5 if exc.errno == errno.EEXIST and os.path.isdir(path): pass else: # pragma: no cover raise class push_dir(ContextDecorator): """Context manager to change current directory. """ def __init__(self, directory=None, make_directory=False): """ :param directory: Path to set as current working directory. If ``None`` is passed, ``os.getcwd()`` is used instead. :param make_directory: If True, ``directory`` is created. """ self.directory = None self.make_directory = None self.old_cwd = None super(push_dir, self).__init__( directory=directory, make_directory=make_directory) def __enter__(self): self.old_cwd = os.getcwd() if self.directory: if self.make_directory: mkdir_p(self.directory) os.chdir(self.directory) return self def __exit__(self, typ, val, traceback): os.chdir(self.old_cwd) def new_style(klass): """distutils/setuptools command classes are old-style classes, which won't work with mixins. To work around this limitation, we dynamically convert them to new style classes by creating a new class that inherits from them and also . This ensures that is always at the end of the MRO, even after being mixed in with other classes. """ return type("NewStyleClass<{}>".format(klass.__name__), (klass, object), {}) class PythonModuleFinder(new_style(distutils_build_py)): """Convenience class to search for python modules. This class is based on ``distutils.command.build_py.build_by`` and provides a specialized version of ``find_all_modules()``. """ def __init__(self, packages, package_dir, py_modules, alternative_build_base=None): """ :param packages: List of packages to search. :param package_dir: Dictionary mapping ``package`` with ``directory``. :param py_modules: List of python modules. :param alternative_build_base: Additional directory to search in. """ self.distribution = namedtuple('Distribution', 'script_name') self.distribution.script_name = 'setup.py' self.packages = packages self.package_dir = package_dir self.py_modules = py_modules self.alternative_build_base = alternative_build_base def find_all_modules(self, project_dir=None): """Compute the list of all modules that would be built by project located in current directory, whether they are specified one-module-at-a-time ``py_modules`` or by whole packages ``packages``. By default, the function will search for modules in the current directory. Specifying ``project_dir`` parameter allow to change this. Return a list of tuples ``(package, module, module_file)``. """ with push_dir(project_dir): return super(PythonModuleFinder, self).find_all_modules() def find_package_modules(self, package, package_dir): """Temporally prepend the ``alternative_build_base`` to ``module_file``. Doing so will ensure modules can also be found in other location (e.g ``skbuild.constants.CMAKE_INSTALL_DIR``). """ if (package_dir != "" and not os.path.exists(package_dir) and self.alternative_build_base is not None): package_dir = os.path.join(self.alternative_build_base, package_dir) modules = super(PythonModuleFinder, self).find_package_modules( package, package_dir) # Strip the alternative base from module_file def _strip_directory(entry): module_file = entry[2] if (self.alternative_build_base is not None and module_file.startswith(self.alternative_build_base)): module_file = module_file[len(self.alternative_build_base) + 1:] return entry[0], entry[1], module_file return map(_strip_directory, modules) def check_module(self, module, module_file): """Return True if ``module_file`` belongs to ``module``. """ if self.alternative_build_base is not None: updated_module_file = os.path.join( self.alternative_build_base, module_file) if os.path.exists(updated_module_file): module_file = updated_module_file if not os.path.isfile(module_file): distutils_log.warn( "file %s (for module %s) not found", module_file, module) return False return True def to_platform_path(path): """Return a version of ``path`` where all separator are :attr:`os.sep` """ return (path.replace("/", os.sep).replace("\\", os.sep) if path is not None else None) def to_unix_path(path): """Return a version of ``path`` where all separator are ``/``""" return path.replace("\\", "/") if path is not None else None @contextmanager def distribution_hide_listing(distribution): """Given a ``distribution``, this context manager temporarily sets distutils threshold to WARN if ``--hide-listing`` argument was provided. It yields True if ``--hide-listing`` argument was provided. """ # pylint:disable=protected-access old_threshold = distutils_log._global_log.threshold hide_listing = False if (hasattr(distribution, "hide_listing") and distribution.hide_listing): hide_listing = True distutils_log.set_threshold(distutils_log.WARN) yield hide_listing distutils_log.set_threshold(old_threshold) def parse_manifestin(template): """This function parses template file (usually MANIFEST.in)""" if not os.path.exists(template): return [] template = TextFile(template, strip_comments=1, skip_blanks=1, join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) file_list = FileList() try: while True: line = template.readline() if line is None: # end of file break try: file_list.process_template_line(line) # the call above can raise a DistutilsTemplateError for # malformed lines, or a ValueError from the lower-level # convert_path function except (DistutilsTemplateError, ValueError) as msg: print("%s, line %d: %s" % (template.filename, template.current_line, msg)) return file_list.files finally: template.close() PKlCMܭC C &skbuild/resources/cmake/FindF2PY.cmake#.rst: # # The purpose of the F2PY –Fortran to Python interface generator– project is to provide a # connection between Python and Fortran languages. # # F2PY is a Python package (with a command line tool f2py and a module f2py2e) that facilitates # creating/building Python C/API extension modules that make it possible to call Fortran 77/90/95 # external subroutines and Fortran 90/95 module subroutines as well as C functions; to access Fortran # 77 COMMON blocks and Fortran 90/95 module data, including allocatable arrays from Python. # # For more information on the F2PY project, see http://www.f2py.com/. # # The following variables are defined: # # :: # # F2PY_EXECUTABLE - absolute path to the F2PY executable # # :: # # F2PY_VERSION_STRING - the version of F2PY found # F2PY_VERSION_MAJOR - the F2PY major version # F2PY_VERSION_MINOR - the F2PY minor version # F2PY_VERSION_PATCH - the F2PY patch version # # # .. note:: # # By default, the module finds the F2PY program associated with the installed NumPy package. # # Example usage # ^^^^^^^^^^^^^ # # Assuming that a package named ``method`` is declared in ``setup.py`` and that the corresponding directory # containing ``__init__.py`` also exists, the following CMake code can be added to ``method/CMakeLists.txt`` # to ensure the C sources associated with ``cylinder_methods.f90`` are generated and the corresponding module # is compiled: # # .. code-block:: cmake # # find_package(F2PY REQUIRED) # # set(f2py_module_name "_cylinder_methods") # set(fortran_src_file "${CMAKE_CURRENT_SOURCE_DIR}/cylinder_methods.f90") # # set(generated_module_file ${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}${PYTHON_EXTENSION_MODULE_SUFFIX}) # # add_custom_target(${f2py_module_name} ALL # DEPENDS ${generated_module_file} # ) # # add_custom_command( # OUTPUT ${generated_module_file} # COMMAND ${F2PY_EXECUTABLE} # -m ${f2py_module_name} # -c # ${fortran_src_file} # WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} # ) # # install(FILES ${generated_module_file} DESTINATION methods) # # .. warning:: # # Using ``f2py`` with ``-c`` argument means that f2py is also responsible to build the module. In that # case, CMake is not used to find the compiler and configure the associated build system. # find_program(F2PY_EXECUTABLE NAMES f2py f2py${PYTHON_VERSION_MAJOR}) if(F2PY_EXECUTABLE) # extract the version string execute_process(COMMAND "${F2PY_EXECUTABLE}" -v OUTPUT_VARIABLE F2PY_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE) if("${F2PY_VERSION_STRING}" MATCHES "^([0-9]+)(.([0-9+]))?(.([0-9+]))?$") set(F2PY_VERSION_MAJOR ${CMAKE_MATCH_1}) set(F2PY_VERSION_MINOR "${CMAKE_MATCH_3}") set(F2PY_VERSION_PATCH "${CMAKE_MATCH_5}") endif() endif() # handle the QUIETLY and REQUIRED arguments and set F2PY_FOUND to TRUE if # all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(F2PY REQUIRED_VARS F2PY_EXECUTABLE VERSION_VAR F2PY_VERSION_STRING ) mark_as_advanced(F2PY_EXECUTABLE) PKlCMfkSS2skbuild/resources/cmake/FindPythonExtensions.cmake#.rst: # # This module defines CMake functions to build Python extension modules and # stand-alone executables. # # The following variables are defined: # :: # # PYTHON_PREFIX - absolute path to the current Python # distribution's prefix # PYTHON_SITE_PACKAGES_DIR - absolute path to the current Python # distribution's site-packages directory # PYTHON_RELATIVE_SITE_PACKAGES_DIR - path to the current Python # distribution's site-packages directory # relative to its prefix # PYTHON_SEPARATOR - separator string for file path # components. Equivalent to ``os.sep`` in # Python. # PYTHON_PATH_SEPARATOR - separator string for PATH-style # environment variables. Equivalent to # ``os.pathsep`` in Python. # PYTHON_EXTENSION_MODULE_SUFFIX - suffix of the compiled module. For example, on # Linux, based on environment, it could be ``.cpython-35m-x86_64-linux-gnu.so``. # # # # The following functions are defined: # # .. cmake:command:: python_extension_module # # For libraries meant to be used as Python extension modules, either dynamically # loaded or directly linked. Amend the configuration of the library target # (created using ``add_library``) with additional options needed to build and # use the referenced library as a Python extension module. # # python_extension_module( # [LINKED_MODULES_VAR ] # [FORWARD_DECL_MODULES_VAR ] # [MODULE_SUFFIX ]) # # Only extension modules that are configured to be built as MODULE libraries can # be runtime-loaded through the standard Python import mechanism. All other # modules can only be included in standalone applications that are written to # expect their presence. In addition to being linked against the libraries for # these modules, such applications must forward declare their entry points and # initialize them prior to use. To generate these forward declarations and # initializations, see ``python_modules_header``. # # If ```` does not refer to a target, then it is assumed to refer to an # extension module that is not linked at all, but compiled along with other # source files directly into an executable. Adding these modules does not cause # any library configuration modifications, and they are not added to the list of # linked modules. They still must be forward declared and initialized, however, # and so are added to the forward declared modules list. # # If the associated target is of type ``MODULE_LIBRARY``, the LINK_FLAGS target # property is used to set symbol visibility and export only the module init function. # This applies to GNU and MSVC compilers. # # Options: # # ``LINKED_MODULES_VAR `` # Name of the variable referencing a list of extension modules whose libraries # must be linked into the executables of any stand-alone applications that use # them. By default, the global property ``PY_LINKED_MODULES_LIST`` is used. # # ``FORWARD_DECL_MODULES_VAR `` # Name of the variable referencing a list of extension modules whose entry # points must be forward declared and called by any stand-alone applications # that use them. By default, the global property # ``PY_FORWARD_DECL_MODULES_LIST`` is used. # # ``MODULE_SUFFIX `` # Suffix appended to the python extension module file. # The default suffix is retrieved using ``sysconfig.get_config_var("SO")"``, # if not available, the default is then ``.so`` on unix and ``.pyd`` on # windows. # Setting the variable ``PYTHON_EXTENSION_MODULE_SUFFIX`` in the caller # scope defines the value used for all extensions not having a suffix # explicitly specified using ``MODULE_SUFFIX`` parameter. # # # .. cmake:command:: python_standalone_executable # # python_standalone_executable() # # For standalone executables that initialize their own Python runtime # (such as when building source files that include one generated by Cython with # the --embed option). Amend the configuration of the executable target # (created using ``add_executable``) with additional options needed to properly # build the referenced executable. # # # .. cmake:command:: python_modules_header # # Generate a header file that contains the forward declarations and # initialization routines for the given list of Python extension modules. # ```` is the logical name for the header file (no file extensions). # ```` is the actual destination filename for the header file # (e.g.: decl_modules.h). # # python_modules_header( [HeaderFilename] # [FORWARD_DECL_MODULES_LIST ] # [HEADER_OUTPUT_VAR ] # [INCLUDE_DIR_OUTPUT_VAR ]) # # If only ```` is provided, and it ends in the ".h" extension, then it # is assumed to be the ````. The filename of the header file # without the extension is used as the logical name. If only ```` is # provided, and it does not end in the ".h" extension, then the # ```` is assumed to ``.h``. # # The exact contents of the generated header file depend on the logical # ````. It should be set to a value that corresponds to the target # application, or for the case of multiple applications, some identifier that # conveyes its purpose. It is featured in the generated multiple inclusion # guard as well as the names of the generated initialization routines. # # The generated header file includes forward declarations for all listed # modules, as well as implementations for the following class of routines: # # ``int _(void)`` # Initializes the python extension module, ````. Returns an integer # handle to the module. # # ``void _LoadAllPythonModules(void)`` # Initializes all listed python extension modules. # # ``void CMakeLoadAllPythonModules(void);`` # Alias for ``_LoadAllPythonModules`` whose name does not depend on # ````. This function is excluded during preprocessing if the # preprocessing macro ``EXCLUDE_LOAD_ALL_FUNCTION`` is defined. # # ``void Py_Initialize_Wrapper();`` # Wrapper arpund ``Py_Initialize()`` that initializes all listed python # extension modules. This function is excluded during preprocessing if the # preprocessing macro ``EXCLUDE_PY_INIT_WRAPPER`` is defined. If this # function is generated, then ``Py_Initialize()`` is redefined to a macro # that calls this function. # # Options: # # ``FORWARD_DECL_MODULES_LIST `` # List of extension modules for which to generate forward declarations of # their entry points and their initializations. By default, the global # property ``PY_FORWARD_DECL_MODULES_LIST`` is used. # # ``HEADER_OUTPUT_VAR `` # Name of the variable to set to the path to the generated header file. By # default, ```` is used. # # ``INCLUDE_DIR_OUTPUT_VAR `` # Name of the variable to set to the path to the directory containing the # generated header file. By default, ``_INCLUDE_DIRS`` is used. # # Defined variables: # # ```` # The path to the generated header file # # ```` # Directory containing the generated header file # # # Example usage # ^^^^^^^^^^^^^ # # .. code-block:: cmake # # find_package(PythonInterp) # find_package(PythonLibs) # find_package(PythonExtensions) # find_package(Cython) # find_package(Boost COMPONENTS python) # # # Simple Cython Module -- no executables # add_cython_target(_module.pyx) # add_library(_module MODULE ${_module}) # python_extension_module(_module) # # # Mix of Cython-generated code and C++ code using Boost Python # # Stand-alone executable -- no modules # include_directories(${Boost_INCLUDE_DIRS}) # add_cython_target(main.pyx CXX EMBED_MAIN) # add_executable(main boost_python_module.cxx ${main}) # target_link_libraries(main ${Boost_LIBRARIES}) # python_standalone_executable(main) # # # stand-alone executable with three extension modules: # # one statically linked, one dynamically linked, and one loaded at runtime # # # # Freely mixes Cython-generated code, code using Boost-Python, and # # hand-written code using the CPython API. # # # module1 -- statically linked # add_cython_target(module1.pyx) # add_library(module1 STATIC ${module1}) # python_extension_module(module1 # LINKED_MODULES_VAR linked_module_list # FORWARD_DECL_MODULES_VAR fdecl_module_list) # # # module2 -- dynamically linked # include_directories({Boost_INCLUDE_DIRS}) # add_library(module2 SHARED boost_module2.cxx) # target_link_libraries(module2 ${Boost_LIBRARIES}) # python_extension_module(module2 # LINKED_MODULES_VAR linked_module_list # FORWARD_DECL_MODULES_VAR fdecl_module_list) # # # module3 -- loaded at runtime # add_cython_target(module3a.pyx) # add_library(module1 MODULE ${module3a} module3b.cxx) # target_link_libraries(module3 ${Boost_LIBRARIES}) # python_extension_module(module3 # LINKED_MODULES_VAR linked_module_list # FORWARD_DECL_MODULES_VAR fdecl_module_list) # # # application executable -- generated header file + other source files # python_modules_header(modules # FORWARD_DECL_MODULES_LIST ${fdecl_module_list}) # include_directories(${modules_INCLUDE_DIRS}) # # add_cython_target(mainA) # add_cython_target(mainC) # add_executable(main ${mainA} mainB.cxx ${mainC} mainD.c) # # target_link_libraries(main ${linked_module_list} ${Boost_LIBRARIES}) # python_standalone_executable(main) # #============================================================================= # Copyright 2011 Kitware, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #============================================================================= find_package(PythonInterp REQUIRED) find_package(PythonLibs) include(targetLinkLibrariesWithDynamicLookup) set(_command " import distutils.sysconfig import itertools import os import os.path import site import sys import sysconfig result = None rel_result = None candidate_lists = [] try: candidate_lists.append((distutils.sysconfig.get_python_lib(),)) except AttributeError: pass try: candidate_lists.append(site.getsitepackages()) except AttributeError: pass try: candidate_lists.append((site.getusersitepackages(),)) except AttributeError: pass candidates = itertools.chain.from_iterable(candidate_lists) for candidate in candidates: rel_candidate = os.path.relpath( candidate, sys.prefix) if not rel_candidate.startswith(\"..\"): result = candidate rel_result = rel_candidate break sys.stdout.write(\";\".join(( os.sep, os.pathsep, sys.prefix, result, rel_result, sysconfig.get_config_var('SO') ))) ") execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "${_command}" OUTPUT_VARIABLE _list RESULT_VARIABLE _result) list(GET _list 0 _item) set(PYTHON_SEPARATOR "${_item}") mark_as_advanced(PYTHON_SEPARATOR) list(GET _list 1 _item) set(PYTHON_PATH_SEPARATOR "${_item}") mark_as_advanced(PYTHON_PATH_SEPARATOR) list(GET _list 2 _item) set(PYTHON_PREFIX "${_item}") mark_as_advanced(PYTHON_PREFIX) list(GET _list 3 _item) set(PYTHON_SITE_PACKAGES_DIR "${_item}") mark_as_advanced(PYTHON_SITE_PACKAGES_DIR) list(GET _list 4 _item) set(PYTHON_RELATIVE_SITE_PACKAGES_DIR "${_item}") mark_as_advanced(PYTHON_RELATIVE_SITE_PACKAGES_DIR) if(NOT DEFINED PYTHON_EXTENSION_MODULE_SUFFIX) list(GET _list 5 _item) set(PYTHON_EXTENSION_MODULE_SUFFIX "${_item}") endif() function(_set_python_extension_symbol_visibility _target) if(PYTHON_VERSION_MAJOR VERSION_GREATER 2) set(_modinit_prefix "PyInit_") else() set(_modinit_prefix "init") endif() message("_modinit_prefix:${_modinit_prefix}") if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") set_target_properties(${_target} PROPERTIES LINK_FLAGS "/EXPORT:${_modinit_prefix}${_target}" ) elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") set(_script_path ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${_target}-version-script.map ) file(WRITE ${_script_path} "{global: ${_modinit_prefix}${_target}; local: *; };" ) set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--version-script=${_script_path}" ) endif() endfunction() function(python_extension_module _target) set(one_ops LINKED_MODULES_VAR FORWARD_DECL_MODULES_VAR MODULE_SUFFIX) cmake_parse_arguments(_args "" "${one_ops}" "" ${ARGN}) set(_lib_type "NA") if(TARGET ${_target}) get_property(_lib_type TARGET ${_target} PROPERTY TYPE) endif() set(_is_non_lib TRUE) set(_is_static_lib FALSE) if(_lib_type STREQUAL "STATIC_LIBRARY") set(_is_static_lib TRUE) set(_is_non_lib FALSE) endif() set(_is_shared_lib FALSE) if(_lib_type STREQUAL "SHARED_LIBRARY") set(_is_shared_lib TRUE) set(_is_non_lib FALSE) endif() set(_is_module_lib FALSE) if(_lib_type STREQUAL "MODULE_LIBRARY") set(_is_module_lib TRUE) set(_is_non_lib FALSE) endif() if(_is_static_lib OR _is_shared_lib OR _is_non_lib) if(_is_static_lib OR _is_shared_lib) if(_args_LINKED_MODULES_VAR) set(${_args_LINKED_MODULES_VAR} ${${_args_LINKED_MODULES_VAR}} ${_target} PARENT_SCOPE) else() set_property(GLOBAL APPEND PROPERTY PY_LINKED_MODULES_LIST ${_target}) endif() endif() if(_args_FORWARD_DECL_MODULES_VAR) set(${_args_FORWARD_DECL_MODULES_VAR} ${${_args_FORWARD_DECL_MODULES_VAR}} ${_target} PARENT_SCOPE) else() set_property(GLOBAL APPEND PROPERTY PY_FORWARD_DECL_MODULES_LIST ${_target}) endif() endif() if(NOT _is_non_lib) include_directories("${PYTHON_INCLUDE_DIRS}") endif() if(_is_module_lib) set_target_properties(${_target} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") endif() if(_is_module_lib OR _is_shared_lib) if(_is_module_lib) if(NOT _args_MODULE_SUFFIX) set(_args_MODULE_SUFFIX "${PYTHON_EXTENSION_MODULE_SUFFIX}") endif() if(_args_MODULE_SUFFIX STREQUAL "" AND WIN32 AND NOT CYGWIN) set(_args_MODULE_SUFFIX ".pyd") endif() if(NOT _args_MODULE_SUFFIX STREQUAL "") set_target_properties(${_target} PROPERTIES SUFFIX ${_args_MODULE_SUFFIX}) endif() endif() target_link_libraries_with_dynamic_lookup(${_target} ${PYTHON_LIBRARIES}) if(_is_module_lib) _set_python_extension_symbol_visibility(${_target}) endif() endif() endfunction() function(python_standalone_executable _target) include_directories(${PYTHON_INCLUDE_DIRS}) target_link_libraries(${_target} ${PYTHON_LIBRARIES}) endfunction() function(python_modules_header _name) set(one_ops FORWARD_DECL_MODULES_LIST HEADER_OUTPUT_VAR INCLUDE_DIR_OUTPUT_VAR) cmake_parse_arguments(_args "" "${one_ops}" "" ${ARGN}) list(GET _args_UNPARSED_ARGUMENTS 0 _arg0) # if present, use arg0 as the input file path if(_arg0) set(_source_file ${_arg0}) # otherwise, must determine source file from name, or vice versa else() get_filename_component(_name_ext "${_name}" EXT) # if extension provided, _name is the source file if(_name_ext) set(_source_file ${_name}) get_filename_component(_name "${_source_file}" NAME_WE) # otherwise, assume the source file is ${_name}.h else() set(_source_file ${_name}.h) endif() endif() if(_args_FORWARD_DECL_MODULES_LIST) set(static_mod_list ${_args_FORWARD_DECL_MODULES_LIST}) else() get_property(static_mod_list GLOBAL PROPERTY PY_FORWARD_DECL_MODULES_LIST) endif() string(REPLACE "." "_" _header_name "${_name}") string(TOUPPER ${_header_name} _header_name_upper) set(_header_name_upper "_${_header_name_upper}_H") set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${_source_file}) set(generated_file_tmp "${generated_file}.in") file(WRITE ${generated_file_tmp} "/* Created by CMake. DO NOT EDIT; changes will be lost. */\n") set(_chunk "") set(_chunk "${_chunk}#ifndef ${_header_name_upper}\n") set(_chunk "${_chunk}#define ${_header_name_upper}\n") set(_chunk "${_chunk}\n") set(_chunk "${_chunk}#include \n") set(_chunk "${_chunk}\n") set(_chunk "${_chunk}#ifdef __cplusplus\n") set(_chunk "${_chunk}extern \"C\" {\n") set(_chunk "${_chunk}#endif /* __cplusplus */\n") set(_chunk "${_chunk}\n") set(_chunk "${_chunk}#if PY_MAJOR_VERSION < 3\n") file(APPEND ${generated_file_tmp} "${_chunk}") foreach(_module ${static_mod_list}) file(APPEND ${generated_file_tmp} "PyMODINIT_FUNC init${PYTHON_MODULE_PREFIX}${_module}(void);\n") endforeach() file(APPEND ${generated_file_tmp} "#else /* PY_MAJOR_VERSION >= 3*/\n") foreach(_module ${static_mod_list}) file(APPEND ${generated_file_tmp} "PyMODINIT_FUNC PyInit_${PYTHON_MODULE_PREFIX}${_module}(void);\n") endforeach() set(_chunk "") set(_chunk "${_chunk}#endif /* PY_MAJOR_VERSION >= 3*/\n\n") set(_chunk "${_chunk}#ifdef __cplusplus\n") set(_chunk "${_chunk}}\n") set(_chunk "${_chunk}#endif /* __cplusplus */\n") set(_chunk "${_chunk}\n") file(APPEND ${generated_file_tmp} "${_chunk}") foreach(_module ${static_mod_list}) set(_import_function "${_header_name}_${_module}") set(_prefixed_module "${PYTHON_MODULE_PREFIX}${_module}") set(_chunk "") set(_chunk "${_chunk}int ${_import_function}(void)\n") set(_chunk "${_chunk}{\n") set(_chunk "${_chunk} static char name[] = \"${_prefixed_module}\";\n") set(_chunk "${_chunk} #if PY_MAJOR_VERSION < 3\n") set(_chunk "${_chunk} return PyImport_AppendInittab(") set(_chunk "${_chunk}name, init${_prefixed_module});\n") set(_chunk "${_chunk} #else /* PY_MAJOR_VERSION >= 3 */\n") set(_chunk "${_chunk} return PyImport_AppendInittab(") set(_chunk "${_chunk}name, PyInit_${_prefixed_module});\n") set(_chunk "${_chunk} #endif /* PY_MAJOR_VERSION >= 3 */\n") set(_chunk "${_chunk}}\n\n") file(APPEND ${generated_file_tmp} "${_chunk}") endforeach() file(APPEND ${generated_file_tmp} "void ${_header_name}_LoadAllPythonModules(void)\n{\n") foreach(_module ${static_mod_list}) file(APPEND ${generated_file_tmp} " ${_header_name}_${_module}();\n") endforeach() file(APPEND ${generated_file_tmp} "}\n\n") set(_chunk "") set(_chunk "${_chunk}#ifndef EXCLUDE_LOAD_ALL_FUNCTION\n") set(_chunk "${_chunk}void CMakeLoadAllPythonModules(void)\n") set(_chunk "${_chunk}{\n") set(_chunk "${_chunk} ${_header_name}_LoadAllPythonModules();\n") set(_chunk "${_chunk}}\n") set(_chunk "${_chunk}#endif /* !EXCLUDE_LOAD_ALL_FUNCTION */\n\n") set(_chunk "${_chunk}#ifndef EXCLUDE_PY_INIT_WRAPPER\n") set(_chunk "${_chunk}static void Py_Initialize_Wrapper()\n") set(_chunk "${_chunk}{\n") set(_chunk "${_chunk} ${_header_name}_LoadAllPythonModules();\n") set(_chunk "${_chunk} Py_Initialize();\n") set(_chunk "${_chunk}}\n") set(_chunk "${_chunk}#define Py_Initialize Py_Initialize_Wrapper\n") set(_chunk "${_chunk}#endif /* !EXCLUDE_PY_INIT_WRAPPER */\n\n") set(_chunk "${_chunk}#endif /* !${_header_name_upper} */\n") file(APPEND ${generated_file_tmp} "${_chunk}") # with configure_file() cmake complains that you may not use a file created # using file(WRITE) as input file for configure_file() execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${generated_file_tmp}" "${generated_file}" OUTPUT_QUIET ERROR_QUIET) set(_header_output_var ${_name}) if(_args_HEADER_OUTPUT_VAR) set(_header_output_var ${_args_HEADER_OUTPUT_VAR}) endif() set(${_header_output_var} ${generated_file} PARENT_SCOPE) set(_include_dir_var ${_name}_INCLUDE_DIRS) if(_args_INCLUDE_DIR_OUTPUT_VAR) set(_include_dir_var ${_args_INCLUDE_DIR_OUTPUT_VAR}) endif() set(${_include_dirs_var} ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) endfunction() PKlCMZN N (skbuild/resources/cmake/FindCython.cmake#.rst: # # Find ``cython`` executable. # # This module will set the following variables in your project: # # ``CYTHON_EXECUTABLE`` # path to the ``cython`` program # # ``CYTHON_VERSION`` # version of ``cython`` # # ``CYTHON_FOUND`` # true if the program was found # # For more information on the Cython project, see http://cython.org/. # # *Cython is a language that makes writing C extensions for the Python language # as easy as Python itself.* # #============================================================================= # Copyright 2011 Kitware, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #============================================================================= # Use the Cython executable that lives next to the Python executable # if it is a local installation. find_package(PythonInterp) if(PYTHONINTERP_FOUND) get_filename_component(_python_path ${PYTHON_EXECUTABLE} PATH) find_program(CYTHON_EXECUTABLE NAMES cython cython.bat cython3 HINTS ${_python_path} DOC "path to the cython executable") else() find_program(CYTHON_EXECUTABLE NAMES cython cython.bat cython3 DOC "path to the cython executable") endif() if(CYTHON_EXECUTABLE) set(CYTHON_version_command ${CYTHON_EXECUTABLE} --version) execute_process(COMMAND ${CYTHON_version_command} OUTPUT_VARIABLE CYTHON_version_output ERROR_VARIABLE CYTHON_version_error RESULT_VARIABLE CYTHON_version_result OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT ${CYTHON_version_result} EQUAL 0) set(_error_msg "Command \"${CYTHON_version_command}\" failed with") set(_error_msg "${_error_msg} output:\n${CYTHON_version_error}") message(SEND_ERROR "${_error_msg}") else() if("${CYTHON_version_output}" MATCHES "^[Cc]ython version ([^,]+)") set(CYTHON_VERSION "${CMAKE_MATCH_1}") endif() endif() endif() include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cython REQUIRED_VARS CYTHON_EXECUTABLE) mark_as_advanced(CYTHON_EXECUTABLE) include(UseCython) PKlCM1un5n5'skbuild/resources/cmake/UseCython.cmake#.rst: # # The following functions are defined: # # .. cmake:command:: add_cython_target # # Create a custom rule to generate the source code for a Python extension module # using cython. # # add_cython_target( [] # [EMBED_MAIN] # [C | CXX] # [PY2 | PY3] # [OUTPUT_VAR ]) # # ```` is the name of the new target, and ```` # is the path to a cython source file. Note that, despite the name, no new # targets are created by this function. Instead, see ``OUTPUT_VAR`` for # retrieving the path to the generated source for subsequent targets. # # If only ```` is provided, and it ends in the ".pyx" extension, then it # is assumed to be the ````. The name of the input without the # extension is used as the target name. If only ```` is provided, and it # does not end in the ".pyx" extension, then the ```` is assumed to # be ``.pyx``. # # The Cython include search path is amended with any entries found in the # ``INCLUDE_DIRECTORIES`` property of the directory containing the # ```` file. Use ``include_directories`` to add to the Cython # include search path. # # Options: # # ``EMBED_MAIN`` # Embed a main() function in the generated output (for stand-alone # applications that initialize their own Python runtime). # # ``C | CXX`` # Force the generation of either a C or C++ file. By default, a C file is # generated, unless the C language is not enabled for the project; in this # case, a C++ file is generated by default. # # ``PY2 | PY3`` # Force compilation using either Python-2 or Python-3 syntax and code # semantics. By default, Python-2 syntax and semantics are used if the major # version of Python found is 2. Otherwise, Python-3 syntax and sematics are # used. # # ``OUTPUT_VAR `` # Set the variable ```` in the parent scope to the path to the # generated source file. By default, ```` is used as the output # variable name. # # Defined variables: # # ```` # The path of the generated source file. # # Cache variables that effect the behavior include: # # ``CYTHON_ANNOTATE`` # whether to create an annotated .html file when compiling # # ``CYTHON_FLAGS`` # additional flags to pass to the Cython compiler # # Example usage # ^^^^^^^^^^^^^ # # .. code-block:: cmake # # find_package(Cython) # # # Note: In this case, either one of these arguments may be omitted; their # # value would have been inferred from that of the other. # add_cython_target(cy_code cy_code.pyx) # # add_library(cy_code MODULE ${cy_code}) # target_link_libraries(cy_code ...) # #============================================================================= # Copyright 2011 Kitware, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #============================================================================= # Configuration options. set(CYTHON_ANNOTATE OFF CACHE BOOL "Create an annotated .html file when compiling *.pyx.") set(CYTHON_FLAGS "" CACHE STRING "Extra flags to the cython compiler.") mark_as_advanced(CYTHON_ANNOTATE CYTHON_FLAGS) string(REGEX REPLACE " " ";" CYTHON_FLAGS_LIST "${CYTHON_FLAGS}") find_package(PythonLibs REQUIRED) set(CYTHON_CXX_EXTENSION "cxx") set(CYTHON_C_EXTENSION "c") get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) function(add_cython_target _name) set(options EMBED_MAIN C CXX PY2 PY3) set(options1 OUTPUT_VAR) cmake_parse_arguments(_args "${options}" "${options1}" "" ${ARGN}) list(GET _args_UNPARSED_ARGUMENTS 0 _arg0) # if provided, use _arg0 as the input file path if(_arg0) set(_source_file ${_arg0}) # otherwise, must determine source file from name, or vice versa else() get_filename_component(_name_ext "${_name}" EXT) # if extension provided, _name is the source file if(_name_ext) set(_source_file ${_name}) get_filename_component(_name "${_source_file}" NAME_WE) # otherwise, assume the source file is ${_name}.pyx else() set(_source_file ${_name}.pyx) endif() endif() set(_embed_main FALSE) if("C" IN_LIST languages) set(_output_syntax "C") elseif("CXX" IN_LIST languages) set(_output_syntax "CXX") else() message(FATAL_ERROR "Either C or CXX must be enabled to use Cython") endif() if("${PYTHONLIBS_VERSION_STRING}" MATCHES "^2.") set(_input_syntax "PY2") else() set(_input_syntax "PY3") endif() if(_args_EMBED_MAIN) set(_embed_main TRUE) endif() if(_args_C) set(_output_syntax "C") endif() if(_args_CXX) set(_output_syntax "CXX") endif() if(_args_PY2) set(_input_syntax "PY2") endif() if(_args_PY3) set(_input_syntax "PY3") endif() set(embed_arg "") if(_embed_main) set(embed_arg "--embed") endif() set(cxx_arg "") set(extension "c") if(_output_syntax STREQUAL "CXX") set(cxx_arg "--cplus") set(extension "cxx") endif() set(py_version_arg "") if(_input_syntax STREQUAL "PY2") set(py_version_arg "-2") elseif(_input_syntax STREQUAL "PY3") set(py_version_arg "-3") endif() set(generated_file "${CMAKE_CURRENT_BINARY_DIR}/${_name}.${extension}") set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE) set(_output_var ${_name}) if(_args_OUTPUT_VAR) set(_output_var ${_args_OUTPUT_VAR}) endif() set(${_output_var} ${generated_file} PARENT_SCOPE) file(RELATIVE_PATH generated_file_relative ${CMAKE_BINARY_DIR} ${generated_file}) set(comment "Generating ${_output_syntax} source ${generated_file_relative}") set(cython_include_directories "") set(pxd_dependencies "") set(c_header_dependencies "") # Get the include directories. get_source_file_property(pyx_location ${_source_file} LOCATION) get_filename_component(pyx_path ${pyx_location} PATH) get_directory_property(cmake_include_directories DIRECTORY ${pyx_path} INCLUDE_DIRECTORIES) list(APPEND cython_include_directories ${cmake_include_directories}) # Determine dependencies. # Add the pxd file with the same basename as the given pyx file. get_filename_component(pyx_file_basename ${_source_file} NAME_WE) unset(corresponding_pxd_file CACHE) find_file(corresponding_pxd_file ${pyx_file_basename}.pxd PATHS "${pyx_path}" ${cmake_include_directories} NO_DEFAULT_PATH) if(corresponding_pxd_file) list(APPEND pxd_dependencies "${corresponding_pxd_file}") endif() # pxd files to check for additional dependencies set(pxds_to_check "${_source_file}" "${pxd_dependencies}") set(pxds_checked "") set(number_pxds_to_check 1) while(number_pxds_to_check GREATER 0) foreach(pxd ${pxds_to_check}) list(APPEND pxds_checked "${pxd}") list(REMOVE_ITEM pxds_to_check "${pxd}") # look for C headers file(STRINGS "${pxd}" extern_from_statements REGEX "cdef[ ]+extern[ ]+from.*$") foreach(statement ${extern_from_statements}) # Had trouble getting the quote in the regex string(REGEX REPLACE "cdef[ ]+extern[ ]+from[ ]+[\"]([^\"]+)[\"].*" "\\1" header "${statement}") unset(header_location CACHE) find_file(header_location ${header} PATHS ${cmake_include_directories}) if(header_location) list(FIND c_header_dependencies "${header_location}" header_idx) if(${header_idx} LESS 0) list(APPEND c_header_dependencies "${header_location}") endif() endif() endforeach() # check for pxd dependencies # Look for cimport statements. set(module_dependencies "") file(STRINGS "${pxd}" cimport_statements REGEX cimport) foreach(statement ${cimport_statements}) if(${statement} MATCHES from) string(REGEX REPLACE "from[ ]+([^ ]+).*" "\\1" module "${statement}") else() string(REGEX REPLACE "cimport[ ]+([^ ]+).*" "\\1" module "${statement}") endif() list(APPEND module_dependencies ${module}) endforeach() # check for pxi dependencies # Look for include statements. set(include_dependencies "") file(STRINGS "${pxd}" include_statements REGEX include) foreach(statement ${include_statements}) string(REGEX REPLACE "include[ ]+[\"]([^\"]+)[\"].*" "\\1" module "${statement}") list(APPEND include_dependencies ${module}) endforeach() list(REMOVE_DUPLICATES module_dependencies) list(REMOVE_DUPLICATES include_dependencies) # Add modules to the files to check, if appropriate. foreach(module ${module_dependencies}) unset(pxd_location CACHE) find_file(pxd_location ${module}.pxd PATHS "${pyx_path}" ${cmake_include_directories} NO_DEFAULT_PATH) if(pxd_location) list(FIND pxds_checked ${pxd_location} pxd_idx) if(${pxd_idx} LESS 0) list(FIND pxds_to_check ${pxd_location} pxd_idx) if(${pxd_idx} LESS 0) list(APPEND pxds_to_check ${pxd_location}) list(APPEND pxd_dependencies ${pxd_location}) endif() # if it is not already going to be checked endif() # if it has not already been checked endif() # if pxd file can be found endforeach() # for each module dependency discovered # Add includes to the files to check, if appropriate. foreach(_include ${include_dependencies}) unset(pxi_location CACHE) find_file(pxi_location ${_include} PATHS "${pyx_path}" ${cmake_include_directories} NO_DEFAULT_PATH) if(pxi_location) list(FIND pxds_checked ${pxi_location} pxd_idx) if(${pxd_idx} LESS 0) list(FIND pxds_to_check ${pxi_location} pxd_idx) if(${pxd_idx} LESS 0) list(APPEND pxds_to_check ${pxi_location}) list(APPEND pxd_dependencies ${pxi_location}) endif() # if it is not already going to be checked endif() # if it has not already been checked endif() # if include file can be found endforeach() # for each include dependency discovered endforeach() # for each include file to check list(LENGTH pxds_to_check number_pxds_to_check) endwhile() # Set additional flags. set(annotate_arg "") if(CYTHON_ANNOTATE) set(annotate_arg "--annotate") endif() set(no_docstrings_arg "") if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") set(no_docstrings_arg "--no-docstrings") endif() set(cython_debug_arg "") set(embed_pos_arg "") set(line_directives_arg "") if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") set(cython_debug_arg "--gdb") set(embed_pos_arg "--embed-positions") set(line_directives_arg "--line-directives") endif() # Include directory arguments. list(REMOVE_DUPLICATES cython_include_directories) set(include_directory_arg "") foreach(_include_dir ${cython_include_directories}) set(include_directory_arg ${include_directory_arg} "--include-dir" "${_include_dir}") endforeach() list(REMOVE_DUPLICATES pxd_dependencies) list(REMOVE_DUPLICATES c_header_dependencies) # Add the command to run the compiler. add_custom_command(OUTPUT ${generated_file} COMMAND ${CYTHON_EXECUTABLE} ARGS ${cxx_arg} ${include_directory_arg} ${py_version_arg} ${embed_arg} ${annotate_arg} ${no_docstrings_arg} ${cython_debug_arg} ${embed_pos_arg} ${line_directives_arg} ${CYTHON_FLAGS_LIST} ${pyx_location} --output-file ${generated_file} DEPENDS ${_source_file} ${pxd_dependencies} IMPLICIT_DEPENDS ${_output_syntax} ${c_header_dependencies} COMMENT ${comment}) # NOTE(opadron): I thought about making a proper target, but after trying it # out, I decided that it would be far too convenient to use the same name as # the target for the extension module (e.g.: for single-file modules): # # ... # add_cython_target(_module.pyx) # add_library(_module ${_module}) # ... # # The above example would not be possible since the "_module" target name # would already be taken by the cython target. Since I can't think of a # reason why someone would need the custom target instead of just using the # generated file directly, I decided to leave this commented out. # # add_custom_target(${_name} DEPENDS ${generated_file}) # Remove their visibility to the user. set(corresponding_pxd_file "" CACHE INTERNAL "") set(header_location "" CACHE INTERNAL "") set(pxd_location "" CACHE INTERNAL "") endfunction() PKlCMG'skbuild/resources/cmake/FindNumPy.cmake#.rst: # # Find the include directory for ``numpy/arrayobject.h`` as well as other NumPy tools like ``conv-template`` and # ``from-template``. # # This module sets the following variables: # # ``NumPy_FOUND`` # True if NumPy was found. # ``NumPy_INCLUDE_DIRS`` # The include directories needed to use NumpPy. # ``NumPy_VERSION`` # The version of NumPy found. # ``NumPy_CONV_TEMPLATE_EXECUTABLE`` # Path to conv-template executable. # ``NumPy_FROM_TEMPLATE_EXECUTABLE`` # Path to from-template executable. # # The module will also explicitly define one cache variable: # # ``NumPy_INCLUDE_DIR`` # # .. note:: # # To support NumPy < v0.15.0 where ``from-template`` and ``conv-template`` are not declared as entry points, # the module emulates the behavior of standalone executables by setting the corresponding variables with the # path the the python interpreter and the path to the associated script. For example: # :: # # set(NumPy_CONV_TEMPLATE_EXECUTABLE /path/to/python /path/to/site-packages/numpy/distutils/conv_template.py CACHE STRING "Command executing conv-template program" FORCE) # # set(NumPy_FROM_TEMPLATE_EXECUTABLE /path/to/python /path/to/site-packages/numpy/distutils/from_template.py CACHE STRING "Command executing from-template program" FORCE) # if(NOT NumPy_FOUND) set(_find_extra_args) if(NumPy_FIND_REQUIRED) list(APPEND _find_extra_args REQUIRED) endif() if(NumPy_FIND_QUIET) list(APPEND _find_extra_args QUIET) endif() find_package(PythonInterp ${_find_extra_args}) find_package(PythonLibs ${_find_extra_args}) find_program(NumPy_CONV_TEMPLATE_EXECUTABLE NAMES conv-template) find_program(NumPy_FROM_TEMPLATE_EXECUTABLE NAMES from-template) if(PYTHON_EXECUTABLE) execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "import numpy; print(numpy.get_include())" OUTPUT_VARIABLE _numpy_include_dir OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "import numpy; print(numpy.__version__)" OUTPUT_VARIABLE NumPy_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) # XXX This is required to support NumPy < v0.15.0. See note in module documentation above. if(NOT NumPy_CONV_TEMPLATE_EXECUTABLE) execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "from numpy.distutils import conv_template; print(conv_template.__file__)" OUTPUT_VARIABLE _numpy_conv_template_file OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) set(NumPy_CONV_TEMPLATE_EXECUTABLE "${PYTHON_EXECUTABLE}" "${_numpy_conv_template_file}" CACHE STRING "Command executing conv-template program" FORCE) endif() # XXX This is required to support NumPy < v0.15.0. See note in module documentation above. if(NOT NumPy_FROM_TEMPLATE_EXECUTABLE) execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "from numpy.distutils import from_template; print(from_template.__file__)" OUTPUT_VARIABLE _numpy_from_template_file OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) set(NumPy_FROM_TEMPLATE_EXECUTABLE "${PYTHON_EXECUTABLE}" "${_numpy_from_template_file}" CACHE STRING "Command executing from-template program" FORCE) endif() endif() endif() find_path(NumPy_INCLUDE_DIR numpy/arrayobject.h PATHS "${_numpy_include_dir}" "${PYTHON_INCLUDE_DIR}" PATH_SUFFIXES numpy/core/include ) set(NumPy_INCLUDE_DIRS ${NumPy_INCLUDE_DIR}) # handle the QUIETLY and REQUIRED arguments and set NumPy_FOUND to TRUE if # all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(NumPy REQUIRED_VARS NumPy_INCLUDE_DIR NumPy_CONV_TEMPLATE_EXECUTABLE NumPy_FROM_TEMPLATE_EXECUTABLE VERSION_VAR NumPy_VERSION ) mark_as_advanced(NumPy_INCLUDE_DIR) PKlCM׆AABskbuild/resources/cmake/targetLinkLibrariesWithDynamicLookup.cmake#.rst: # # Public Functions # ^^^^^^^^^^^^^^^^ # # The following functions are defined: # # .. cmake:command:: target_link_libraries_with_dynamic_lookup # # :: # # target_link_libraries_with_dynamic_lookup( []) # # # Useful to "weakly" link a loadable module. For example, it should be used # when compiling a loadable module when the symbols should be resolve from # the run-time environment where the module is loaded, and not a specific # system library. # # Like proper linking, except that the given ```` are not necessarily # linked. Instead, the ```` is produced in a manner that allows for # symbols unresolved within it to be resolved at runtime, presumably by the # given ````. If such a target can be produced, the provided # ```` are not actually linked. # # It links a library to a target such that the symbols are resolved at # run-time not link-time. # # The linker is checked to see if it supports undefined # symbols when linking a shared library. If it does then the library # is not linked when specified with this function. # # On platforms that do not support weak-linking, this function works just # like ``target_link_libraries``. # # .. note:: # # For OSX it uses ``undefined dynamic_lookup``. This is similar to using # ``-shared`` on Linux where undefined symbols are ignored. # # For more details, see `blog `_ # from Tim D. Smith. # # # .. cmake:command:: check_dynamic_lookup # # Check if the linker requires a command line flag to allow leaving symbols # unresolved when producing a target of type ```` that is # weakly-linked against a dependency of type ````. # # ```` # can be one of "STATIC", "SHARED", "MODULE", or "EXE". # # ```` # can be one of "STATIC", "SHARED", or "MODULE". # # Long signature: # # :: # # check_dynamic_lookup( # # # []) # # # Short signature: # # :: # # check_dynamic_lookup() # set to "MODULE" # # set to "SHARED" # # # The result is cached between invocations and recomputed only when the value # of CMake's linker flag list changes; ``CMAKE_STATIC_LINKER_FLAGS`` if # ```` is "STATIC", and ``CMAKE_SHARED_LINKER_FLAGS`` otherwise. # # # Defined variables: # # ```` # Whether the current C toolchain supports weak-linking for target binaries of # type ```` that are weakly-linked against a dependency target of # type ````. # # ```` # List of flags to add to the linker command to produce a working target # binary of type ```` that is weakly-linked against a dependency # target of type ````. # # ``HAS_DYNAMIC_LOOKUP__`` # Cached, global alias for ```` # # ``DYNAMIC_LOOKUP_FLAGS__`` # Cached, global alias for ```` # # # Private Functions # ^^^^^^^^^^^^^^^^^ # # The following private functions are defined: # # .. warning:: These functions are not part of the scikit-build API. They # exist purely as an implementation detail and may change from version # to version without notice, or even be removed. # # We mean it. # # # .. cmake:command:: _get_target_type # # :: # # _get_target_type( ) # # # Shorthand for querying an abbreviated version of the target type # of the given ````. # # ```` is set to: # # - "STATIC" for a STATIC_LIBRARY, # - "SHARED" for a SHARED_LIBRARY, # - "MODULE" for a MODULE_LIBRARY, # - and "EXE" for an EXECUTABLE. # # Defined variables: # # ```` # The abbreviated version of the ````'s type. # # # .. cmake:command:: _test_weak_link_project # # :: # # _test_weak_link_project( # # # ) # # # Attempt to compile and run a test project where a target of type # ```` is weakly-linked against a dependency of type ````: # # - ```` can be one of "STATIC", "SHARED", "MODULE", or "EXE". # - ```` can be one of "STATIC", "SHARED", or "MODULE". # # Defined variables: # # ```` # Whether the current C toolchain can produce a working target binary of type # ```` that is weakly-linked against a dependency target of type # ````. # # ```` # List of flags to add to the linker command to produce a working target # binary of type ```` that is weakly-linked against a dependency # target of type ````. # function(_get_target_type result_var target) set(target_type "SHARED_LIBRARY") if(TARGET ${target}) get_property(target_type TARGET ${target} PROPERTY TYPE) endif() set(result "STATIC") if(target_type STREQUAL "STATIC_LIBRARY") set(result "STATIC") endif() if(target_type STREQUAL "SHARED_LIBRARY") set(result "SHARED") endif() if(target_type STREQUAL "MODULE_LIBRARY") set(result "MODULE") endif() if(target_type STREQUAL "EXECUTABLE") set(result "EXE") endif() set(${result_var} ${result} PARENT_SCOPE) endfunction() function(_test_weak_link_project target_type lib_type can_weak_link_var project_name) set(gnu_ld_ignore "-Wl,--unresolved-symbols=ignore-all") set(osx_dynamic_lookup "-undefined dynamic_lookup") set(no_flag "") foreach(link_flag_spec gnu_ld_ignore osx_dynamic_lookup no_flag) set(link_flag "${${link_flag_spec}}") set(test_project_dir "${PROJECT_BINARY_DIR}/CMakeTmp") set(test_project_dir "${test_project_dir}/${project_name}") set(test_project_dir "${test_project_dir}/${link_flag_spec}") set(test_project_dir "${test_project_dir}/${target_type}") set(test_project_dir "${test_project_dir}/${lib_type}") set(test_project_src_dir "${test_project_dir}/src") set(test_project_bin_dir "${test_project_dir}/build") file(MAKE_DIRECTORY ${test_project_src_dir}) file(MAKE_DIRECTORY ${test_project_bin_dir}) set(mod_type "STATIC") set(link_mod_lib TRUE) set(link_exe_lib TRUE) set(link_exe_mod FALSE) if("${target_type}" STREQUAL "EXE") set(link_exe_lib FALSE) set(link_exe_mod TRUE) else() set(mod_type "${target_type}") endif() if("${mod_type}" STREQUAL "MODULE") set(link_mod_lib FALSE) endif() file(WRITE "${test_project_src_dir}/CMakeLists.txt" " cmake_minimum_required(VERSION ${CMAKE_VERSION}) project(${project_name} C) include_directories(${test_project_src_dir}) add_library(number ${lib_type} number.c) add_library(counter ${mod_type} counter.c) ") if("${mod_type}" STREQUAL "MODULE") file(APPEND "${test_project_src_dir}/CMakeLists.txt" " set_target_properties(counter PROPERTIES PREFIX \"\") ") endif() if(link_mod_lib) file(APPEND "${test_project_src_dir}/CMakeLists.txt" " target_link_libraries(counter number) ") elseif(NOT link_flag STREQUAL "") file(APPEND "${test_project_src_dir}/CMakeLists.txt" " set_target_properties(counter PROPERTIES LINK_FLAGS \"${link_flag}\") ") endif() file(APPEND "${test_project_src_dir}/CMakeLists.txt" " add_executable(main main.c) ") if(link_exe_lib) file(APPEND "${test_project_src_dir}/CMakeLists.txt" " target_link_libraries(main number) ") elseif(NOT link_flag STREQUAL "") file(APPEND "${test_project_src_dir}/CMakeLists.txt" " target_link_libraries(main \"${link_flag}\") ") endif() if(link_exe_mod) file(APPEND "${test_project_src_dir}/CMakeLists.txt" " target_link_libraries(main counter) ") else() file(APPEND "${test_project_src_dir}/CMakeLists.txt" " target_link_libraries(main \"${CMAKE_DL_LIBS}\") ") endif() file(WRITE "${test_project_src_dir}/number.c" " #include static int _number; void set_number(int number) { _number = number; } int get_number() { return _number; } ") file(WRITE "${test_project_src_dir}/number.h" " #ifndef _NUMBER_H #define _NUMBER_H extern void set_number(int); extern int get_number(void); #endif ") file(WRITE "${test_project_src_dir}/counter.c" " #include int count() { int result = get_number(); set_number(result + 1); return result; } ") file(WRITE "${test_project_src_dir}/counter.h" " #ifndef _COUNTER_H #define _COUNTER_H extern int count(void); #endif ") file(WRITE "${test_project_src_dir}/main.c" " #include #include #include ") if(NOT link_exe_mod) file(APPEND "${test_project_src_dir}/main.c" " #include ") endif() file(APPEND "${test_project_src_dir}/main.c" " int my_count() { int result = get_number(); set_number(result + 1); return result; } int main(int argc, char **argv) { int result; ") if(NOT link_exe_mod) file(APPEND "${test_project_src_dir}/main.c" " void *counter_module; int (*count)(void); counter_module = dlopen(\"./counter.so\", RTLD_LAZY | RTLD_GLOBAL); if(!counter_module) goto error; count = dlsym(counter_module, \"count\"); if(!count) goto error; ") endif() file(APPEND "${test_project_src_dir}/main.c" " result = count() != 0 ? EXIT_FAILURE : my_count() != 1 ? EXIT_FAILURE : my_count() != 2 ? EXIT_FAILURE : count() != 3 ? EXIT_FAILURE : count() != 4 ? EXIT_FAILURE : count() != 5 ? EXIT_FAILURE : my_count() != 6 ? EXIT_FAILURE : EXIT_SUCCESS; ") if(NOT link_exe_mod) file(APPEND "${test_project_src_dir}/main.c" " goto done; error: fprintf(stderr, \"Error occured:\\n %s\\n\", dlerror()); result = 1; done: if(counter_module) dlclose(counter_module); ") endif() file(APPEND "${test_project_src_dir}/main.c" " return result; } ") set(_rpath_arg) if(APPLE AND ${CMAKE_VERSION} VERSION_GREATER 2.8.11) set(_rpath_arg "-DCMAKE_MACOSX_RPATH='${CMAKE_MACOSX_RPATH}'") endif() try_compile(project_compiles "${test_project_bin_dir}" "${test_project_src_dir}" "${project_name}" CMAKE_FLAGS "-DCMAKE_SHARED_LINKER_FLAGS='${CMAKE_SHARED_LINKER_FLAGS}'" "-DCMAKE_ENABLE_EXPORTS=ON" ${_rpath_arg} OUTPUT_VARIABLE compile_output) set(project_works 1) set(run_output) if(project_compiles) execute_process(COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} "${test_project_bin_dir}/main" WORKING_DIRECTORY "${test_project_bin_dir}" RESULT_VARIABLE project_works OUTPUT_VARIABLE run_output ERROR_VARIABLE run_output) endif() set(test_description "Weak Link ${target_type} -> ${lib_type} (${link_flag_spec})") if(project_works EQUAL 0) set(project_works TRUE) message(STATUS "Performing Test ${test_description} - Success") else() set(project_works FALSE) message(STATUS "Performing Test ${test_description} - Failed") file(APPEND ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeError.log "Performing Test ${test_description} failed with the " "following output:\n" "BUILD\n-----\n${compile_output}\nRUN\n---\n${run_output}\n") endif() set(${can_weak_link_var} ${project_works} PARENT_SCOPE) if(project_works) set(${project_name} ${link_flag} PARENT_SCOPE) break() endif() endforeach() endfunction() function(check_dynamic_lookup) # Two signatures are supported: if(ARGC EQUAL "1") # # check_dynamic_lookup() # set(target_type "MODULE") set(lib_type "SHARED") set(has_dynamic_lookup_var "${ARGV0}") set(link_flags_var "unused") elseif(ARGC GREATER "2") # # check_dynamic_lookup( # # # []) # set(target_type "${ARGV0}") set(lib_type "${ARGV1}") set(has_dynamic_lookup_var "${ARGV2}") if(ARGC EQUAL "3") set(link_flags_var "unused") else() set(link_flags_var "${ARGV3}") endif() else() message(FATAL_ERROR "missing arguments") endif() _check_dynamic_lookup( ${target_type} ${lib_type} ${has_dynamic_lookup_var} ${link_flags_var} ) set(${has_dynamic_lookup_var} ${${has_dynamic_lookup_var}} PARENT_SCOPE) if(NOT "x${link_flags_var}x" STREQUAL "xunusedx") set(${link_flags_var} ${${link_flags_var}} PARENT_SCOPE) endif() endfunction() function(_check_dynamic_lookup target_type lib_type has_dynamic_lookup_var link_flags_var ) # hash the CMAKE_FLAGS passed and check cache to know if we need to rerun if("${target_type}" STREQUAL "STATIC") string(MD5 cmake_flags_hash "${CMAKE_STATIC_LINKER_FLAGS}") else() string(MD5 cmake_flags_hash "${CMAKE_SHARED_LINKER_FLAGS}") endif() set(cache_var "HAS_DYNAMIC_LOOKUP_${target_type}_${lib_type}") set(cache_hash_var "HAS_DYNAMIC_LOOKUP_${target_type}_${lib_type}_hash") set(result_var "DYNAMIC_LOOKUP_FLAGS_${target_type}_${lib_type}") if( NOT DEFINED ${cache_hash_var} OR NOT "${${cache_hash_var}}" STREQUAL "${cmake_flags_hash}") unset(${cache_var} CACHE) endif() if(NOT DEFINED ${cache_var}) set(skip_test FALSE) if(CMAKE_CROSSCOMPILING AND NOT CMAKE_CROSSCOMPILING_EMULATOR) set(skip_test TRUE) endif() if(skip_test) set(has_dynamic_lookup FALSE) set(link_flags) else() _test_weak_link_project(${target_type} ${lib_type} has_dynamic_lookup link_flags) endif() set(caveat " (when linking ${target_type} against ${lib_type})") set(${cache_var} "${has_dynamic_lookup}" CACHE BOOL "linker supports dynamic lookup for undefined symbols${caveat}") mark_as_advanced(${cache_var}) set(${result_var} "${link_flags}" CACHE STRING "linker flags for dynamic lookup${caveat}") mark_as_advanced(${result_var}) set(${cache_hash_var} "${cmake_flags_hash}" CACHE INTERNAL "hashed flags for ${cache_var} check") endif() set(${has_dynamic_lookup_var} "${${cache_var}}" PARENT_SCOPE) set(${link_flags_var} "${${result_var}}" PARENT_SCOPE) endfunction() function(target_link_libraries_with_dynamic_lookup target) _get_target_type(target_type ${target}) set(link_props) set(link_items) set(link_libs) foreach(lib ${ARGN}) _get_target_type(lib_type ${lib}) check_dynamic_lookup(${target_type} ${lib_type} has_dynamic_lookup dynamic_lookup_flags) if(has_dynamic_lookup) if(dynamic_lookup_flags) if("${target_type}" STREQUAL "EXE") list(APPEND link_items "${dynamic_lookup_flags}") else() list(APPEND link_props "${dynamic_lookup_flags}") endif() endif() elseif(${lib} MATCHES "(debug|optimized|general)") # See gh-255 else() list(APPEND link_libs "${lib}") endif() endforeach() if(link_props) list(REMOVE_DUPLICATES link_props) endif() if(link_items) list(REMOVE_DUPLICATES link_items) endif() if(link_libs) list(REMOVE_DUPLICATES link_libs) endif() if(link_props) set_target_properties(${target} PROPERTIES LINK_FLAGS "${link_props}") endif() set(links "${link_items}" "${link_libs}") if(links) target_link_libraries(${target} "${links}") endif() endfunction() PKmCM)lo77,scikit_build-0.8.1.dist-info/DESCRIPTION.rst=============================== scikit-build =============================== Improved build system generator for CPython C/C++/Fortran/Cython extensions. Better support is available for additional compilers, build systems, cross compilation, and locating dependencies and determining their build requirements. The **scikit-build** package is fundamentally just glue between the `setuptools` Python module and `CMake `_. To get started, see `this example `_. Latest Release -------------- .. table:: +-----------------------------------------------------------------------------+-------------------------------------------------------------------------------+ | Versions | Downloads | +=============================================================================+===============================================================================+ | .. image:: https://img.shields.io/pypi/v/scikit-build.svg | .. image:: https://img.shields.io/badge/downloads-54k%20total-green.svg | | :target: https://pypi.python.org/pypi/scikit-build | :target: https://pypi.python.org/pypi/scikit-build | +-----------------------------------------------------------------------------+-------------------------------------------------------------------------------+ | .. image:: https://anaconda.org/conda-forge/scikit-build/badges/version.svg | .. image:: https://anaconda.org/conda-forge/scikit-build/badges/downloads.svg | | :target: https://anaconda.org/conda-forge/scikit-build | :target: https://anaconda.org/conda-forge/scikit-build | +-----------------------------------------------------------------------------+-------------------------------------------------------------------------------+ Build Status ------------ .. table:: +---------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+ | | Linux | MacOSX | Windows | +===============+=========================================================================================+=========================================================================================+===========================================================================================================+ | PyPI | .. image:: https://circleci.com/gh/scikit-build/scikit-build.svg?style=shield | .. image:: https://img.shields.io/travis/scikit-build/scikit-build.svg?maxAge=2592000 | .. image:: https://ci.appveyor.com/api/projects/status/77bjtsihsjaywjr0?svg=true | | | :target: https://circleci.com/gh/scikit-build/scikit-build | :target: https://travis-ci.org/scikit-build/scikit-build | :target: https://ci.appveyor.com/project/scikit-build/scikit-build/branch/master | +---------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+ | Conda | .. image:: https://circleci.com/gh/conda-forge/scikit-build-feedstock.svg?style=shield | .. image:: https://travis-ci.org/conda-forge/scikit-build-feedstock.svg?branch=master | .. image:: https://ci.appveyor.com/api/projects/status/github/conda-forge/scikit-build-feedstock?svg=True | | | :target: https://circleci.com/gh/conda-forge/scikit-build-feedstock | :target: https://travis-ci.org/conda-forge/scikit-build-feedstock | :target: https://ci.appveyor.com/project/conda-forge/scikit-build-feedstock/branch/master | +---------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+ Overall Health -------------- .. image:: https://requires.io/github/scikit-build/scikit-build/requirements.svg?branch=master :target: https://requires.io/github/scikit-build/scikit-build/requirements/?branch=master :alt: Requirements Status .. image:: https://codecov.io/gh/scikit-build/scikit-build/branch/master/graph/badge.svg :target: https://codecov.io/gh/scikit-build/scikit-build .. image:: https://landscape.io/github/scikit-build/scikit-build/master/landscape.svg?style=flat :target: https://landscape.io/github/scikit-build/scikit-build :alt: Code Health Miscellaneous ------------- * Free software: MIT license * Documentation: http://scikit-build.readthedocs.org * Source code: https://github.com/scikit-build/scikit-build * Mailing list: https://groups.google.com/forum/#!forum/scikit-build History ------- PyCMake was created at SciPy 2014 in response to general difficulties building C++ and Fortran based Python extensions across platforms. It was renamed to "scikit-build" in 2016. PKmCMcc*scikit_build-0.8.1.dist-info/metadata.json{"classifiers": ["Development Status :: 2 - Pre-Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7"], "extensions": {"python.details": {"contacts": [{"email": "scikit-build@googlegroups.com", "name": "The scikit-build team", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/scikit-build/scikit-build"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "keywords": ["scikit-build"], "license": "MIT", "metadata_version": "2.0", "name": "scikit-build", "run_requires": [{"requires": ["packaging", "setuptools (>=28.0.0)", "wheel (>=0.29.0)"]}], "summary": "Improved build system generator for Python C/C++/Fortran/Cython extensions", "test_requires": [{"requires": ["codecov (>=2.0.5)", "coverage (>=4.2)", "cython (>=0.25.1)", "flake8 (>=3.0.4)", "path.py (>=11.5.0)", "pytest (>=3.0.3)", "pytest-cov (>=2.4.0)", "pytest-mock (>=1.4.0)", "pytest-runner (>=2.9)", "pytest-virtualenv (>=1.2.5)", "requests", "six (>=1.10.0)", "virtualenv"]}], "version": "0.8.1"}PKmCM]\*scikit_build-0.8.1.dist-info/top_level.txtskbuild PKmCMndnn"scikit_build-0.8.1.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py2-none-any Tag: py3-none-any PKmCMaD%scikit_build-0.8.1.dist-info/METADATAMetadata-Version: 2.0 Name: scikit-build Version: 0.8.1 Summary: Improved build system generator for Python C/C++/Fortran/Cython extensions Home-page: https://github.com/scikit-build/scikit-build Author: The scikit-build team Author-email: scikit-build@googlegroups.com License: MIT Keywords: scikit-build Platform: UNKNOWN Classifier: Development Status :: 2 - Pre-Alpha Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Requires-Dist: packaging Requires-Dist: setuptools (>=28.0.0) Requires-Dist: wheel (>=0.29.0) =============================== scikit-build =============================== Improved build system generator for CPython C/C++/Fortran/Cython extensions. Better support is available for additional compilers, build systems, cross compilation, and locating dependencies and determining their build requirements. The **scikit-build** package is fundamentally just glue between the `setuptools` Python module and `CMake `_. To get started, see `this example `_. Latest Release -------------- .. table:: +-----------------------------------------------------------------------------+-------------------------------------------------------------------------------+ | Versions | Downloads | +=============================================================================+===============================================================================+ | .. image:: https://img.shields.io/pypi/v/scikit-build.svg | .. image:: https://img.shields.io/badge/downloads-54k%20total-green.svg | | :target: https://pypi.python.org/pypi/scikit-build | :target: https://pypi.python.org/pypi/scikit-build | +-----------------------------------------------------------------------------+-------------------------------------------------------------------------------+ | .. image:: https://anaconda.org/conda-forge/scikit-build/badges/version.svg | .. image:: https://anaconda.org/conda-forge/scikit-build/badges/downloads.svg | | :target: https://anaconda.org/conda-forge/scikit-build | :target: https://anaconda.org/conda-forge/scikit-build | +-----------------------------------------------------------------------------+-------------------------------------------------------------------------------+ Build Status ------------ .. table:: +---------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+ | | Linux | MacOSX | Windows | +===============+=========================================================================================+=========================================================================================+===========================================================================================================+ | PyPI | .. image:: https://circleci.com/gh/scikit-build/scikit-build.svg?style=shield | .. image:: https://img.shields.io/travis/scikit-build/scikit-build.svg?maxAge=2592000 | .. image:: https://ci.appveyor.com/api/projects/status/77bjtsihsjaywjr0?svg=true | | | :target: https://circleci.com/gh/scikit-build/scikit-build | :target: https://travis-ci.org/scikit-build/scikit-build | :target: https://ci.appveyor.com/project/scikit-build/scikit-build/branch/master | +---------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+ | Conda | .. image:: https://circleci.com/gh/conda-forge/scikit-build-feedstock.svg?style=shield | .. image:: https://travis-ci.org/conda-forge/scikit-build-feedstock.svg?branch=master | .. image:: https://ci.appveyor.com/api/projects/status/github/conda-forge/scikit-build-feedstock?svg=True | | | :target: https://circleci.com/gh/conda-forge/scikit-build-feedstock | :target: https://travis-ci.org/conda-forge/scikit-build-feedstock | :target: https://ci.appveyor.com/project/conda-forge/scikit-build-feedstock/branch/master | +---------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+ Overall Health -------------- .. image:: https://requires.io/github/scikit-build/scikit-build/requirements.svg?branch=master :target: https://requires.io/github/scikit-build/scikit-build/requirements/?branch=master :alt: Requirements Status .. image:: https://codecov.io/gh/scikit-build/scikit-build/branch/master/graph/badge.svg :target: https://codecov.io/gh/scikit-build/scikit-build .. image:: https://landscape.io/github/scikit-build/scikit-build/master/landscape.svg?style=flat :target: https://landscape.io/github/scikit-build/scikit-build :alt: Code Health Miscellaneous ------------- * Free software: MIT license * Documentation: http://scikit-build.readthedocs.org * Source code: https://github.com/scikit-build/scikit-build * Mailing list: https://groups.google.com/forum/#!forum/scikit-build History ------- PyCMake was created at SciPy 2014 in response to general difficulties building C++ and Fortran based Python extensions across platforms. It was renamed to "scikit-build" in 2016. PKmCM:w33#scikit_build-0.8.1.dist-info/RECORDscikit_build-0.8.1.dist-info/DESCRIPTION.rst,sha256=9ztNWsfPcyr69AJDsQ-YPVsHnZW3tV0S94pLvZaNdts,5943 scikit_build-0.8.1.dist-info/METADATA,sha256=JSLWBBaZbzE0lS-GhHRybQsYVpGat6JApdrG13k1jXE,6891 scikit_build-0.8.1.dist-info/RECORD,, scikit_build-0.8.1.dist-info/WHEEL,sha256=GrqQvamwgBV4nLoJe0vhYRSWzWsx7xjlt74FT0SWYfE,110 scikit_build-0.8.1.dist-info/metadata.json,sha256=AVnEJjtvG4aRYepnHmnYEJA3rBRuzeulcEQaK-4wQT0,1379 scikit_build-0.8.1.dist-info/top_level.txt,sha256=TZ1cmVqJF82btiOqPPcH8sa7dLh6S1v1p-n05TNEQvo,8 skbuild/__init__.py,sha256=pqZJuY5EjVm8VVpVi7tGSpIks4kcWR8PF31NUGwJfo8,458 skbuild/_version.py,sha256=Fgk7_D5WeUojP3_5esLVNXzPnjBUZPLMZBrzDECIBbk,497 skbuild/cmaker.py,sha256=X7JZ0JSBzeMrYmkDvSzLdJ7QBa4UA08nifV5aP-he0k,19111 skbuild/compat.py,sha256=vetim0k47XDHNyf7343ndBXJha5t823uCo1UpxWkC-c,800 skbuild/constants.py,sha256=kHB27qMhaCey6mOsC7q6TbU9mnVj_-MYYYLPCqbFz-8,918 skbuild/exceptions.py,sha256=x_BiMGWjzSgDe4gCWowqjGRAWIXOvgl42Lmh-3n71l4,373 skbuild/setuptools_wrap.py,sha256=tEJym-c2IK5knQdcuul6tQPR1TM9Qd3Wo8joIMnB5Zw,35404 skbuild/command/__init__.py,sha256=Doew63Xx8sd-KJlrp2cCSpglVlix91hb9BG0BPkMcLg,640 skbuild/command/bdist.py,sha256=2XTBDom5-U1itXk6idpls4nzeM6GHKJy8jPXUGUylmA,416 skbuild/command/bdist_wheel.py,sha256=TJ4E8OcviPF6fLS3n1P_0H8NX_TIjfpJI3cctEailwU,3252 skbuild/command/build.py,sha256=kdytMqFgsCURKlWqCPPwrwvKqUDD30e-1S7ivVHF4YM,416 skbuild/command/build_py.py,sha256=_Mmy6rO09YtU5yEzEsFUFS2f7ldKxTahc9CHxTdsjik,3858 skbuild/command/clean.py,sha256=zS1Yzna-N19SOUrr31rVOujxkdTNSeeOcDYcE3DWEII,1065 skbuild/command/egg_info.py,sha256=zvdxf-qNlLdN_X6MspmMSR10ie7haYGG8XQFx_ZZg78,1916 skbuild/command/generate_source_manifest.py,sha256=f4LQjlqz8tgZXstETRiv1t1e3Viib_wyMNE4U7qzznc,3170 skbuild/command/install.py,sha256=_FdyA-Y-pOkfLawwv3rna1mO4JedzbMwHzpzkQS3WVk,958 skbuild/command/install_lib.py,sha256=hZip612nCdS4PgdfJFzjkmWCwP_u9ohkRv6SAdct2Sc,719 skbuild/command/install_scripts.py,sha256=cbZTDiR1PIu5ujrURbrdwrTIme5zQXPOEqruAtayHg4,739 skbuild/command/sdist.py,sha256=6kRadbdMw8eetsQ1H6nAq_DagDZXo8U--4n3ThYwBps,1465 skbuild/command/test.py,sha256=MhJ0C-bNskd9-g38lqSh0U3u8NwmmI58q1YFTHQcd1A,483 skbuild/platform_specifics/__init__.py,sha256=xU3UQm4GPSxxBrqlsisHpdO_03w01SRnkme2kbbc0tE,303 skbuild/platform_specifics/abstract.py,sha256=LfEvWbaE-F1FPNOBeIgZpF4Yf3IWHh1SudeClTxjTxw,8685 skbuild/platform_specifics/bsd.py,sha256=QyWdJeUIA7XqfKdXM0FqSTSBtw_JtkxLGaYx_3hGoGE,227 skbuild/platform_specifics/linux.py,sha256=sZ40jBW3FtEMsGwqophtphfDnqqqw3ZWZQ-c5FMCQkk,2903 skbuild/platform_specifics/osx.py,sha256=lTVfHKdv69QivOIX54V0ItEl1eQXvemY8HOLswF_ezo,623 skbuild/platform_specifics/platform_factory.py,sha256=I1dguWhZj0rHAgh_X9wSpsJnVLq2SYPXUTAV35da8Q0,827 skbuild/platform_specifics/unix.py,sha256=Zu5en1huGEVFauhVRafrUrJRBWE0AEE-9-6TXh2JBKI,466 skbuild/platform_specifics/windows.py,sha256=H9FUWfT80DI-_eazgBb2r_fiz3HgfUU01OFxijlgOG0,6994 skbuild/resources/cmake/FindCython.cmake,sha256=pwQQzFUU4FeiR9_auBE2ZCPGfkKtXCCfR-Gup0HBqb4,2638 skbuild/resources/cmake/FindF2PY.cmake,sha256=OON0oz1SpSqrH_GXfmcDgv8tNICUfJc3S_y8bjvuQR0,3139 skbuild/resources/cmake/FindNumPy.cmake,sha256=H1QnicwLzaRVBW2zxl4Stcp80tchBXQFwLuf1kaFQY4,4075 skbuild/resources/cmake/FindPythonExtensions.cmake,sha256=5myWsgR0VJ5EMnLELuH4uqWb4UPE3FzOZZj_St5IEHM,21390 skbuild/resources/cmake/UseCython.cmake,sha256=P5epQvCFgvoA9_k6eV5TF_9MOjEplMIcPPHpCDrdGIo,13678 skbuild/resources/cmake/targetLinkLibrariesWithDynamicLookup.cmake,sha256=tWTgp_16c728wTer8QHLtzNEkZB9iFB6T8M6ASdVuGU,16669 skbuild/utils/__init__.py,sha256=UsLHZuUvp5Z2KpsSjay5G4yqN26rFaLBcYWgPKSpLEU,8051 PKlCM uuskbuild/exceptions.pyPKlCMYQiYLLskbuild/setuptools_wrap.pyPKmCM,skbuild/_version.pyPKlCMڪ2JJNskbuild/cmaker.pyPKlCMuƳ$skbuild/constants.pyPKlCMQ  skbuild/compat.pyPKlCMѹ3;skbuild/__init__.pyPKlCMR"6skbuild/platform_specifics/unix.pyPKlCMl;!Hskbuild/platform_specifics/bsd.pyPKlCMz;;.jskbuild/platform_specifics/platform_factory.pyPKlCM//&skbuild/platform_specifics/__init__.pyPKlCM oo!dskbuild/platform_specifics/osx.pyPKlCM3W W #skbuild/platform_specifics/linux.pyPKlCM)!!!&skbuild/platform_specifics/abstract.pyPKlCM;-ŸRR%skbuild/platform_specifics/windows.pyPKlCMߔ(b b +p6skbuild/command/generate_source_manifest.pyPKlCMugCskbuild/command/build_py.pyPKlCMfRskbuild/command/install.pyPKlCMYԺǴ \Vskbuild/command/bdist_wheel.pyPKlCMR@))Lcskbuild/command/clean.pyPKlCM,gskbuild/command/install_lib.pyPKlCM>bZjskbuild/command/bdist.pyPKlCM%lskbuild/command/sdist.pyPKlCM='S{rskbuild/command/__init__.pyPKlCMa||4uskbuild/command/egg_info.pyPKlCM)"t|skbuild/command/test.pyPKlCMg"skbuild/command/install_scripts.pyPKlCM)]$skbuild/command/build.pyPKlCMossskbuild/utils/__init__.pyPKlCMܭC C &skbuild/resources/cmake/FindF2PY.cmakePKlCMfkSS2+skbuild/resources/cmake/FindPythonExtensions.cmakePKlCMZN N ( skbuild/resources/cmake/FindCython.cmakePKlCM1un5n5'skbuild/resources/cmake/UseCython.cmakePKlCMG'PDskbuild/resources/cmake/FindNumPy.cmakePKlCM׆AABTskbuild/resources/cmake/targetLinkLibrariesWithDynamicLookup.cmakePKmCM)lo77,scikit_build-0.8.1.dist-info/DESCRIPTION.rstPKmCMcc*~scikit_build-0.8.1.dist-info/metadata.jsonPKmCM]\*)scikit_build-0.8.1.dist-info/top_level.txtPKmCMndnn"yscikit_build-0.8.1.dist-info/WHEELPKmCMaD%'scikit_build-0.8.1.dist-info/METADATAPKmCM:w33#Uscikit_build-0.8.1.dist-info/RECORDPK))