diff --git a/math/Makefile b/math/Makefile index 94cbe6fcf223..553bc278ca84 100644 --- a/math/Makefile +++ b/math/Makefile @@ -1,1359 +1,1360 @@ COMMENT = Mathematics SUBDIR += 4ti2 SUBDIR += GiNaC SUBDIR += Imath SUBDIR += R SUBDIR += R-cran-ADGofTest SUBDIR += R-cran-Amelia SUBDIR += R-cran-BsMD SUBDIR += R-cran-CVST SUBDIR += R-cran-ChangeAnomalyDetection SUBDIR += R-cran-DEoptimR SUBDIR += R-cran-DRR SUBDIR += R-cran-Deriv SUBDIR += R-cran-DoE.base SUBDIR += R-cran-FNN SUBDIR += R-cran-Formula SUBDIR += R-cran-FrF2 SUBDIR += R-cran-GPArotation SUBDIR += R-cran-KFAS SUBDIR += R-cran-LearnBayes SUBDIR += R-cran-MCMCpack SUBDIR += R-cran-MSwM SUBDIR += R-cran-MatchIt SUBDIR += R-cran-Matching SUBDIR += R-cran-MatrixModels SUBDIR += R-cran-NMF SUBDIR += R-cran-RcppArmadillo SUBDIR += R-cran-RcppEigen SUBDIR += R-cran-RcppParallel SUBDIR += R-cran-RcppRoll SUBDIR += R-cran-Rmpfr SUBDIR += R-cran-Rsolnp SUBDIR += R-cran-SQUAREM SUBDIR += R-cran-SparseM SUBDIR += R-cran-VGAM SUBDIR += R-cran-XLConnect SUBDIR += R-cran-Zelig SUBDIR += R-cran-acepack SUBDIR += R-cran-admisc SUBDIR += R-cran-alabama SUBDIR += R-cran-ankiR SUBDIR += R-cran-ash SUBDIR += R-cran-assertthat SUBDIR += R-cran-backports SUBDIR += R-cran-bdsmatrix SUBDIR += R-cran-car SUBDIR += R-cran-carData SUBDIR += R-cran-coda SUBDIR += R-cran-collections SUBDIR += R-cran-combinat SUBDIR += R-cran-conf.design SUBDIR += R-cran-conquer SUBDIR += R-cran-cvar SUBDIR += R-cran-date SUBDIR += R-cran-ddalpha SUBDIR += R-cran-deldir SUBDIR += R-cran-dimRed SUBDIR += R-cran-dlmodeler SUBDIR += R-cran-doBy SUBDIR += R-cran-dplyr SUBDIR += R-cran-eRm SUBDIR += R-cran-energy SUBDIR += R-cran-exactRankTests SUBDIR += R-cran-expm SUBDIR += R-cran-forcats SUBDIR += R-cran-forecast SUBDIR += R-cran-fracdiff SUBDIR += R-cran-gbutils SUBDIR += R-cran-geepack SUBDIR += R-cran-geometry SUBDIR += R-cran-gmp SUBDIR += R-cran-gower SUBDIR += R-cran-gpclib SUBDIR += R-cran-gsl SUBDIR += R-cran-gss SUBDIR += R-cran-gtable SUBDIR += R-cran-haven SUBDIR += R-cran-hdrcde SUBDIR += R-cran-hexbin SUBDIR += R-cran-igraph SUBDIR += R-cran-influenceR SUBDIR += R-cran-inline SUBDIR += R-cran-intervals SUBDIR += R-cran-ipred SUBDIR += R-cran-irlba SUBDIR += R-cran-isoband SUBDIR += R-cran-labeling SUBDIR += R-cran-lava SUBDIR += R-cran-lazyeval SUBDIR += R-cran-linprog SUBDIR += R-cran-lme4 SUBDIR += R-cran-locfit SUBDIR += R-cran-lpSolve SUBDIR += R-cran-ltm SUBDIR += R-cran-magic SUBDIR += R-cran-maps SUBDIR += R-cran-mathjaxr SUBDIR += R-cran-matrixStats SUBDIR += R-cran-maxLik SUBDIR += R-cran-mclust SUBDIR += R-cran-mcmc SUBDIR += R-cran-memisc SUBDIR += R-cran-minqa SUBDIR += R-cran-misc3d SUBDIR += R-cran-miscTools SUBDIR += R-cran-mitools SUBDIR += R-cran-mnormt SUBDIR += R-cran-moments SUBDIR += R-cran-mpoly SUBDIR += R-cran-mvtnorm SUBDIR += R-cran-ncdf4 SUBDIR += R-cran-nloptr SUBDIR += R-cran-nnls SUBDIR += R-cran-nortest SUBDIR += R-cran-numDeriv SUBDIR += R-cran-numbers SUBDIR += R-cran-orthopolynom SUBDIR += R-cran-outliers SUBDIR += R-cran-partitions SUBDIR += R-cran-pbkrtest SUBDIR += R-cran-plot3D SUBDIR += R-cran-pls SUBDIR += R-cran-polyclip SUBDIR += R-cran-polycor SUBDIR += R-cran-polynom SUBDIR += R-cran-pracma SUBDIR += R-cran-prodlim SUBDIR += R-cran-proxy SUBDIR += R-cran-psych SUBDIR += R-cran-psychTools SUBDIR += R-cran-pwr SUBDIR += R-cran-quadprog SUBDIR += R-cran-qualityTools SUBDIR += R-cran-quantreg SUBDIR += R-cran-raster SUBDIR += R-cran-recipes SUBDIR += R-cran-reformulas SUBDIR += R-cran-rgenoud SUBDIR += R-cran-robustbase SUBDIR += R-cran-sandwich SUBDIR += R-cran-scatterplot3d SUBDIR += R-cran-sets SUBDIR += R-cran-sf SUBDIR += R-cran-slam SUBDIR += R-cran-sm SUBDIR += R-cran-sp SUBDIR += R-cran-spData SUBDIR += R-cran-spdep SUBDIR += R-cran-sspir SUBDIR += R-cran-stabledist SUBDIR += R-cran-statmod SUBDIR += R-cran-survey SUBDIR += R-cran-tensor SUBDIR += R-cran-terra SUBDIR += R-cran-truncnorm SUBDIR += R-cran-units SUBDIR += R-cran-uroot SUBDIR += R-cran-wk SUBDIR += R-cran-xts SUBDIR += R-cran-zoo SUBDIR += SCIP SUBDIR += SoPlex SUBDIR += aamath SUBDIR += abella SUBDIR += abs SUBDIR += acalc SUBDIR += adasat SUBDIR += add SUBDIR += adept SUBDIR += adol-c SUBDIR += alberta SUBDIR += algae SUBDIR += alglib SUBDIR += alps SUBDIR += alt-ergo SUBDIR += amath SUBDIR += ambit SUBDIR += amgcl SUBDIR += analitza SUBDIR += ann SUBDIR += annoy SUBDIR += antic SUBDIR += apache-commons-math SUBDIR += apc SUBDIR += apron SUBDIR += arb SUBDIR += arborx SUBDIR += aribas SUBDIR += armadillo SUBDIR += arpack++ SUBDIR += arpack-ng SUBDIR += ascent SUBDIR += asl SUBDIR += asymptote SUBDIR += atlas SUBDIR += audi SUBDIR += barvinok SUBDIR += basic-stats SUBDIR += bcal SUBDIR += bcps SUBDIR += bitwise SUBDIR += bitwuzla SUBDIR += blacs SUBDIR += blahtexml SUBDIR += blas SUBDIR += blasfeo SUBDIR += blaspp SUBDIR += blaze SUBDIR += blazeiterative SUBDIR += blis SUBDIR += bliss SUBDIR += blocksolve95 SUBDIR += bonmin SUBDIR += boolector SUBDIR += brial SUBDIR += bsdnt SUBDIR += btor2tools SUBDIR += cadabra2 SUBDIR += cadiback SUBDIR += cadical SUBDIR += cado-nfs SUBDIR += calc SUBDIR += calcium SUBDIR += calcoo SUBDIR += cantor SUBDIR += casadi SUBDIR += cbc SUBDIR += cblas SUBDIR += ccmath SUBDIR += cddlib SUBDIR += ceres-solver SUBDIR += cgal SUBDIR += cgl SUBDIR += cgl-conic SUBDIR += cglm SUBDIR += chaco SUBDIR += chryzodus SUBDIR += chuffed SUBDIR += cimod SUBDIR += clad SUBDIR += clasp SUBDIR += clblas SUBDIR += clblast SUBDIR += clfft SUBDIR += clingcon SUBDIR += clingo SUBDIR += cliquer SUBDIR += cln SUBDIR += cloog SUBDIR += clp SUBDIR += clrng SUBDIR += cm SUBDIR += cmh SUBDIR += cminpack SUBDIR += cmlib SUBDIR += cocoalib SUBDIR += coin-or-data-netlib SUBDIR += coin-or-data-sample SUBDIR += coin-or-data-stochastic SUBDIR += coin-or-metis SUBDIR += coin-or-mumps SUBDIR += coinmp SUBDIR += coinutils SUBDIR += colpack SUBDIR += combblas SUBDIR += conauto SUBDIR += concorde SUBDIR += convertall SUBDIR += coq SUBDIR += cosma SUBDIR += costa SUBDIR += couenne SUBDIR += coxeter3 SUBDIR += cppad SUBDIR += creme SUBDIR += crlibm SUBDIR += cryptominisat SUBDIR += csdp SUBDIR += ctl-sat SUBDIR += cudd SUBDIR += curv SUBDIR += cvc5 SUBDIR += dbcsr SUBDIR += ddfun SUBDIR += deal.ii SUBDIR += dgl SUBDIR += dieharder SUBDIR += dihydrogen SUBDIR += dionysus SUBDIR += disco SUBDIR += dqfun SUBDIR += drgeo SUBDIR += dsdp SUBDIR += dsfmt SUBDIR += dune-alugrid SUBDIR += dune-common SUBDIR += dune-curvedgeometry SUBDIR += dune-fem SUBDIR += dune-foamgrid SUBDIR += dune-functions SUBDIR += dune-geometry SUBDIR += dune-grid SUBDIR += dune-grid-glue SUBDIR += dune-istl SUBDIR += dune-localfunctions SUBDIR += dune-metagrid SUBDIR += dune-multidomaingrid SUBDIR += dune-pdelab SUBDIR += dune-polygongrid SUBDIR += dune-spgrid SUBDIR += dune-typetree SUBDIR += dune-uggrid SUBDIR += dune-vtk SUBDIR += e-antic SUBDIR += eclib SUBDIR += ecos SUBDIR += edenmath SUBDIR += eigen3 SUBDIR += eigen5 SUBDIR += eispack SUBDIR += elan SUBDIR += elemental SUBDIR += elementary-calculator SUBDIR += elpa SUBDIR += emc2 SUBDIR += ensmallen SUBDIR += ent SUBDIR += eprover SUBDIR += ess SUBDIR += eukleides SUBDIR += eval SUBDIR += exprtk SUBDIR += facile SUBDIR += faiss SUBDIR += fann SUBDIR += fast_float SUBDIR += fastops SUBDIR += fcl SUBDIR += fcl05 SUBDIR += fend SUBDIR += fenics-basix SUBDIR += fflas-ffpack SUBDIR += fftw SUBDIR += fftw-float SUBDIR += fftw3 SUBDIR += fftw3-float SUBDIR += fftw3-long SUBDIR += fftw3-quad SUBDIR += flann SUBDIR += flexfloat SUBDIR += flexiblas SUBDIR += flint SUBDIR += flint2 SUBDIR += flintqs SUBDIR += flopc++ SUBDIR += form SUBDIR += formfactor SUBDIR += fparser SUBDIR += fplll SUBDIR += freefem++ SUBDIR += fricas SUBDIR += frobby SUBDIR += fxt SUBDIR += g2o SUBDIR += galculator SUBDIR += gambit SUBDIR += gap SUBDIR += gau2grid SUBDIR += gecode SUBDIR += gemmlowp SUBDIR += geogebra SUBDIR += geogram SUBDIR += gexpr SUBDIR += gf2x SUBDIR += gfan SUBDIR += gfanlib SUBDIR += ggobi SUBDIR += gh-bc SUBDIR += giacxcas SUBDIR += gismo SUBDIR += givaro SUBDIR += gkmap SUBDIR += glgraph SUBDIR += glm SUBDIR += glpk SUBDIR += glucose SUBDIR += gmm++ SUBDIR += gmp SUBDIR += gmp-ecm SUBDIR += gnome-calculator SUBDIR += gnubc SUBDIR += gnumeric SUBDIR += gnuplot SUBDIR += gnuplot-lite SUBDIR += gnuplot-tex-extras SUBDIR += gp2c SUBDIR += grace SUBDIR += gravity SUBDIR += gretl SUBDIR += grpn SUBDIR += gsl SUBDIR += half SUBDIR += hexcalc SUBDIR += hexowl SUBDIR += heyoka SUBDIR += highs SUBDIR += hmat-oss SUBDIR += hpcombi SUBDIR += hpipm SUBDIR += hptt SUBDIR += hs-Agda SUBDIR += hsl SUBDIR += hydrogen SUBDIR += hyperdeal SUBDIR += ideep SUBDIR += ignition-math SUBDIR += igraph SUBDIR += iml SUBDIR += intx SUBDIR += ipopt SUBDIR += ised SUBDIR += jacal SUBDIR += jacop SUBDIR += jags SUBDIR += jama SUBDIR += jeuclid SUBDIR += jlatexmath SUBDIR += jsmath-fonts SUBDIR += jtransforms SUBDIR += jts SUBDIR += kahip SUBDIR += kalc SUBDIR += kalgebra SUBDIR += kalk SUBDIR += kalker SUBDIR += kamis SUBDIR += kbruch SUBDIR += kcalc SUBDIR += kfr SUBDIR += kig SUBDIR += kissat SUBDIR += kktdirect SUBDIR += kmplot SUBDIR += labplot SUBDIR += lambda SUBDIR += lapack SUBDIR += lapack++ SUBDIR += lapack95 SUBDIR += lapacke SUBDIR += lapackpp SUBDIR += laspack SUBDIR += latte-integrale SUBDIR += lcalc SUBDIR += ldouble SUBDIR += lean4 SUBDIR += leangz SUBDIR += lemon SUBDIR += levmar SUBDIR += lib2geom SUBDIR += libRmath SUBDIR += libbraiding SUBDIR += libccd SUBDIR += libceed SUBDIR += libcerf SUBDIR += libdivide SUBDIR += libdivsufsort SUBDIR += libfixmath SUBDIR += libflame SUBDIR += libhomfly SUBDIR += libmesh SUBDIR += libnormaliz SUBDIR += libocas SUBDIR += liborigin SUBDIR += libpoly SUBDIR += libqalculate SUBDIR += libranlip SUBDIR += librdata SUBDIR += librsb SUBDIR += libsemigroups SUBDIR += libtexprintf SUBDIR += libtommath SUBDIR += libxls SUBDIR += libxlsxwriter SUBDIR += libxsmm SUBDIR += lidia SUBDIR += linbox SUBDIR += lingeling SUBDIR += linpack SUBDIR += lis SUBDIR += lll_spect SUBDIR += lmfit SUBDIR += lp_solve SUBDIR += lrcalc SUBDIR += lrng SUBDIR += lrslib SUBDIR += ltl2ba SUBDIR += m4ri SUBDIR += m4rie SUBDIR += manifold SUBDIR += mate-calc SUBDIR += math77 SUBDIR += mathex SUBDIR += mathgl SUBDIR += mathicsscript SUBDIR += mathmod SUBDIR += mathomatic SUBDIR += mathpresso SUBDIR += matio SUBDIR += maxima SUBDIR += mbasecalc SUBDIR += mcsim SUBDIR += mdal SUBDIR += mesquite SUBDIR += metis SUBDIR += mfem SUBDIR += minisat SUBDIR += minizinc SUBDIR += minizinc-ide SUBDIR += minizinc-solvers SUBDIR += minorminer SUBDIR += miracl SUBDIR += mlpack SUBDIR += moab SUBDIR += moo SUBDIR += mpc SUBDIR += mpdecimal SUBDIR += mpexpr SUBDIR += mpfi SUBDIR += mpfr SUBDIR += mpfrc++ SUBDIR += mpfrcx SUBDIR += mpir SUBDIR += mppp SUBDIR += mprime SUBDIR += mpsolve SUBDIR += mtrxmath SUBDIR += multichoose SUBDIR += mumps SUBDIR += mumps4 SUBDIR += munkres-cpp SUBDIR += muparser SUBDIR += muparserx SUBDIR += nanoflann SUBDIR += nauty SUBDIR += ndiff SUBDIR += newmat SUBDIR += nfft SUBDIR += ngraph SUBDIR += nlopt SUBDIR += ntl SUBDIR += ntpoly SUBDIR += numdiff SUBDIR += obake SUBDIR += ocaml-farith SUBDIR += ocaml-num SUBDIR += ocaml-ocamlgraph SUBDIR += ocaml-ocplib-simplex SUBDIR += ocaml-zarith SUBDIR += ocamlgsl SUBDIR += octave SUBDIR += octave-forge SUBDIR += octave-forge-actuarial SUBDIR += octave-forge-apa SUBDIR += octave-forge-audio SUBDIR += octave-forge-automatic-differentiation SUBDIR += octave-forge-base SUBDIR += octave-forge-bim SUBDIR += octave-forge-bioinfo SUBDIR += octave-forge-biosig SUBDIR += octave-forge-bsltl SUBDIR += octave-forge-cfitsio SUBDIR += octave-forge-cgi SUBDIR += octave-forge-chartjs SUBDIR += octave-forge-civil-engineering SUBDIR += octave-forge-coder SUBDIR += octave-forge-communications SUBDIR += octave-forge-control SUBDIR += octave-forge-csg-dataset SUBDIR += octave-forge-csg-toolkit SUBDIR += octave-forge-data-smoothing SUBDIR += octave-forge-database SUBDIR += octave-forge-dataframe SUBDIR += octave-forge-datatypes SUBDIR += octave-forge-devtools SUBDIR += octave-forge-dicom SUBDIR += octave-forge-divand SUBDIR += octave-forge-doctest SUBDIR += octave-forge-drafting SUBDIR += octave-forge-dsppack SUBDIR += octave-forge-econometrics SUBDIR += octave-forge-fda SUBDIR += octave-forge-femoctave SUBDIR += octave-forge-fenv SUBDIR += octave-forge-fileio SUBDIR += octave-forge-financial SUBDIR += octave-forge-fits SUBDIR += octave-forge-fl-core SUBDIR += octave-forge-fpl SUBDIR += octave-forge-fuzzy-logic-toolkit SUBDIR += octave-forge-fxp SUBDIR += octave-forge-ga SUBDIR += octave-forge-general SUBDIR += octave-forge-generate_html SUBDIR += octave-forge-geographiclib SUBDIR += octave-forge-geometry SUBDIR += octave-forge-gnuplot SUBDIR += octave-forge-gsl SUBDIR += octave-forge-hdf5oct SUBDIR += octave-forge-ident SUBDIR += octave-forge-image SUBDIR += octave-forge-informationtheory SUBDIR += octave-forge-instrument-control SUBDIR += octave-forge-integration SUBDIR += octave-forge-internal-fluid-flow SUBDIR += octave-forge-interval SUBDIR += octave-forge-io SUBDIR += octave-forge-irsa SUBDIR += octave-forge-joystick SUBDIR += octave-forge-level-set SUBDIR += octave-forge-linear-algebra SUBDIR += octave-forge-llms SUBDIR += octave-forge-lssa SUBDIR += octave-forge-ltfat SUBDIR += octave-forge-mapping SUBDIR += octave-forge-matgeom SUBDIR += octave-forge-mboct-fem-pkg SUBDIR += octave-forge-mboct-mbdyn-pkg SUBDIR += octave-forge-mboct-numerical-pkg SUBDIR += octave-forge-mboct-octave-pkg SUBDIR += octave-forge-mccabe-thiele SUBDIR += octave-forge-mechanics SUBDIR += octave-forge-miscellaneous SUBDIR += octave-forge-missing-functions SUBDIR += octave-forge-mpi SUBDIR += octave-forge-mqtt SUBDIR += octave-forge-msh SUBDIR += octave-forge-multicore SUBDIR += octave-forge-mvn SUBDIR += octave-forge-mysql SUBDIR += octave-forge-nan SUBDIR += octave-forge-ncarray SUBDIR += octave-forge-netcdf SUBDIR += octave-forge-nlwing2 SUBDIR += octave-forge-nnet SUBDIR += octave-forge-nurbs SUBDIR += octave-forge-oct2mat SUBDIR += octave-forge-octave-pool SUBDIR += octave-forge-octave_boost SUBDIR += octave-forge-octave_ffmpeg_free SUBDIR += octave-forge-octave_mermaid_js SUBDIR += octave-forge-octave_php_wrapper SUBDIR += octave-forge-octave_tar SUBDIR += octave-forge-octave_zstd SUBDIR += octave-forge-octclip SUBDIR += octave-forge-octproj SUBDIR += octave-forge-odbc SUBDIR += octave-forge-odebvp SUBDIR += octave-forge-optics SUBDIR += octave-forge-optim SUBDIR += octave-forge-optiminterp SUBDIR += octave-forge-outliers SUBDIR += octave-forge-parallel SUBDIR += octave-forge-pde1dm SUBDIR += octave-forge-piqp SUBDIR += octave-forge-pkg-octave-doc SUBDIR += octave-forge-plot SUBDIR += octave-forge-ponchon-savarit SUBDIR += octave-forge-prompt SUBDIR += octave-forge-psychrometrics SUBDIR += octave-forge-pythonic SUBDIR += octave-forge-quaternion SUBDIR += octave-forge-queueing SUBDIR += octave-forge-rf SUBDIR += octave-forge-rtree SUBDIR += octave-forge-secs1d SUBDIR += octave-forge-secs2d SUBDIR += octave-forge-secs3d SUBDIR += octave-forge-signal SUBDIR += octave-forge-simp SUBDIR += octave-forge-sockets SUBDIR += octave-forge-sole SUBDIR += octave-forge-sparsersb SUBDIR += octave-forge-specfun SUBDIR += octave-forge-special-matrix SUBDIR += octave-forge-splines SUBDIR += octave-forge-sqlite SUBDIR += octave-forge-statistics SUBDIR += octave-forge-statistics-resampling SUBDIR += octave-forge-stk SUBDIR += octave-forge-strings SUBDIR += octave-forge-struct SUBDIR += octave-forge-symband SUBDIR += octave-forge-symbolic SUBDIR += octave-forge-tablicious SUBDIR += octave-forge-tcl-octave SUBDIR += octave-forge-timer SUBDIR += octave-forge-tsa SUBDIR += octave-forge-velas SUBDIR += octave-forge-video SUBDIR += octave-forge-websockets SUBDIR += octave-forge-zenity SUBDIR += octave-forge-zeromq SUBDIR += octomap SUBDIR += ogdf SUBDIR += oink SUBDIR += oleo SUBDIR += onednn SUBDIR += onednn252 SUBDIR += openblas SUBDIR += openblas64 SUBDIR += openfst SUBDIR += openfst-vosk SUBDIR += openlibm SUBDIR += openmesh SUBDIR += openscop SUBDIR += openturns SUBDIR += optpp SUBDIR += or-tools SUBDIR += orpie SUBDIR += osi SUBDIR += osi-conic SUBDIR += osiipopt SUBDIR += osqp SUBDIR += p5-AI-DecisionTree SUBDIR += p5-AI-Genetic SUBDIR += p5-AI-NeuralNet-BackProp SUBDIR += p5-AI-Perceptron SUBDIR += p5-Algorithm-Combinatorics SUBDIR += p5-Algorithm-CurveFit SUBDIR += p5-Algorithm-Munkres SUBDIR += p5-Bit-ShiftReg SUBDIR += p5-Bit-Vector SUBDIR += p5-Bit-Vector-Minimal SUBDIR += p5-CAD-Calc SUBDIR += p5-Chart-Math-Axis SUBDIR += p5-Data-Float SUBDIR += p5-Date-Handler SUBDIR += p5-GIS-Distance SUBDIR += p5-GIS-Distance-Fast SUBDIR += p5-GIS-Distance-Lite SUBDIR += p5-Geo-Coordinates-UTM SUBDIR += p5-Geo-Distance SUBDIR += p5-Geo-Distance-XS SUBDIR += p5-Graph SUBDIR += p5-Math-Algebra-Symbols SUBDIR += p5-Math-Base36 SUBDIR += p5-Math-Base85 SUBDIR += p5-Math-BaseCalc SUBDIR += p5-Math-BaseCnv SUBDIR += p5-Math-Bezier SUBDIR += p5-Math-Bezier-Convert SUBDIR += p5-Math-BigInt SUBDIR += p5-Math-BigInt-FastCalc SUBDIR += p5-Math-BigInt-GMP SUBDIR += p5-Math-BigInt-Lite SUBDIR += p5-Math-BigInt-Pari SUBDIR += p5-Math-CDF SUBDIR += p5-Math-Calc-Units SUBDIR += p5-Math-Cephes SUBDIR += p5-Math-Combinatorics SUBDIR += p5-Math-Complex SUBDIR += p5-Math-ConvexHull SUBDIR += p5-Math-Currency SUBDIR += p5-Math-Derivative SUBDIR += p5-Math-Evol SUBDIR += p5-Math-Expr SUBDIR += p5-Math-FFT SUBDIR += p5-Math-FixedPrecision SUBDIR += p5-Math-Fleximal SUBDIR += p5-Math-GMP SUBDIR += p5-Math-GMPf SUBDIR += p5-Math-GMPq SUBDIR += p5-Math-GMPz SUBDIR += p5-Math-GSL SUBDIR += p5-Math-GSL-Alien SUBDIR += p5-Math-Geometry SUBDIR += p5-Math-Geometry-Planar SUBDIR += p5-Math-Geometry-Planar-GPC SUBDIR += p5-Math-Geometry-Planar-GPC-PolygonXS SUBDIR += p5-Math-Geometry-Planar-Offset SUBDIR += p5-Math-Geometry-Voronoi SUBDIR += p5-Math-Gradient SUBDIR += p5-Math-Int128 SUBDIR += p5-Math-Int64 SUBDIR += p5-Math-Interpolate SUBDIR += p5-Math-Intersection-StraightLine SUBDIR += p5-Math-Logic SUBDIR += p5-Math-MPC SUBDIR += p5-Math-MPFR SUBDIR += p5-Math-Matrix SUBDIR += p5-Math-MatrixReal SUBDIR += p5-Math-NumberCruncher SUBDIR += p5-Math-Pari SUBDIR += p5-Math-Polygon SUBDIR += p5-Math-Polygon-Tree SUBDIR += p5-Math-Polynomial-Solve SUBDIR += p5-Math-Prime-Util SUBDIR += p5-Math-Prime-Util-GMP SUBDIR += p5-Math-Prime-XS SUBDIR += p5-Math-ProvablePrime SUBDIR += p5-Math-RPN SUBDIR += p5-Math-Random SUBDIR += p5-Math-Random-ISAAC SUBDIR += p5-Math-Random-ISAAC-XS SUBDIR += p5-Math-Random-MT SUBDIR += p5-Math-Random-MT-Auto SUBDIR += p5-Math-Random-OO SUBDIR += p5-Math-Random-Secure SUBDIR += p5-Math-RandomOrg SUBDIR += p5-Math-Round SUBDIR += p5-Math-Round-Var SUBDIR += p5-Math-Sequence SUBDIR += p5-Math-Series SUBDIR += p5-Math-SigFigs SUBDIR += p5-Math-SimpleVariable SUBDIR += p5-Math-Spline SUBDIR += p5-Math-String SUBDIR += p5-Math-Symbolic SUBDIR += p5-Math-Symbolic-Custom-CCompiler SUBDIR += p5-Math-Symbolic-Custom-Contains SUBDIR += p5-Math-Symbolic-Custom-ErrorPropagation SUBDIR += p5-Math-Symbolic-Custom-LaTeXDumper SUBDIR += p5-Math-Symbolic-Custom-Pattern SUBDIR += p5-Math-Symbolic-Custom-Simplification SUBDIR += p5-Math-Symbolic-Custom-Transformation SUBDIR += p5-Math-SymbolicX-BigNum SUBDIR += p5-Math-SymbolicX-Complex SUBDIR += p5-Math-SymbolicX-Error SUBDIR += p5-Math-SymbolicX-Inline SUBDIR += p5-Math-SymbolicX-NoSimplification SUBDIR += p5-Math-SymbolicX-ParserExtensionFactory SUBDIR += p5-Math-SymbolicX-Statistics-Distributions SUBDIR += p5-Math-TrulyRandom SUBDIR += p5-Math-Units SUBDIR += p5-Math-Utils SUBDIR += p5-Math-Vec SUBDIR += p5-Math-VecStat SUBDIR += p5-Math-VectorReal SUBDIR += p5-NetCDF SUBDIR += p5-Number-Compare SUBDIR += p5-Number-Fraction SUBDIR += p5-Number-Misc SUBDIR += p5-Number-Uncertainty SUBDIR += p5-Number-WithError SUBDIR += p5-Number-WithError-LaTeX SUBDIR += p5-PDL SUBDIR += p5-PDL-DateTime SUBDIR += p5-PDL-Fit SUBDIR += p5-PDL-GSL SUBDIR += p5-PDL-Graphics-IIS SUBDIR += p5-PDL-Graphics-Limits SUBDIR += p5-PDL-Graphics-PLplot SUBDIR += p5-PDL-IO-Browser SUBDIR += p5-PDL-IO-Dicom SUBDIR += p5-PDL-IO-ENVI SUBDIR += p5-PDL-IO-GD SUBDIR += p5-PDL-IO-HDF SUBDIR += p5-PDL-IO-IDL SUBDIR += p5-PDL-LinearAlgebra SUBDIR += p5-PDL-Minuit SUBDIR += p5-PDL-Opt-Simplex SUBDIR += p5-PDL-Perldl2 SUBDIR += p5-PDL-Transform-Proj4 SUBDIR += p5-Parse-Range SUBDIR += p5-Roman SUBDIR += p5-Set-IntSpan SUBDIR += p5-Set-IntSpan-Fast SUBDIR += p5-Set-Partition SUBDIR += p5-Set-Window SUBDIR += p5-Statistics-Basic SUBDIR += p5-Statistics-Benford SUBDIR += p5-Statistics-CaseResampling SUBDIR += p5-Statistics-ChiSquare SUBDIR += p5-Statistics-Contingency SUBDIR += p5-Statistics-Descriptive SUBDIR += p5-Statistics-Descriptive-Discrete SUBDIR += p5-Statistics-Distributions SUBDIR += p5-Statistics-Forecast SUBDIR += p5-Statistics-Frequency SUBDIR += p5-Statistics-LTU SUBDIR += p5-Statistics-LineFit SUBDIR += p5-Statistics-Lite SUBDIR += p5-Statistics-OLS SUBDIR += p5-Statistics-R SUBDIR += p5-Statistics-Regression SUBDIR += p5-Statistics-TTest SUBDIR += p5-Task-Math-Symbolic SUBDIR += p5-Text-AsciiTeX SUBDIR += p5-bignum SUBDIR += palp SUBDIR += pari SUBDIR += pari_elldata SUBDIR += pari_galdata SUBDIR += pari_galpol SUBDIR += pari_nflistdata SUBDIR += pari_nftables SUBDIR += pari_seadata SUBDIR += paritwine SUBDIR += parmetis SUBDIR += parmgridgen SUBDIR += pcalc SUBDIR += pdal SUBDIR += pear-Math_BigInteger SUBDIR += pear-Math_Combinatorics SUBDIR += pecl-bitset SUBDIR += perlinnoise SUBDIR += permlib SUBDIR += petanque SUBDIR += petiga SUBDIR += pffft SUBDIR += php82-bcmath SUBDIR += php82-gmp SUBDIR += php83-bcmath SUBDIR += php83-gmp SUBDIR += php84-bcmath SUBDIR += php84-gmp SUBDIR += php85-bcmath SUBDIR += php85-gmp SUBDIR += php86-bcmath SUBDIR += php86-gmp SUBDIR += physcalc SUBDIR += picosat SUBDIR += piranha SUBDIR += planarity SUBDIR += plantri SUBDIR += plman SUBDIR += plplot SUBDIR += poly2tri SUBDIR += polyclipper SUBDIR += polylib SUBDIR += polymake SUBDIR += primecount SUBDIR += primegen SUBDIR += primesieve SUBDIR += primesum SUBDIR += primme SUBDIR += prng SUBDIR += proxsuite SUBDIR += psurface SUBDIR += py-CyLP SUBDIR += py-GridDataFormats SUBDIR += py-MutatorMath SUBDIR += py-POT SUBDIR += py-PuLP SUBDIR += py-Py-BOBYQA SUBDIR += py-PyMetis SUBDIR += py-PySCIPOpt SUBDIR += py-Pyomo SUBDIR += py-SQNomad SUBDIR += py-affine SUBDIR += py-algopy SUBDIR += py-altgraph SUBDIR += py-ambit SUBDIR += py-amply SUBDIR += py-animatplot SUBDIR += py-animatplot-ng SUBDIR += py-annoy SUBDIR += py-apgl SUBDIR += py-apted SUBDIR += py-arviz SUBDIR += py-arviz-base SUBDIR += py-arviz-plots SUBDIR += py-arviz-stats SUBDIR += py-arybo SUBDIR += py-autograd SUBDIR += py-awkward SUBDIR += py-awkward-cpp SUBDIR += py-baycomp SUBDIR += py-bayesian-optimization SUBDIR += py-benford_py SUBDIR += py-bitmath SUBDIR += py-bitvector SUBDIR += py-blis SUBDIR += py-bottleneck SUBDIR += py-brial + SUBDIR += py-cbcbox SUBDIR += py-chaospy SUBDIR += py-clarabel SUBDIR += py-claripy SUBDIR += py-clingcon SUBDIR += py-clingo SUBDIR += py-cma SUBDIR += py-cmaes SUBDIR += py-cmyt SUBDIR += py-colormath SUBDIR += py-contourpy SUBDIR += py-conway-polynomials SUBDIR += py-cryptominisat SUBDIR += py-cvxopt SUBDIR += py-cvxpy SUBDIR += py-cyipopt SUBDIR += py-cypari2 SUBDIR += py-daqp SUBDIR += py-dcor SUBDIR += py-deap SUBDIR += py-dgl SUBDIR += py-diffcp SUBDIR += py-dionysus SUBDIR += py-disjoint-set SUBDIR += py-distance SUBDIR += py-docplex SUBDIR += py-ducc0 SUBDIR += py-ecos SUBDIR += py-edit-distance SUBDIR += py-emcee SUBDIR += py-evalidate SUBDIR += py-fairlearn SUBDIR += py-faiss SUBDIR += py-fastcluster SUBDIR += py-fdasrsf SUBDIR += py-fenics-basix SUBDIR += py-fenics-ffcx SUBDIR += py-fenics-ufl SUBDIR += py-findiff SUBDIR += py-flax SUBDIR += py-formulaic SUBDIR += py-formulaic-contrasts SUBDIR += py-fpylll SUBDIR += py-fraction SUBDIR += py-fsph SUBDIR += py-fvcore SUBDIR += py-gau2grid SUBDIR += py-gimmik SUBDIR += py-gmpy2 SUBDIR += py-grandalf SUBDIR += py-graphillion SUBDIR += py-gym SUBDIR += py-gym-notices SUBDIR += py-hdbscan SUBDIR += py-hdmedians SUBDIR += py-hepstats SUBDIR += py-heyoka SUBDIR += py-highspy SUBDIR += py-hmmlearn SUBDIR += py-hypernetx SUBDIR += py-ibis-framework SUBDIR += py-igraph SUBDIR += py-iminuit SUBDIR += py-intspan SUBDIR += py-iohexperimenter SUBDIR += py-ipyopt SUBDIR += py-islpy SUBDIR += py-isosurfaces SUBDIR += py-jacobi SUBDIR += py-jax SUBDIR += py-jij-cimod SUBDIR += py-kahip SUBDIR += py-keras SUBDIR += py-keras-applications SUBDIR += py-keras-preprocessing SUBDIR += py-kiwisolver SUBDIR += py-latex2sympy2-extended SUBDIR += py-levmar SUBDIR += py-libceed SUBDIR += py-libpoly SUBDIR += py-linearmodels SUBDIR += py-lmfit SUBDIR += py-logical-unification SUBDIR += py-lrcalc SUBDIR += py-mapbox-earcut SUBDIR += py-math-verify SUBDIR += py-mathics SUBDIR += py-mathics-scanner SUBDIR += py-matplotlib SUBDIR += py-matplotlib-inline SUBDIR += py-matplotlib-scalebar SUBDIR += py-minorminer SUBDIR += py-mip SUBDIR += py-mixsimulator SUBDIR += py-ml-dtypes SUBDIR += py-mnnpy SUBDIR += py-moarchiving SUBDIR += py-modin SUBDIR += py-moocore SUBDIR += py-mpmath SUBDIR += py-munkres SUBDIR += py-narwhals SUBDIR += py-ndindex SUBDIR += py-ndonnx SUBDIR += py-networkx SUBDIR += py-nevergrad SUBDIR += py-nlopt SUBDIR += py-numba-stats SUBDIR += py-numdifftools SUBDIR += py-numexpr SUBDIR += py-numpoly SUBDIR += py-numpy SUBDIR += py-numpy-groupies SUBDIR += py-numpy-stl SUBDIR += py-numpy1 SUBDIR += py-openTSNE SUBDIR += py-opt-einsum SUBDIR += py-or-tools SUBDIR += py-osqp SUBDIR += py-pandas SUBDIR += py-pandas-datareader SUBDIR += py-pandas-gbq SUBDIR += py-pandas-stubs SUBDIR += py-patsy SUBDIR += py-pcodec SUBDIR += py-pdal SUBDIR += py-permutation SUBDIR += py-petsc4py SUBDIR += py-plastex SUBDIR += py-point-annotator SUBDIR += py-pplpy SUBDIR += py-primecountpy SUBDIR += py-primme SUBDIR += py-pwlf SUBDIR += py-py-find-1st SUBDIR += py-pyFFTW SUBDIR += py-pyaudi SUBDIR += py-pybloom SUBDIR += py-pyclipper SUBDIR += py-pycosat SUBDIR += py-pygsl SUBDIR += py-pygslodeiv2 SUBDIR += py-pyhdfe SUBDIR += py-pyhull SUBDIR += py-pymc3 SUBDIR += py-pynauty SUBDIR += py-pyneqsys SUBDIR += py-pynleq2 SUBDIR += py-pynndescent SUBDIR += py-pyodeint SUBDIR += py-pyodesys SUBDIR += py-pyprobables SUBDIR += py-pyreadr SUBDIR += py-pyreadstat SUBDIR += py-pyrfr SUBDIR += py-pyrr SUBDIR += py-pysmt SUBDIR += py-pysym SUBDIR += py-pytanque SUBDIR += py-pytensor SUBDIR += py-python-fcl SUBDIR += py-python-louvain SUBDIR += py-python-picard SUBDIR += py-pytorchvideo SUBDIR += py-pyvtk SUBDIR += py-pywavelets SUBDIR += py-qats SUBDIR += py-qdldl SUBDIR += py-quadprog SUBDIR += py-random2 SUBDIR += py-reals SUBDIR += py-rectangle-packer SUBDIR += py-resample SUBDIR += py-roman SUBDIR += py-rpy2 SUBDIR += py-rustworkx SUBDIR += py-rvlib SUBDIR += py-scikit-datasets SUBDIR += py-scikit-fda SUBDIR += py-scikit-fem SUBDIR += py-scikit-umfpack SUBDIR += py-scs SUBDIR += py-seaborn SUBDIR += py-secp256k1 SUBDIR += py-seriate SUBDIR += py-simhash SUBDIR += py-slepc4py SUBDIR += py-snuggs SUBDIR += py-sparsediffpy SUBDIR += py-spectral SUBDIR += py-spglm SUBDIR += py-spint SUBDIR += py-splot SUBDIR += py-spopt SUBDIR += py-spot SUBDIR += py-spox SUBDIR += py-spreg SUBDIR += py-squarify SUBDIR += py-ssm SUBDIR += py-statsmodels SUBDIR += py-svgmath SUBDIR += py-sym SUBDIR += py-symengine SUBDIR += py-sympy SUBDIR += py-theano SUBDIR += py-timple SUBDIR += py-topologic SUBDIR += py-torchsde SUBDIR += py-triangle SUBDIR += py-umap-learn SUBDIR += py-uncertainties SUBDIR += py-unyt SUBDIR += py-vector SUBDIR += py-vincenty SUBDIR += py-yt SUBDIR += py-z3-solver SUBDIR += qalculate-gtk SUBDIR += qalculate-qt SUBDIR += qd SUBDIR += qhull SUBDIR += qhull7 SUBDIR += qposases SUBDIR += qrupdate SUBDIR += qtiplot-doc SUBDIR += quich SUBDIR += qwtplot3d SUBDIR += qxfun SUBDIR += randlib SUBDIR += rankwidth SUBDIR += readstat SUBDIR += reduce-psl SUBDIR += reed-solomon SUBDIR += rehearse SUBDIR += rexx-regmath SUBDIR += rkward SUBDIR += rngstreams SUBDIR += rocs SUBDIR += rpcalc SUBDIR += rubiks SUBDIR += rubygem-algebra SUBDIR += rubygem-bigdecimal SUBDIR += rubygem-bigdecimal-gitlab SUBDIR += rubygem-cmath SUBDIR += rubygem-enumerable-statistics SUBDIR += rubygem-expression_parser SUBDIR += rubygem-fftw3 SUBDIR += rubygem-mathn SUBDIR += rubygem-matrix SUBDIR += rubygem-mtrc SUBDIR += rubygem-narray SUBDIR += rubygem-narray_miss SUBDIR += rubygem-numru-misc SUBDIR += rubygem-numru-units SUBDIR += rubygem-prime SUBDIR += rumur SUBDIR += saga SUBDIR += savage SUBDIR += sc SUBDIR += sc-im SUBDIR += scalapack SUBDIR += scalapackfx SUBDIR += scilab SUBDIR += scilab-toolbox-swt SUBDIR += scipoptsuite SUBDIR += scorec-core SUBDIR += scs SUBDIR += sdpa SUBDIR += secp256k1 SUBDIR += sfft SUBDIR += simd-viterbi SUBDIR += singular SUBDIR += sisl SUBDIR += slatec SUBDIR += sleef SUBDIR += slepc SUBDIR += slgrace SUBDIR += slicot SUBDIR += snns SUBDIR += solitaire SUBDIR += sound-of-sorting SUBDIR += spar SUBDIR += spblas SUBDIR += spectra SUBDIR += speedcrunch SUBDIR += spfft SUBDIR += spla SUBDIR += spooles SUBDIR += spooles-mpich SUBDIR += spot SUBDIR += sprng SUBDIR += ssht SUBDIR += stan SUBDIR += stanmath SUBDIR += stp SUBDIR += suitesparse SUBDIR += suitesparse-Example SUBDIR += suitesparse-amd SUBDIR += suitesparse-btf SUBDIR += suitesparse-camd SUBDIR += suitesparse-ccolamd SUBDIR += suitesparse-cholmod SUBDIR += suitesparse-colamd SUBDIR += suitesparse-config SUBDIR += suitesparse-csparse SUBDIR += suitesparse-cxsparse SUBDIR += suitesparse-graphblas SUBDIR += suitesparse-klu SUBDIR += suitesparse-lagraph SUBDIR += suitesparse-ldl SUBDIR += suitesparse-mongoose SUBDIR += suitesparse-paru SUBDIR += suitesparse-rbio SUBDIR += suitesparse-spex SUBDIR += suitesparse-spqr SUBDIR += suitesparse-umfpack SUBDIR += sundials SUBDIR += superlu SUBDIR += superlu-dist SUBDIR += superlu-mt SUBDIR += symengine SUBDIR += symfpu SUBDIR += symmetrica SUBDIR += symphony SUBDIR += sympol SUBDIR += sympow SUBDIR += taucs SUBDIR += tblis SUBDIR += testu01 SUBDIR += tetgen SUBDIR += teyjus SUBDIR += the-algorithms-c++ SUBDIR += timbl SUBDIR += tiny-bignum-c SUBDIR += tinyexpr SUBDIR += tinymt SUBDIR += tlapack SUBDIR += tlfloat SUBDIR += tmv SUBDIR += tomsfastmath SUBDIR += topcom SUBDIR += topologic SUBDIR += triangle SUBDIR += trlan SUBDIR += trlib SUBDIR += ttmath SUBDIR += tvmet SUBDIR += ump SUBDIR += units SUBDIR += universal SUBDIR += unuran SUBDIR += usearch SUBDIR += vampire SUBDIR += vdt SUBDIR += verdict SUBDIR += viennacl SUBDIR += vinci SUBDIR += visualpolylib SUBDIR += vowpal_wabbit SUBDIR += vtk9 SUBDIR += wavelib SUBDIR += wcalc SUBDIR += wide-integer SUBDIR += wxmaxima SUBDIR += xblas SUBDIR += xfce4-calculator-plugin SUBDIR += xgap SUBDIR += xlapack SUBDIR += xldlas SUBDIR += xlife++ SUBDIR += xplot SUBDIR += xspread SUBDIR += xtensor SUBDIR += xtensor-blas SUBDIR += xtensor-io SUBDIR += xtensor-python SUBDIR += yacas SUBDIR += yices SUBDIR += z3 SUBDIR += zarray SUBDIR += zegrapher SUBDIR += zimpl SUBDIR += zn_poly .include diff --git a/math/py-cbcbox/Makefile b/math/py-cbcbox/Makefile new file mode 100644 index 000000000000..ffedfc5518a8 --- /dev/null +++ b/math/py-cbcbox/Makefile @@ -0,0 +1,33 @@ +PORTNAME= cbcbox +DISTVERSION= 2.935 # not tagged on GH +CATEGORIES= math python +PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX} + +MAINTAINER= yuri@FreeBSD.org +COMMENT= Python access to the CBC MILP solver +WWW= https://github.com/h-g-s/cbcbox + +LICENSE= EPL + +BUILD_DEPENDS= ${PYTHON_PKGNAMEPREFIX}setuptools>0:devel/py-setuptools@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}wheel>0:devel/py-wheel@${PY_FLAVOR} +RUN_DEPENDS= cbc:math/cbc + +USES= python +USE_PYTHON= pep517 concurrent autoplist pytest + +USE_GITHUB= yes +GH_ACCOUNT= h-g-s +GH_TAGNAME= adf09a5ea6f3d697b9a0b38831d7ad711b0cfe7a # adequate commit for 2.935 release + +NO_ARCH= yes + +TEST_ENV= PYTHONPATH=${WRKSRC}/build/lib +TEST_ARGS= --disable-plugin-autoload + +post-patch: + @${REINPLACE_CMD} -e 's|@LOCALBASE@|${LOCALBASE}|g' ${WRKSRC}/src/__init__.py + +# tests as of 2.935: 11 passed in 107.00s + +.include diff --git a/math/py-cbcbox/distinfo b/math/py-cbcbox/distinfo new file mode 100644 index 000000000000..96bd05948fbe --- /dev/null +++ b/math/py-cbcbox/distinfo @@ -0,0 +1,3 @@ +TIMESTAMP = 1788910090 +SHA256 (h-g-s-cbcbox-2.935-adf09a5ea6f3d697b9a0b38831d7ad711b0cfe7a_GH0.tar.gz) = d0ccf7902cdc09550d6c8f01ac501051008905cefe53b988bc2360c6721f6c16 +SIZE (h-g-s-cbcbox-2.935-adf09a5ea6f3d697b9a0b38831d7ad711b0cfe7a_GH0.tar.gz) = 13095448 diff --git a/math/py-cbcbox/files/patch-pyproject.toml b/math/py-cbcbox/files/patch-pyproject.toml new file mode 100644 index 000000000000..849279cfa7a1 --- /dev/null +++ b/math/py-cbcbox/files/patch-pyproject.toml @@ -0,0 +1,14 @@ +-- Remove the "cbc" console script so this port does not conflict with the +-- bin/cbc executable already provided by math/cbc. + +--- pyproject.toml.orig 2026-09-08 23:28:23 UTC ++++ pyproject.toml +@@ -35,8 +35,5 @@ Homepage = "https://github.com/h-g-s/cbcbox" + Homepage = "https://github.com/h-g-s/cbcbox" + "Bug Tracker" = "https://github.com/h-g-s/cbcbox/issues" + +-[project.scripts] +-cbc = "cbcbox.__main__:main" +- + [tool.cibuildwheel] + build-verbosity = 1 diff --git a/math/py-cbcbox/files/patch-setup.py b/math/py-cbcbox/files/patch-setup.py new file mode 100644 index 000000000000..5d79daa3b495 --- /dev/null +++ b/math/py-cbcbox/files/patch-setup.py @@ -0,0 +1,1127 @@ +-- Replace the upstream setup.py with a minimal setuptools configuration. +-- Upstream setup.py rebuilds OpenBLAS, SuiteSparse AMD and the full COIN-OR +-- stack from git sources and bundles the resulting binaries into a wheel. +-- FreeBSD already provides math/cbc, so this port installs only the Python +-- wrapper and points it at the system CBC binary. + +--- setup.py.orig 2026-09-08 23:28:23 UTC ++++ setup.py +@@ -1,1109 +1,15 @@ +-import glob as _glob +-import multiprocessing + import os +-import platform +-import re +-import shlex +-import shutil +-import subprocess +-import sys +- + from setuptools import setup +-from wheel.bdist_wheel import bdist_wheel as _bdist_wheel + ++THIS_DIR = os.path.abspath(os.path.dirname(__file__)) + +-# ── Wheel customisation ─────────────────────────────────────────────────────── ++with open(os.path.join(THIS_DIR, "README.md"), "r", encoding="utf-8") as f: ++ long_description = f.read() + +-class genericpy_bdist_wheel(_bdist_wheel): +- def finalize_options(self): +- _bdist_wheel.finalize_options(self) +- self.root_is_pure = False +- +- def get_tag(self): +- python, abi, plat = _bdist_wheel.get_tag(self) +- python, abi = "py3", "none" +- if os.environ.get("CIBUILDWHEEL", "0") == "1": +- if plat == "linux_x86_64": +- plat = "manylinux2014_x86_64" +- elif plat == "linux_aarch64": +- plat = "manylinux2014_aarch64" +- return python, abi, plat +- +- +-cmdclass = {"bdist_wheel": genericpy_bdist_wheel} +- +- +-# ── Constants ───────────────────────────────────────────────────────────────── +- +-THIS_DIR = os.path.abspath(os.path.dirname(__file__)) +-DIST_DIR = os.path.join(THIS_DIR, "cbc_dist") +-DIST_DIR_AVX2 = os.path.join(THIS_DIR, "cbc_dist_avx2") +-DIST_DIR_DEBUG = os.path.join(THIS_DIR, "cbc_dist_debug") +-DIST_DIR_DEBUG_AVX2 = os.path.join(THIS_DIR, "cbc_dist_debug_avx2") +-LIB_DIR = os.path.join(DIST_DIR, "lib") +-NPROC = str(max(1, multiprocessing.cpu_count())) +- +-SUITESPARSE_TAG = "v7.12.2" +-OPENBLAS_TAG = "v0.3.31" +- +-# Development of the COIN-OR stack has moved to the "next" branch of each +-# repository (the "master" branch is now the last stable release line). +-COIN_OR_BRANCH = "next" +- +-# -ffp-contract=off disables the compiler's automatic fusion of separate +-# multiply/add operations into a single FMA instruction. FMA computes the +-# product with full (unrounded) intermediate precision before the final +-# rounding, so results can differ slightly (in the last bit) from the +-# strictly-IEEE separate multiply + add. This tiny discrepancy is enough to +-# make CBC's numerical routines (which rely on exact reproducibility across +-# the stack) occasionally behave inconsistently, so this flag is applied to +-# the COIN-OR stack (CoinUtils, Osi, Clp, Cgl, Cbc) only — third-party +-# dependencies built from source (OpenBLAS, SuiteSparse AMD) keep their +-# default FMA-contraction behaviour. +-FP_CONTRACT_OFF = "-ffp-contract=off" +- +-# Build order matters: each project depends on the ones before it. +-COIN_REPOS = [ +- ("CoinUtils", "https://github.com/coin-or/CoinUtils.git"), +- ("Osi", "https://github.com/coin-or/Osi.git"), +- ("Clp", "https://github.com/coin-or/Clp.git"), +- ("Cgl", "https://github.com/coin-or/Cgl.git"), +- ("Cbc", "https://github.com/coin-or/Cbc.git"), +-] +- +-# Shared libraries allowed by the manylinux2014 policy (PEP 599). +-# Anything NOT matching this pattern must be either linked statically +-# or bundled inside the wheel. +-_MANYLINUX_ALLOWED = re.compile( +- r"^lib(gcc_s|stdc\+\+|m|dl|rt|pthread|c|nsl|util|z|gomp|crypt|resolv)\." +- r"|^(linux-vdso|linux-gate|ld-linux)" ++setup( ++ long_description=long_description, ++ long_description_content_type="text/markdown", ++ packages=["cbcbox"], ++ package_dir={"cbcbox": "src"}, ++ zip_safe=False, + ) +- +-# ── Windows / MSYS2-MinGW64 constants ──────────────────────────────────────── +- +-# MSYS2 is pre-installed on windows-latest GitHub Actions runners. +-_MSYS2_BASH = r"C:\msys64\usr\bin\bash.exe" +- +-# DLLs that ship with Windows itself and must NOT be bundled. +-_WIN_SYS_DLL = re.compile( +- r"^(kernel32|user32|ntdll|msvcrt|api-ms-win|ext-ms-win|advapi32|" +- r"shell32|ole32|oleaut32|ws2_32|mswsock|bcrypt|crypt32|secur32|" +- r"ucrtbase|vcruntime|hid|setupapi|cfgmgr32|imm32|version|winmm|" +- r"shlwapi|rpcrt4|comctl32|comdlg32|gdi32|netapi32|psapi|dbghelp)" +- r"\.dll$", +- re.IGNORECASE, +-) +- +- +-def _win_to_msys2(s: str) -> str: +- """Convert Windows absolute path references within *s* to MSYS2 format. +- +- 'C:\\foo\\bar' → '/c/foo/bar' +- '--prefix=C:/foo/bar' → '--prefix=/c/foo/bar' +- '-LC:/foo/bar' → '-L/c/foo/bar' (even when preceded by a flag letter) +- 'https://example.com' → unchanged +- Strings without drive letters pass through unchanged. +- """ +- s = str(s) +- # Protect URL schemes (e.g. "https://") so they aren't misidentified as +- # Windows drive letters. Use a lambda so Python doesn't interpret \x in +- # the replacement string (re.sub string replacement doesn't allow \x). +- placeholder = "\x00\x00" +- s = re.sub(r'([A-Za-z]+)://', lambda m: m.group(1) + placeholder, s) +- # Convert Windows drive letters to MSYS2 /x/ format. +- s = re.sub(r'([A-Za-z]):[/\\]', lambda m: f"/{m.group(1).lower()}/", s) +- # Restore URL schemes and normalise remaining back-slashes. +- return s.replace('\x00\x00', '://').replace('\\', '/') +- +- +-# ── Generic helpers ─────────────────────────────────────────────────────────── +- +-def run(*cmd, cwd=None, env=None): +- print(f">>> {' '.join(str(c) for c in cmd)}", flush=True) +- if platform.system() == "Windows": +- # Route every build command through MSYS2/MinGW64 so that autotools, +- # make, pkg-config, gfortran etc. are all available. +- parts = ["export PATH=/mingw64/bin:/usr/bin:$PATH"] +- if cwd: +- parts.append(f"cd {shlex.quote(_win_to_msys2(str(cwd)))}") +- parts.append(" ".join(shlex.quote(_win_to_msys2(str(c))) for c in cmd)) +- subprocess.run([_MSYS2_BASH, "-lc", " && ".join(parts)], +- check=True, env=env) +- else: +- subprocess.run(list(cmd), check=True, cwd=cwd, env=env) +- +- +-def _is_x86_64() -> bool: +- return platform.machine().lower() in ("x86_64", "amd64") +- +- +-def clone_if_missing(name, url, branch="master"): +- dest = os.path.join(THIS_DIR, name) +- if not os.path.exists(dest): +- # Use native git directly — avoids routing through MSYS2 where git +- # may not be on PATH, and avoids any path-conversion of the URL. +- print(f">>> git clone --depth 1 --branch {branch} {url} {dest}", flush=True) +- subprocess.run( +- ["git", "clone", "--depth", "1", "--branch", branch, url, dest], +- check=True, +- ) +- else: +- # Pull the latest commits so that a stale shallow clone never causes +- # API-mismatch build failures (e.g. a new method added to Clp that +- # Cbc already calls, but the local clone predates the push). +- print(f">>> git -C {dest} pull --ff-only", flush=True) +- subprocess.run( +- ["git", "-C", dest, "pull", "--ff-only"], +- check=True, +- ) +- return dest +- +- +- +-# ── Build OpenBLAS (static, with Fortran/LAPACK) ───────────────────────────── +- +-def build_openblas(dest_dir, *, dynamic_arch=False, target=None, extra_cflags="", +- dynamic_list=None): +- src = clone_if_missing( +- "OpenBLAS", +- "https://github.com/xianyi/OpenBLAS.git", +- OPENBLAS_TAG, +- ) +- # OpenBLAS builds in-tree; always clean before each build so that a +- # second (AVX2) pass doesn't inherit object files from the first. +- run("make", "clean", cwd=src) +- +- make_vars = [] +- if platform.system() == "Windows": +- make_vars.append("BINARY=64") +- if target: +- # Explicit CPU target (e.g. TARGET=HASWELL for AVX2 build). +- make_vars.append(f"TARGET={target}") +- elif dynamic_arch: +- # DYNAMIC_ARCH=1 compiles multiple kernels and dispatches at runtime. +- # NO_AVX512=1: AVX-512 kernels use very large stack frames (ZMM spills) +- # that overflow the 512 KB default pthread stack on macOS, causing +- # SIGSEGV inside dgetrf_single on CI runners with Ice Lake Xeons. +- # Our wheel targets Haswell (AVX2) as the high-water mark, so AVX-512 +- # is never needed. +- # This must ALSO be applied on Windows: without DYNAMIC_ARCH/NO_AVX512, +- # OpenBLAS falls back to build-time CPUID auto-detection of the CI +- # runner's host CPU, and some GitHub-hosted Windows runners land on +- # AVX-512-capable hosts, which then intermittently fail to compile +- # OpenBLAS's SkylakeX kernel under MinGW GCC 16.2 ("inlining failed +- # in call to always_inline ...: target specific option mismatch"). +- # That is the root cause of the flaky "Compile Windows *" job failures +- # seen across many CI runs — it depends on which physical host the +- # runner happens to land on, not on any code change. +- make_vars.append("DYNAMIC_ARCH=1") +- make_vars.append("NO_AVX512=1") +- # Limit the set of compiled kernels to modern CPUs; pre-2010 +- # architectures (BARCELONA, CORE2, …) are dropped. CPUs not in the +- # list fall back to the generic kernel — correctness is unaffected. +- if dynamic_list: +- make_vars.append(f"DYNAMIC_LIST={dynamic_list}") +- +- # Never build the CBLAS C interface — COIN-OR uses Fortran-style BLAS +- # (dgemm_, dtrsm_, …) so the cblas_* wrappers are dead weight. +- make_vars.append("NO_CBLAS=1") +- +- if extra_cflags: +- make_vars.append(f"CFLAGS={extra_cflags}") +- make_vars.append(f"FFLAGS={extra_cflags}") +- +- # Build static + shared libs (libs target skips test suite). +- # Building shared is required on all platforms so configure scripts +- # (CoinUtils LAPACK test) can link against the shared library — static +- # requires explicit Fortran runtime flags which is fragile. +- run("make", f"-j{NPROC}", "libs", "shared", *make_vars, cwd=src) +- run("make", *make_vars, f"PREFIX={dest_dir}", "install", cwd=src) +- +- +-# ── Build SuiteSparse AMD (static only, direct compilation) ────────────────── +- +-def build_amd(extra_cflags=""): +- src = clone_if_missing( +- "SuiteSparse", +- "https://github.com/DrTimothyAldenDavis/SuiteSparse.git", +- SUITESPARSE_TAG, +- ) +- ss_dir = os.path.join(src, "SuiteSparse_config") +- amd_src = os.path.join(src, "AMD", "Source") +- amd_inc = os.path.join(src, "AMD", "Include") +- +- os.makedirs(LIB_DIR, exist_ok=True) +- inc_out = os.path.join(DIST_DIR, "include", "suitesparse") +- os.makedirs(inc_out, exist_ok=True) +- +- # AMD is a pure combinatorial/integer library — it doesn't use BLAS or +- # LAPACK at all. Compiling directly from C source avoids the SuiteSparse +- # cmake build system which unconditionally runs FindBLAS (and fails when +- # only a static OpenBLAS is present because the link test needs the +- # Fortran runtime libraries). +- cc = os.environ.get("CC", "gcc") +- cflags = ["-O2", "-fPIC", f"-I{ss_dir}", f"-I{amd_inc}"] +- if extra_cflags: +- cflags.extend(extra_cflags.split()) +- +- # SuiteSparse_config.c → libsuitesparseconfig.a +- ss_obj = os.path.join(THIS_DIR, "_ss_config.o") +- run(cc, *cflags, "-c", +- os.path.join(ss_dir, "SuiteSparse_config.c"), "-o", ss_obj) +- run("ar", "rcs", os.path.join(LIB_DIR, "libsuitesparseconfig.a"), ss_obj) +- +- # AMD/Source/*.c → libamd.a +- amd_objs = [] +- for c_file in sorted(_glob.glob(os.path.join(amd_src, "*.c"))): +- obj = c_file[:-2] + ".o" +- run(cc, *cflags, "-c", c_file, "-o", obj) +- amd_objs.append(obj) +- run("ar", "rcs", os.path.join(LIB_DIR, "libamd.a"), *amd_objs) +- +- # Install headers +- for h in _glob.glob(os.path.join(amd_inc, "*.h")): +- shutil.copy2(h, inc_out) +- shutil.copy2(os.path.join(ss_dir, "SuiteSparse_config.h"), inc_out) +- +- +-# ── Build COIN-OR projects ──────────────────────────────────────────────────── +- +-def build_coin_or(dest_dir=None, extra_cxxflags="", extra_ldflags="", is_debug=False): +- """Build the full COIN-OR stack and install into *dest_dir*. +- +- *extra_cxxflags* is appended to CXXFLAGS and can be used to enable +- architecture-specific optimisations (e.g. "-O3 -march=haswell -DCOIN_AVX2=4" +- for the Haswell-optimised build) or debug flags. +- +- *extra_ldflags* is appended to LDFLAGS for all configure calls. On macOS, +- the Clp project already gets "-L{lib_dir} -lopenblas"; extra_ldflags is +- merged into that rather than passed separately. +- +- *is_debug* controls whether C assert()s are compiled in. COIN-OR's own +- AC_COIN_PROG_CXX/AC_COIN_PROG_CC autoconf macros normally default +- CXXFLAGS/CFLAGS to "-O2 -DNDEBUG" (release) or "-g" (--enable-debug), but +- only via ": ${CXXFLAGS:=...}" -- a shell default that never fires because +- we always pass CXXFLAGS/CFLAGS explicitly on the configure command line +- (to control -march, -ffp-contract, etc.). That silently opted every +- release build (generic and AVX2, on every platform) out of -DNDEBUG, +- leaving internal consistency assert()s compiled into the SHIPPED wheels: +- an assert failing in the field aborts (SIGABRT/access violation) the +- caller's process instead of leaving debugging to an explicit debug build. +- So: pass is_debug=True for the debug/debug_avx2 variants (which +- deliberately want assertions active, see scripts/build_mip_debug_cuts.sh) +- and leave it False (the default) for the generic/avx2 release variants, +- which now get -DNDEBUG explicitly. +- """ +- if dest_dir is None: +- dest_dir = DIST_DIR +- lib_dir = os.path.join(dest_dir, "lib") +- +- # AMD is a pure combinatorial/integer library that does not benefit from +- # AVX2 and is only built once (into the base cbc_dist/). Both COIN-OR +- # variants can safely link against the same static archive. +- amd_inc = os.path.join(DIST_DIR, "include", "suitesparse") +- +- env = os.environ.copy() +- pkg_config_dir = os.path.join(lib_dir, "pkgconfig") +- # MSYS2 bash uses ':' as separator and MSYS2-format paths. +- if platform.system() == "Windows": +- env["PKG_CONFIG_PATH"] = ( +- _win_to_msys2(pkg_config_dir) + ":" + env.get("PKG_CONFIG_PATH", "") +- ) +- else: +- env["PKG_CONFIG_PATH"] = ( +- pkg_config_dir + os.pathsep + env.get("PKG_CONFIG_PATH", "") +- ) +- +- # Flags common to every project. +- # zlib is intentionally kept enabled (it is manylinux2014-allowed and +- # lets CBC read compressed MPS/LP files). +- common = [ +- f"--prefix={dest_dir}", +- f"--libdir={lib_dir}", +- "--enable-static" if platform.system() != "Windows" else "--disable-static", +- "--enable-shared", # produce .so/.dylib/.dll for cffi use +- "--disable-readline", # libreadline not manylinux-allowed +- "--disable-bzlib", # libbz2 not manylinux-allowed +- "--without-cholmod", # use AMD instead +- "--without-glpk", # not needed +- "--without-asl", # AMPL solver library not needed +- ] +- if platform.system() == "Windows": +- # Declare both build and host as MinGW64 so that autoconf sets +- # cross_compiling=no (build==host) and uses the plain gcc/g++ from +- # /mingw64/bin rather than looking for x86_64-w64-mingw32-prefixed +- # cross-compiler tools. With host_os=mingw32, libtool names DLLs as +- # lib*.dll (MinGW convention) rather than cyg*.dll (Cygwin convention). +- common += ["--build=x86_64-w64-mingw32", "--host=x86_64-w64-mingw32"] +- +- # Use a distinct build sub-directory per variant so that generic, +- # AVX2, and debug builds can coexist in the same cloned source tree. +- if dest_dir == DIST_DIR: +- bld_suffix = "_build" +- elif dest_dir == DIST_DIR_AVX2: +- bld_suffix = "_build_avx2" +- elif dest_dir == DIST_DIR_DEBUG_AVX2: +- bld_suffix = "_build_debug_avx2" +- else: +- bld_suffix = "_build_debug" +- +- for name, url in COIN_REPOS: +- src = clone_if_missing(name, url, COIN_OR_BRANCH) +- bld = os.path.join(src, bld_suffix) +- os.makedirs(bld, exist_ok=True) +- +- extra = [] +- ldflags_in_extra = False +- if name == "CoinUtils": +- # OpenBLAS provides both BLAS and LAPACK in one archive. +- # AMD provides fill-reducing ordering for sparse systems. +- # +- # On macOS, COINUTILS_HAS_LAPACK causes CoinDenseFactorization to +- # call OpenBLAS's dgetrf_single, which uses aligned AVX2 loads +- # (vmovdqa). CoinDenseFactorization's elements_ buffer is allocated +- # with plain new[] (8/16-byte aligned), causing SIGSEGV on the +- # unaligned 32-byte AVX2 access. Disabling LAPACK for CoinUtils +- # makes it fall back to the built-in pure-C pivot factorization, +- # which is correct and fast enough for the small dense bases +- # encountered in practice (e.g. 36-row LP). Clp still gets LAPACK +- # via its own --with-lapack-lflags. +- if platform.system() == "Darwin": +- extra += ["--without-lapack"] +- else: +- extra += [f"--with-lapack-lflags=-L{lib_dir} -lopenblas"] +- extra += [ +- f"--with-amd-cflags=-I{amd_inc}", +- f"--with-amd-lflags=-L{LIB_DIR} -lamd -lsuitesparseconfig", +- ] +- elif name == "Clp": +- # Do NOT pass --with-amd-cflags here: Clp wraps #include +- # inside extern "C" {} in ClpCholeskyUfl.cpp, and SuiteSparse v7's +- # amd.h transitively includes C++ headers ( etc.) which +- # clang rejects inside extern "C". AMD ordering is still available +- # to CBC through CoinUtils which doesn't have this wrapping issue. +- # --without-amd is required (not just omitting the flag): Clp's +- # configure auto-probes default system paths (e.g. +- # /usr/include/suitesparse) for AMD and, if found, compiles +- # ClpCholeskyUfl.cpp against it — but without --with-amd-lflags +- # the resulting libClp fails to link with undefined references to +- # SuiteSparse_malloc/SuiteSparse_free on any host that happens to +- # have a system SuiteSparse package installed. +- extra += [ +- "--without-amd", +- f"--with-lapack-lflags=-L{lib_dir} -lopenblas", +- ] +- if platform.system() == "Darwin": +- # ClpMain.cpp calls openblas_set_num_threads() when CLP_USE_OPENBLAS=1. +- # On macOS two-level namespace, the clp executable must link -lopenblas +- # explicitly — transitive propagation via libClp.dylib is not enough. +- # --with-lapack-lflags covers shared library dependencies but the +- # executable link step needs LDFLAGS for direct symbol resolution. +- darwin_ldflags = f"-L{lib_dir} -lopenblas" +- if extra_ldflags: +- darwin_ldflags += f" {extra_ldflags}" +- extra += [f"LDFLAGS={darwin_ldflags}"] +- ldflags_in_extra = True +- elif platform.system() == "Linux": +- # ClpRacingSolver.cpp resolves openblas_set_num_threads() via +- # dlsym(RTLD_DEFAULT, ...) when CLP_USE_OPENBLAS is defined +- # (which it always is here). glibc < 2.34 (e.g. manylinux2014, +- # manylinux_2_28) keeps dlopen/dlsym in libdl rather than libc, +- # and it is not linked automatically, causing "undefined +- # reference to `dlsym'" when linking libClp.so. Newer glibc +- # (>= 2.34) folds libdl into libc, so -ldl is a harmless no-op +- # there. +- linux_ldflags = "-ldl" +- if extra_ldflags: +- linux_ldflags += f" {extra_ldflags}" +- extra += [f"LDFLAGS={linux_ldflags}"] +- ldflags_in_extra = True +- elif name == "Cbc": +- extra += [ +- "--without-nauty", # symmetry detection via nauty disabled +- "--without-lapack", +- # Enable multi-threaded MIP search (parallel branch-and-bound). +- # Requires pthreads — available on all supported platforms. +- "--enable-cbc-parallel", +- ] +- if platform.system() == "Linux": +- # Same dlsym/libdl requirement as Clp above: CbcModel.cpp and +- # Cbc_C_Interface.cpp also resolve openblas_set_num_threads() +- # and omp_set_num_threads() via dlsym(RTLD_DEFAULT, ...). +- linux_ldflags = "-ldl" +- if extra_ldflags: +- linux_ldflags += f" {extra_ldflags}" +- extra += [f"LDFLAGS={linux_ldflags}"] +- ldflags_in_extra = True +- else: # Osi, Cgl — do not use LAPACK directly +- extra += ["--without-lapack"] +- +- configure = os.path.join(src, "configure") +- # clang (macOS) requires C++17 mode to accept aggregate assignment from +- # braced initializer lists (e.g. CoinDynamicConflictGraph.cpp). +- # -std=c++17 is harmless on GCC as well. +- # Note: -no-undefined is NOT passed here via LDFLAGS because it is a +- # libtool-specific flag, not a raw linker flag. Passing it via LDFLAGS +- # causes configure's own link tests ("C compiler cannot create +- # executables") to fail with exit code 77 on MinGW. COIN-OR's +- # AC_COIN_PROG_LIBTOOL macro already appends -no-undefined to +- # LT_LDFLAGS internally (aclocal.m4), which is the correct path — +- # it reaches libtool only when building shared libraries. +- # Clp and Cbc both check CLP_USE_OPENBLAS to conditionally compile +- # the OpenBLAS thread-count management (openblas_set_num_threads). +- # This enables CbcModel to cap BLAS threads to 1 during parallel B&B, +- # preventing stack overflow crashes on macOS whose secondary threads +- # have a 512 KB default stack (vs 8 MB on Linux). +- openblas_flag = "-DCLP_USE_OPENBLAS=1" if name in ("Clp", "Cbc") else "" +- # -DNDEBUG strips assert()s for release builds (never added by +- # autoconf's own defaults here -- see the is_debug docstring above); +- # debug builds must NOT get it so assertions stay active for gdb/ASan. +- ndebug_flag = "" if is_debug else "-DNDEBUG" +- cxxflags_parts = ["-std=c++17", FP_CONTRACT_OFF] +- if ndebug_flag: +- cxxflags_parts.append(ndebug_flag) +- if extra_cxxflags: +- cxxflags_parts.append(extra_cxxflags) +- if openblas_flag: +- cxxflags_parts.append(openblas_flag) +- cxxflags = " ".join(cxxflags_parts) +- # Also set CFLAGS: the COIN-OR stack is pure C++ (no .c sources as of +- # this writing), so this is mostly a defensive no-op, but configure's +- # own link/feature-detection tests invoke $CC directly and future .c +- # files would silently pick up FMA contraction otherwise. +- cflags_parts = [FP_CONTRACT_OFF] +- if ndebug_flag: +- cflags_parts.append(ndebug_flag) +- configure_args = [ +- configure, *common, *extra, +- f"CXXFLAGS={cxxflags}", f"CFLAGS={' '.join(cflags_parts)}", +- ] +- if extra_ldflags and not ldflags_in_extra: +- configure_args.append(f"LDFLAGS={extra_ldflags}") +- run(*configure_args, cwd=bld, env=env) +- run("make", "-j", NPROC, cwd=bld) +- run("make", "install", cwd=bld) +- +- +-# ── Bundle dynamic dependencies ─────────────────────────────────────────────── +- +-def _is_system_lib(path: str) -> bool: +- """Return True for libs that should NOT be bundled into the wheel.""" +- name = os.path.basename(path) +- if platform.system() == "Linux": +- return bool(_MANYLINUX_ALLOWED.match(name)) +- # macOS: only the standard system library trees are truly "system". +- # A loader-relative (@rpath/@loader_path/@executable_path) install name +- # does NOT necessarily mean the lib has already been bundled: modern +- # Homebrew GCC reports its own runtime libs (libgcc_s, libstdc++, ...) +- # with an @rpath install name from the start, before cbcbox's own +- # bundling pass ever touches them. Those still need to be resolved to +- # a real file on disk and copied in; see _resolve_macos_dep(). +- return path.startswith("/usr/lib/") or path.startswith("/System/") +- +- +-def _resolve_macos_dep(binary: str, dep: str) -> str: +- """Resolve a loader-relative (@rpath/@loader_path/@executable_path) +- dependency reference *dep* found in *binary* to an absolute file path. +- +- Returns "" if it cannot be resolved. +- """ +- if not dep.startswith("@"): +- return dep +- name = os.path.basename(dep) +- base_dir = os.path.dirname(os.path.realpath(binary)) +- +- # 0) @loader_path/@executable_path are directly relative to the +- # binary's own directory -- no need to consult LC_RPATH. +- if dep.startswith("@loader_path/") or dep.startswith("@executable_path/"): +- candidate = os.path.join(base_dir, name) +- if os.path.exists(candidate): +- return candidate +- +- # 1) Look at the binary's own LC_RPATH entries (this is how the +- # dynamic linker would actually resolve an @rpath/ reference). +- if dep.startswith("@rpath/"): +- out = subprocess.run( +- ["otool", "-l", binary], capture_output=True, text=True +- ).stdout +- lines = out.splitlines() +- rpaths = [] +- for i, line in enumerate(lines): +- if line.strip() == "cmd LC_RPATH": +- for j in range(i, min(i + 4, len(lines))): +- m = re.search(r"path (.+) \(offset", lines[j]) +- if m: +- rpaths.append(m.group(1).strip()) +- break +- for rp in rpaths: +- rp = rp.replace("@loader_path", base_dir).replace( +- "@executable_path", base_dir +- ) +- candidate = os.path.join(rp, name) +- if os.path.exists(candidate): +- return candidate +- +- # 2) Fall back to the compiler toolchain -- this covers GCC runtime +- # libs (libgcc_s, libstdc++, libquadmath, libgfortran) that Homebrew +- # GCC reports with an @rpath install name but which live in the +- # toolchain's own lib directory, not next to *binary*. +- for cc in ("gfortran", "gcc", "g++"): +- try: +- r = subprocess.run( +- [cc, "-print-file-name=" + name], +- capture_output=True, text=True, +- ) +- except FileNotFoundError: +- continue +- candidate = r.stdout.strip() +- if candidate and candidate != name and os.path.exists(candidate): +- return candidate +- +- return "" +- +- +-def _soname_linux(lib_path: str) -> str: +- """Return the ELF SONAME of *lib_path*, falling back to its basename.""" +- try: +- r = subprocess.run( +- ["patchelf", "--print-soname", lib_path], +- capture_output=True, text=True, +- ) +- soname = r.stdout.strip() +- if soname: +- return soname +- except Exception: +- pass +- return os.path.basename(lib_path) +- +- +-def _dynamic_deps_linux(path: str) -> dict: +- """Return {soname: resolved_path} for non-system deps on Linux.""" +- out = subprocess.run(["ldd", path], capture_output=True, text=True).stdout +- deps = {} +- for line in out.splitlines(): +- m = re.search(r"\s=>\s(/\S+)", line) +- if m and not _is_system_lib(m.group(1)): +- resolved = m.group(1) +- # Use the ELF soname as the destination filename so the dynamic +- # linker finds it even when ldd reports the versioned real file. +- deps[_soname_linux(resolved)] = resolved +- return deps +- +- +-def _dynamic_deps_macos(path: str) -> list: +- """Return [install_name, ...] for non-system deps on macOS.""" +- out = subprocess.run( +- ["otool", "-L", path], capture_output=True, text=True +- ).stdout +- deps = [] +- for line in out.splitlines()[1:]: +- parts = line.strip().split() +- if parts and not _is_system_lib(parts[0]): +- deps.append(parts[0]) +- return deps +- +- +-def _dynamic_deps_windows(path: str) -> dict: +- """Return {dll_name: source_path} for non-system MinGW DLLs needed by *path*. +- +- Uses objdump (from MinGW64) to list DLL imports, then resolves each name +- against C:\\msys64\\mingw64\\bin\\ and DIST_DIR\\bin\\ (for DLLs installed +- by our own build, such as libopenblas.dll). +- """ +- search_dirs = [r"C:\msys64\mingw64\bin", os.path.join(DIST_DIR, "bin")] +- r = subprocess.run( +- [_MSYS2_BASH, "-lc", +- "export PATH=/mingw64/bin:/usr/bin:$PATH && " +- f"objdump -p {shlex.quote(_win_to_msys2(path))} | grep 'DLL Name:'"], +- capture_output=True, text=True, +- ) +- deps = {} +- for line in r.stdout.splitlines(): +- m = re.search(r"DLL Name:\s+(\S+\.dll)", line, re.IGNORECASE) +- if m: +- name = m.group(1) +- if not _WIN_SYS_DLL.match(name): +- for search_dir in search_dirs: +- candidate = os.path.join(search_dir, name) +- if os.path.exists(candidate): +- deps[name] = candidate +- break +- return deps +- +- +-def bundle_dynamic_deps(binary: str, lib_dir: str, _visited: set = None): +- """ +- Inspect *binary* for non-system dynamic dependencies and handle them so +- the wheel is self-contained: +- +- Linux — copies each .so to *lib_dir* and uses patchelf to set an +- $ORIGIN-relative RPATH on both the binary and every copied lib. +- macOS — copies each .dylib to *lib_dir*, rewrites the install-name +- reference inside *binary* to @rpath/name, sets the copied +- lib's own id to @rpath/name, and adds an @loader_path rpath +- to the binary. +- Windows — copies each non-system MinGW DLL next to the binary (in its +- own directory); no rpath patching needed since Windows searches +- the executable's directory first. +- +- Recurses into copied libraries so transitive deps are also covered. +- If everything was statically linked this function is a no-op. +- """ +- if _visited is None: +- _visited = set() +- os.makedirs(lib_dir, exist_ok=True) +- +- in_lib_dir = ( +- os.path.dirname(os.path.realpath(binary)) == os.path.realpath(lib_dir) +- ) +- +- if platform.system() == "Linux": +- rpath = "$ORIGIN" if in_lib_dir else "$ORIGIN/../lib" +- subprocess.run(["patchelf", "--set-rpath", rpath, binary], check=True) +- +- for name, src_path in _dynamic_deps_linux(binary).items(): +- if name in _visited: +- continue +- _visited.add(name) +- dst = os.path.join(lib_dir, name) +- if not os.path.exists(dst): +- shutil.copy2(src_path, dst) +- os.chmod(dst, 0o755) +- bundle_dynamic_deps(dst, lib_dir, _visited) +- +- elif platform.system() == "Darwin": +- rpath = "@loader_path" if in_lib_dir else "@loader_path/../lib" +- # Silently ignore "already exists" errors from install_name_tool. +- subprocess.run( +- ["install_name_tool", "-add_rpath", rpath, binary], +- capture_output=True, +- ) +- +- for install_name in _dynamic_deps_macos(binary): +- name = os.path.basename(install_name) +- +- # Always resolve a real on-disk source for this dependency (needed +- # to copy it into lib_dir even when `binary`'s reference is +- # already @rpath/name and needs no rewrite -- e.g. Homebrew GCC's +- # own libgcc_s reported natively via @rpath). +- src_path = install_name +- if install_name.startswith("@"): +- resolved = _resolve_macos_dep(binary, install_name) +- if not resolved: +- print( +- f"warning: could not resolve {install_name} " +- f"referenced by {binary}; not bundled, may " +- f"fail to load at runtime", +- file=sys.stderr, +- ) +- src_path = resolved or None +- +- # Always fix up *this* binary's own reference, regardless of +- # whether the target dependency file has already been bundled +- # ("visited") via some other referencing binary. The previous +- # code skipped this whenever `name in _visited`, which meant +- # only the *first* binary reaching a given dependency (in DFS +- # traversal order) got its reference rewritten to @rpath -- +- # every other binary kept the absolute build-machine path. +- if install_name != f"@rpath/{name}": +- subprocess.run( +- ["install_name_tool", "-change", install_name, f"@rpath/{name}", binary], +- check=True, +- ) +- +- if name in _visited: +- continue +- _visited.add(name) +- +- dst = os.path.join(lib_dir, name) +- if not os.path.exists(dst) and src_path: +- shutil.copy2(src_path, dst) +- os.chmod(dst, 0o755) +- if os.path.exists(dst): +- # Normalize the lib's own id to @rpath/name. This also +- # covers libraries that were already sitting in lib_dir +- # from the start (e.g. sibling COIN-OR libs built straight +- # there) and never went through the "freshly copied" path +- # above, which previously left their LC_ID_DYLIB as an +- # absolute build-machine path. +- subprocess.run( +- ["install_name_tool", "-id", f"@rpath/{name}", dst], +- capture_output=True, +- ) +- bundle_dynamic_deps(dst, lib_dir, _visited) +- +- elif platform.system() == "Windows": +- # On Windows the loader finds DLLs in the same directory as the +- # executable. Copy all non-system MinGW DLLs there and recurse for +- # transitive dependencies (libgfortran → libquadmath, etc.). +- bin_dir = os.path.dirname(os.path.realpath(binary)) +- for name, src_path in _dynamic_deps_windows(binary).items(): +- if name in _visited: +- continue +- _visited.add(name) +- dst = os.path.join(bin_dir, name) +- if not os.path.exists(dst): +- shutil.copy2(src_path, dst) +- os.chmod(dst, 0o755) +- bundle_dynamic_deps(dst, lib_dir, _visited) +- +- +-# ── Windows: mirror DLLs into lib/ ─────────────────────────────────────────── +- +-def copy_win_dlls_to_lib(dist_dir=None): +- """Copy every DLL from bin/ into lib/ as well. +- +- On Windows, libtool installs DLLs to bindir (bin/) and import libs +- (.dll.a) to libdir (lib/). python-mip and other ctypes/cffi consumers +- locate libraries via cbcbox.cbc_lib_dir() which points to lib/, so all +- DLLs must also be present there — both the COIN-OR ones (libCbc.dll, …) +- and the bundled MinGW runtime DLLs they depend on. +- """ +- if dist_dir is None: +- dist_dir = DIST_DIR +- bin_dir = os.path.join(dist_dir, "bin") +- lib_dir = os.path.join(dist_dir, "lib") +- os.makedirs(lib_dir, exist_ok=True) +- for dll in _glob.glob(os.path.join(bin_dir, "*.dll")): +- dst = os.path.join(lib_dir, os.path.basename(dll)) +- if not os.path.exists(dst): +- shutil.copy2(dll, dst) +- +- +- +-_cbc_exe = "cbc.exe" if platform.system() == "Windows" else "cbc" +- +-# CBCBOX_BUILD_VARIANT controls which variants are compiled (used by CI to run +-# builds in parallel jobs): +-# unset / "all" — build generic, AVX2 (x86_64), and debug: +-# x86_64: generic + avx2 + debug_avx2 +-# other arch: generic + debug +-# "generic" — build only the generic variant (no debug) +-# "avx2" — build only the AVX2 variant (x86_64 only, no debug) +-# "debug" — build only the non-AVX2 debug variant (all platforms) +-# COIN-OR flags: -O1 -g -fno-omit-frame-pointer +-# AddressSanitizer automatically enabled on Linux and macOS. +-# "debug_avx2" — build only the debug+AVX2 variant (x86_64 only) +-# COIN-OR flags: -O1 -g -march=haswell -fno-omit-frame-pointer +-# AddressSanitizer automatically enabled on Linux and macOS. +-# Use this to debug AVX2-specific issues or to run a debuggable +-# binary that exercises the same AVX2 code paths as the release. +-# "release_symbols" — build only the generic *release* variant (same CXXFLAGS, +-# same optimisation level, same -DNDEBUG) with -g added on +-# top, so the resulting binary is bit-for-bit behaviourally +-# identical to what actually ships, just with debug symbols. +-# Use this (under gdb) to get a real backtrace for bugs that +-# only reproduce with release codegen/optimisation and do +-# NOT reproduce in the "debug" (-O1) variant. +-# In "avx2" mode AMD is still compiled (as a link-time static dep for the +-# COIN-OR AVX2 build) but with Haswell-optimised flags. +-# OpenBLAS and AMD are always built without debug flags; only the COIN-OR stack +-# (CoinUtils, Osi, Clp, Cgl, Cbc) carries debug symbols in debug builds. +-# +-# CBCBOX_BUILD_ONLY=1 — skip the wheel-packaging stage (used by CI compile +-# jobs that only need the binaries, not the final .whl). +-_build_variant = os.environ.get("CBCBOX_BUILD_VARIANT", "") +-_build_release_symbols = _build_variant == "release_symbols" +-_build_generic = _build_variant not in ("avx2", "debug", "debug_avx2", "release_symbols") +-_build_avx2 = _is_x86_64() and _build_variant not in ("generic", "debug", "debug_avx2", "release_symbols") +-# Debug (non-AVX2): built by default on non-x86_64; on x86_64 only when +-# explicitly requested so we avoid a redundant generic-debug wheel alongside +-# the haswell-debug one. +-_build_debug = _build_variant == "debug" or (_build_variant == "" and not _is_x86_64()) +-# Debug+AVX2: built by default on x86_64 (the only debug variant for that arch). +-_build_debug_avx2 = _is_x86_64() and (_build_variant == "debug_avx2" or _build_variant == "") +- +-if _build_variant == "debug_avx2" and not _is_x86_64(): +- print( +- f"[cbcbox] WARNING: CBCBOX_BUILD_VARIANT=debug_avx2 is only supported on x86_64 " +- f"(current arch: {platform.machine()}). No build will be performed.", +- flush=True, +- ) +- +-# Flags applied to all C/C++ code in the AVX2 variant, including the static +-# AMD library that is ultimately linked into COIN-OR .so/.dylib. +-_AVX2_CFLAGS = "-O3 -march=haswell" +- +-# OpenBLAS DYNAMIC_ARCH kernel lists for x86_64 (reduces library size by +-# dropping pre-2010 architectures that are unlikely to be encountered). +-# CPUs not covered by the list fall back to the generic kernel automatically. +-# Generic: SSE4.2 baseline (Nehalem 2008+) through current Zen. +-# AVX2: only AVX2-capable targets (Haswell 2013+). +-# ZEN2, ZEN3, SKYLAKE are excluded: OpenBLAS 0.3.31 compiles their generic C +-# dot/nrm2 kernels with AVX2+FMA intrinsics but omits -mfma from the compiler +-# invocation, causing an "always_inline target mismatch" build error. +-# ZEN2/ZEN3 users fall back to the ZEN kernel (still AVX2); SKYLAKE falls back +-# to HASWELL — both negligible in practice. +-_OPENBLAS_DYNLIST_X86_GENERIC = "NEHALEM SANDYBRIDGE HASWELL SKYLAKEX ZEN" +-_OPENBLAS_DYNLIST_X86_AVX2 = "HASWELL SKYLAKEX" +- +-# AddressSanitizer is automatically enabled for debug builds on Linux and macOS. +-# Windows/MinGW does not support ASan, so it is skipped there. +-# OpenBLAS is always built without ASan to avoid false positives from its +-# hand-optimised BLAS kernels; only the COIN-OR stack is instrumented. +-# Debug build flags: -O1 -g (no ASan — ASan proved too fragile across +-# the different CI container toolchains; debug info alone is sufficient +-# for stack traces and debugger use). +-_DEBUG_CFLAGS = "-O1 -g -fno-omit-frame-pointer" +-_DEBUG_LDFLAGS = "" +-_DEBUG_AVX2_CFLAGS = "-O1 -g -march=haswell -fno-omit-frame-pointer" +-_DEBUG_AVX2_LDFLAGS = "" +- +-if _build_generic and not os.path.exists(os.path.join(DIST_DIR, "bin", _cbc_exe)): +- build_openblas(DIST_DIR, dynamic_arch=True, +- dynamic_list=_OPENBLAS_DYNLIST_X86_GENERIC if _is_x86_64() else None) +- build_amd() +- build_coin_or(DIST_DIR) +- +-# Release-with-symbols build: identical CXXFLAGS/optimisation/-DNDEBUG to the +-# generic release build above, with only "-g -fno-omit-frame-pointer" added. +-# Used to get real backtraces (via gdb) for bugs that reproduce only with +-# release codegen and do NOT reproduce in the (differently-optimised) "debug" +-# variant. Built into DIST_DIR itself (mutually exclusive with _build_generic) +-# since it's meant to stand in for the release binary, not ship alongside it. +-if _build_release_symbols and not os.path.exists(os.path.join(DIST_DIR, "bin", _cbc_exe)): +- build_openblas(DIST_DIR, dynamic_arch=True, +- dynamic_list=_OPENBLAS_DYNLIST_X86_GENERIC if _is_x86_64() else None) +- build_amd() +- build_coin_or(DIST_DIR, extra_cxxflags="-g -fno-omit-frame-pointer") +- +-# AVX2-optimised build: all x86_64 platforms (Linux, macOS, Windows). +-# In avx2-only mode AMD is still needed as a link-time static dep for the +-# COIN-OR AVX2 build; compile it with Haswell flags so it is fully +-# optimised and ends up embedded in the AVX2 COIN-OR shared libraries. +-if (not _build_generic and not _build_debug and not _build_debug_avx2 +- and not _build_release_symbols +- and not os.path.exists(os.path.join(LIB_DIR, "libamd.a"))): +- build_amd(extra_cflags=_AVX2_CFLAGS) +- +-if _build_avx2 and not os.path.exists(os.path.join(DIST_DIR_AVX2, "bin", _cbc_exe)): +- # Use DYNAMIC_ARCH=1 rather than TARGET=HASWELL for OpenBLAS: TARGET=HASWELL +- # mandates aligned AVX2 loads in dgetrf_single; CoinDenseFactorization may +- # pass unaligned data which causes SIGSEGV on macOS Intel. DYNAMIC_ARCH +- # dispatches to the best available kernel at runtime without that assumption. +- # The Haswell advantage comes from -march=haswell on the COIN-OR stack. +- build_openblas(DIST_DIR_AVX2, dynamic_arch=True, +- dynamic_list=_OPENBLAS_DYNLIST_X86_AVX2) +- build_coin_or(DIST_DIR_AVX2, extra_cxxflags=f"{_AVX2_CFLAGS} -DCOIN_AVX2=4") +- +-# Debug build: OpenBLAS is built WITHOUT debug flags (no debug info for +-# third-party code); only the COIN-OR stack gets full debug flags + optional +-# ASan. AMD is a static link-time dep shared with the base dist. +-if _build_debug and not os.path.exists(os.path.join(DIST_DIR_DEBUG, "bin", _cbc_exe)): +- build_openblas(DIST_DIR_DEBUG, dynamic_arch=True, +- dynamic_list=_OPENBLAS_DYNLIST_X86_GENERIC if _is_x86_64() else None) +- if not os.path.exists(os.path.join(LIB_DIR, "libamd.a")): +- build_amd() +- build_coin_or(DIST_DIR_DEBUG, +- extra_cxxflags=_DEBUG_CFLAGS, +- extra_ldflags=_DEBUG_LDFLAGS, +- is_debug=True) +- +-# Debug+AVX2 build (x86_64 only): like the debug build but with -march=haswell +-# and -DCOIN_AVX2=4 so the binary exercises the same AVX2 code paths as the +-# release. OpenBLAS is built WITHOUT debug flags (no debug info for third-party +-# code); only the COIN-OR stack gets debug+AVX2 flags. +-# AMD is shared with the base dist (a pure integer lib, no SIMD). +-if _build_debug_avx2 and not os.path.exists(os.path.join(DIST_DIR_DEBUG_AVX2, "bin", _cbc_exe)): +- build_openblas(DIST_DIR_DEBUG_AVX2, dynamic_arch=True, +- dynamic_list=_OPENBLAS_DYNLIST_X86_AVX2) +- if not os.path.exists(os.path.join(LIB_DIR, "libamd.a")): +- build_amd() +- build_coin_or(DIST_DIR_DEBUG_AVX2, +- extra_cxxflags=f"{_DEBUG_AVX2_CFLAGS} -DCOIN_AVX2=4", +- extra_ldflags=_DEBUG_AVX2_LDFLAGS, +- is_debug=True) +- +- +-def _bundle_dist(dist_dir): +- """Patch rpaths / bundle DLLs for all binaries and shared libs in *dist_dir*.""" +- lib_dir = os.path.join(dist_dir, "lib") +- bundle_dir = os.path.join(dist_dir, "bin") if platform.system() == "Windows" else lib_dir +- +- # Share one _visited set across every top-level call below so a +- # dependency file bundled/recursed-into while processing one binary is +- # recognized as already-copied when reached again from a different +- # top-level binary -- while each binary's own load-command references +- # are still always fixed up regardless (see bundle_dynamic_deps). +- _visited = set() +- +- for bin_name in [_cbc_exe, "clp.exe" if platform.system() == "Windows" else "clp"]: +- bin_path = os.path.join(dist_dir, "bin", bin_name) +- if os.path.exists(bin_path): +- bundle_dynamic_deps(bin_path, bundle_dir, _visited) +- +- if platform.system() == "Windows": +- shared_pattern = os.path.join(dist_dir, "bin", "*.dll") +- elif platform.system() == "Darwin": +- shared_pattern = os.path.join(lib_dir, "*.dylib") +- else: +- shared_pattern = os.path.join(lib_dir, "*.so*") +- +- for lib_path in _glob.glob(shared_pattern): +- if not os.path.islink(lib_path): +- bundle_dynamic_deps(lib_path, bundle_dir, _visited) +- if platform.system() == "Darwin": +- # Unconditionally normalize this dylib's own LC_ID_DYLIB to +- # @rpath/name. bundle_dynamic_deps only does this when the +- # file is reached as some *other* binary's dependency; libs +- # that happen to never appear in anyone's dependency list +- # (or are reached only here, first) would otherwise keep +- # their absolute build-machine install name forever. +- subprocess.run( +- ["install_name_tool", "-id", f"@rpath/{os.path.basename(lib_path)}", lib_path], +- capture_output=True, +- ) +- +- if platform.system() == "Windows": +- copy_win_dlls_to_lib(dist_dir) +- +- +-_bundle_dist(DIST_DIR) +-if _build_avx2 and os.path.isdir(DIST_DIR_AVX2): +- _bundle_dist(DIST_DIR_AVX2) +-if _build_debug and os.path.isdir(DIST_DIR_DEBUG): +- _bundle_dist(DIST_DIR_DEBUG) +-if _build_debug_avx2 and os.path.isdir(DIST_DIR_DEBUG_AVX2): +- _bundle_dist(DIST_DIR_DEBUG_AVX2) +- +- +-def _remove_static_libs(dist_dir: str) -> None: +- """Remove static (.a) and libtool (.la) files — not needed at runtime.""" +- lib_dir = os.path.join(dist_dir, "lib") +- removed = [] +- for pattern in ("*.a", "*.la"): +- for path in _glob.glob(os.path.join(lib_dir, pattern)): +- os.remove(path) +- removed.append(os.path.basename(path)) +- if removed: +- print(f"[cbcbox] removed static libs from {lib_dir}: {', '.join(sorted(removed))}") +- +- +-def _strip_binaries(dist_dir: str) -> None: +- """Strip debug/unneeded symbols from shared libraries and executables. +- +- Linux: ``strip --strip-unneeded`` removes unreferenced symbols while +- keeping all exported symbols needed for dynamic linking. +- macOS: ``strip -x`` removes local/private symbols, preserving exports. +- Windows: skipped — strip on MinGW DLLs is unreliable. +- Callers must NOT invoke this on debug builds (symbols are intentional). +- """ +- system = platform.system() +- if system == "Windows": +- return +- +- if system == "Darwin": +- strip_args = ["strip", "-x"] +- lib_glob = os.path.join(dist_dir, "lib", "*.dylib") +- else: +- strip_args = ["strip", "--strip-unneeded"] +- lib_glob = os.path.join(dist_dir, "lib", "*.so*") +- +- targets = [ +- p for p in +- _glob.glob(lib_glob) + _glob.glob(os.path.join(dist_dir, "bin", "*")) +- if os.path.isfile(p) and not os.path.islink(p) +- ] +- +- stripped, skipped = [], [] +- for path in targets: +- r = subprocess.run([*strip_args, path], capture_output=True) +- (stripped if r.returncode == 0 else skipped).append(os.path.basename(path)) +- +- if stripped: +- print(f"[cbcbox] stripped symbols: {', '.join(sorted(stripped))}", flush=True) +- if skipped: +- print(f"[cbcbox] strip skipped (already stripped?): {', '.join(sorted(skipped))}", flush=True) +- +- +-# On Windows, libCbc.dll.a is the MinGW import library needed to link +-# against the Cbc DLL (e.g. by scripts/build_mip_debug_cuts.sh, which runs +-# as a separate CI step *after* build_ext / CBCBOX_BUILD_ONLY=1 completes). +-# Keep static libs around for the debug variants in that case so the +-# mip-debug-cuts diagnostic tool can still be linked; they're stripped from +-# the final wheel by the "Package ..." jobs' own build (CBCBOX_BUILD_ONLY +-# unset), which is a separate setup.py invocation. +-_keep_debug_static_libs = ( +- platform.system() == "Windows" and os.environ.get("CBCBOX_BUILD_ONLY") +-) +- +-_remove_static_libs(DIST_DIR) +-# Skip stripping for release_symbols builds: stripping would defeat the +-# entire point (removing the -g symbols we just added for gdb backtraces). +-if not _build_release_symbols: +- _strip_binaries(DIST_DIR) +-if _build_avx2 and os.path.isdir(DIST_DIR_AVX2): +- _remove_static_libs(DIST_DIR_AVX2) +- _strip_binaries(DIST_DIR_AVX2) +-if _build_debug and os.path.isdir(DIST_DIR_DEBUG) and not _keep_debug_static_libs: +- _remove_static_libs(DIST_DIR_DEBUG) +-if _build_debug_avx2 and os.path.isdir(DIST_DIR_DEBUG_AVX2) and not _keep_debug_static_libs: +- _remove_static_libs(DIST_DIR_DEBUG_AVX2) +- +- +-# ── Package ─────────────────────────────────────────────────────────────────── +-# Skip the wheel-packaging stage when CBCBOX_BUILD_ONLY=1 (CI compile jobs +-# that only need the pre-built binaries, not the final .whl). +-if not os.environ.get("CBCBOX_BUILD_ONLY"): +- long_description = """\ +-**cbcbox** ships pre-built binaries of the +-[CBC](https://github.com/coin-or/Cbc) MILP solver (COIN-OR Branch and Cut), +-built from the latest next branch of the COIN-OR repositories. +- +-Built with: +-- OpenBLAS for optimised BLAS/LAPACK routines +-- AMD reordering (SuiteSparse) for improved numerical performance +-- zlib for reading compressed MPS/LP files +-""" +- +- # setuptools requires package_dir values to be relative paths (not absolute). +- # Use a staging dir inside THIS_DIR so we can pass a simple relative name. +- _PKG_STAGING = "_cbcbox_pkg" +- _pkg_dir = os.path.join(THIS_DIR, _PKG_STAGING) +- if os.path.exists(_pkg_dir): +- shutil.rmtree(_pkg_dir) +- os.makedirs(_pkg_dir) +- +- try: +- dist_name = "cbc_dist" +- shutil.copytree(DIST_DIR, os.path.join(_pkg_dir, dist_name), dirs_exist_ok=True) +- +- package_data_patterns = [f"{dist_name}/**"] +- +- # Include the AVX2-optimised build when present (x86_64 Linux/macOS/Windows). +- dist_name_avx2 = "cbc_dist_avx2" +- if os.path.isdir(DIST_DIR_AVX2): +- shutil.copytree(DIST_DIR_AVX2, os.path.join(_pkg_dir, dist_name_avx2), +- dirs_exist_ok=True) +- package_data_patterns.append(f"{dist_name_avx2}/**") +- +- # Include the debug build when present (non-x86_64: generic debug; +- # x86_64: debug+AVX2 only, shipped as cbc_dist_debug_avx2). +- dist_name_debug = "cbc_dist_debug" +- if os.path.isdir(DIST_DIR_DEBUG): +- shutil.copytree(DIST_DIR_DEBUG, os.path.join(_pkg_dir, dist_name_debug), +- dirs_exist_ok=True) +- package_data_patterns.append(f"{dist_name_debug}/**") +- +- dist_name_debug_avx2 = "cbc_dist_debug_avx2" +- if os.path.isdir(DIST_DIR_DEBUG_AVX2): +- shutil.copytree(DIST_DIR_DEBUG_AVX2, os.path.join(_pkg_dir, dist_name_debug_avx2), +- dirs_exist_ok=True) +- package_data_patterns.append(f"{dist_name_debug_avx2}/**") +- +- for fname in ["__init__.py", "__main__.py"]: +- shutil.copy2(os.path.join(THIS_DIR, "src", fname), os.path.join(_pkg_dir, fname)) +- +- setup( +- cmdclass=cmdclass, +- long_description=long_description, +- long_description_content_type="text/markdown", +- packages=["cbcbox"], +- zip_safe=False, +- package_dir={"cbcbox": _PKG_STAGING}, +- package_data={ +- "cbcbox": package_data_patterns, +- }, +- ) +- finally: +- shutil.rmtree(_pkg_dir, ignore_errors=True) diff --git a/math/py-cbcbox/files/patch-src_____init____.py b/math/py-cbcbox/files/patch-src_____init____.py new file mode 100644 index 000000000000..0483adbd8598 --- /dev/null +++ b/math/py-cbcbox/files/patch-src_____init____.py @@ -0,0 +1,55 @@ +-- Make cbc_dist_dir() return the system LOCALBASE directory instead of a +-- bundled cbc_dist subdirectory. The other path helpers then automatically +-- resolve to the math/cbc binary, libraries and headers installed by FreeBSD. + +--- src/__init__.py.orig 2026-08-17 02:08:17 UTC ++++ src/__init__.py +@@ -56,45 +56,11 @@ def cbc_dist_dir() -> str: + + + def cbc_dist_dir() -> str: +- pkg_dir = os.path.abspath(os.path.dirname(__file__)) +- base_dir = os.path.join(pkg_dir, "cbc_dist") +- avx2_dir = os.path.join(pkg_dir, "cbc_dist_avx2") +- debug_dir = os.path.join(pkg_dir, "cbc_dist_debug") +- debug_avx2_dir = os.path.join(pkg_dir, "cbc_dist_debug_avx2") ++ """Return the system LOCALBASE directory where math/cbc is installed.""" ++ chosen = "@LOCALBASE@" + +- override = os.environ.get("CBCBOX_BUILD", "").strip().lower() +- if override == "avx2": +- if not os.path.isdir(avx2_dir): +- raise RuntimeError( +- "CBCBOX_BUILD=avx2 requested but the AVX2 build is not " +- "present in this installation (x86_64 Linux/macOS/Windows only)." +- ) +- chosen = avx2_dir +- elif override == "debug": +- # On x86_64 the only debug variant shipped is debug+AVX2 (haswell). +- # On other architectures the plain debug build is used. +- if os.path.isdir(debug_avx2_dir): +- chosen = debug_avx2_dir +- elif os.path.isdir(debug_dir): +- chosen = debug_dir +- else: +- raise RuntimeError( +- "CBCBOX_BUILD=debug requested but no debug build is present " +- "in this installation." +- ) +- elif override == "generic": +- chosen = base_dir +- elif override: +- raise ValueError( +- f"Unknown CBCBOX_BUILD value {override!r}. " +- "Use 'generic', 'avx2', or 'debug'." +- ) +- else: +- # Auto-select: prefer AVX2 when available and supported by the CPU. +- chosen = avx2_dir if os.path.isdir(avx2_dir) and _has_avx2() else base_dir +- + verbose = os.environ.get("CBCBOX_VERBOSE", "").strip() == "1" +- if override or verbose: ++ if verbose: + _print_build_info(chosen) + + return chosen diff --git a/math/py-cbcbox/files/patch-tests_conftest.py b/math/py-cbcbox/files/patch-tests_conftest.py new file mode 100644 index 000000000000..b8a4cda5c437 --- /dev/null +++ b/math/py-cbcbox/files/patch-tests_conftest.py @@ -0,0 +1,29 @@ +-- Make the test fixture report a single "system" CBC variant that points at +-- the math/cbc binary, since this port does not bundle cbc_dist* builds. + +--- tests/conftest.py.orig 2026-09-08 23:28:23 UTC ++++ tests/conftest.py +@@ -23,19 +23,12 @@ def _get_build_variants(): + + + def _get_build_variants(): +- """Return [(variant_name, binary_path), ...] for every available CBC build. ++ """Return a single system CBC build variant. + +- Always includes 'generic'; adds 'avx2' when cbc_dist_avx2/ is present +- (x86_64 Linux/macOS/Windows wheels only). ++ The FreeBSD port uses the system math/cbc binary instead of bundled ++ cbc_dist* subdirectories. + """ +- pkg_dir = os.path.abspath(os.path.dirname(cbcbox.__file__)) +- cbc_exe = "cbc.exe" if os.name == "nt" else "cbc" +- variants = [] +- for name, subdir in [("generic", "cbc_dist"), ("avx2", "cbc_dist_avx2")]: +- binary = os.path.join(pkg_dir, subdir, "bin", cbc_exe) +- if os.path.isfile(binary): +- variants.append((name, binary)) +- return variants ++ return [("system", cbcbox.cbc_bin_path())] + + + def pytest_configure(config): diff --git a/math/py-cbcbox/files/patch-tests_test__solve.py b/math/py-cbcbox/files/patch-tests_test__solve.py new file mode 100644 index 000000000000..b5c0d52b3ff0 --- /dev/null +++ b/math/py-cbcbox/files/patch-tests_test__solve.py @@ -0,0 +1,52 @@ +-- Reduce the test set to a small representative subset of MIP instances and +-- lower the per-instance CBC time limit from 2000 s to 120 s so that the +-- pytest suite finishes in a reasonable amount of time during port testing. +-- The full 30-instance list with 2000-second limits is aimed at slow CI runners +-- and includes cases that do not reliably reach optimality with the system +-- CBC within 120 s when run in parallel mode. + +--- tests/test_solve.py.orig 2026-08-17 02:08:17 UTC ++++ tests/test_solve.py +@@ -36,36 +36,12 @@ CASES = [ + # Time limits are generous to avoid false failures on slow CI runners. + # subprocess timeout = cbc_time_limit + 120 s. + CASES = [ +- ("pp08a.mps.gz", 7350.0, 2000), +- ("sprint_hidden06_j.mps.gz", 130.0, 2000), +- ("air03.mps.gz", 340160.0, 2000), +- ("air04.mps.gz", 56137.0, 2000), +- ("air05.mps.gz", 26374.0, 2000), +- ("nw04.mps.gz", 16862.0, 2000), +- ("mzzv11.mps.gz", -21718.0, 2000), +- ("trd445c.mps.gz", -153419.078836, 2000), +- ("nursesched-sprint02.mps.gz", 58.0, 2000), +- ("stein45.mps.gz", 30.0, 2000), +- ("neos-810286.mps.gz", 2877.0, 2000), +- ("neos-1281048.mps.gz", 601.0, 2000), +- ("j3050_8.mps.gz", 1.0, 2000), +- ("qiu.mps.gz", -132.873136947, 2000), +- ("gesa2-o.mps.gz", 25779856.3717, 2000), +- ("pk1.mps.gz", 11.0, 2000), +- ("mas76.mps.gz", 40005.054142, 2000), +- ("app1-1.mps.gz", -3.0, 2000), +- ("eil33-2.mps.gz", 934.007916, 2000), +- ("fiber.mps.gz", 405935.18, 2000), +- ("neos-2987310-joes.mps.gz", -607702988.291, 2000), +- ("neos-827175.mps.gz", 112.00152, 2000), +- ("neos-3083819-nubu.mps.gz", 6307996.0, 2000), +- ("markshare_4_0.mps.gz", 1.0, 2000), +- ("irp.mps.gz", 12159.49283539698, 2000), +- ("qap10.mps.gz", 340.0, 2000), +- ("swath1.mps.gz", 379.07129575, 2000), +- ("physiciansched6-2.mps.gz", 49324.0, 2000), +- ("mzzv42z.mps.gz", -20540.0, 2000), +- ("neos-860300.mps.gz", 3201.0, 2000), ++ # Small representative subset that solves quickly with the system CBC. ++ ("pp08a.mps.gz", 7350.0, 120), ++ ("stein45.mps.gz", 30.0, 120), ++ ("pk1.mps.gz", 11.0, 120), ++ ("air03.mps.gz", 340160.0, 120), ++ ("qiu.mps.gz", -132.873136947, 120), + ] + + _REL_TOL = 1e-6 # relative tolerance for objective comparison diff --git a/math/py-cbcbox/pkg-descr b/math/py-cbcbox/pkg-descr new file mode 100644 index 000000000000..2555975fd4db --- /dev/null +++ b/math/py-cbcbox/pkg-descr @@ -0,0 +1,9 @@ +cbcbox provides Python access to the COIN-OR CBC (Coin-or Branch and Cut) +mixed-integer linear programming (MILP) solver. + +It exposes helpers for locating the CBC binary, library and include +directories, and a Python module entry point that forwards to the CBC +executable. + +This FreeBSD port uses the system math/cbc CBC installation instead of +the bundled binaries that upstream ships in its wheels.