#!/usr/bin/make -f

export PYBUILD_NAME=scipy

include /usr/share/dpkg/default.mk

unexport LDFLAGS
export FFLAGS="-fPIC"
export ATLAS=None
export PATH := $(CURDIR)/debian/extra_bin:$(PATH)
export SCIPY_USE_PYTHRAN=0

PY3VERS:= $(shell py3versions -v -s)
PY3_DEFAULT:= $(shell py3versions -dv)
TMPDIR := $(CURDIR)/build/tmp
BASE=$(shell pwd)/debian

export SCIPY_USE_PYTHRAN = $(shell if dpkg-query -s python3-pythran >/dev/null 2>/dev/null; then echo 1; else echo 0; fi )

# specify build against generic BLAS/LAPACK. Preferred optimised implementation should be installed
# by the end user, not by the package build.
export PYBUILD_BUILD_ARGS := -Csetup-args=-Dblas=blas -Csetup-args=-Dlapack=lapack -Csetup-args=-Duse-system-libraries=qhull

ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
  export NPY_NUM_BUILD_JOBS = $(DEB_BUILD_OPTION_PARALLEL)
  export PYBUILD_BUILD_ARGS += -Ccompile-args=-j$(DEB_BUILD_OPTION_PARALLEL)
endif

# identify if any tests are particularly slow
EXTRA_TEST_FLAGS += --durations=20

# some arches time out. Run verbose to see where they got stuck.
VERBOSE_ARCH_LIST := mips64el riscv64 sparc64

# 32-bit stability degraded in scipy 1.12 with more tests
# getting MemoryError, especially in stats tests
# Run verbose to track more closely.
ifneq (,$(findstring $(DEB_HOST_ARCH_BITS), 32))
    VERBOSE_ARCH_LIST += $(DEB_HOST_ARCH)
endif

ifneq (,$(findstring $(space)$(DEB_HOST_ARCH)$(space), $(space)$(VERBOSE_ARCH_LIST)$(space)))
    EXTRA_TEST_FLAGS += -v
endif

# stats/tests/test_continuous_basic.py::test_cont_basic[500-200-ncf-arg74] test fails with IntegrationWarning
# https://github.com/scipy/scipy/issues/14519
# test_data (pooch) needs internet or cached data files
SKIP_TEST_LIST += test_cont_basic[500-200-ncf-arg74] test_existence_all test_ascent test_face test_electrocardiogram

# multi-Ellipsis indexing in sparse will be dropped in scipy 1.13
# see https://github.com/scipy/scipy/pull/18541
# it fails tests now so skip and reinstate later for scipy 1.13
SKIP_TEST_LIST += test_multiple_ellipsis_slicing

ifneq (,$(findstring $(DEB_HOST_ARCH), arm64))
    SKIP_TEST_LIST += test_maxiter_worsening[lgmres]
endif

# linalg/tests/test_decomp.py started segfaulting on armel
ifneq (,$(findstring $(DEB_HOST_ARCH), armel))
    SKIP_TEST_LIST += test_decomp test_random_exact test_brunnermunzel_normal_dist test_sparse_dense_divide
    SKIP_TEST_LIST += test_some_code_paths test_gh12218 test_random_state
    SKIP_TEST_LIST += test_against_anderson_gumbel_r test_bootstrap_against_R test_bootstrap_against_itself_1samp
endif

ifneq (,$(findstring $(DEB_HOST_ARCH), armhf))
    SKIP_TEST_LIST += test_gh12218 test_random_state
    SKIP_TEST_LIST += test_against_anderson_gumbel_r test_bootstrap_against_R test_bootstrap_against_itself_1samp
endif

