diff --git a/build/Jamfile b/build/Jamfile index 313fdab3..aedeed67 100644 --- a/build/Jamfile +++ b/build/Jamfile @@ -6,6 +6,7 @@ import os ; import indirect ; import modules ; import feature ; +import property ; import python ; @@ -30,21 +31,8 @@ else ; } -rule find-py3-version -{ - local versions = [ feature.values python ] ; - local py3ver ; - for local v in $(versions) - { - if $(v) >= 3.0 - { - py3ver = $(v) ; - } - } - return $(py3ver) ; -} - -py3-version = [ find-py3-version ] ; +py2-version = [ py-version 2 ] ; +py3-version = [ py-version 3 ] ; project boost/python : source-location ../src @@ -52,11 +40,14 @@ project boost/python rule cond ( test ? : yes * : no * ) { if $(test) { return $(yes) ; } else { return $(no) ; } } rule unless ( test ? : yes * : no * ) { if ! $(test) { return $(yes) ; } else { return $(no) ; } } +local rule eq ( a : b ) { if $(a) = $(b) { return 1 ; } } -rule lib_boost_python ( is-py3 ? ) +lib_boost_python($(py2-version)) = boost_python ; +lib_boost_python($(py3-version)) = boost_python3 ; + +rule lib_boost_python ( version ) { - - lib [ cond $(is-py3) : boost_python3 : boost_python ] + lib $(lib_boost_python($(version))) : # sources numeric.cpp list.cpp @@ -112,11 +103,13 @@ rule lib_boost_python ( is-py3 ? ) config-warning on:BOOST_DEBUG_PYTHON - [ cond $(is-py3) : $(py3-version) ] + $(version) -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag @$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).python-tag + @python.require-py + : # default build shared : # usage requirements @@ -125,51 +118,57 @@ rule lib_boost_python ( is-py3 ? ) ; } -rule lib_boost_numpy ( is-py3 ? ) +lib_boost_numpy($(py2-version)) = boost_numpy ; +lib_boost_numpy($(py3-version)) = boost_numpy3 ; + +rule lib_boost_numpy ( version ) { numpy-include = [ python.numpy-include ] ; - lib [ cond $(is-py3) : boost_numpy3 : boost_numpy ] + lib $(lib_boost_numpy($(version))) : # sources numpy/dtype.cpp numpy/matrix.cpp numpy/ndarray.cpp - numpy/numpy.cpp - numpy/scalars.cpp - numpy/ufunc.cpp + numpy/numpy.cpp + numpy/scalars.cpp + numpy/ufunc.cpp : # requirements + static:BOOST_NUMPY_STATIC_LIB + BOOST_NUMPY_SOURCE [ cond [ python.numpy ] : /python//python_for_extensions ] [ unless [ python.numpy ] : no ] - $(numpy-include) - boost_python + $(numpy-include) + $(lib_boost_python($(version))) on:BOOST_DEBUG_PYTHON - [ cond $(is-py3) : $(py3-version) ] + $(version) -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag @$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).python-tag + @python.require-py + : # default build shared : # usage requirements + static:BOOST_NUMPY_STATIC_LIB on:BOOST_DEBUG_PYTHON ; } -libraries = boost_python ; -libraries3 = boost_python3 ; -if [ python.numpy ] -{ - libraries += boost_numpy ; - libraries3 += boost_numpy3 ; -} +libraries = ; -lib_boost_python ; -lib_boost_numpy ; - -if $(py3-version) +for local N in 2 3 { - lib_boost_python yes ; - lib_boost_numpy yes ; - libraries += $(libraries3) ; + if $(py$(N)-version) + { + lib_boost_python $(py$(N)-version) ; + libraries += $(lib_boost_python($(py$(N)-version))) ; + if [ python.numpy ] + { + lib_boost_numpy $(py$(N)-version) ; + libraries += $(lib_boost_numpy($(py$(N)-version))) ; + } + } } boost-install $(libraries) ; diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp index 11c16308..c92ecb32 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -64,31 +64,18 @@ #endif #if defined(BOOST_PYTHON_DYNAMIC_LIB) - -# if !defined(_WIN32) && !defined(__CYGWIN__) \ - && !defined(BOOST_PYTHON_USE_GCC_SYMBOL_VISIBILITY) \ - && BOOST_WORKAROUND(__GNUC__, >= 3) && (__GNUC_MINOR__ >=5 || __GNUC__ > 3) -# define BOOST_PYTHON_USE_GCC_SYMBOL_VISIBILITY 1 -# endif - -# if BOOST_PYTHON_USE_GCC_SYMBOL_VISIBILITY +# if defined(BOOST_SYMBOL_EXPORT) # if defined(BOOST_PYTHON_SOURCE) -# define BOOST_PYTHON_DECL __attribute__ ((__visibility__("default"))) +# define BOOST_PYTHON_DECL BOOST_SYMBOL_EXPORT +# define BOOST_PYTHON_DECL_FORWARD BOOST_SYMBOL_FORWARD_EXPORT +# define BOOST_PYTHON_DECL_EXCEPTION BOOST_EXCEPTION_EXPORT # define BOOST_PYTHON_BUILD_DLL # else -# define BOOST_PYTHON_DECL -# endif -# define BOOST_PYTHON_DECL_FORWARD -# define BOOST_PYTHON_DECL_EXCEPTION __attribute__ ((__visibility__("default"))) -# elif (defined(_WIN32) || defined(__CYGWIN__)) -# if defined(BOOST_PYTHON_SOURCE) -# define BOOST_PYTHON_DECL __declspec(dllexport) -# define BOOST_PYTHON_BUILD_DLL -# else -# define BOOST_PYTHON_DECL __declspec(dllimport) +# define BOOST_PYTHON_DECL BOOST_SYMBOL_IMPORT +# define BOOST_PYTHON_DECL_FORWARD BOOST_SYMBOL_FORWARD_IMPORT +# define BOOST_PYTHON_DECL_EXCEPTION BOOST_EXCEPTION_IMPORT # endif # endif - #endif #ifndef BOOST_PYTHON_DECL @@ -96,11 +83,11 @@ #endif #ifndef BOOST_PYTHON_DECL_FORWARD -# define BOOST_PYTHON_DECL_FORWARD BOOST_PYTHON_DECL +# define BOOST_PYTHON_DECL_FORWARD #endif #ifndef BOOST_PYTHON_DECL_EXCEPTION -# define BOOST_PYTHON_DECL_EXCEPTION BOOST_PYTHON_DECL +# define BOOST_PYTHON_DECL_EXCEPTION #endif #if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) diff --git a/include/boost/python/detail/exception_handler.hpp b/include/boost/python/detail/exception_handler.hpp index 7f49868b..fdc99898 100644 --- a/include/boost/python/detail/exception_handler.hpp +++ b/include/boost/python/detail/exception_handler.hpp @@ -11,7 +11,7 @@ namespace boost { namespace python { namespace detail { -struct BOOST_PYTHON_DECL_FORWARD exception_handler; +struct exception_handler; typedef function2 const&> handler_function; diff --git a/include/boost/python/detail/wrapper_base.hpp b/include/boost/python/detail/wrapper_base.hpp old mode 100755 new mode 100644 index e5b93aa4..2a79e0c5 --- a/include/boost/python/detail/wrapper_base.hpp +++ b/include/boost/python/detail/wrapper_base.hpp @@ -14,7 +14,7 @@ class override; namespace detail { - class BOOST_PYTHON_DECL_FORWARD wrapper_base; + class wrapper_base; namespace wrapper_base_ // ADL disabler { diff --git a/include/boost/python/errors.hpp b/include/boost/python/errors.hpp index 72960d9e..1eec6c2f 100644 --- a/include/boost/python/errors.hpp +++ b/include/boost/python/errors.hpp @@ -14,7 +14,7 @@ namespace boost { namespace python { -struct BOOST_PYTHON_DECL_EXCEPTION error_already_set +struct BOOST_PYTHON_DECL error_already_set { virtual ~error_already_set(); }; diff --git a/include/boost/python/numpy.hpp b/include/boost/python/numpy.hpp index cd5876a8..18a6389d 100644 --- a/include/boost/python/numpy.hpp +++ b/include/boost/python/numpy.hpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace boost { namespace python { namespace numpy { @@ -26,7 +27,7 @@ namespace boost { namespace python { namespace numpy { * and "import_ufunc()", and then calls * dtype::register_scalar_converters(). */ -void initialize(bool register_scalar_converters=true); +BOOST_NUMPY_DECL void initialize(bool register_scalar_converters=true); }}} // namespace boost::python::numpy diff --git a/include/boost/python/numpy/config.hpp b/include/boost/python/numpy/config.hpp new file mode 100644 index 00000000..6f39d3ce --- /dev/null +++ b/include/boost/python/numpy/config.hpp @@ -0,0 +1,78 @@ +// (C) Copyright Samuli-Petrus Korhonen 2017. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The author gratefully acknowleges the support of NMR Solutions, Inc., in +// producing this work. + +// Revision History: +// 15 Feb 17 Initial version + +#ifndef CONFIG_NUMPY20170215_H_ +# define CONFIG_NUMPY20170215_H_ + +# include + +/***************************************************************************** + * + * Set up dll import/export options: + * + ****************************************************************************/ + +// backwards compatibility: +#ifdef BOOST_NUMPY_STATIC_LIB +# define BOOST_NUMPY_STATIC_LINK +# elif !defined(BOOST_NUMPY_DYNAMIC_LIB) +# define BOOST_NUMPY_DYNAMIC_LIB +#endif + +#if defined(BOOST_NUMPY_DYNAMIC_LIB) +# if defined(BOOST_SYMBOL_EXPORT) +# if defined(BOOST_NUMPY_SOURCE) +# define BOOST_NUMPY_DECL BOOST_SYMBOL_EXPORT +# define BOOST_NUMPY_DECL_FORWARD BOOST_SYMBOL_FORWARD_EXPORT +# define BOOST_NUMPY_DECL_EXCEPTION BOOST_EXCEPTION_EXPORT +# define BOOST_NUMPY_BUILD_DLL +# else +# define BOOST_NUMPY_DECL BOOST_SYMBOL_IMPORT +# define BOOST_NUMPY_DECL_FORWARD BOOST_SYMBOL_FORWARD_IMPORT +# define BOOST_NUMPY_DECL_EXCEPTION BOOST_EXCEPTION_IMPORT +# endif +# endif + +#endif + +#ifndef BOOST_NUMPY_DECL +# define BOOST_NUMPY_DECL +#endif + +#ifndef BOOST_NUMPY_DECL_FORWARD +# define BOOST_NUMPY_DECL_FORWARD +#endif + +#ifndef BOOST_NUMPY_DECL_EXCEPTION +# define BOOST_NUMPY_DECL_EXCEPTION +#endif + +// enable automatic library variant selection ------------------------------// + +#if !defined(BOOST_NUMPY_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_NUMPY_NO_LIB) +// +// Set the name of our library, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#define BOOST_LIB_NAME boost_numpy +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +#ifdef BOOST_NUMPY_DYNAMIC_LIB +# define BOOST_DYN_LINK +#endif +// +// And include the header that does the work: +// +#include +#endif // auto-linking disabled + +#endif // CONFIG_NUMPY20170215_H_ diff --git a/include/boost/python/numpy/dtype.hpp b/include/boost/python/numpy/dtype.hpp index 1284f9e5..32bb3d4a 100644 --- a/include/boost/python/numpy/dtype.hpp +++ b/include/boost/python/numpy/dtype.hpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -25,7 +26,7 @@ namespace boost { namespace python { namespace numpy { * * @todo This could have a lot more interesting accessors. */ -class dtype : public object { +class BOOST_NUMPY_DECL dtype : public object { static python::detail::new_reference convert(object::object_cref arg, bool align); public: diff --git a/include/boost/python/numpy/matrix.hpp b/include/boost/python/numpy/matrix.hpp index af20e8f9..43335e1f 100644 --- a/include/boost/python/numpy/matrix.hpp +++ b/include/boost/python/numpy/matrix.hpp @@ -14,6 +14,8 @@ #include #include #include +#include + namespace boost { namespace python { namespace numpy { @@ -27,7 +29,7 @@ namespace boost { namespace python { namespace numpy { * bad things happen when Python shuts down. I think this solution is safe, but I'd * love to get that confirmed. */ -class matrix : public ndarray +class BOOST_NUMPY_DECL matrix : public ndarray { static object construct(object_cref obj, dtype const & dt, bool copy); static object construct(object_cref obj, bool copy); @@ -59,7 +61,7 @@ public: * return a numpy.matrix instead. */ template -struct as_matrix : Base +struct BOOST_NUMPY_DECL as_matrix : Base { static PyObject * postcall(PyObject *, PyObject * result) { diff --git a/include/boost/python/numpy/ndarray.hpp b/include/boost/python/numpy/ndarray.hpp index 2985907b..9ad0f20e 100644 --- a/include/boost/python/numpy/ndarray.hpp +++ b/include/boost/python/numpy/ndarray.hpp @@ -16,6 +16,8 @@ #include #include #include +#include + #include namespace boost { namespace python { namespace numpy { @@ -26,7 +28,8 @@ namespace boost { namespace python { namespace numpy { * @todo This could have a lot more functionality (like boost::python::numeric::array). * Right now all that exists is what was needed to move raw data between C++ and Python. */ -class ndarray : public object + +class BOOST_NUMPY_DECL ndarray : public object { /** diff --git a/include/boost/python/numpy/ufunc.hpp b/include/boost/python/numpy/ufunc.hpp index 9262b378..4c2331c9 100644 --- a/include/boost/python/numpy/ufunc.hpp +++ b/include/boost/python/numpy/ufunc.hpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace boost { namespace python { namespace numpy { @@ -34,7 +35,7 @@ namespace boost { namespace python { namespace numpy { * It's more dangerous than most object managers, however - maybe it actually belongs in * a detail namespace? */ -class multi_iter : public object +class BOOST_NUMPY_DECL multi_iter : public object { public: diff --git a/include/boost/python/object/instance.hpp b/include/boost/python/object/instance.hpp index 177576ef..9c28d682 100644 --- a/include/boost/python/object/instance.hpp +++ b/include/boost/python/object/instance.hpp @@ -11,7 +11,7 @@ namespace boost { namespace python { - struct BOOST_PYTHON_DECL_FORWARD instance_holder; + struct instance_holder; }} // namespace boost::python namespace boost { namespace python { namespace objects { diff --git a/src/converter/builtin_converters.cpp b/src/converter/builtin_converters.cpp index 9900602b..1c28af7f 100644 --- a/src/converter/builtin_converters.cpp +++ b/src/converter/builtin_converters.cpp @@ -430,6 +430,22 @@ namespace // Remember that this will be used to construct the result object static std::wstring extract(PyObject* intermediate) { + // On Windows, with Python >= 3.3, PyObject_Length cannot be used to get + // the size of the wchar_t string, because it will count the number of + // *code points*, but some characters not on the BMP will use two UTF-16 + // *code units* (surrogate pairs). + // This is not a problem on Unix, since wchar_t is 32-bit. +#if defined(_WIN32) && PY_VERSION_HEX >= 0x03030000 + BOOST_STATIC_ASSERT(sizeof(wchar_t) == 2); + + Py_ssize_t size = 0; + wchar_t *buf = PyUnicode_AsWideCharString(intermediate, &size); + if (buf == NULL) { + boost::python::throw_error_already_set(); + } + std::wstring result(buf, size); + PyMem_Free(buf); +#else std::wstring result(::PyObject_Length(intermediate), L' '); if (!result.empty()) { @@ -444,6 +460,7 @@ namespace if (err == -1) throw_error_already_set(); } +#endif return result; } static PyTypeObject const* get_pytype() { return &PyUnicode_Type;} diff --git a/test/test_builtin_converters.py b/test/test_builtin_converters.py index fb3c55c1..adc397e1 100644 --- a/test/test_builtin_converters.py +++ b/test/test_builtin_converters.py @@ -1,9 +1,6 @@ # Copyright David Abrahams 2004. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -import sys -if (sys.version_info.major >= 3): - long = int r""" >>> from builtin_converters_ext import * @@ -136,6 +133,9 @@ True >>> print(rewrap_value_wstring(u'yo, wassup?')) yo, wassup? +>>> print(rewrap_value_wstring(u'\U0001f4a9')) +\U0001f4a9 + test that overloading on unicode works: >>> print(rewrap_value_string(u'yo, wassup?')) @@ -283,6 +283,10 @@ Check that classic classes also work >>> assert return_null_handle() is None """ +import sys +if (sys.version_info.major >= 3): + long = int + def run(args = None): import sys import doctest