Skip to content

Commit

Permalink
Merge branch 'meson_extension_experiment' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
gbarter committed Jan 8, 2024
2 parents 8d0fb38 + d34420d commit eb2ac00
Showing 1 changed file with 71 additions and 90 deletions.
161 changes: 71 additions & 90 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
#!/usr/bin/env python
# encoding: utf-8

# setup.py
# only if building in place: ``python setup.py build_ext --inplace``
import os
import re
import platform
import shutil
import platform
import setuptools
import subprocess
from setuptools.command.build_ext import build_ext

#######
# This forces wheels to be platform specific
Expand All @@ -25,93 +20,79 @@ class BinaryDistribution(Distribution):
def has_ext_modules(foo):
return True
#######


def run_meson_build(staging_dir):
prefix = os.path.join(os.getcwd(), staging_dir)
purelibdir = "."

# check if meson extra args are specified
meson_args = ""
if "MESON_ARGS" in os.environ:
meson_args = os.environ["MESON_ARGS"]
# A weird add-on on mac github action runners needs to be removed
if meson_args.find("buildtype") >= 0: meson_args = ""

if platform.system() == "Windows":
if not "FC" in os.environ:
os.environ["FC"] = "gfortran"
if not "CC" in os.environ:
os.environ["CC"] = "gcc"

# configure
meson_path = shutil.which("meson")
if meson_path is None:
raise OSError("The meson command cannot be found on the system")

meson_call = [meson_path, "setup", staging_dir, "--wipe",
f"--prefix={prefix}", f"-Dpython.purelibdir={purelibdir}",
f"-Dpython.platlibdir={purelibdir}", meson_args]
meson_call = [m for m in meson_call if m != ""]
print(meson_call)
p1 = subprocess.run(meson_call, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
os.makedirs(staging_dir, exist_ok=True)
setup_log = os.path.join(staging_dir, "setup.log")
with open(setup_log, "wb") as f:
f.write(p1.stdout)
if p1.returncode != 0:
with open(setup_log, "r") as f:
print(f.read())
raise OSError(meson_call, f"The meson setup command failed! Check the log at {setup_log} for more information.")

# build
meson_call = [meson_path, "compile", "-vC", staging_dir]
meson_call = [m for m in meson_call if m != ""]
print(meson_call)
p2 = subprocess.run(meson_call, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
compile_log = os.path.join(staging_dir, "compile.log")
with open(compile_log, "wb") as f:
f.write(p2.stdout)
if p2.returncode != 0:
with open(compile_log, "r") as f:
print(f.read())
raise OSError(meson_call, f"The meson compile command failed! Check the log at {compile_log} for more information.")

this_dir = os.path.abspath(os.path.dirname(__file__))
staging_dir = os.path.join(this_dir, "meson_build")
build_dir = os.path.join(this_dir, "build")

def copy_shared_libraries():
build_path = os.path.join(staging_dir, "pyframe3dd")
for root, _dirs, files in os.walk(build_path):
for file in files:
# move pyframe3dd to just under staging_dir
if file.endswith((".so", ".lib", ".pyd", ".pdb", ".dylib", ".dll", ".mod")):
if ".so.p" in root or ".pyd.p" in root: # excludes intermediate object files
continue
file_path = os.path.join(root, file)
new_path = str(file_path)
match = re.search(staging_dir, new_path)
new_path = new_path[match.span()[1] + 1 :]
for f in files:
if f.endswith((".so", ".lib", ".pyd", ".pdb", ".dylib", ".dll")):
file_path = os.path.join(root, f)
new_path = str(file_path).replace(staging_dir + os.sep, "")
print(f"Copying build file {file_path} -> {new_path}")
shutil.move(file_path, new_path)

shutil.copy(file_path, new_path)

#######
class MesonExtension(setuptools.Extension):

def __init__(self, name, sourcedir="", **kwa):
setuptools.Extension.__init__(self, name, sources=[], **kwa)
self.sourcedir = os.path.abspath(sourcedir)

class MesonBuildExt(build_ext):

def copy_extensions_to_source(self):
newext = []
for ext in self.extensions:
if isinstance(ext, MesonExtension): continue
newext.append( ext )
self.extensions = newext
super().copy_extensions_to_source()

def build_extension(self, ext):
if not isinstance(ext, MesonExtension):
super().build_extension(ext)

else:

# Ensure that Meson is present and working
try:
self.spawn(["meson", "--version"])
except OSError:
raise RuntimeError("Cannot find meson executable")

# check if meson extra args are specified
meson_args = ""
if "MESON_ARGS" in os.environ:
meson_args = os.environ["MESON_ARGS"]

if platform.system() == "Windows":
if "FC" not in os.environ:
os.environ["FC"] = "gfortran"
if "CC" not in os.environ:
os.environ["CC"] = "gcc"

purelibdir = "."
configure_call = ["meson", "setup", staging_dir, "--wipe",
f"-Dpython.purelibdir={purelibdir}", f"--prefix={staging_dir}",
f"-Dpython.platlibdir={purelibdir}"] + meson_args.split()
configure_call = [m for m in configure_call if m.strip() != ""]
print(configure_call)

build_call = ["meson", "compile", "-vC", staging_dir]
print(build_call)

self.build_temp = build_dir

self.spawn(configure_call)
self.spawn(build_call)
copy_shared_libraries()


if __name__ == "__main__":
# This is where the meson build system will install to, it is then
# used as the sources for setuptools
staging_dir = "meson_build"

# this keeps the meson build system from running more than once
if "dist" not in str(os.path.abspath(__file__)):
cwd = os.getcwd()
run_meson_build(staging_dir)
os.chdir(cwd)
copy_shared_libraries()

init_file = os.path.join("pyframe3dd", "__init__.py")
#__version__ = re.findall(
# r"""__version__ = ["']+([0-9\.]*)["']+""",
# open(init_file).read(),
#)[0]

setuptools.setup(cmdclass={'bdist_wheel': bdist_wheel}, distclass=BinaryDistribution)

#os.environ['NPY_DISTUTILS_APPEND_FLAGS'] = '1'
setuptools.setup(cmdclass={"bdist_wheel": bdist_wheel, "build_ext": MesonBuildExt},
distclass=BinaryDistribution,
ext_modules=[ MesonExtension("pyframe3dd", this_dir) ],
)

0 comments on commit eb2ac00

Please sign in to comment.