Skip to content

Commit

Permalink
try msvc build
Browse files Browse the repository at this point in the history
  • Loading branch information
mikedh committed Mar 8, 2024
1 parent 530406d commit 69c5c01
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 76 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
os: [ubuntu-latest, windows-latest]

steps:
- uses: actions/checkout@v3
Expand Down
115 changes: 71 additions & 44 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,91 +8,118 @@
do some level of manual wangling here.
# Steps
- build the wheel with `pip wheel`
- build the library for the current platform using subprocess
- inject the library into the wheel
- fix the wheel tags to be `py3-none-{platform}`
1. build the library for the current platform using subprocess
2. build the wheel with `pip wheel` which only contains Python
3. Inject the built library into the wheel
4. Fix the wheel tags to be `py3-none-{platform}`
"""

import os
import zipfile
import tempfile
import platform
import subprocess

cwd = os.path.abspath(os.path.dirname(__file__))
ctm_lib = os.path.join(cwd, 'upstream', 'OpenCTM', 'lib')
ctm_lib = os.path.join(cwd, "upstream", "OpenCTM", "lib")


def build_manylinux(image: str):
"""
Build OpenCTM on a manylinux image.
"""

# remove any prior built artifacts from the library
subprocess.check_call(['git', 'clean', '-xdf'],
cwd=ctm_lib)
subprocess.check_call(["git", "clean", "-xdf"], cwd=ctm_lib)

# compose a docker command to run
command = ['docker', 'run',
'-v', f'{ctm_lib}:/ctmlib',
'-w', '/ctmlib',
image,
'make -f Makefile.linux']
print(' '.join(command))
# compose a docker command to run
command = [
"docker",
"run",
"-v",
f"{ctm_lib}:/ctmlib",
"-w",
"/ctmlib",
image,
"make -f Makefile.linux",
]
print(" ".join(command))

# build in the manylinux image
# not sure why this doesn't work as a non-shell command
subprocess.check_call(' '.join(command), shell=True)
subprocess.check_call(" ".join(command), shell=True)

libname = 'libopenctm.so'
with open(os.path.join(ctm_lib, libname), 'rb') as f:
libname = "libopenctm.so"
with open(os.path.join(ctm_lib, libname), "rb") as f:
return {libname: f.read()}





def build_windows(lib_name: str = "openctm.dll") -> dict:
"""
Build in a windows environment with make
"""
# remove any prior built artifacts from the library
subprocess.check_call(["git", "clean", "-xdf"], cwd=ctm_lib)
# run in the windows environment
subprocess.check_call(["make", "-f", "Makefile.msvc"], cwd=ctm_lib)

with open(os.path.join(ctm_lib, lib_name), "rb") as f:
return {lib_name: f.read()}


def to_wheel(libs: dict):

with tempfile.TemporaryDirectory() as tmp:
subprocess.check_call(['pip', 'wheel', '.', f'--wheel-dir={tmp}'])
subprocess.check_call(["pip", "wheel", ".", f"--wheel-dir={tmp}"])

# there should only be one file in this temp directory
wheel_name = os.listdir(tmp)[-1]
file_name = os.path.join(tmp, wheel_name)
assert file_name.endswith('.whl')
assert file_name.endswith(".whl")

# append the requested libraries to the zip archive
with zipfile.ZipFile(file_name, 'a') as zipped:
with zipfile.ZipFile(file_name, "a") as zipped:
for lib, raw in libs.items():
zipped.writestr(f'openctm/{lib}', raw)
with open(file_name, 'rb') as f:
zipped.writestr(f"openctm/{lib}", raw)

with open(file_name, "rb") as f:
return {wheel_name: f.read()}

def main():

wheelhouse = os.path.join(cwd, 'wheelhouse')

def main(wheelhouse=None):
"""
Generate wheels for the current platform.
"""
if wheelhouse is None:
wheelhouse = os.path.join(cwd, "wheelhouse")
os.makedirs(wheelhouse, exist_ok=True)
if platform.system() == 'Linux':

if platform.system() == "Linux":
# build on specific manylinux tag images
manylinux = ['quay.io/pypa/manylinux2014_x86_64',
'quay.io/pypa/manylinux2014_i686']
manylinux = [
"quay.io/pypa/manylinux2014_x86_64",
"quay.io/pypa/manylinux2014_i686",
]
for image in manylinux:
tag_platform = image.rsplit('/', 1)[-1]
tag_platform = image.rsplit("/", 1)[-1]
wheel = to_wheel(build_manylinux(image))
tag_none = next(iter(wheel.keys()))
# keep the `none` ABI
# replace the `any` platform with manylinux
tag_new = tag_none.replace('any', tag_platform)

with open(os.path.join(wheelhouse, tag_new), 'wb') as f:
tag_new = tag_none.replace("any", tag_platform)
with open(os.path.join(wheelhouse, tag_new), "wb") as f:
f.write(wheel[tag_none])

elif platform.system() == 'Windows':
build_windows()

elif platform.system() == "Windows":
wheel = to_wheel(build_windows())
tag_none = next(iter(wheel.keys()))
# keep the `none` ABI
# replace the `any` platform with windows
tag_platform = "win_amd64"
tag_new = tag_none.replace("any", tag_platform)
with open(os.path.join(wheelhouse, tag_new), "wb") as f:
f.write(wheel[tag_none])
else:
raise NotImplementedError(platform.system())

if __name__ == '__main__':

if __name__ == "__main__":
main()

2 changes: 1 addition & 1 deletion openctm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .binding import load_ctm

__all__ = ['load_ctm']
__all__ = ["load_ctm"]
17 changes: 8 additions & 9 deletions openctm/binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@

_cwd = os.path.abspath(os.path.dirname(__file__))
if os.name == "nt":
_ctm_lib = ctypes.WinDLL(
os.path.join(_cwd, 'libopenctm.dll'))
elif os.name == 'posix':
_ctm_lib = ctypes.WinDLL(os.path.join(_cwd, "openctm.dll"))
elif os.name == "posix":
# hardcode the support library to the location from the wheel
_ctm_lib = ctypes.CDLL(
os.path.join(_cwd, 'libopenctm.so'))
_ctm_lib = ctypes.CDLL(os.path.join(_cwd, "libopenctm.so"))


def load_ctm(file_obj, file_type=None, **kwargs):
"""
Load OpenCTM files from a file object.
Expand Down Expand Up @@ -126,9 +125,9 @@ def load_ctm(file_obj, file_type=None, **kwargs):
vertex_count = ctmGetInteger(ctm, CTM_VERTEX_COUNT)
vertex_ctm = ctmGetFloatArray(ctm, CTM_VERTICES)
# use fromiter to avoid loop
vertices = np.fromiter(vertex_ctm, dtype=np.float64, count=vertex_count * 3).reshape(
(-1, 3)
)
vertices = np.fromiter(
vertex_ctm, dtype=np.float64, count=vertex_count * 3
).reshape((-1, 3))
# get faces
face_count = ctmGetInteger(ctm, CTM_TRIANGLE_COUNT)
face_ctm = ctmGetIntegerArray(ctm, CTM_INDICES)
Expand Down
23 changes: 2 additions & 21 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ requires = ["setuptools >= 61.0", "wheel"]

