116 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Python
		
	
	
		
		
			
		
	
	
			116 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Python
		
	
	
|  | #!/usr/bin/env python | ||
|  | # -*- coding: utf-8 -*- | ||
|  | 
 | ||
|  | # Setup script for PyPI; use CMakeFile.txt to build extension modules | ||
|  | 
 | ||
|  | import contextlib | ||
|  | import os | ||
|  | import re | ||
|  | import shutil | ||
|  | import string | ||
|  | import subprocess | ||
|  | import sys | ||
|  | import tempfile | ||
|  | 
 | ||
|  | import setuptools.command.sdist | ||
|  | 
 | ||
|  | DIR = os.path.abspath(os.path.dirname(__file__)) | ||
|  | VERSION_REGEX = re.compile( | ||
|  |     r"^\s*#\s*define\s+PYBIND11_VERSION_([A-Z]+)\s+(.*)$", re.MULTILINE | ||
|  | ) | ||
|  | 
 | ||
|  | # PYBIND11_GLOBAL_SDIST will build a different sdist, with the python-headers | ||
|  | # files, and the sys.prefix files (CMake and headers). | ||
|  | 
 | ||
|  | global_sdist = os.environ.get("PYBIND11_GLOBAL_SDIST", False) | ||
|  | 
 | ||
|  | setup_py = "tools/setup_global.py.in" if global_sdist else "tools/setup_main.py.in" | ||
|  | extra_cmd = 'cmdclass["sdist"] = SDist\n' | ||
|  | 
 | ||
|  | to_src = ( | ||
|  |     ("pyproject.toml", "tools/pyproject.toml"), | ||
|  |     ("setup.py", setup_py), | ||
|  | ) | ||
|  | 
 | ||
|  | # Read the listed version | ||
|  | with open("pybind11/_version.py") as f: | ||
|  |     code = compile(f.read(), "pybind11/_version.py", "exec") | ||
|  |     loc = {} | ||
|  |     exec(code, loc) | ||
|  |     version = loc["__version__"] | ||
|  | 
 | ||
|  | # Verify that the version matches the one in C++ | ||
|  | with open("include/pybind11/detail/common.h") as f: | ||
|  |     matches = dict(VERSION_REGEX.findall(f.read())) | ||
|  | cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches) | ||
|  | if version != cpp_version: | ||
|  |     msg = "Python version {} does not match C++ version {}!".format( | ||
|  |         version, cpp_version | ||
|  |     ) | ||
|  |     raise RuntimeError(msg) | ||
|  | 
 | ||
|  | 
 | ||
|  | def get_and_replace(filename, binary=False, **opts): | ||
|  |     with open(filename, "rb" if binary else "r") as f: | ||
|  |         contents = f.read() | ||
|  |     # Replacement has to be done on text in Python 3 (both work in Python 2) | ||
|  |     if binary: | ||
|  |         return string.Template(contents.decode()).substitute(opts).encode() | ||
|  |     else: | ||
|  |         return string.Template(contents).substitute(opts) | ||
|  | 
 | ||
|  | 
 | ||
|  | # Use our input files instead when making the SDist (and anything that depends | ||
|  | # on it, like a wheel) | ||
|  | class SDist(setuptools.command.sdist.sdist): | ||
|  |     def make_release_tree(self, base_dir, files): | ||
|  |         setuptools.command.sdist.sdist.make_release_tree(self, base_dir, files) | ||
|  | 
 | ||
|  |         for to, src in to_src: | ||
|  |             txt = get_and_replace(src, binary=True, version=version, extra_cmd="") | ||
|  | 
 | ||
|  |             dest = os.path.join(base_dir, to) | ||
|  | 
 | ||
|  |             # This is normally linked, so unlink before writing! | ||
|  |             os.unlink(dest) | ||
|  |             with open(dest, "wb") as f: | ||
|  |                 f.write(txt) | ||
|  | 
 | ||
|  | 
 | ||
|  | # Backport from Python 3 | ||
|  | @contextlib.contextmanager | ||
|  | def TemporaryDirectory():  # noqa: N802 | ||
|  |     "Prepare a temporary directory, cleanup when done" | ||
|  |     try: | ||
|  |         tmpdir = tempfile.mkdtemp() | ||
|  |         yield tmpdir | ||
|  |     finally: | ||
|  |         shutil.rmtree(tmpdir) | ||
|  | 
 | ||
|  | 
 | ||
|  | # Remove the CMake install directory when done | ||
|  | @contextlib.contextmanager | ||
|  | def remove_output(*sources): | ||
|  |     try: | ||
|  |         yield | ||
|  |     finally: | ||
|  |         for src in sources: | ||
|  |             shutil.rmtree(src) | ||
|  | 
 | ||
|  | 
 | ||
|  | with remove_output("pybind11/include", "pybind11/share"): | ||
|  |     # Generate the files if they are not present. | ||
|  |     with TemporaryDirectory() as tmpdir: | ||
|  |         cmd = ["cmake", "-S", ".", "-B", tmpdir] + [ | ||
|  |             "-DCMAKE_INSTALL_PREFIX=pybind11", | ||
|  |             "-DBUILD_TESTING=OFF", | ||
|  |             "-DPYBIND11_NOPYTHON=ON", | ||
|  |         ] | ||
|  |         cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr) | ||
|  |         subprocess.check_call(cmd, **cmake_opts) | ||
|  |         subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts) | ||
|  | 
 | ||
|  |     txt = get_and_replace(setup_py, version=version, extra_cmd=extra_cmd) | ||
|  |     code = compile(txt, setup_py, "exec") | ||
|  |     exec(code, {"SDist": SDist}) |