Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
gbarter committed Jan 8, 2024
2 parents cd41945 + 58f34b5 commit 0bb95f8
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 141 deletions.
127 changes: 76 additions & 51 deletions .github/workflows/CI_CCBlade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,85 +5,110 @@ on: [push, pull_request]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build_conda:
name: Build (${{ matrix.os }} Python ${{ matrix.python-version }})
build_pip:
name: Pip Build (${{ matrix.os }}) - ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}

defaults:
run:
shell: bash -l {0}

strategy:
fail-fast: False
fail-fast: false #true
matrix:
os: ["ubuntu-latest", "windows-latest"]
python-version: ["3.8", "3.9", "3.10"]
os: ["ubuntu-latest", "macOS-latest", "windows-latest"]
python-version: ["3.9", "3.10", "3.11"]

steps:
- name: Setup GNU Fortran
# if: false == contains( matrix.os, 'windows')
uses: awvwgk/setup-fortran@v1 #modflowpy/install-intelfortran-action@v1 #

- name: checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
id: cp
with:
python-version: ${{ matrix.python-version }}
update-environment: true

#- name: Setup tmate session
# if: contains( matrix.os, 'windows')
# uses: mxschmitt/action-tmate@v3

# Official way to do miniconda, but it messes with the worker environment and shell
- name: Install miniconda
uses: conda-incubator/setup-miniconda@v2
- name: Pip Install CCBlade
env:
MESON_ARGS: -Dpython_target=${{ steps.cp.outputs.python-path }}
run: |
'${{ steps.cp.outputs.python-path }}' -m pip install -v -e .[test]
- name: Test run
run: |
cd test
'${{ steps.cp.outputs.python-path }}' -m pytest .
build_conda:
name: Conda Build (${{ matrix.os }}) - ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash -el {0}

strategy:
fail-fast: false #true
matrix:
os: ["ubuntu-latest", "macOS-latest", "windows-latest"]
python-version: ["3.9", "3.10", "3.11"]

steps:
- name: checkout repository
uses: actions/checkout@v4

- uses: conda-incubator/setup-miniconda@v2
# https://github.com/marketplace/actions/setup-miniconda
with:
miniconda-version: "latest"
channels: conda-forge
#mamba-version: "*"
miniforge-version: "latest"
auto-update-conda: true
python-version: ${{ matrix.python-version }}
environment-file: environment.yml
activate-environment: test
auto-activate-base: false

# This is a less official, but more lightweight way to do miniconda
#- name: Install miniconda
# uses: s-weigand/setup-conda@v1
# # https://github.com/marketplace/actions/setup-conda
# with:
# update-conda: true
# python-version: ${{ matrix.python-version }}
# conda-channels: conda-forge
# activate-conda: true
#
#- name: Update environment
# run: |
# conda env update --file environment.yml

# Install compilers
#- name: Add compilers
# run: |
# conda install compilers

# Install dependencies of WISDEM specific to linux/mac
#- name: Add dependencies linux specific
# if: false == contains( matrix.os, 'windows')
# run: |
# conda install ninja
# conda init bash

# Install dependencies of WISDEM specific to windows
- name: Add dependencies windows specific
if: contains( matrix.os, 'windows')
run: |
conda install -y m2w64-toolchain libpython
- name: Add dependencies mac specific
if: contains( matrix.os, 'mac')
run: |
conda install -y compilers
gfortran --version
# Install
- name: Debug
run: |
conda list
printenv
#- name: Setup tmate session
# uses: mxschmitt/action-tmate@v3
# with:
# detached: true
# if: contains( matrix.os, 'windows')

# Install
- name: Conda Install CCBlade
env:
MESON_ARGS: ""
run: |
python setup.py develop
# Peek
#- name: Library name
# run: |
# ls
# echo "BREAK"
# ls ccblade
# echo "BREAK"
# ls meson_build/ccblade

# Run tests
- name: Conda Run pytest
- name: Test run
run: |
pytest test
cd test
pytest .
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, "ccblade")
for root, _dirs, files in os.walk(build_path):
for file in files:
# move ccblade 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={build_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("ccblade", "__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("ccblade", this_dir) ],
)

0 comments on commit 0bb95f8

Please sign in to comment.