From 7eadd4a1bc3ee898938ac9dd03d8c2e8d8a89363 Mon Sep 17 00:00:00 2001 From: Matthew McEneaney Date: Wed, 12 Mar 2025 16:22:14 -0400 Subject: [PATCH 1/6] refactor!: Remove personal hipo repo dependency. --- .gitmodules | 3 --- hipo | 1 - 2 files changed, 4 deletions(-) delete mode 160000 hipo diff --git a/.gitmodules b/.gitmodules index 8a5dccd..a90eb86 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "pybind11"] path = pybind11 url = https://github.com/pybind/pybind11.git -[submodule "hipo"] - path = hipo - url = https://github.com/mfmceneaney/hipo.git diff --git a/hipo b/hipo deleted file mode 160000 index f6a88e6..0000000 --- a/hipo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f6a88e659b91a97d90d51197c5556bb6b989cd3d From 93e068c5c5bb0991026488229e909ac52ebd77ef Mon Sep 17 00:00:00 2001 From: Matthew McEneaney Date: Wed, 12 Mar 2025 16:38:03 -0400 Subject: [PATCH 2/6] refactor!: Updated hipo dependency to main repo. --- .gitmodules | 3 +++ hipo | 1 + 2 files changed, 4 insertions(+) create mode 160000 hipo diff --git a/.gitmodules b/.gitmodules index a90eb86..a363dd4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "pybind11"] path = pybind11 url = https://github.com/pybind/pybind11.git +[submodule "hipo"] + path = hipo + url = https://github.com/gavalian/hipo.git diff --git a/hipo b/hipo new file mode 160000 index 0000000..7f6d729 --- /dev/null +++ b/hipo @@ -0,0 +1 @@ +Subproject commit 7f6d72988fde3f9f954b9b6e7915d3007a033f47 From 0a7879bb13286621cd71ef10bfc563bd2102a829 Mon Sep 17 00:00:00 2001 From: Matthew McEneaney Date: Thu, 13 Mar 2025 10:38:08 -0400 Subject: [PATCH 3/6] refactor!: Removed old build scripts. --- CMakeLists.txt | 41 -------------- setup.py | 148 ------------------------------------------------- 2 files changed, 189 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 setup.py diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 64b6247..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -cmake_minimum_required(VERSION 3.4...3.18) - -#-----------------------------------------# -project(hipopybind) - -#-----------------------------------------# -# Add LZ4 dependency -add_compile_definitions(__LZ4__) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/hipo/lz4/lib) - -#-----------------------------------------# -# Add HIPO dependency -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/hipo) - -#-----------------------------------------# -# Add pybind11 dependency and module -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/pybind11) - -#-----------------------------------------# -file (GLOB SOURCE_FILES "hipo/hipo4/*.cpp") -file (GLOB HEADER_FILES "hipo/hipo4/*.h") -file (GLOB PYTHON_FILES "src/*.cpp" "src/*.h") -file (GLOB LZ4SRC_FILES "hipo/lz4/lib/*.c") -file (GLOB LZ4HDR_FILES "hipo/lz4/lib/*.h") - -pybind11_add_module(hipopybind - ${SOURCE_FILES} - ${HEADER_FILES} - ${PYTHON_FILES} - ${LZ4SRC_FILES} - ${LZ4HDR_FILES} -) - -# EXAMPLE_VERSION_INFO is defined by setup.py and passed into the C++ code as a -# define (VERSION_INFO) here. -target_compile_definitions(hipopybind - PRIVATE VERSION_INFO=${EXAMPLE_VERSION_INFO}) - -#-----------------------------------------# -# Link header files from subdirectories -target_include_directories(hipopybind PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/setup.py b/setup.py deleted file mode 100644 index 1a467b0..0000000 --- a/setup.py +++ /dev/null @@ -1,148 +0,0 @@ -import os -import re -import subprocess -import sys -from pathlib import Path - -from setuptools import Extension, setup -from setuptools.command.build_ext import build_ext - -#NOTE: Build file based off the one in https://github.com/pybind/cmake_example.git - -# Convert distutils Windows platform specifiers to CMake -A arguments -PLAT_TO_CMAKE = { - "win32": "Win32", - "win-amd64": "x64", - "win-arm32": "ARM", - "win-arm64": "ARM64", -} - - -# A CMakeExtension needs a sourcedir instead of a file list. -# The name must be the _single_ output extension from the CMake build. -# If you need multiple extensions, see scikit-build. -class CMakeExtension(Extension): - def __init__(self, name: str, sourcedir: str = "") -> None: - super().__init__(name, sources=[]) - self.sourcedir = os.fspath(Path(sourcedir).resolve()) - - -class CMakeBuild(build_ext): - def build_extension(self, ext: CMakeExtension) -> None: - # Must be in this form due to bug in .resolve() only fixed in Python 3.10+ - ext_fullpath = Path.cwd() / self.get_ext_fullpath(ext.name) - extdir = ext_fullpath.parent.resolve() - - # Using this requires trailing slash for auto-detection & inclusion of - # auxiliary "native" libs - - debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug - cfg = "Debug" if debug else "Release" - - # CMake lets you override the generator - we need to check this. - # Can be set with Conda-Build, for example. - cmake_generator = os.environ.get("CMAKE_GENERATOR", "") - - # Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON - # EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code - # from Python. - cmake_args = [ - f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}{os.sep}", - f"-DPYTHON_EXECUTABLE={sys.executable}", - f"-DCMAKE_BUILD_TYPE={cfg}", # not used on MSVC, but no harm - ] - build_args = [] - # Adding CMake arguments set as environment variable - # (needed e.g. to build for ARM OSx on conda-forge) - if "CMAKE_ARGS" in os.environ: - cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item] - - # In this example, we pass in the version to C++. You might not need to. - cmake_args += [f"-DEXAMPLE_VERSION_INFO={self.distribution.get_version()}"] - - if self.compiler.compiler_type != "msvc": - # Using Ninja-build since it a) is available as a wheel and b) - # multithreads automatically. MSVC would require all variables be - # exported for Ninja to pick it up, which is a little tricky to do. - # Users can override the generator with CMAKE_GENERATOR in CMake - # 3.15+. - if (not cmake_generator or cmake_generator == "Ninja") and not sys.platform.startswith('linux'): #NOTE: #DEBUGGING: ADDED FOR BUILD TO WORK ON IFARM - try: - import ninja - - ninja_executable_path = Path(ninja.BIN_DIR) / "ninja" - cmake_args += [ - "-GNinja", - f"-DCMAKE_MAKE_PROGRAM:FILEPATH={ninja_executable_path}", - ] - except ImportError: - pass - - else: - # Single config generators are handled "normally" - single_config = any(x in cmake_generator for x in {"NMake", "Ninja"}) - - # CMake allows an arch-in-generator style for backward compatibility - contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"}) - - # Specify the arch if using MSVC generator, but only if it doesn't - # contain a backward-compatibility arch spec already in the - # generator name. - if not single_config and not contains_arch: - cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]] - - # Multi-config generators have a different way to specify configs - if not single_config: - cmake_args += [ - f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}" - ] - build_args += ["--config", cfg] - - if sys.platform.startswith("darwin"): - # Cross-compile support for macOS - respect ARCHFLAGS if set - archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", "")) - if archs: - cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))] - - # Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level - # across all generators. - if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ: - # self.parallel is a Python 3 only way to set parallel jobs by hand - # using -j in the build_ext call, not supported by pip or PyPA-build. - if hasattr(self, "parallel") and self.parallel: - # CMake 3.12+ only. - build_args += [f"-j{self.parallel}"] - - build_temp = Path(self.build_temp) / ext.name - if not build_temp.exists(): - build_temp.mkdir(parents=True) - - subprocess.run( - ["cmake", ext.sourcedir, *cmake_args], cwd=build_temp, check=True - ) - subprocess.run( - ["cmake", "--build", ".", *build_args], cwd=build_temp, check=True - ) - -#NOTE: Define function for reading README file into long description -def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read() - -# The information here can also be placed in setup.cfg - better separation of -# logic and declaration, and simpler if you include description/version in a file. -setup( - name="hipopybind", - version="1.1.1", - author="Matthew McEneaney", - author_email="matthew.mceneaney@duke.edu", - license="MIT", - url="https://github.com/mfmceneaney/hipopybind.git", - description="A HIPO python library using PyBind11 and CMake", - long_description=read('README.md'), - long_description_content_type='text/markdown', - ext_modules=[CMakeExtension("hipopybind")], - cmdclass={"build_ext": CMakeBuild}, - zip_safe=False, - extras_require={"test": ["pytest>=6.0"]}, - python_requires=">=3.7", -) From cf34202e4b0b3bcc7ec93ef6415f072c11831183 Mon Sep 17 00:00:00 2001 From: Matthew McEneaney Date: Thu, 13 Mar 2025 11:07:40 -0400 Subject: [PATCH 4/6] refactor!: Removed git submodules. --- .gitmodules | 6 ------ hipo | 1 - pybind11 | 1 - 3 files changed, 8 deletions(-) delete mode 160000 hipo delete mode 160000 pybind11 diff --git a/.gitmodules b/.gitmodules index a363dd4..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +0,0 @@ -[submodule "pybind11"] - path = pybind11 - url = https://github.com/pybind/pybind11.git -[submodule "hipo"] - path = hipo - url = https://github.com/gavalian/hipo.git diff --git a/hipo b/hipo deleted file mode 160000 index 7f6d729..0000000 --- a/hipo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7f6d72988fde3f9f954b9b6e7915d3007a033f47 diff --git a/pybind11 b/pybind11 deleted file mode 160000 index fac23b6..0000000 --- a/pybind11 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fac23b6f65e6d0b9aa8525712936b036e372eae1 From 9fc3190436482bfe4d88a20ebcb7110934906ddc Mon Sep 17 00:00:00 2001 From: Matthew McEneaney Date: Thu, 13 Mar 2025 17:18:23 -0400 Subject: [PATCH 5/6] build: switch to meson build system. --- meson.build | 47 +++++++++++++++++++++++++++++++++++++++ pyproject.toml | 36 ++++++++++++------------------ requirements.txt | 2 ++ subprojects/hipo4.wrap | 9 ++++++++ subprojects/pybind11.wrap | 5 +++++ 5 files changed, 77 insertions(+), 22 deletions(-) create mode 100644 meson.build create mode 100644 requirements.txt create mode 100644 subprojects/hipo4.wrap create mode 100644 subprojects/pybind11.wrap diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..ab5aa71 --- /dev/null +++ b/meson.build @@ -0,0 +1,47 @@ +project( + 'hipopybind', + 'cpp', + version: '2.0.0', + license: 'MIT', + meson_version: '>= 1.2.0', + default_options: [ + 'cpp_std=c++17', + 'buildtype=release', + ], +) + +#---------- Find python ----------# +py = import('python').find_installation(pure: false) + +#---------- Add CMake subprojects ----------# +# Setup a CMake dependency +cmake = import('cmake') +opt_var = cmake.subproject_options() + +# Call CMake with `-DSOME_OTHER_VAR=ON` +opt_var.add_cmake_defines({'DOWNLOAD_CATCH': true}) +opt_var.add_cmake_defines({'PYBIND11_INSTALL': false}) +opt_var.add_cmake_defines({'PYBIND11_TEST': false}) +opt_var.set_install(false) + +# Configure the CMake project +pybind11_sub = cmake.subproject('pybind11', options : opt_var) + +# Fetch the dependency object +pybind11_dep = pybind11_sub.dependency('pybind11_headers') + +#---------- Add meson subprojects ----------# +hipo_dep = subproject('hipo4', + default_options : { + 'build_examples' : false, + 'dataframes' : false, + 'prefix' : get_option('prefix'), + }) +hipo_dep = dependency('hipo4') + +#---------- Compile Pybind11 Module ----------# +py.extension_module('hipopybind', + 'src/main.cpp', + install: true, + dependencies : [pybind11_dep,hipo_dep], +) diff --git a/pyproject.toml b/pyproject.toml index feeda5f..463b641 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,25 +1,17 @@ -[build-system] -requires = [ - "setuptools>61.0", - "wheel", - "ninja", - "cmake>=3.12", -] -build-backend = "setuptools.build_meta" +[tool.poetry] +name = "hipopybind" +version = "2.0.0" +description = "Python bindings for CLAS12 HIPO C++ classes with PyBind11" +authors = ["Matthew McEneaney "] +license = "MIT" +readme = "README.md" -[tool.isort] -profile = "black" +[tool.poetry.dependencies] +python = "^3.11" -[tool.pytest.ini_options] -minversion = "6.0" -addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"] -xfail_strict = true -filterwarnings = ["error"] -testpaths = ["tests"] +[tool.poetry.build] +script = "meson.build" -[tool.cibuildwheel] -test-command = "pytest {project}/tests" -test-extras = ["test"] -test-skip = ["*universal2:arm64"] -# Setuptools bug causes collision between pypy and cpython artifacts -before-build = "rm -rf {project}/build" +[build-system] +requires = ["poetry-core","meson-python","pybind11"] +build-backend = "mesonpy" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..dc5945e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +meson-python +cmake diff --git a/subprojects/hipo4.wrap b/subprojects/hipo4.wrap new file mode 100644 index 0000000..15d1c4e --- /dev/null +++ b/subprojects/hipo4.wrap @@ -0,0 +1,9 @@ +[wrap-file] +directory = hipo-4.2.0 +source_url = https://github.com/gavalian/hipo/archive/refs/tags/4.2.0.tar.gz +source_filename = hipo-4.2.0.tar.gz +source_hash = a5feb44af5ca77d5af0aaae66571241e2eb82abf95c45d563a4541718d1abc6a +method = meson + +[provide] +hipo4_dep = hipo-4.2.0/hipo4 diff --git a/subprojects/pybind11.wrap b/subprojects/pybind11.wrap new file mode 100644 index 0000000..3a375a5 --- /dev/null +++ b/subprojects/pybind11.wrap @@ -0,0 +1,5 @@ +[wrap-file] +directory = pybind11-2.13.6 +source_url = https://github.com/pybind/pybind11/archive/refs/tags/v2.13.6.tar.gz +source_filename = pybind11-2.13.6.tgz +source_hash = e08cb87f4773da97fa7b5f035de8763abc656d87d5773e62f6da0587d1f0ec20 From 4dba9c74b62b408a273a6cdc352c3937cf87011b Mon Sep 17 00:00:00 2001 From: Matthew McEneaney Date: Tue, 9 Sep 2025 16:48:08 -0400 Subject: [PATCH 6/6] fix: Partial fix for meson build. --- meson.build | 110 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 9 deletions(-) diff --git a/meson.build b/meson.build index ab5aa71..a9fcee5 100644 --- a/meson.build +++ b/meson.build @@ -10,10 +10,13 @@ project( ], ) +# meson modules +pkg = import('pkgconfig') + #---------- Find python ----------# py = import('python').find_installation(pure: false) -#---------- Add CMake subprojects ----------# +#---------- Add PyBind11 as a CMake subproject ----------# # Setup a CMake dependency cmake = import('cmake') opt_var = cmake.subproject_options() @@ -30,14 +33,88 @@ pybind11_sub = cmake.subproject('pybind11', options : opt_var) # Fetch the dependency object pybind11_dep = pybind11_sub.dependency('pybind11_headers') -#---------- Add meson subprojects ----------# -hipo_dep = subproject('hipo4', - default_options : { - 'build_examples' : false, - 'dataframes' : false, - 'prefix' : get_option('prefix'), - }) -hipo_dep = dependency('hipo4') +#---------- Add hipo4 from pkg-config OR from subproject ----------# +hipo_dep = dependency( + 'hipo4', + version: '>=4.2.0', + method: 'pkg-config', +) +if not hipo_dep.found() + hipo_dep = subproject('hipo4', + default_options : { + 'build_examples' : false, + 'dataframes' : false, + 'prefix' : get_option('prefix'), + }) +endif + +#---------- Declare package dependencies ----------# + +# list of dependencies +# FIXME: for users which use LD_LIBRARY_PATH, we should try to keep this list +# ordered such that the ones users are *least likely* to try to build +# themselves are listed last (see FIXME in meson/this_iguana.sh.in) +# NOTE: omit ROOT (handled differently, and most ROOT users already have it in their environment) +dep_list = [] +foreach dep : [ hipo_dep ] + if dep.found() + dep_list += dep + endif +endforeach + +# pkgconfig configuration: make a list of dependency library and include directories +dep_lib_dirs = [] +dep_include_dirs = [] +dep_pkgconfig_dirs = [] +foreach dep : dep_list + + # get library and include dirs + if dep.type_name() == 'pkgconfig' + libdirs = [ dep.get_variable(pkgconfig: 'libdir') ] + incdirs = [ dep.get_variable(pkgconfig: 'includedir') ] + elif dep.type_name() == 'cmake' + libdirs = [] + foreach lib : dep.get_variable(cmake: 'PACKAGE_LIBRARIES').split(';') + libdirs += run_command('dirname', lib, check: true).stdout().strip() + endforeach + incdirs = ROOT_dep.get_variable(cmake: 'PACKAGE_INCLUDE_DIRS').split(';') + else + name = dep.get_variable(internal: 'name', default_value: dep.name()) + warning(f'Unknown dependency "@name@"') + continue + endif + + # append to `dep_*_dirs` arrays, uniquely + foreach libdir : libdirs + if not dep_lib_dirs.contains(libdir) + dep_lib_dirs += libdir + endif + if dep.type_name() == 'pkgconfig' + pkgconfigdir = libdir / 'pkgconfig' + if not dep_pkgconfig_dirs.contains(pkgconfigdir) + dep_pkgconfig_dirs += pkgconfigdir + endif + endif + endforeach + foreach incdir : incdirs + if not dep_include_dirs.contains(incdir) + dep_include_dirs += incdir + endif + endforeach +endforeach + +# general project vars +project_inc = include_directories('src') +project_libs = [] +project_deps = declare_dependency(dependencies: dep_list) # do NOT include ROOT here +project_etc = get_option('sysconfdir') / meson.project_name() +project_test_env = environment() +project_pkg_vars = [ + 'bindir=' + '${prefix}' / get_option('bindir'), + 'dep_pkgconfigdirs=' + ':'.join(dep_pkgconfig_dirs), + 'dep_libdirs=' + ':'.join(dep_lib_dirs), + 'dep_includedirs=' + ':'.join(dep_include_dirs), +] #---------- Compile Pybind11 Module ----------# py.extension_module('hipopybind', @@ -45,3 +122,18 @@ py.extension_module('hipopybind', install: true, dependencies : [pybind11_dep,hipo_dep], ) + +# generate pkg-config file +project_pkg_vars_nonempty = [] +foreach var : project_pkg_vars + if not var.endswith('=') # remove empty variable values + project_pkg_vars_nonempty += var + endif +endforeach +pkg.generate( + name: meson.project_name(), + description: project_description, + libraries: project_libs, + requires: [ pybind11_dep, hipo_dep ], # pkg-config dependencies only + variables: project_pkg_vars_nonempty, +)