From c8e99ca0865b72728acf372ea75b9941d71e4e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 8 Sep 2019 15:44:14 +0200 Subject: [PATCH] python: expose corrade and magnum compilation defines. --- doc/python/conf.py | 46 ++++++++++++++- doc/python/corrade.rst | 50 ++++++++++++++++ doc/python/magnum.rst | 15 +++-- doc/python/pages/api-conventions.rst | 33 ++++++++++- src/python/CMakeLists.txt | 1 - src/python/corrade/CMakeLists.txt | 31 +++++----- src/python/corrade/__init__.py | 25 ++++---- src/python/corrade/corrade.cpp | 85 ++++++++++++++++++++++++++-- src/python/magnum/__init__.py | 4 ++ src/python/magnum/magnum.cpp | 47 +++++++++++++++ src/python/setup.py.cmake | 2 +- 11 files changed, 295 insertions(+), 44 deletions(-) create mode 100644 doc/python/corrade.rst diff --git a/doc/python/conf.py b/doc/python/conf.py index 2d96d79..69da6e0 100644 --- a/doc/python/conf.py +++ b/doc/python/conf.py @@ -22,10 +22,51 @@ import magnum.trade # So the doc see everything # TODO: use just +=, m.css should reorder this on its own -corrade.__all__ = ['containers'] -magnum.__all__ = ['math', 'gl', 'meshtools', 'platform', 'primitives', 'shaders', 'scenegraph', 'trade'] + magnum.__all__ +corrade.__all__ = ['containers', 'BUILD_STATIC', 'BUILD_MULTITHREADED', 'TARGET_UNIX', 'TARGET_APPLE', 'TARGET_IOS', 'TARGET_IOS_SIMULATOR', 'TARGET_WINDOWS', 'TARGET_WINDOWS_RT', 'TARGET_EMSCRIPTEN', 'TARGET_ANDROID'] +magnum.__all__ = ['math', 'gl', 'meshtools', 'platform', 'primitives', 'shaders', 'scenegraph', 'trade', 'BUILD_STATIC', 'TARGET_GL', 'TARGET_GLES', 'TARGET_GLES2', 'TARGET_WEBGL', 'TARGET_VK'] + magnum.__all__ + +# hide values of the preprocessor defines to avoid confusion by assigning a +# class without __repr__ to them +# TODO: more systematic solution directly in m.css +class DoNotPrintValue: pass +corrade.BUILD_STATIC = DoNotPrintValue() +corrade.BUILD_MULTITHREADED = DoNotPrintValue() +corrade.TARGET_UNIX = DoNotPrintValue() +corrade.TARGET_APPLE = DoNotPrintValue() +corrade.TARGET_IOS = DoNotPrintValue() +corrade.TARGET_IOS_SIMULATOR = DoNotPrintValue() +corrade.TARGET_WINDOWS = DoNotPrintValue() +corrade.TARGET_WINDOWS_RT = DoNotPrintValue() +corrade.TARGET_EMSCRIPTEN = DoNotPrintValue() +corrade.TARGET_ANDROID = DoNotPrintValue() +magnum.BUILD_STATIC = DoNotPrintValue() +magnum.TARGET_GL = DoNotPrintValue() +magnum.TARGET_GLES = DoNotPrintValue() +magnum.TARGET_GLES2 = DoNotPrintValue() +magnum.TARGET_WEBGL = DoNotPrintValue() +magnum.TARGET_VK = DoNotPrintValue() # TODO ugh... can this be expressed directly in pybind? +corrade.__annotations__ = { + 'BUILD_STATIC': bool, + 'BUILD_MULTITHREADED': bool, + 'TARGET_UNIX': bool, + 'TARGET_APPLE': bool, + 'TARGET_IOS': bool, + 'TARGET_IOS_SIMULATOR': bool, + 'TARGET_WINDOWS': bool, + 'TARGET_WINDOWS_RT': bool, + 'TARGET_EMSCRIPTEN': bool, + 'TARGET_ANDROID': bool +} +magnum.__annotations__ = { + 'BUILD_STATIC': bool, + 'TARGET_GL': bool, + 'TARGET_GLES': bool, + 'TARGET_GLES2': bool, + 'TARGET_WEBGL': bool, + 'TARGET_VK': bool +} magnum.gl.__annotations__ = {} magnum.gl.__annotations__['default_framebuffer'] = magnum.gl.DefaultFramebuffer magnum.shaders.VertexColor2D.__annotations__ = {} @@ -54,6 +95,7 @@ INPUT_PAGES = [ '../../../magnum-examples/doc/python/examples.rst' ] INPUT_DOCS = [ + 'corrade.rst', 'corrade.containers.rst', 'magnum.rst', diff --git a/doc/python/corrade.rst b/doc/python/corrade.rst new file mode 100644 index 0000000..12789b4 --- /dev/null +++ b/doc/python/corrade.rst @@ -0,0 +1,50 @@ +.. + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +.. + +.. roles used for all other docs + +.. role:: cpp(code) + :language: c++ +.. role:: py(code) + :language: py +.. role:: sh(code) + :language: sh + +.. doctest setup + >>> from corrade import * + +.. default-role:: ref + +.. py:module:: corrade + :data BUILD_STATIC: Static library build + :data BUILD_MULTITHREADED: Multi-threaded build + :data TARGET_UNIX: Unix target + :data TARGET_APPLE: Apple target + :data TARGET_IOS: iOS target + :data TARGET_IOS_SIMULATOR: iOS simulator target + :data TARGET_WINDOWS: Windows target + :data TARGET_WINDOWS_RT: Windows RT target + :data TARGET_EMSCRIPTEN: Emscripten target + :data TARGET_ANDROID: Android target diff --git a/doc/python/magnum.rst b/doc/python/magnum.rst index b6d8270..3fd837e 100644 --- a/doc/python/magnum.rst +++ b/doc/python/magnum.rst @@ -25,14 +25,13 @@ .. roles used for all other docs -.. role:: cpp(code) - :language: c++ -.. role:: py(code) - :language: py -.. role:: sh(code) - :language: sh - .. doctest setup >>> from magnum import * -.. default-role:: ref +.. py:module:: magnum + :data BUILD_STATIC: Static library build + :data TARGET_GL: OpenGL interoperability + :data TARGET_GLES: OpenGL ES target + :data TARGET_GLES2: OpenGL ES 2.0 target + :data TARGET_WEBGL: WebGL target + :data TARGET_VK: Vulkan interoperability diff --git a/doc/python/pages/api-conventions.rst b/doc/python/pages/api-conventions.rst index 6427f19..0a77ad4 100644 --- a/doc/python/pages/api-conventions.rst +++ b/doc/python/pages/api-conventions.rst @@ -44,8 +44,23 @@ Python API conventions - constants and enums ``UPPERCASE``, again underscores omitted if it doesn't hurt readability -`Namespaces`_ -------------- +`Preprocessor definitions`_ +--------------------------- + +Exposed to Python as plain boolean constants, and only those that actually are +useful in a Python setting. + +.. class:: m-table + +=================================== ============================ +C++ Python +=================================== ============================ +:dox:`CORRADE_BUILD_MULTITHREADED` `corrade.BUILD_MULTITHREADED` +:dox:`MAGNUM_TARGET_GLES` `magnum.TARGET_GLES` +=================================== ============================ + +`Namespaces / modules`_ +----------------------- .. class:: m-table @@ -178,6 +193,20 @@ subnamespaces *do* have generic names. The :dox:`GL::version()` / generic name isn't a problem, but you wouldn't find anything of similar genericity in the root namespace / module. +An exception to this rule is exposed preprocessor definitions --- these are +*not* pulled in when doing :py:`from magnum import *` as this would likely +cause conflicts (in particular, `BUILD_STATIC` is defined by Corrade as well). +Instead, you have to access them like this: + +.. code:: py + + import magnum + + if magnum.TARGET_GLES2: + format = gl.TextureFormat.RGBA8 + else: + format = gl.TextureFormat.R8 + `Handling of alternate implementations`_ ---------------------------------------- diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index c28e5dd..8d03206 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -46,7 +46,6 @@ add_subdirectory(magnum) # CMake 3.12, so I need to do two passes, first replacing variables using # configure_file() and then replacing generator expressions with file(GENERATE) foreach(target - corrade corrade_containers magnum_gl magnum_meshtools diff --git a/src/python/corrade/CMakeLists.txt b/src/python/corrade/CMakeLists.txt index fac1187..4952796 100644 --- a/src/python/corrade/CMakeLists.txt +++ b/src/python/corrade/CMakeLists.txt @@ -23,6 +23,12 @@ # DEALINGS IN THE SOFTWARE. # +set(corrade_SRCS + corrade.cpp) + +# Extra libraries to link to. Populated only in case of CORRADE_BUILD_STATIC. +set(corrade_LIBS ) + set(corrade_containers_SRCS containers.cpp) @@ -45,20 +51,19 @@ if(NOT CORRADE_BUILD_STATIC) # point of static builds). It also nicely avoids problems with multiply-defined # global data. else() - set(corrade_SRCS - corrade.cpp - ${corrade_containers_SRCS}) - - pybind11_add_module(corrade SYSTEM ${corrade_SRCS}) - target_include_directories(corrade PRIVATE - ${PROJECT_SOURCE_DIR}/src - ${PROJECT_SOURCE_DIR}/src/python) - target_link_libraries(corrade PRIVATE Corrade::Utility ${corrade_LIBS}) - set_target_properties(corrade PROPERTIES - FOLDER "python" - OUTPUT_NAME "_corrade" - LIBRARY_OUTPUT_DIRECTORY ${output_dir}) + list(APPEND corrade_SRCS ${corrade_containers_SRCS}) + list(APPEND corrade_LIBS Corrade::Containers) endif() +pybind11_add_module(corrade SYSTEM ${corrade_SRCS}) +target_include_directories(corrade PRIVATE + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_SOURCE_DIR}/src/python) +target_link_libraries(corrade PRIVATE Corrade::Utility ${corrade_LIBS}) +set_target_properties(corrade PROPERTIES + FOLDER "python" + OUTPUT_NAME "_corrade" + LIBRARY_OUTPUT_DIRECTORY ${output_dir}) + file(GENERATE OUTPUT ${output_dir}/corrade/__init__.py INPUT ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py) diff --git a/src/python/corrade/__init__.py b/src/python/corrade/__init__.py index a715e31..4e1432f 100644 --- a/src/python/corrade/__init__.py +++ b/src/python/corrade/__init__.py @@ -25,22 +25,21 @@ """Root Corrade module""" +from _corrade import * + import sys # In case Corrade is built statically, the whole core project is put into -# _corrade. If corrade is built dynamically, there's no core library at the -# moment. -try: - from _corrade import * - - # The following feels extremely hackish, but without that it wouldn't be - # possible to do `import corrade.containers`, which is weird - # (`from corrade import containers` works, tho, for whatever reason) - for i in ['containers']: - if i in globals(): sys.modules['corrade.' + i] = globals()[i] -except ImportError: - pass +# _corrade. The following feels extremely hackish, but without that it wouldn't +# be possible to do `import corrade.containers`, which is weird +# (`from corrade import containers` works, tho, for whatever reason) +for i in ['containers']: + if i in globals(): sys.modules['corrade.' + i] = globals()[i] # Prevent all submodules being pulled in when saying `from corrade import *` -- # this is consistent with behavior in magnum -__all__ = [] +__all__ = [ + # TARGET_*, BUILD_* are omitted as `from corrade import *` would pull them + # to globals and this would likely cause conflicts (magnum also defines + # BUILD_*) +] diff --git a/src/python/corrade/corrade.cpp b/src/python/corrade/corrade.cpp index 8fd1b58..bc1ed78 100644 --- a/src/python/corrade/corrade.cpp +++ b/src/python/corrade/corrade.cpp @@ -28,16 +28,93 @@ #include "corrade/bootstrap.h" -#ifndef CORRADE_BUILD_STATIC -#error this file should be compiled only in the static build -#endif - namespace py = pybind11; /* TODO: remove declaration when https://github.com/pybind/pybind11/pull/1863 is released */ extern "C" PYBIND11_EXPORT PyObject* PyInit__corrade(); PYBIND11_MODULE(_corrade, m) { + m.doc() = "Root Corrade module"; + m.attr("BUILD_STATIC") = + #ifdef CORRADE_BUILD_STATIC + true + #else + false + #endif + ; + m.attr("BUILD_MULTITHREADED") = + #ifdef CORRADE_BUILD_MULTITHREADED + true + #else + false + #endif + ; + m.attr("TARGET_APPLE") = + #ifdef CORRADE_TARGET_APPLE + true + #else + false + #endif + ; + m.attr("TARGET_IOS") = + #ifdef CORRADE_TARGET_IOS + true + #else + false + #endif + ; + m.attr("TARGET_IOS_SIMULATOR") = + #ifdef CORRADE_TARGET_IOS_SIMULATOR + true + #else + false + #endif + ; + m.attr("TARGET_UNIX") = + #ifdef CORRADE_TARGET_UNIX + true + #else + false + #endif + ; + m.attr("TARGET_WINDOWS") = + #ifdef CORRADE_TARGET_WINDOWS + true + #else + false + #endif + ; + m.attr("TARGET_WINDOWS_RT") = + #ifdef CORRADE_TARGET_WINDOWS_RT + true + #else + false + #endif + ; + m.attr("TARGET_EMSCRIPTEN") = + #ifdef CORRADE_TARGET_EMSCRIPTEN + true + #else + false + #endif + ; + m.attr("TARGET_ANDROID") = + #ifdef CORRADE_TARGET_ANDROID + true + #else + false + #endif + ; + /* Not exposing CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT as this + is a plugin itself and so if this works, plugin manager should too */ + + /* In case Corrade is a bunch of static libraries, put everything into a + single shared lib to make it easier to install (which is the point of + static builds) and avoid issues with multiply-defined global symbols. + + These need to be defined in the order they depend on. */ + #ifdef CORRADE_BUILD_STATIC py::module containers = m.def_submodule("containers"); corrade::containers(containers); + #endif } diff --git a/src/python/magnum/__init__.py b/src/python/magnum/__init__.py index fa4244a..92377a3 100644 --- a/src/python/magnum/__init__.py +++ b/src/python/magnum/__init__.py @@ -91,4 +91,8 @@ __all__ = [ 'PixelFormat', 'PixelStorage', 'ImageView1D', 'ImageView2D', 'ImageView3D', 'MutableImageView1D', 'MutableImageView2D', 'MutableImageView3D' + + # TARGET_*, BUILD_* are omitted as `from magnum import *` would pull them + # to globals and this would likely cause conflicts (corrade also defines + # BUILD_*) ] diff --git a/src/python/magnum/magnum.cpp b/src/python/magnum/magnum.cpp index f8cda0f..d4e90db 100644 --- a/src/python/magnum/magnum.cpp +++ b/src/python/magnum/magnum.cpp @@ -133,6 +133,53 @@ template void imageViewFromMutable(py::class_>& } void magnum(py::module& m) { + m.attr("BUILD_STATIC") = + #ifdef MAGNUM_BUILD_STATIC + true + #else + false + #endif + ; + m.attr("TARGET_GL") = + #ifdef MAGNUM_TARGET_GL + true + #else + false + #endif + ; + m.attr("TARGET_GLES") = + #ifdef MAGNUM_TARGET_GLES + true + #else + false + #endif + ; + m.attr("TARGET_GLES2") = + #ifdef MAGNUM_TARGET_GLES2 + true + #else + false + #endif + ; + /** @todo do we need TARGET_GLES3? i hope not */ + m.attr("TARGET_WEBGL") = + #ifdef MAGNUM_TARGET_WEBGL + true + #else + false + #endif + ; + /* TARGET_DESKTOP_GLES, TARGET_HEADLESS skipped as they make sense only + on native side (affecting what the builtin utilities use), not really in + Python */ + m.attr("TARGET_VK") = + #ifdef MAGNUM_TARGET_VK + true + #else + false + #endif + ; + py::enum_{m, "MeshPrimitive", "Mesh primitive type"} .value("POINTS", MeshPrimitive::Points) .value("LINES", MeshPrimitive::Lines) diff --git a/src/python/setup.py.cmake b/src/python/setup.py.cmake index 994f373..1d1e946 100644 --- a/src/python/setup.py.cmake +++ b/src/python/setup.py.cmake @@ -33,7 +33,7 @@ extension_paths = { # Filled in by cmake. This works for both static and dynamic builds -- in # case a library is built statically, only the underscored name will be # present. - '_corrade': '${corrade_file}', + '_corrade': '$', 'corrade.containers': '${corrade_containers_file}', '_magnum': '$', 'magnum.gl': '${magnum_gl_file}',