[project]
name = "openctm"
version = "0.0.1"
version = "0.0.2"
requires-python = ">=3.7"
authors = [{name = "Michael Dawson-Haggerty", email = "[email protected]"}]
license = {file = "LICENSE.md"}
Expand All @@ -23,7 +23,7 @@ classifiers = [
"Topic :: Multimedia :: Graphics",
"Topic :: Multimedia :: Graphics :: 3D Modeling"
]
urls = {Homepage = "https://github.com/trimesh/cascadio"}
urls = {Homepage = "https://github.com/trimesh/openctm"}

[project.readme]
file = "README.md"
Expand All @@ -37,22 +37,3 @@ packages = [
[project.optional-dependencies]
tests = ["pytest", "trimesh"]

[tool.cibuildwheel]
# `yum` would need to be replaced in the `before-all`
# script before the musl linux can build OpenCASCADE
skip = "*musl*"

[tool.cibuildwheel.linux]
# build OCCT on linux from source on the manylinux image
before-all = [
'cd OpenCTM',
'git clean -xdf',
'cd lib',
'make -f Makefile.linux'
]

test-extras = "tests"
test-command = "pytest {project}/tests"

# point auditwheel at the OCCT libraries
repair-wheel-command = "LD_LIBRARY_PATH=/project/OpenCTM/lib auditwheel repair --lib-sdir . -w {dest_dir} {wheel}"

0 comments on commit 69c5c01

Please sign in to comment.