# some tests broken on i386, see https://github.com/scipy/scipy/issues/17839
ifneq (,$(findstring $(DEB_HOST_ARCH), i386))
    SKIP_TEST_LIST += test_find_peaks_exact test_find_peaks_withnoise test_x0_equals_Mb[bicgstab] test_rv_sample
    SKIP_TEST_LIST += test_location_scale[pdf test_examples[True-float64] test_pdf_nolan_samples test_cdf_nolan_samples
    SKIP_TEST_LIST += ellint_rg_xy0_ipp-ellint_rg_xy0 test_hermitian test_random_state
    SKIP_TEST_LIST += test_against_anderson_gumbel_r test_bootstrap_against_R test_bootstrap_against_itself_1samp
    SKIP_TEST_LIST += test_svd_gesdd_nofegfault
endif

ifneq (,$(findstring $(DEB_HOST_ARCH), mips64el))
    # integrate/_ivp/tests/test_ivp.py fail on mips64el
    # see https://github.com/scipy/scipy/issues/16883
    # https://github.com/scipy/scipy/issues/17839#issuecomment-1400636840
    SKIP_TEST_LIST += test_first_step test_classes test_integrality test_integrator test_double_integrator
    SKIP_TEST_LIST += test_nanminmax TestLogM TestExpmFrechet
    SKIP_TEST_LIST += test_2x2_input test_nx2x2_input test_random_matrices_and_powers
    # there are also further complex number problems with numpy 2 on mips64el
    # again see Bug#1094477 and https://github.com/scipy/scipy/issues/21393
    SKIP_TEST_LIST += TestCephes TestEllipCarlson TestErf TestFresnel TestHyper
    SKIP_TEST_LIST += test_boost TestHyp1f1 test_nan_inputs[wofz] test_eval_chebyt_gh20129
    SKIP_TEST_LIST += test_sici_consistency test_shichi_consistency test_wrightomega
    SKIP_TEST_LIST += test_cont_basic test_norm_logcdf test_nan_inputs[airye]
endif

# https://github.com/scipy/scipy/issues/17839#issuecomment-1401780853
ifneq (,$(findstring $(DEB_HOST_ARCH), riscv64))
    SKIP_TEST_LIST += test_maxiter_worsening[lgmres] test_milp_timeout_16545
endif

# test_atol[bicg] only just misses tolerance on s390x, but the design of the test makes it difficult to workaround,
# so skip. See https://github.com/scipy/scipy/issues/17839#issuecomment-1399477182
ifneq (,$(findstring $(DEB_HOST_ARCH), s390x))
    SKIP_TEST_LIST += test_maxiter_worsening test_atol[bicg] test_distance_transform_cdt05
endif

# Bug#1017864 test_kolmogorov.py segfaults on i386 (including hurd)
SKIP_KOLMOGOROV_ARCH_LIST := i386 hurd-i386
ifneq (,$(findstring $(space)$(DEB_HOST_ARCH)$(space), $(space)$(SKIP_KOLMOGOROV_ARCH_LIST)$(space)))
    SKIP_TEST_LIST += TestSmirnovp
endif

# some tests in linalg test_matfuncs.py fail on several arches
# in particular riscv64 hppa sparc64 share many common test failure
SKIP_TestLogM_ARCH_LIST := riscv64 hppa sparc64
ifneq (,$(findstring $(space)$(DEB_HOST_ARCH)$(space), $(space)$(SKIP_TestLogM_ARCH_LIST)$(space)))
    SKIP_TEST_LIST += TestLogM TestExp test_expm
    SKIP_TEST_LIST += test_random_matrices_and_powers test_2x2_input test_nx2x2_input
    SKIP_TEST_LIST += test_zoh test_foh test_transferfunction
    SKIP_TEST_LIST += test_zerospolesgain test_discrete_approx test_simo_tf test_multioutput
    SKIP_TEST_LIST += test_simo_tf test_multioutput TestC2dLti TestC2dInvariants
    SKIP_TEST_LIST += test_second_order test_integrator test_double_integrator
    SKIP_TEST_LIST += test_jordan_block test_array_like TestStep test_operators
    SKIP_TEST_LIST += test_nan_inputs[airye] test_nan_inputs[sph_harm]
endif

# some archs fail test_cython (special test_extending) with numpy 1.26
# but will pass with numpy 2 due to complex type changes
# see https://github.com/scipy/scipy/issues/21393
SKIP_NEEDS_NUMPY2_ARCH_LIST := mips64el alpha hppa powerpc ppc64
ifneq (,$(findstring $(space)$(DEB_HOST_ARCH)$(space), $(space)$(SKIP_NEEDS_NUMPY2_ARCH_LIST)$(space)))
    SKIP_TEST_LIST += test_cython
endif

ifneq (,$(findstring $(DEB_HOST_ARCH), alpha))
    SKIP_TEST_LIST += test_read_over64bit_integer_dense test_read_over64bit_integer_sparse
    SKIP_TEST_LIST += test_hyp0f1 test_eval_chebyt_gh20129 test_rvs_gh18372
endif

# hppa runs out of memory in test_bootstrap_against_theory
ifneq (,$(findstring $(DEB_HOST_ARCH), hppa))
    SKIP_TEST_LIST += test_nodata test_cont_basic[500-200-semicircular-arg89] test_bootstrap_against_theory test_distance_transform_cdt05
    SKIP_TEST_LIST += test_onenormest_linear_operator test_against_anderson_gumbel_r test_gh12218
    SKIP_TEST_LIST += test_roots_hermite_asy test_bootstrap_against_R bootstrap_against_itself test_against_f_oneway
    SKIP_TEST_LIST += test_QRVS_shape_consistency[1-d_out1-1-size_out1-qrng1-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[None-d_out0-size_in4-size_out4-None-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[None-d_out0-size_in4-size_out4-qrng1-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[None-d_out0-size_in4-size_out4-qrng2-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[1-d_out1-size_in3-size_out3-None-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[1-d_out1-size_in4-size_out4-None-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[1-d_out1-size_in4-size_out4-qrng1-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[1-d_out1-size_in4-size_out4-qrng2-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[1-d_out1-4-size_out2-qrng1-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[3-d_out2-None-size_out0-None-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[3-d_out2-4-size_out2-None-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[3-d_out2-1-size_out1-qrng1-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[3-d_out2-4-size_out2-qrng1-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[3-d_out2-1-size_out1-qrng2-NumericalInversePolynomial] \
	test_QRVS_shape_consistency[3-d_out2-1-size_out1-None-NumericalInversePolynomial]
    SKIP_TEST_LIST += test_svd_gesdd_nofegfault
    SKIP_TEST_LIST += "(test_boost_ufuncs and test_landau)"  test_basic_fit_mle[landau]
    SKIP_TEST_LIST += "(test_continuous_basic and (test_cont_basic[500-landau-arg63] or test_moments[landau-arg64-True-True-True-False]))"
    SKIP_TEST_LIST += test_accuracy[numpy-case28] "(TestCubatureProblems and test_scalar_output)"
endif

# hppa, powerpc have problems with all 64-bit numbers (long, int64, etc) and sparse matrices, skip 'em all
SKIP_COMPLEX_64BIT_ARCH_LIST := hppa powerpc
ifneq (,$(findstring $(space)$(DEB_HOST_ARCH)$(space), $(space)$(SKIP_COMPLEX_64BIT_ARCH_LIST)$(space)))
    SKIP_TEST_LIST += long int64 float64 complex64 complex128
    SKIP_TEST_LIST += test_splu_smoketest test_spilu_smoketest test_lu_attr test_threads_parallel
    SKIP_TEST_LIST += test_hermitian_modes test_real_nonsymmetric_modes test_complex_nonsymmetric_modes
    SKIP_TEST_LIST += test_sparse_expm_multiply_interval_dtypes test_misc_types test_padecases_dtype_sparse_complex
    SKIP_TEST_LIST += TestVsNumpyNorm test_dot[int32 "(TestMikotaPair and test_dot)"
    SKIP_TEST_LIST += test_empty_arithmetic "(TestArithmetic1D and (test_empty_arithmetic or test_sub or test_add0))"
    SKIP_TEST_LIST += "(sparse and (test_fancy_assignment_dtypes or test_add_sub or test_mu or test_mu or test_eq or test_ne or test_lt or test_gt or test_le or test_ge))"
    SKIP_TEST_LIST += "(sparse and (test_empty_arithmetic or test_sum or test_mean or test_sparse_format_conversions or test_transpose or test_maximum_minimum))"
    SKIP_TEST_LIST += "(TestCommon1D and (test_add[c or test_radd[c or test_add_dense_to_sparse[c ))"
    SKIP_TEST_LIST += "((TestCSR or TestLIL or TestBSR) and test_solve)"
    SKIP_TEST_LIST += "(TestLIL and test_dot)"
    SKIP_TEST_LIST += "((TestCSC or TestBSRNonCanonical) and test_from_sparse)"
    SKIP_TEST_LIST += "((TestCSC or TestBSR) and (test_add or test_elementwise_divide or test_elementwise_multiply))"
    SKIP_TEST_LIST += "(TestBSRNonCanonical and (test_minmax or test_from or test_astype))"
    SKIP_TEST_LIST += "(TestCSCNonCanonical and (test_dtype_preservation or test_real or test_imag))"
    SKIP_TEST_LIST += test_simple_det_shapes_real_complex
endif

# hurd's threading module is incompatible. Skip affected tests.
SKIP_BAD_THREADING_ARCH_LIST := hurd-amd64 hurd-i386
ifneq (,$(findstring $(space)$(DEB_HOST_ARCH)$(space), $(space)$(SKIP_BAD_THREADING_ARCH_LIST)$(space)))
    SKIP_TEST_LIST += test_backend_call test_backend_plan test_memmap test_fortran test_write_roundtrip test_mmio
endif

ifneq (,$(findstring $(DEB_HOST_ARCH), hurd-i386))
    SKIP_TEST_LIST += test_mip1 test_find_peaks_exact test_find_peaks_withnoise test_examples[True-float64] test_rv_sample test_location_scale[pdf
    SKIP_TEST_LIST += test_pdf_nolan_samples[pct_range0-alpha_range0-beta_range0] ellint_rg_xy0_ipp-ellint_rg_xy0
    SKIP_TEST_LIST += test_logpdf_pdf_consistency test_gh12218 test_ttest_many_dims test_domain_argus_large_chi
    SKIP_TEST_LIST += test_setting_loc_scale test_ignore_shape_range test_QRVS_size_tuple TestGoodnessOfFit
    SKIP_TEST_LIST += TestBoxcox iterative hop crash evolution marginals vector
    SKIP_TEST_LIST += test_kurtosis test_exact_basic
endif

# powerpc: failures in stats/tests/test_stats.py: overflow encountered in _hypergeom_*
ifneq (,$(findstring $(DEB_HOST_ARCH), powerpc))
    SKIP_TEST_LIST += test_hypergeom_cdf test_hypergeom_sf test_nch_hypergeom test_precision test_precise
    SKIP_TEST_LIST += test_less_greater test_maxiter_worsening[lgmres] test_distance_transform_cdt05
    SKIP_TEST_LIST += test_roots_hermite_asy test_bootstrap_against_R bootstrap_against_itself test_against_f_oneway
    SKIP_TEST_LIST += test_against_anderson_gumbel_r test_gh12218 test_svd_gesdd_nofegfault
    SKIP_TEST_LIST += test_hyp0f1 test_eval_chebyt_gh20129
endif

# https://github.com/scipy/scipy/issues/17839#issuecomment-1399478853
ifneq (,$(findstring $(DEB_HOST_ARCH), ppc64))
    SKIP_TEST_LIST += test_precond_dummy test_maxiter_worsening[lgmres] test_distance_transform_cdt05
    SKIP_TEST_LIST += test_hyp0f1 test_eval_chebyt_gh20129
endif

ifneq (,$(findstring $(DEB_HOST_ARCH), sparc64))
    SKIP_TEST_LIST += test_distance_transform_cdt05 test_milp_timeout_16545
    # cython (complex) and stats (nan) failing on sparc64
    # see https://github.com/scipy/scipy/issues/22577
    SKIP_TEST_LIST += test_wofz test_elliprc test_elliprd test_elliprf test_elliprg test_elliprj \
	test_erfc_consistent test_erfcx_consistent test_erfi_consistent test_dawsn_consistent test_wofz_nan_inf \
	test_hyp0f1 test_cython_api[airy] test_cython_api[airye] test_cython_api[dawsn] \
	test_cython_api[elliprc] test_cython_api[elliprf] test_cython_api[elliprg] test_cython_api[elliprj] \
	test_cython_api[erf] test_cython_api[erfc] test_cython_api[erfcx] test_cython_api[erfi] \
	test_cython_api[expm1] test_cython_api[log1p] test_cython_api[xlog1py] test_cython_api[xlogy] \
	test_cython_api[eval_chebyc] test_cython_api[eval_legendre] test_cython_api[eval_sh_chebyt] \
	test_cython_api[eval_sh_legendre] test_cython_api[exp1] test_cython_api[expi] test_cython_api[fresnel] test_cython_api[gamma] \
	test_cython_api[hankel1] test_cython_api[hankel1e] test_cython_api[hankel2] test_cython_api[hankel2e] \
	test_cython_api[hyp0f1] test_cython_api[hyp1f1] test_cython_api[hyp2f1] \
	test_cython_api[iv] test_cython_api[ive] test_cython_api[jv] test_cython_api[jve] test_cython_api[kv] test_cython_api[kve] \
	test_cython_api[log_ndtr] test_cython_api[loggamma] test_cython_api[ndtr] test_cython_api[psi] test_cython_api[rgamma] \
	test_cython_api[shichi] test_cython_api[sici] test_cython_api[wofz] test_cython_api[yv] test_cython_api[yve] \
	erf_data_ipp erf_large_data_ipp erf_small_data_ipp test_complex_z \
	test_nan_inputs[sph_harm] test_eval_chebyt_gh20129 test_sici_consistency test_shichi_consistency \
	test_wrightomega_inf_branch test_wrightomega_inf test_wrightomega_singular test_wrightomega_real_versus_complex \
	test_cont_basic[500-alpha-arg0] test_cont_basic[500-crystalball-arg13] test_cont_basic[500-exponnorm-arg19] \
	test_cont_basic[500-fatiguelife-arg23] test_cont_basic[500-foldnorm-arg26] test_cont_basic[500-gibrat-arg40] \
	test_cont_basic[500-halfnorm-arg46] test_cont_basic[500-invgauss-arg49] test_cont_basic[500-johnsonsu-arg54] \
	test_cont_basic[500-levy-arg66] test_cont_basic[500-lognorm-arg71] test_cont_basic[500-moyal-arg76] \
	test_cont_basic[500-norm-arg81] test_cont_basic[500-powerlognorm-arg88] test_cont_basic[500-powernorm-arg89] \
	test_cont_basic[500-wald-arg113] test_norm_logcdf \
	"(special and test_extending and test_cython)"
endif

ifneq (,$(findstring $(DEB_HOST_ARCH), x32))
    SKIP_TEST_LIST += test_input_validation test_basic test_sign test_flexible_input \
	test_perm_discrepancy test_integers_nd test_0dim test_0sample test_1sample \
	test_bounds test_random_generator test_sample test_continuing \
	test_svd_random_state_2 ellint_rg_xy0_ipp-ellint_rg_xy0 test_reset
endif

%:
	dh $@ --buildsystem=pybuild

execute_after_dh_auto_clean:
	rm -rf build .pybuild
	-find $(CURDIR) -name __pycache__ -type d -exec rm -rf {} +
	-rm -rf doc/source/fontList*
	-rm -rf doc/source/reference/generated
	-rm -rf doc/build

execute_before_dh_clean:
	# make sure symlinks to submodules are cleaned up or empty directories from tarball are removed
	rm -rf doc/source/_static/scipy-mathjax
	rm -rf scipy/sparse/linalg/_propack/PROPACK
	for submod_lib in submodules/scipy/_lib/*; do \
	  submod_libname=`basename $$submod_lib`; \
	  rm -rf scipy/_lib/$$submod_libname; \
	done
	# and clean up submodules/subprojects symlinks
	find subprojects/ -type l -delete

execute_before_dh_auto_configure:
	echo "Symlink to submodules"
	ln -sf ../../../submodules/doc/source/_static/scipy-mathjax		doc/source/_static/scipy-mathjax
	ln -sf ../../../../submodules/scipy/sparse/linalg/_propack/PROPACK	scipy/sparse/linalg/_propack/PROPACK
	for submod_lib in submodules/scipy/_lib/*; do \
	  submod_libname=`basename $$submod_lib`; \
	  ln -sf ../../$$submod_lib scipy/_lib/$$submod_libname; \
	done
	# scipy subprojects are a mess
	# highs and xsf are git submodules (updated by git submodule update --init)
	# boost_math is a git submodule only in the math subdir
	# qhull_r is not a git submodule at all
	# link git submodules to their rightful place in subprojects
	# git removes empty dirs, so allow for both git (without) and .dsc (with) builds
	subproj_submod=`for d in $(CURDIR)/submodules/subprojects/*; do find $$d -type f -printf '%h\n' | awk '{ print length, $$0 }' | sort -n | head -n 1| cut -d" " -f2- ; done`; \
	for m in $$subproj_submod; do \
	  p=`echo $$m | sed "s|$(CURDIR)/submodules/subprojects/||"`; \
	  if [ -d $(CURDIR)/subprojects/$$p ]; then \
	    ln -sf $$m/*  $(CURDIR)/subprojects/$$p; \
	  else \
	    ln -sf $$m  $(CURDIR)/subprojects/$$p; \
	  fi; \
	done
	echo "Building scipy with SCIPY_USE_PYTHRAN=$(SCIPY_USE_PYTHRAN)"

execute_before_dh_installdocs-indep:
	(export MPLCONFIGDIR=. ; \
	PYLIBPATH=`pybuild --print build_dir -p$(PY3_DEFAULT) | awk '{print $$3}'`; \
	echo "building docs using PYLIBPATH=$$PYLIBPATH"; \
	JUPYTER_PLATFORM_DIRS=1 \
	    PYTHONPATH=$$PYLIBPATH \
	    HOME=/tmp \
	    make -C doc html PYTHONPATH=$$PYLIBPATH PYVER=3) || /bin/true

override_dh_auto_test:
	echo "Build-time tests will be run after the installation dir is installed"

ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
execute_after_dh_auto_install:
	set -e; \
	SKIP_TESTS=""; \
	list_initialised=0; \
	for t in $(SKIP_TEST_LIST); do \
	    if [ $${list_initialised} = 0 ]; then \
	        SKIP_TESTS=$$t; \
	        list_initialised=1; \
	    else \
	        SKIP_TESTS="$${SKIP_TESTS} or $$t"; \
	    fi; \
	done; \
	if [ "x$${SKIP_TESTS}" != "x" ]; then \
	    SKIP_TESTS="not ( $${SKIP_TESTS} )"; \
	fi; \
	echo "skipping tests: $${SKIP_TESTS}"; \
	for py in $(PY3VERS); do \
	  PYLIBPATH=`pybuild --print build_dir -p$$py | awk '{print $$3}'`; \
	  echo "If we need to report a bug upstream, they will ask for the following information:"; \
	  echo "\$$ python$$py -c \"import sys, scipy, numpy; print(scipy.__version__, numpy.__version__, sys.version_info); scipy.show_config()\""; \
	  (cd .pybuild; PYTHONPATH=$$PYLIBPATH:$$PYTHONPATH python$$py -c "import sys, scipy, numpy; print(scipy.__version__, numpy.__version__, sys.version_info); scipy.show_config()"); \
	  (cd $$PYLIBPATH; \
	  PYTHONPATH=$$PYLIBPATH:$$PYTHONPATH python$$py \
	        -m pytest $(EXTRA_TEST_FLAGS) -k "$${SKIP_TESTS}"); \
	done
endif

execute_after_dh_python3:
	dh_numpy3
