diff options
author | Matti Picus <matti.picus@gmail.com> | 2021-10-22 14:51:14 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-22 14:51:14 +0300 |
commit | 53d2a831668a58aa069e3bd891dd9d342dd058b3 (patch) | |
tree | 401ac37d2b7e9f274c80144a09154bac42a0d417 | |
parent | d8653001e5342d002b133dce999286fcafbd8bf0 (diff) | |
parent | 2ae7aeb3aa909b1a16bc58fd0e40dc4476dff35d (diff) | |
download | numpy-53d2a831668a58aa069e3bd891dd9d342dd058b3.tar.gz |
Merge pull request #19713 from serge-sans-paille/feature/to-cxx-and-beyond
[demo] how-to replacing numpy custom generation engine by raw C++
-rw-r--r-- | .github/workflows/cygwin.yml | 2 | ||||
-rw-r--r-- | numpy/core/setup.py | 15 | ||||
-rw-r--r-- | numpy/core/src/common/npy_sort.h.src | 7 | ||||
-rw-r--r-- | numpy/core/src/common/numpy_tag.h | 34 | ||||
-rw-r--r-- | numpy/core/src/npymath/npy_math_private.h | 12 | ||||
-rw-r--r-- | numpy/core/src/npysort/radixsort.c.src | 231 | ||||
-rw-r--r-- | numpy/core/src/npysort/radixsort.cpp | 254 | ||||
-rw-r--r-- | numpy/core/src/umath/clip.c.src | 125 | ||||
-rw-r--r-- | numpy/core/src/umath/clip.cpp | 131 | ||||
-rw-r--r-- | numpy/core/src/umath/clip.h | 33 | ||||
-rw-r--r-- | numpy/core/src/umath/clip.h.src | 18 | ||||
-rw-r--r-- | numpy/distutils/ccompiler.py | 7 | ||||
-rw-r--r-- | numpy/distutils/ccompiler_opt.py | 16 | ||||
-rw-r--r-- | numpy/distutils/command/build_clib.py | 49 | ||||
-rw-r--r-- | numpy/distutils/command/build_ext.py | 57 | ||||
-rw-r--r-- | numpy/distutils/extension.py | 4 | ||||
-rw-r--r-- | numpy/distutils/misc_util.py | 15 | ||||
-rwxr-xr-x | setup.py | 5 |
18 files changed, 580 insertions, 435 deletions
diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index 930ce39ff..2e644b3c1 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -24,7 +24,7 @@ jobs: python38-cython python38-pip python38-wheel python38-cffi python38-pytz python38-setuptools python38-pytest python38-hypothesis liblapack-devel libopenblas - gcc-fortran git dash + gcc-fortran gcc-g++ git dash - name: Set Windows PATH uses: egor-tensin/cleanup-path@v1 with: diff --git a/numpy/core/setup.py b/numpy/core/setup.py index f2524ae13..6800f65e9 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -909,7 +909,7 @@ def configuration(parent_package='',top_path=None): join('src', 'npysort', 'mergesort.c.src'), join('src', 'npysort', 'timsort.c.src'), join('src', 'npysort', 'heapsort.c.src'), - join('src', 'npysort', 'radixsort.c.src'), + join('src', 'npysort', 'radixsort.cpp'), join('src', 'common', 'npy_partition.h.src'), join('src', 'npysort', 'selection.c.src'), join('src', 'common', 'npy_binsearch.h.src'), @@ -948,8 +948,8 @@ def configuration(parent_package='',top_path=None): join('src', 'umath', 'loops_exponent_log.dispatch.c.src'), join('src', 'umath', 'matmul.h.src'), join('src', 'umath', 'matmul.c.src'), - join('src', 'umath', 'clip.h.src'), - join('src', 'umath', 'clip.c.src'), + join('src', 'umath', 'clip.h'), + join('src', 'umath', 'clip.cpp'), join('src', 'umath', 'dispatching.c'), join('src', 'umath', 'legacy_array_method.c'), join('src', 'umath', 'ufunc_object.c'), @@ -979,6 +979,9 @@ def configuration(parent_package='',top_path=None): svml_objs = glob.glob(svml_path + '/**/*.s', recursive=True) config.add_extension('_multiarray_umath', + # Forcing C language even though we have C++ sources. + # It forces the C linker and don't link C++ runtime. + language = 'c', sources=multiarray_src + umath_src + common_src + [generate_config_h, @@ -993,7 +996,11 @@ def configuration(parent_package='',top_path=None): common_deps, libraries=['npymath'], extra_objects=svml_objs, - extra_info=extra_info) + extra_info=extra_info, + extra_cxx_compile_args=['-std=c++11', + '-D__STDC_VERSION__=0', + '-fno-exceptions', + '-fno-rtti']) ####################################################################### # umath_tests module # diff --git a/numpy/core/src/common/npy_sort.h.src b/numpy/core/src/common/npy_sort.h.src index ddbde0c9b..b4a1e9b0c 100644 --- a/numpy/core/src/common/npy_sort.h.src +++ b/numpy/core/src/common/npy_sort.h.src @@ -49,9 +49,14 @@ NPY_NO_EXPORT int atimsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void * * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, * longlong, ulonglong# */ - +#ifdef __cplusplus +extern "C" { +#endif NPY_NO_EXPORT int radixsort_@suff@(void *vec, npy_intp cnt, void *null); NPY_NO_EXPORT int aradixsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null); +#ifdef __cplusplus +} +#endif /**end repeat**/ diff --git a/numpy/core/src/common/numpy_tag.h b/numpy/core/src/common/numpy_tag.h new file mode 100644 index 000000000..a2269d3c7 --- /dev/null +++ b/numpy/core/src/common/numpy_tag.h @@ -0,0 +1,34 @@ +#ifndef _NPY_COMMON_TAG_H_ +#define _NPY_COMMON_TAG_H_ + +namespace npy { + + struct integral_tag {}; + struct floating_point_tag {}; + struct complex_tag {}; + struct date_tag {}; + + struct bool_tag : integral_tag { using type = npy_bool; }; + struct byte_tag : integral_tag {using type = npy_byte; } ; + struct ubyte_tag : integral_tag {using type = npy_ubyte; } ; + struct short_tag : integral_tag {using type = npy_short; } ; + struct ushort_tag : integral_tag {using type = npy_ushort; } ; + struct int_tag : integral_tag {using type = npy_int; } ; + struct uint_tag : integral_tag {using type = npy_uint; } ; + struct long_tag : integral_tag {using type = npy_long ; } ; + struct ulong_tag : integral_tag {using type = npy_ulong ; } ; + struct longlong_tag : integral_tag {using type = npy_longlong ; } ; + struct ulonglong_tag : integral_tag {using type = npy_ulonglong ; } ; + struct half_tag {using type = npy_half ; } ; + struct float_tag : floating_point_tag {using type = npy_float ; } ; + struct double_tag : floating_point_tag {using type = npy_double ; } ; + struct longdouble_tag : floating_point_tag {using type = npy_longdouble ; } ; + struct cfloat_tag : complex_tag {using type = npy_cfloat ; } ; + struct cdouble_tag : complex_tag {using type = npy_cdouble ; } ; + struct clongdouble_tag : complex_tag {using type = npy_clongdouble ; } ; + struct datetime_tag : date_tag {using type = npy_datetime ; } ; + struct timedelta_tag : date_tag {using type = npy_timedelta ; } ; + +} + +#endif diff --git a/numpy/core/src/npymath/npy_math_private.h b/numpy/core/src/npymath/npy_math_private.h index 212d11a0b..d475919b0 100644 --- a/numpy/core/src/npymath/npy_math_private.h +++ b/numpy/core/src/npymath/npy_math_private.h @@ -507,17 +507,29 @@ typedef union { #else /* !_MSC_VER */ typedef union { npy_cdouble npy_z; +#ifdef __cplusplus + std::complex<double> c99z; +#else complex double c99_z; +#endif } __npy_cdouble_to_c99_cast; typedef union { npy_cfloat npy_z; +#ifdef __cplusplus + std::complex<float> c99z; +#else complex float c99_z; +#endif } __npy_cfloat_to_c99_cast; typedef union { npy_clongdouble npy_z; +#ifdef __cplusplus + std::complex<long double> c99_z; +#else complex long double c99_z; +#endif } __npy_clongdouble_to_c99_cast; #endif /* !_MSC_VER */ diff --git a/numpy/core/src/npysort/radixsort.c.src b/numpy/core/src/npysort/radixsort.c.src deleted file mode 100644 index 99d8ed42a..000000000 --- a/numpy/core/src/npysort/radixsort.c.src +++ /dev/null @@ -1,231 +0,0 @@ -#define NPY_NO_DEPRECATED_API NPY_API_VERSION - -#include "npy_sort.h" -#include "npysort_common.h" -#include <stdlib.h> - -/* - ***************************************************************************** - ** INTEGER SORTS ** - ***************************************************************************** - */ - - -/**begin repeat - * - * #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG, - * LONGLONG, ULONGLONG# - * #suff = bool, byte, ubyte, short, ushort, int, uint, long, ulong, - * longlong, ulonglong# - * #type = npy_ubyte, npy_ubyte, npy_ubyte, npy_ushort, npy_ushort, npy_uint, - * npy_uint, npy_ulong, npy_ulong, npy_ulonglong, npy_ulonglong# - * #sign = 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0# - * #floating = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0# - */ - -// Reference: https://github.com/eloj/radix-sorting#-key-derivation -#if @sign@ - // Floating-point is currently disabled. - // Floating-point tests succeed for double and float on macOS but not on Windows/Linux. - // Basic sorting tests succeed but others relying on sort fail. - // Possibly related to floating-point normalisation or multiple NaN reprs? Not sure. - #if @floating@ - // For floats, we invert the key if the sign bit is set, else we invert the sign bit. - #define KEY_OF(x) ((x) ^ (-((x) >> (sizeof(@type@) * 8 - 1)) | ((@type@)1 << (sizeof(@type@) * 8 - 1)))) - #else - // For signed ints, we flip the sign bit so the negatives are below the positives. - #define KEY_OF(x) ((x) ^ ((@type@)1 << (sizeof(@type@) * 8 - 1))) - #endif -#else - // For unsigned ints, the key is as-is - #define KEY_OF(x) (x) -#endif - -static inline npy_ubyte -nth_byte_@suff@(@type@ key, npy_intp l) { - return (key >> (l << 3)) & 0xFF; -} - -static @type@* -radixsort0_@suff@(@type@ *arr, @type@ *aux, npy_intp num) -{ - npy_intp cnt[sizeof(@type@)][1 << 8] = { { 0 } }; - npy_intp i; - size_t l; - @type@ key0 = KEY_OF(arr[0]); - size_t ncols = 0; - npy_ubyte cols[sizeof(@type@)]; - - for (i = 0; i < num; i++) { - @type@ k = KEY_OF(arr[i]); - - for (l = 0; l < sizeof(@type@); l++) { - cnt[l][nth_byte_@suff@(k, l)]++; - } - } - - for (l = 0; l < sizeof(@type@); l++) { - if (cnt[l][nth_byte_@suff@(key0, l)] != num) { - cols[ncols++] = l; - } - } - - for (l = 0; l < ncols; l++) { - npy_intp a = 0; - for (i = 0; i < 256; i++) { - npy_intp b = cnt[cols[l]][i]; - cnt[cols[l]][i] = a; - a += b; - } - } - - for (l = 0; l < ncols; l++) { - @type@* temp; - for (i = 0; i < num; i++) { - @type@ k = KEY_OF(arr[i]); - npy_intp dst = cnt[cols[l]][nth_byte_@suff@(k, cols[l])]++; - aux[dst] = arr[i]; - } - - temp = aux; - aux = arr; - arr = temp; - } - - return arr; -} - -NPY_NO_EXPORT int -radixsort_@suff@(void *start, npy_intp num, void *NPY_UNUSED(varr)) -{ - void *sorted; - @type@ *aux; - @type@ *arr = start; - @type@ k1, k2; - npy_bool all_sorted = 1; - - if (num < 2) { - return 0; - } - - k1 = KEY_OF(arr[0]); - for (npy_intp i = 1; i < num; i++) { - k2 = KEY_OF(arr[i]); - if (k1 > k2) { - all_sorted = 0; - break; - } - k1 = k2; - } - - if (all_sorted) { - return 0; - } - - aux = malloc(num * sizeof(@type@)); - if (aux == NULL) { - return -NPY_ENOMEM; - } - - sorted = radixsort0_@suff@(start, aux, num); - if (sorted != start) { - memcpy(start, sorted, num * sizeof(@type@)); - } - - free(aux); - return 0; -} - -static npy_intp* -aradixsort0_@suff@(@type@ *arr, npy_intp *aux, npy_intp *tosort, npy_intp num) -{ - npy_intp cnt[sizeof(@type@)][1 << 8] = { { 0 } }; - npy_intp i; - size_t l; - @type@ key0 = KEY_OF(arr[0]); - size_t ncols = 0; - npy_ubyte cols[sizeof(@type@)]; - - for (i = 0; i < num; i++) { - @type@ k = KEY_OF(arr[i]); - - for (l = 0; l < sizeof(@type@); l++) { - cnt[l][nth_byte_@suff@(k, l)]++; - } - } - - for (l = 0; l < sizeof(@type@); l++) { - if (cnt[l][nth_byte_@suff@(key0, l)] != num) { - cols[ncols++] = l; - } - } - - for (l = 0; l < ncols; l++) { - npy_intp a = 0; - for (i = 0; i < 256; i++) { - npy_intp b = cnt[cols[l]][i]; - cnt[cols[l]][i] = a; - a += b; - } - } - - for (l = 0; l < ncols; l++) { - npy_intp* temp; - for (i = 0; i < num; i++) { - @type@ k = KEY_OF(arr[tosort[i]]); - npy_intp dst = cnt[cols[l]][nth_byte_@suff@(k, cols[l])]++; - aux[dst] = tosort[i]; - } - - temp = aux; - aux = tosort; - tosort = temp; - } - - return tosort; -} - -NPY_NO_EXPORT int -aradixsort_@suff@(void *start, npy_intp* tosort, npy_intp num, void *NPY_UNUSED(varr)) -{ - npy_intp *sorted; - npy_intp *aux; - @type@ *arr = start; - @type@ k1, k2; - npy_bool all_sorted = 1; - - if (num < 2) { - return 0; - } - - k1 = KEY_OF(arr[tosort[0]]); - for (npy_intp i = 1; i < num; i++) { - k2 = KEY_OF(arr[tosort[i]]); - if (k1 > k2) { - all_sorted = 0; - break; - } - k1 = k2; - } - - if (all_sorted) { - return 0; - } - - aux = malloc(num * sizeof(npy_intp)); - if (aux == NULL) { - return -NPY_ENOMEM; - } - - sorted = aradixsort0_@suff@(start, aux, tosort, num); - if (sorted != tosort) { - memcpy(tosort, sorted, num * sizeof(npy_intp)); - } - - free(aux); - return 0; -} - -#undef KEY_OF - -/**end repeat**/ diff --git a/numpy/core/src/npysort/radixsort.cpp b/numpy/core/src/npysort/radixsort.cpp new file mode 100644 index 000000000..502613689 --- /dev/null +++ b/numpy/core/src/npysort/radixsort.cpp @@ -0,0 +1,254 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include "npy_sort.h" +#include "npysort_common.h" +#include "../common/numpy_tag.h" +#include <stdlib.h> + +#include <type_traits> + +/* + ***************************************************************************** + ** INTEGER SORTS ** + ***************************************************************************** + */ + + +// Reference: https://github.com/eloj/radix-sorting#-key-derivation +template<class T> +T KEY_OF(T x) { + // Floating-point is currently disabled. + // Floating-point tests succeed for double and float on macOS but not on Windows/Linux. + // Basic sorting tests succeed but others relying on sort fail. + // Possibly related to floating-point normalisation or multiple NaN reprs? Not sure. + if(std::is_floating_point<T>::value) { + // For floats, we invert the key if the sign bit is set, else we invert the sign bit. + return ((x) ^ (-((x) >> (sizeof(T) * 8 - 1)) | ((T)1 << (sizeof(T) * 8 - 1)))); + } + else if(std::is_signed<T>::value) { + // For signed ints, we flip the sign bit so the negatives are below the positives. + return ((x) ^ ((T)1 << (sizeof(T) * 8 - 1))); + } + else { + return x; + } +} + + +template<class T> +static inline npy_ubyte +nth_byte(T key, npy_intp l) { + return (key >> (l << 3)) & 0xFF; +} + +template<class T> +static T* +radixsort0(T *start, T *aux, npy_intp num) +{ + npy_intp cnt[sizeof(T)][1 << 8] = { { 0 } }; + T key0 = KEY_OF(start[0]); + + for (npy_intp i = 0; i < num; i++) { + T k = KEY_OF(start[i]); + + for (size_t l = 0; l < sizeof(T); l++) { + cnt[l][nth_byte(k, l)]++; + } + } + + size_t ncols = 0; + npy_ubyte cols[sizeof(T)]; + for (size_t l = 0; l < sizeof(T); l++) { + if (cnt[l][nth_byte(key0, l)] != num) { + cols[ncols++] = l; + } + } + + for (size_t l = 0; l < ncols; l++) { + npy_intp a = 0; + for (npy_intp i = 0; i < 256; i++) { + npy_intp b = cnt[cols[l]][i]; + cnt[cols[l]][i] = a; + a += b; + } + } + + for (size_t l = 0; l < ncols; l++) { + T* temp; + for (npy_intp i = 0; i < num; i++) { + T k = KEY_OF(start[i]); + npy_intp dst = cnt[cols[l]][nth_byte(k, cols[l])]++; + aux[dst] = start[i]; + } + + temp = aux; + aux = start; + start = temp; + } + + return start; +} + +template<class T> +static int +radixsort_(T *start, npy_intp num) +{ + + if (num < 2) { + return 0; + } + + npy_bool all_sorted = 1; + T k1 = KEY_OF(start[0]), k2; + for (npy_intp i = 1; i < num; i++) { + k2 = KEY_OF(start[i]); + if (k1 > k2) { + all_sorted = 0; + break; + } + k1 = k2; + } + + if (all_sorted) { + return 0; + } + + T* aux = (T*)malloc(num * sizeof(T)); + if (aux == nullptr) { + return -NPY_ENOMEM; + } + + T *sorted = radixsort0(start, aux, num); + if (sorted != start) { + memcpy(start, sorted, num * sizeof(T)); + } + + free(aux); + return 0; +} + +template<class T> +static int +radixsort(void *start, npy_intp num) { + return radixsort_((T*)start, num); +} + +template<class T> +static npy_intp* +aradixsort0(T *start, npy_intp *aux, npy_intp *tosort, npy_intp num) +{ + npy_intp cnt[sizeof(T)][1 << 8] = { { 0 } }; + T key0 = KEY_OF(start[0]); + + for (npy_intp i = 0; i < num; i++) { + T k = KEY_OF(start[i]); + + for (size_t l = 0; l < sizeof(T); l++) { + cnt[l][nth_byte(k, l)]++; + } + } + + size_t ncols = 0; + npy_ubyte cols[sizeof(T)]; + for (size_t l = 0; l < sizeof(T); l++) { + if (cnt[l][nth_byte(key0, l)] != num) { + cols[ncols++] = l; + } + } + + for (size_t l = 0; l < ncols; l++) { + npy_intp a = 0; + for (npy_intp i = 0; i < 256; i++) { + npy_intp b = cnt[cols[l]][i]; + cnt[cols[l]][i] = a; + a += b; + } + } + + for (size_t l = 0; l < ncols; l++) { + npy_intp* temp; + for (npy_intp i = 0; i < num; i++) { + T k = KEY_OF(start[tosort[i]]); + npy_intp dst = cnt[cols[l]][nth_byte(k, cols[l])]++; + aux[dst] = tosort[i]; + } + + temp = aux; + aux = tosort; + tosort = temp; + } + + return tosort; +} + +template<class T> +static int +aradixsort_(T *start, npy_intp* tosort, npy_intp num) +{ + npy_intp *sorted; + npy_intp *aux; + T k1, k2; + npy_bool all_sorted = 1; + + if (num < 2) { + return 0; + } + + k1 = KEY_OF(start[tosort[0]]); + for (npy_intp i = 1; i < num; i++) { + k2 = KEY_OF(start[tosort[i]]); + if (k1 > k2) { + all_sorted = 0; + break; + } + k1 = k2; + } + + if (all_sorted) { + return 0; + } + + aux = (npy_intp*)malloc(num * sizeof(npy_intp)); + if (aux == NULL) { + return -NPY_ENOMEM; + } + + sorted = aradixsort0(start, aux, tosort, num); + if (sorted != tosort) { + memcpy(tosort, sorted, num * sizeof(npy_intp)); + } + + free(aux); + return 0; +} + +template<class T> +static int +aradixsort(void *start, npy_intp* tosort, npy_intp num) { + return aradixsort_((T*)start, tosort, num); +} + +extern "C" { +NPY_NO_EXPORT int radixsort_bool(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_bool>(vec, cnt); } +NPY_NO_EXPORT int radixsort_byte(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_byte>(vec, cnt); } +NPY_NO_EXPORT int radixsort_ubyte(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_ubyte>(vec, cnt); } +NPY_NO_EXPORT int radixsort_short(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_short>(vec, cnt); } +NPY_NO_EXPORT int radixsort_ushort(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_ushort>(vec, cnt); } +NPY_NO_EXPORT int radixsort_int(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_int>(vec, cnt); } +NPY_NO_EXPORT int radixsort_uint(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_uint>(vec, cnt); } +NPY_NO_EXPORT int radixsort_long(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_long>(vec, cnt); } +NPY_NO_EXPORT int radixsort_ulong(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_ulong>(vec, cnt); } +NPY_NO_EXPORT int radixsort_longlong(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_longlong>(vec, cnt); } +NPY_NO_EXPORT int radixsort_ulonglong(void* vec, npy_intp cnt, void *NPY_UNUSED(null)) { return radixsort<npy_ulonglong>(vec, cnt); } +NPY_NO_EXPORT int aradixsort_bool(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_bool>(vec, ind, cnt); } +NPY_NO_EXPORT int aradixsort_byte(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_byte>(vec, ind, cnt); } +NPY_NO_EXPORT int aradixsort_ubyte(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_ubyte>(vec, ind, cnt); } +NPY_NO_EXPORT int aradixsort_short(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_short>(vec, ind, cnt); } +NPY_NO_EXPORT int aradixsort_ushort(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_ushort>(vec, ind, cnt); } +NPY_NO_EXPORT int aradixsort_int(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_int>(vec, ind, cnt); } +NPY_NO_EXPORT int aradixsort_uint(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_uint>(vec, ind, cnt); } +NPY_NO_EXPORT int aradixsort_long(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_long>(vec, ind, cnt); } +NPY_NO_EXPORT int aradixsort_ulong(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_ulong>(vec, ind, cnt); } +NPY_NO_EXPORT int aradixsort_longlong(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_longlong>(vec, ind, cnt); } +NPY_NO_EXPORT int aradixsort_ulonglong(void* vec, npy_intp* ind, npy_intp cnt, void *NPY_UNUSED(null)) { return aradixsort<npy_ulonglong>(vec, ind, cnt); } +} diff --git a/numpy/core/src/umath/clip.c.src b/numpy/core/src/umath/clip.c.src deleted file mode 100644 index 48786d4a2..000000000 --- a/numpy/core/src/umath/clip.c.src +++ /dev/null @@ -1,125 +0,0 @@ -/** - * This module provides the inner loops for the clip ufunc - */ -#define PY_SSIZE_T_CLEAN -#include <Python.h> - -#define _UMATHMODULE -#define _MULTIARRAYMODULE -#define NPY_NO_DEPRECATED_API NPY_API_VERSION - -#include "numpy/halffloat.h" -#include "numpy/npy_math.h" -#include "numpy/ndarraytypes.h" -#include "numpy/npy_common.h" -#include "numpy/utils.h" -#include "fast_loop_macros.h" - -/* - * Produce macros that perform nan/nat-propagating min and max - */ - -/**begin repeat - * #name = BOOL, - * BYTE, UBYTE, SHORT, USHORT, INT, UINT, - * LONG, ULONG, LONGLONG, ULONGLONG# - */ -#define _NPY_@name@_MIN(a, b) PyArray_MIN(a, b) -#define _NPY_@name@_MAX(a, b) PyArray_MAX(a, b) -/**end repeat**/ - -#define _NPY_HALF_MIN(a, b) (npy_half_isnan(a) || npy_half_le(a, b) ? (a) : (b)) -#define _NPY_HALF_MAX(a, b) (npy_half_isnan(a) || npy_half_ge(a, b) ? (a) : (b)) - -/**begin repeat - * #name = FLOAT, DOUBLE, LONGDOUBLE# - */ -#define _NPY_@name@_MIN(a, b) (npy_isnan(a) ? (a) : PyArray_MIN(a, b)) -#define _NPY_@name@_MAX(a, b) (npy_isnan(a) ? (a) : PyArray_MAX(a, b)) -/**end repeat**/ - -/**begin repeat - * #name = CFLOAT, CDOUBLE, CLONGDOUBLE# - */ -#define _NPY_@name@_MIN(a, b) (npy_isnan((a).real) || npy_isnan((a).imag) || PyArray_CLT(a, b) ? (a) : (b)) -#define _NPY_@name@_MAX(a, b) (npy_isnan((a).real) || npy_isnan((a).imag) || PyArray_CGT(a, b) ? (a) : (b)) -/**end repeat**/ - -/**begin repeat - * #name = DATETIME, TIMEDELTA# - */ -#define _NPY_@name@_MIN(a, b) ( \ - (a) == NPY_DATETIME_NAT ? (a) : \ - (b) == NPY_DATETIME_NAT ? (b) : \ - (a) < (b) ? (a) : (b) \ -) -#define _NPY_@name@_MAX(a, b) ( \ - (a) == NPY_DATETIME_NAT ? (a) : \ - (b) == NPY_DATETIME_NAT ? (b) : \ - (a) > (b) ? (a) : (b) \ -) -/**end repeat**/ - -/**begin repeat - * - * #name = BOOL, - * BYTE, UBYTE, SHORT, USHORT, INT, UINT, - * LONG, ULONG, LONGLONG, ULONGLONG, - * HALF, FLOAT, DOUBLE, LONGDOUBLE, - * CFLOAT, CDOUBLE, CLONGDOUBLE, - * DATETIME, TIMEDELTA# - * #type = npy_bool, - * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, - * npy_long, npy_ulong, npy_longlong, npy_ulonglong, - * npy_half, npy_float, npy_double, npy_longdouble, - * npy_cfloat, npy_cdouble, npy_clongdouble, - * npy_datetime, npy_timedelta# - */ - -NPY_NO_EXPORT void -@name@_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) -{ - if (steps[1] == 0 && steps[2] == 0) { - /* min and max are constant throughout the loop, the most common case */ - /* NOTE: it may be possible to optimize these checks for nan */ - @type@ min_val = *(@type@ *)args[1]; - @type@ max_val = *(@type@ *)args[2]; - - char *ip1 = args[0], *op1 = args[3]; - npy_intp is1 = steps[0], os1 = steps[3]; - npy_intp n = dimensions[0]; - - /* contiguous, branch to let the compiler optimize */ - if (is1 == sizeof(@type@) && os1 == sizeof(@type@)) { - for(npy_intp i = 0; i < n; i++, ip1 += is1, op1 += os1) { - @type@ t = *(@type@ *)ip1; - t = _NPY_@name@_MAX(t, min_val); - t = _NPY_@name@_MIN(t, max_val); - *(@type@ *)op1 = t; - } - } - else { - for(npy_intp i = 0; i < n; i++, ip1 += is1, op1 += os1) { - @type@ t = *(@type@ *)ip1; - t = _NPY_@name@_MAX(t, min_val); - t = _NPY_@name@_MIN(t, max_val); - *(@type@ *)op1 = t; - } - } - } - else { - TERNARY_LOOP { - @type@ t = *(@type@ *)ip1; - t = _NPY_@name@_MAX(t, *(@type@ *)ip2); - t = _NPY_@name@_MIN(t, *(@type@ *)ip3); - *(@type@ *)op1 = t; - } - } - npy_clear_floatstatus_barrier((char*)dimensions); -} - -// clean up the macros we defined above -#undef _NPY_@name@_MAX -#undef _NPY_@name@_MIN - -/**end repeat**/ diff --git a/numpy/core/src/umath/clip.cpp b/numpy/core/src/umath/clip.cpp new file mode 100644 index 000000000..830d3a39c --- /dev/null +++ b/numpy/core/src/umath/clip.cpp @@ -0,0 +1,131 @@ +/** + * This module provides the inner loops for the clip ufunc + */ +#define _UMATHMODULE +#define _MULTIARRAYMODULE +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#define PY_SSIZE_T_CLEAN +#include <Python.h> + + +#include "numpy/halffloat.h" +#include "numpy/npy_math.h" +#include "numpy/ndarraytypes.h" +#include "numpy/npy_common.h" +#include "numpy/utils.h" +#include "fast_loop_macros.h" +#include "../common/numpy_tag.h" + + +template<class T> +T _NPY_MIN(T a, T b, npy::integral_tag const &) { return PyArray_MIN(a, b); } +template<class T> +T _NPY_MAX(T a, T b, npy::integral_tag const &) { return PyArray_MAX(a, b); } + +npy_half _NPY_MIN(npy_half a, npy_half b, npy::half_tag const &) { return npy_half_isnan(a) || npy_half_le(a, b) ? (a) : (b); } +npy_half _NPY_MAX(npy_half a, npy_half b, npy::half_tag const &) { return npy_half_isnan(a) || npy_half_ge(a, b) ? (a) : (b); } + +template<class T> +T _NPY_MIN(T a, T b, npy::floating_point_tag const &) { return npy_isnan(a) ? (a) : PyArray_MIN(a, b); } +template<class T> +T _NPY_MAX(T a, T b, npy::floating_point_tag const &) { return npy_isnan(a) ? (a) : PyArray_MAX(a, b); } + +template<class T> +T _NPY_MIN(T a, T b, npy::complex_tag const &) { return npy_isnan((a).real) || npy_isnan((a).imag) || PyArray_CLT(a, b) ? (a) : (b); } +template<class T> +T _NPY_MAX(T a, T b, npy::complex_tag const &) { return npy_isnan((a).real) || npy_isnan((a).imag) || PyArray_CGT(a, b) ? (a) : (b); } + +template<class T> +T _NPY_MIN(T a, T b, npy::date_tag const &) { + return (a) == NPY_DATETIME_NAT + ? (a) + : (b) == NPY_DATETIME_NAT ? (b) : (a) < (b) ? (a) : (b); +} +template<class T> +T _NPY_MAX(T a, T b, npy::date_tag const &) { + return (a) == NPY_DATETIME_NAT + ? (a) + : (b) == NPY_DATETIME_NAT ? (b) : (a) > (b) ? (a) : (b); +} + +/* generic dispatcher */ +template<class Tag, class T=typename Tag::type> +T _NPY_MIN(T const& a, T const& b) { + return _NPY_MIN(a, b, Tag{}); +} +template<class Tag, class T=typename Tag::type> +T _NPY_MAX(T const& a, T const& b) { + return _NPY_MAX(a, b, Tag{}); +} + + +template<class Tag, class T> +T _NPY_CLIP(T x, T min, T max) { + return _NPY_MIN<Tag>(_NPY_MAX<Tag>((x), (min)), (max)); +} + +template<class Tag, class T=typename Tag::type> +static void +_npy_clip_(T **args, npy_intp const *dimensions, npy_intp const *steps) +{ + npy_intp n = dimensions[0]; + if (steps[1] == 0 && steps[2] == 0) { + /* min and max are constant throughout the loop, the most common case */ + /* NOTE: it may be possible to optimize these checks for nan */ + T min_val = *args[1]; + T max_val = *args[2]; + + T *ip1 = args[0], *op1 = args[3]; + npy_intp is1 = steps[0]/sizeof(T), os1 = steps[3]/sizeof(T); + + /* contiguous, branch to let the compiler optimize */ + if (is1 == 1 && os1 == 1) { + for(npy_intp i = 0; i < n; i++, ip1++, op1++) { + *op1 = _NPY_CLIP<Tag>(*ip1, min_val, max_val); + } + } + else { + for(npy_intp i = 0; i < n; i++, ip1 += is1, op1 += os1) { + *op1 = _NPY_CLIP<Tag>(*ip1, min_val, max_val); + } + } + } + else { + T *ip1 = args[0], *ip2 = args[1], *ip3 = args[2], *op1 = args[3]; + npy_intp is1 = steps[0]/sizeof(T), is2 = steps[1]/sizeof(T), is3 = steps[2]/sizeof(T), os1 = steps[3]/sizeof(T); + for(npy_intp i = 0; i < n; i++, ip1 += is1, ip2 += is2, ip3 += is3, op1 += os1) + *op1 = _NPY_CLIP<Tag>(*ip1, *ip2, *ip3); + } + npy_clear_floatstatus_barrier((char*)dimensions); +} + +template<class Tag> +static void +_npy_clip(char **args, npy_intp const *dimensions, npy_intp const *steps) { + using T = typename Tag::type; + return _npy_clip_<Tag>((T**)args, dimensions, steps); +} + +extern "C" { +NPY_NO_EXPORT void BOOL_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::bool_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void BYTE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::byte_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void UBYTE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::ubyte_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void SHORT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::short_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void USHORT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::ushort_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void INT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::int_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void UINT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::uint_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void LONG_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::long_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void ULONG_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::ulong_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void LONGLONG_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::longlong_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void ULONGLONG_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::ulonglong_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void HALF_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::half_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void FLOAT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::float_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void DOUBLE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::double_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void LONGDOUBLE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::longdouble_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void CFLOAT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::cfloat_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void CDOUBLE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::cdouble_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void CLONGDOUBLE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::clongdouble_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void DATETIME_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::datetime_tag>(args, dimensions, steps); } +NPY_NO_EXPORT void TIMEDELTA_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) { return _npy_clip<npy::timedelta_tag>(args, dimensions, steps); } +} diff --git a/numpy/core/src/umath/clip.h b/numpy/core/src/umath/clip.h new file mode 100644 index 000000000..66b3f5c39 --- /dev/null +++ b/numpy/core/src/umath/clip.h @@ -0,0 +1,33 @@ +#ifndef _NPY_UMATH_CLIP_H_ +#define _NPY_UMATH_CLIP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +NPY_NO_EXPORT void BOOL_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void BYTE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void UBYTE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void SHORT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void USHORT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void INT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void UINT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void LONG_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void ULONG_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void LONGLONG_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void ULONGLONG_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void HALF_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void FLOAT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void DOUBLE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void LONGDOUBLE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void CFLOAT_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void CDOUBLE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void CLONGDOUBLE_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void DATETIME_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); +NPY_NO_EXPORT void TIMEDELTA_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/numpy/core/src/umath/clip.h.src b/numpy/core/src/umath/clip.h.src deleted file mode 100644 index f16856cdf..000000000 --- a/numpy/core/src/umath/clip.h.src +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _NPY_UMATH_CLIP_H_ -#define _NPY_UMATH_CLIP_H_ - - -/**begin repeat - * - * #name = BOOL, - * BYTE, UBYTE, SHORT, USHORT, INT, UINT, - * LONG, ULONG, LONGLONG, ULONGLONG, - * HALF, FLOAT, DOUBLE, LONGDOUBLE, - * CFLOAT, CDOUBLE, CLONGDOUBLE, - * DATETIME, TIMEDELTA# - */ -NPY_NO_EXPORT void -@name@_clip(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)); -/**end repeat**/ - -#endif diff --git a/numpy/distutils/ccompiler.py b/numpy/distutils/ccompiler.py index 4495c8fee..9c85d28b9 100644 --- a/numpy/distutils/ccompiler.py +++ b/numpy/distutils/ccompiler.py @@ -23,7 +23,8 @@ from numpy.distutils.exec_command import ( ) from numpy.distutils.misc_util import cyg2win32, is_sequence, mingw32, \ get_num_build_jobs, \ - _commandline_dep_string + _commandline_dep_string, \ + sanitize_cxx_flags # globals for parallel build management import threading @@ -674,7 +675,9 @@ def CCompiler_cxx_compiler(self): return self cxx = copy(self) - cxx.compiler_so = [cxx.compiler_cxx[0]] + cxx.compiler_so[1:] + cxx.compiler_cxx = cxx.compiler_cxx + cxx.compiler_so = [cxx.compiler_cxx[0]] + \ + sanitize_cxx_flags(cxx.compiler_so[1:]) if sys.platform.startswith('aix') and 'ld_so_aix' in cxx.linker_so[0]: # AIX needs the ld_so_aix script included with Python cxx.linker_so = [cxx.linker_so[0], cxx.compiler_cxx[0]] \ diff --git a/numpy/distutils/ccompiler_opt.py b/numpy/distutils/ccompiler_opt.py index e7fd494d3..9c386b3ac 100644 --- a/numpy/distutils/ccompiler_opt.py +++ b/numpy/distutils/ccompiler_opt.py @@ -188,7 +188,8 @@ class _Config: # native usually works only with x86 native = '-march=native', opt = '-O3', - werror = '-Werror' + werror = '-Werror', + cxx = '-std=c++11', ), clang = dict( native = '-march=native', @@ -198,22 +199,26 @@ class _Config: # cases `-Werror` gets skipped during the availability test due to # "unused arguments" warnings. # see https://github.com/numpy/numpy/issues/19624 - werror = '-Werror-implicit-function-declaration -Werror' + werror = '-Werror=switch -Werror', + cxx = '-std=c++11', ), icc = dict( native = '-xHost', opt = '-O3', - werror = '-Werror' + werror = '-Werror', + cxx = '-std=c++11', ), iccw = dict( native = '/QxHost', opt = '/O3', - werror = '/Werror' + werror = '/Werror', + cxx = '-std=c++11', ), msvc = dict( native = None, opt = '/O2', - werror = '/WX' + werror = '/WX', + cxx = '-std=c++11', ) ) conf_min_features = dict( @@ -555,6 +560,7 @@ class _Distutils: flags = kwargs.pop("extra_postargs", []) + flags if not ccompiler: ccompiler = self._ccompiler + return ccompiler.compile(sources, extra_postargs=flags, **kwargs) def dist_test(self, source, flags, macros=[]): diff --git a/numpy/distutils/command/build_clib.py b/numpy/distutils/command/build_clib.py index 0e31a7dee..a481758c1 100644 --- a/numpy/distutils/command/build_clib.py +++ b/numpy/distutils/command/build_clib.py @@ -264,6 +264,8 @@ class build_clib(old_build_clib): if include_dirs is None: include_dirs = [] extra_postargs = build_info.get('extra_compiler_args') or [] + extra_cflags = build_info.get('extra_cflags') or [] + extra_cxxflags = build_info.get('extra_cxxflags') or [] include_dirs.extend(get_numpy_include_dirs()) # where compiled F90 module files are: @@ -315,38 +317,45 @@ class build_clib(old_build_clib): macros=macros + copt_macros, include_dirs=include_dirs, debug=self.debug, - extra_postargs=extra_postargs, + extra_postargs=extra_postargs + extra_cxxflags, ccompiler=cxx_compiler ) if copt_c_sources: log.info("compiling C dispatch-able sources") - objects += self.compiler_opt.try_dispatch(copt_c_sources, - output_dir=self.build_temp, - src_dir=copt_build_src, - macros=macros + copt_macros, - include_dirs=include_dirs, - debug=self.debug, - extra_postargs=extra_postargs) + objects += self.compiler_opt.try_dispatch( + copt_c_sources, + output_dir=self.build_temp, + src_dir=copt_build_src, + macros=macros + copt_macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_postargs + extra_cflags) if c_sources: log.info("compiling C sources") - objects += compiler.compile(c_sources, - output_dir=self.build_temp, - macros=macros + copt_macros, - include_dirs=include_dirs, - debug=self.debug, - extra_postargs=extra_postargs + copt_baseline_flags) + objects += compiler.compile( + c_sources, + output_dir=self.build_temp, + macros=macros + copt_macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=(extra_postargs + + copt_baseline_flags + + extra_cflags)) if cxx_sources: log.info("compiling C++ sources") cxx_compiler = compiler.cxx_compiler() - cxx_objects = cxx_compiler.compile(cxx_sources, - output_dir=self.build_temp, - macros=macros + copt_macros, - include_dirs=include_dirs, - debug=self.debug, - extra_postargs=extra_postargs + copt_baseline_flags) + cxx_objects = cxx_compiler.compile( + cxx_sources, + output_dir=self.build_temp, + macros=macros + copt_macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=(extra_postargs + + copt_baseline_flags + + extra_cxxflags)) objects.extend(cxx_objects) if f_sources or fmodule_sources: diff --git a/numpy/distutils/command/build_ext.py b/numpy/distutils/command/build_ext.py index b8378d473..7040a2411 100644 --- a/numpy/distutils/command/build_ext.py +++ b/numpy/distutils/command/build_ext.py @@ -243,7 +243,8 @@ class build_ext (old_build_ext): if l and l != ext_language and ext.language: log.warn('resetting extension %r language from %r to %r.' % (ext.name, l, ext_language)) - ext.language = ext_language + if not ext.language: + ext.language = ext_language # global language all_languages.update(ext_languages) @@ -376,6 +377,9 @@ class build_ext (old_build_ext): log.info("building '%s' extension", ext.name) extra_args = ext.extra_compile_args or [] + extra_cflags = ext.extra_c_compile_args or [] + extra_cxxflags = ext.extra_cxx_compile_args or [] + macros = ext.define_macros[:] for undef in ext.undef_macros: macros.append((undef,)) @@ -462,38 +466,43 @@ class build_ext (old_build_ext): macros=macros + copt_macros, include_dirs=include_dirs, debug=self.debug, - extra_postargs=extra_args, + extra_postargs=extra_args + extra_cxxflags, ccompiler=cxx_compiler, **kws ) if copt_c_sources: log.info("compiling C dispatch-able sources") - c_objects += self.compiler_opt.try_dispatch(copt_c_sources, - output_dir=output_dir, - src_dir=copt_build_src, - macros=macros + copt_macros, - include_dirs=include_dirs, - debug=self.debug, - extra_postargs=extra_args, - **kws) + c_objects += self.compiler_opt.try_dispatch( + copt_c_sources, + output_dir=output_dir, + src_dir=copt_build_src, + macros=macros + copt_macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=extra_args + extra_cflags, + **kws) if c_sources: log.info("compiling C sources") - c_objects += self.compiler.compile(c_sources, - output_dir=output_dir, - macros=macros + copt_macros, - include_dirs=include_dirs, - debug=self.debug, - extra_postargs=extra_args + copt_baseline_flags, - **kws) + c_objects += self.compiler.compile( + c_sources, + output_dir=output_dir, + macros=macros + copt_macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=(extra_args + copt_baseline_flags + + extra_cflags), + **kws) if cxx_sources: log.info("compiling C++ sources") - c_objects += cxx_compiler.compile(cxx_sources, - output_dir=output_dir, - macros=macros + copt_macros, - include_dirs=include_dirs, - debug=self.debug, - extra_postargs=extra_args + copt_baseline_flags, - **kws) + c_objects += cxx_compiler.compile( + cxx_sources, + output_dir=output_dir, + macros=macros + copt_macros, + include_dirs=include_dirs, + debug=self.debug, + extra_postargs=(extra_args + copt_baseline_flags + + extra_cxxflags), + **kws) extra_postargs = [] f_objects = [] diff --git a/numpy/distutils/extension.py b/numpy/distutils/extension.py index c90b5d725..3ede013e0 100644 --- a/numpy/distutils/extension.py +++ b/numpy/distutils/extension.py @@ -47,6 +47,8 @@ class Extension(old_Extension): language=None, f2py_options=None, module_dirs=None, + extra_c_compile_args=None, + extra_cxx_compile_args=None, extra_f77_compile_args=None, extra_f90_compile_args=None,): @@ -83,6 +85,8 @@ class Extension(old_Extension): # numpy_distutils features self.f2py_options = f2py_options or [] self.module_dirs = module_dirs or [] + self.extra_c_compile_args = extra_c_compile_args or [] + self.extra_cxx_compile_args = extra_cxx_compile_args or [] self.extra_f77_compile_args = extra_f77_compile_args or [] self.extra_f90_compile_args = extra_f90_compile_args or [] diff --git a/numpy/distutils/misc_util.py b/numpy/distutils/misc_util.py index c9e051237..f0f9b4bd7 100644 --- a/numpy/distutils/misc_util.py +++ b/numpy/distutils/misc_util.py @@ -11,6 +11,7 @@ import multiprocessing import textwrap import importlib.util from threading import local as tlocal +from functools import reduce import distutils from distutils.errors import DistutilsError @@ -43,7 +44,7 @@ __all__ = ['Configuration', 'get_numpy_include_dirs', 'default_config_dict', 'dot_join', 'get_frame', 'minrelpath', 'njoin', 'is_sequence', 'is_string', 'as_list', 'gpaths', 'get_language', 'get_build_architecture', 'get_info', 'get_pkg_info', - 'get_num_build_jobs'] + 'get_num_build_jobs', 'sanitize_cxx_flags'] class InstallableLib: """ @@ -2478,3 +2479,15 @@ def get_build_architecture(): # systems, so delay the import to here. from distutils.msvccompiler import get_build_architecture return get_build_architecture() + + +_cxx_ignore_flags = {'-Werror=implicit-function-declaration'} + + +def sanitize_cxx_flags(cxxflags): + ''' + Some flags are valid for C but not C++. Prune them. + ''' + return [flag for flag in cxxflags if flag not in _cxx_ignore_flags] + + @@ -210,9 +210,8 @@ def get_build_overrides(): class new_build_clib(build_clib): def build_a_library(self, build_info, lib_name, libraries): if _needs_gcc_c99_flag(self): - args = build_info.get('extra_compiler_args') or [] - args.append('-std=c99') - build_info['extra_compiler_args'] = args + build_info['extra_cflags'] = ['-std=c99'] + build_info['extra_cxxflags'] = ['-std=c++11'] build_clib.build_a_library(self, build_info, lib_name, libraries) class new_build_ext(build_ext): |