From e78b745cf259472f58eb0790cfc6eb0443e009e1 Mon Sep 17 00:00:00 2001 From: Stella Laurenzo Date: Sun, 22 Aug 2021 13:43:55 -0700 Subject: [PATCH] [mlir][python] Makes C++ extension code relocatable by way of a macro. * Resolves a TODO by making this configurable by downstreams. * This seems to be the last thing allowing full use of the Python bindings as a library within another project (i.e. be embedding them). Differential Revision: https://reviews.llvm.org/D108523 --- mlir/include/mlir-c/Bindings/Python/Interop.h | 49 ++++++++++++++----- .../mlir/Bindings/Python/PybindAdaptors.h | 30 +++++------- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/mlir/include/mlir-c/Bindings/Python/Interop.h b/mlir/include/mlir-c/Bindings/Python/Interop.h index 882f73d84383..7fcfd028b407 100644 --- a/mlir/include/mlir-c/Bindings/Python/Interop.h +++ b/mlir/include/mlir-c/Bindings/Python/Interop.h @@ -30,19 +30,44 @@ #include "mlir-c/IntegerSet.h" #include "mlir-c/Pass.h" -#define MLIR_PYTHON_CAPSULE_AFFINE_EXPR "mlir.ir.AffineExpr._CAPIPtr" -#define MLIR_PYTHON_CAPSULE_AFFINE_MAP "mlir.ir.AffineMap._CAPIPtr" -#define MLIR_PYTHON_CAPSULE_ATTRIBUTE "mlir.ir.Attribute._CAPIPtr" -#define MLIR_PYTHON_CAPSULE_CONTEXT "mlir.ir.Context._CAPIPtr" +// The 'mlir' Python package is relocatable and supports co-existing in multiple +// projects. Each project must define its outer package prefix with this define +// in order to provide proper isolation and local name resolution. +// The default is for the upstream "import mlir" package layout. +// Note that this prefix is internally stringified, allowing it to be passed +// unquoted on the compiler command line without shell quote escaping issues. +#ifndef MLIR_PYTHON_PACKAGE_PREFIX +#define MLIR_PYTHON_PACKAGE_PREFIX mlir. +#endif + +// Makes a fully-qualified name relative to the MLIR python package. +#define MLIR_PYTHON_STRINGIZE(s) #s +#define MLIR_PYTHON_STRINGIZE_ARG(arg) MLIR_PYTHON_STRINGIZE(arg) +#define MAKE_MLIR_PYTHON_QUALNAME(local) \ + MLIR_PYTHON_STRINGIZE_ARG(MLIR_PYTHON_PACKAGE_PREFIX) local + +#define MLIR_PYTHON_CAPSULE_AFFINE_EXPR \ + MAKE_MLIR_PYTHON_QUALNAME("ir.AffineExpr._CAPIPtr") +#define MLIR_PYTHON_CAPSULE_AFFINE_MAP \ + MAKE_MLIR_PYTHON_QUALNAME("ir.AffineMap._CAPIPtr") +#define MLIR_PYTHON_CAPSULE_ATTRIBUTE \ + MAKE_MLIR_PYTHON_QUALNAME("ir.Attribute._CAPIPtr") +#define MLIR_PYTHON_CAPSULE_CONTEXT \ + MAKE_MLIR_PYTHON_QUALNAME("ir.Context._CAPIPtr") #define MLIR_PYTHON_CAPSULE_EXECUTION_ENGINE \ - "mlir.execution_engine.ExecutionEngine._CAPIPtr" -#define MLIR_PYTHON_CAPSULE_INTEGER_SET "mlir.ir.IntegerSet._CAPIPtr" -#define MLIR_PYTHON_CAPSULE_LOCATION "mlir.ir.Location._CAPIPtr" -#define MLIR_PYTHON_CAPSULE_MODULE "mlir.ir.Module._CAPIPtr" -#define MLIR_PYTHON_CAPSULE_OPERATION "mlir.ir.Operation._CAPIPtr" -#define MLIR_PYTHON_CAPSULE_TYPE "mlir.ir.Type._CAPIPtr" -#define MLIR_PYTHON_CAPSULE_PASS_MANAGER "mlir.passmanager.PassManager._CAPIPtr" -#define MLIR_PYTHON_CAPSULE_VALUE "mlir.ir.Value._CAPIPtr" + MAKE_MLIR_PYTHON_QUALNAME("execution_engine.ExecutionEngine._CAPIPtr") +#define MLIR_PYTHON_CAPSULE_INTEGER_SET \ + MAKE_MLIR_PYTHON_QUALNAME("ir.IntegerSet._CAPIPtr") +#define MLIR_PYTHON_CAPSULE_LOCATION \ + MAKE_MLIR_PYTHON_QUALNAME("ir.Location._CAPIPtr") +#define MLIR_PYTHON_CAPSULE_MODULE \ + MAKE_MLIR_PYTHON_QUALNAME("ir.Module._CAPIPtr") +#define MLIR_PYTHON_CAPSULE_OPERATION \ + MAKE_MLIR_PYTHON_QUALNAME("ir.Operation._CAPIPtr") +#define MLIR_PYTHON_CAPSULE_TYPE MAKE_MLIR_PYTHON_QUALNAME("ir.Type._CAPIPtr") +#define MLIR_PYTHON_CAPSULE_PASS_MANAGER \ + MAKE_MLIR_PYTHON_QUALNAME("passmanager.PassManager._CAPIPtr") +#define MLIR_PYTHON_CAPSULE_VALUE MAKE_MLIR_PYTHON_QUALNAME("ir.Value._CAPIPtr") /** Attribute on MLIR Python objects that expose their C-API pointer. * This will be a type-specific capsule created as per one of the helpers diff --git a/mlir/include/mlir/Bindings/Python/PybindAdaptors.h b/mlir/include/mlir/Bindings/Python/PybindAdaptors.h index db8769d3c35f..61b982193c02 100644 --- a/mlir/include/mlir/Bindings/Python/PybindAdaptors.h +++ b/mlir/include/mlir/Bindings/Python/PybindAdaptors.h @@ -30,10 +30,6 @@ namespace py = pybind11; -// TODO: Move this to Interop.h and make it externally configurable/use it -// consistently to locate the "import mlir" top-level. -#define MLIR_PYTHON_PACKAGE_PREFIX "mlir." - // Raw CAPI type casters need to be declared before use, so always include them // first. namespace pybind11 { @@ -76,7 +72,7 @@ struct type_caster { static handle cast(MlirAffineMap v, return_value_policy, handle) { py::object capsule = py::reinterpret_steal(mlirPythonAffineMapToCapsule(v)); - return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir") + return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")) .attr("AffineMap") .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule) .release(); @@ -98,7 +94,7 @@ struct type_caster { static handle cast(MlirAttribute v, return_value_policy, handle) { py::object capsule = py::reinterpret_steal(mlirPythonAttributeToCapsule(v)); - return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir") + return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")) .attr("Attribute") .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule) .release(); @@ -115,7 +111,7 @@ struct type_caster { // TODO: This raises an error of "No current context" currently. // Update the implementation to pretty-print the helpful error that the // core implementations print in this case. - src = py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir") + src = py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")) .attr("Context") .attr("current"); } @@ -144,7 +140,7 @@ struct type_caster { static handle cast(MlirLocation v, return_value_policy, handle) { py::object capsule = py::reinterpret_steal(mlirPythonLocationToCapsule(v)); - return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir") + return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")) .attr("Location") .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule) .release(); @@ -166,7 +162,7 @@ struct type_caster { static handle cast(MlirModule v, return_value_policy, handle) { py::object capsule = py::reinterpret_steal(mlirPythonModuleToCapsule(v)); - return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir") + return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")) .attr("Module") .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule) .release(); @@ -190,7 +186,7 @@ struct type_caster { return py::none(); py::object capsule = py::reinterpret_steal(mlirPythonOperationToCapsule(v)); - return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir") + return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")) .attr("Operation") .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule) .release(); @@ -226,7 +222,7 @@ struct type_caster { static handle cast(MlirType t, return_value_policy, handle) { py::object capsule = py::reinterpret_steal(mlirPythonTypeToCapsule(t)); - return py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir") + return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")) .attr("Type") .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule) .release(); @@ -266,7 +262,7 @@ public: } template - pure_subclass &def(const char *name, Func &&f, const Extra &...extra) { + pure_subclass &def(const char *name, Func &&f, const Extra &... extra) { py::cpp_function cf( std::forward(f), py::name(name), py::is_method(py::none()), py::sibling(py::getattr(thisClass, name, py::none())), extra...); @@ -276,7 +272,7 @@ public: template pure_subclass &def_property_readonly(const char *name, Func &&f, - const Extra &...extra) { + const Extra &... extra) { py::cpp_function cf( std::forward(f), py::name(name), py::is_method(py::none()), py::sibling(py::getattr(thisClass, name, py::none())), extra...); @@ -288,7 +284,7 @@ public: template pure_subclass &def_staticmethod(const char *name, Func &&f, - const Extra &...extra) { + const Extra &... extra) { static_assert(!std::is_member_function_pointer::value, "def_staticmethod(...) called with a non-static member " "function pointer"); @@ -301,7 +297,7 @@ public: template pure_subclass &def_classmethod(const char *name, Func &&f, - const Extra &...extra) { + const Extra &... extra) { static_assert(!std::is_member_function_pointer::value, "def_classmethod(...) called with a non-static member " "function pointer"); @@ -329,7 +325,7 @@ public: IsAFunctionTy isaFunction) : mlir_attribute_subclass( scope, attrClassName, isaFunction, - py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir") + py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")) .attr("Attribute")) {} /// Subclasses with a provided mlir.ir.Attribute super-class. This must @@ -381,7 +377,7 @@ public: IsAFunctionTy isaFunction) : mlir_type_subclass( scope, typeClassName, isaFunction, - py::module::import(MLIR_PYTHON_PACKAGE_PREFIX "ir").attr("Type")) {} + py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")).attr("Type")) {} /// Subclasses with a provided mlir.ir.Type super-class. This must /// be used if the subclass is being defined in the same extension module