summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatti Picus <matti.picus@gmail.com>2021-10-22 14:51:14 +0300
committerGitHub <noreply@github.com>2021-10-22 14:51:14 +0300
commit53d2a831668a58aa069e3bd891dd9d342dd058b3 (patch)
tree401ac37d2b7e9f274c80144a09154bac42a0d417
parentd8653001e5342d002b133dce999286fcafbd8bf0 (diff)
parent2ae7aeb3aa909b1a16bc58fd0e40dc4476dff35d (diff)
downloadnumpy-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.yml2
-rw-r--r--numpy/core/setup.py15
-rw-r--r--numpy/core/src/common/npy_sort.h.src7
-rw-r--r--numpy/core/src/common/numpy_tag.h34
-rw-r--r--numpy/core/src/npymath/npy_math_private.h12
-rw-r--r--numpy/core/src/npysort/radixsort.c.src231
-rw-r--r--numpy/core/src/npysort/radixsort.cpp254
-rw-r--r--numpy/core/src/umath/clip.c.src125
-rw-r--r--numpy/core/src/umath/clip.cpp131
-rw-r--r--numpy/core/src/umath/clip.h33
-rw-r--r--numpy/core/src/umath/clip.h.src18
-rw-r--r--numpy/distutils/ccompiler.py7
-rw-r--r--numpy/distutils/ccompiler_opt.py16
-rw-r--r--numpy/distutils/command/build_clib.py49
-rw-r--r--numpy/distutils/command/build_ext.py57
-rw-r--r--numpy/distutils/extension.py4
-rw-r--r--numpy/distutils/misc_util.py15
-rwxr-xr-xsetup.py5
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]
+
+
diff --git a/setup.py b/setup.py
index 2d1aec1aa..6fdd3b77e 100755
--- a/setup.py
+++ b/setup.py
@@ -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):