or-tools: 9.12 -> 9.14
Some of the patches we ship(ed) had to be regenerated. or-tools now uses abseil-cpp_202505, and we need to ensure everything uses that, to avoid another version of abseil leaking into the build. pybind11 needs to be downgraded to 2.13.6 (I vendored the old nixpkgs expression for that). pybind11 also needs to be patched to fix math_opt's elemental python binding. or-tools ships this in their repo as a patch to their pybind11_bazel dep, including a patch file there. I decided to pop one layer of patching, and vendor the patch in here. Upstream also patches their scipopts-scip dependency, renaming some CMake targets, so we need to patch our dependency as well (and restore find_package() discovery that broke).
This commit is contained in:
+25
-6
@@ -1,6 +1,20 @@
|
||||
From 077295f6ede59d9e2413b2d19f38cf63b64f4fec Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
|
||||
Date: Tue, 21 Oct 2025 17:05:59 +0300
|
||||
Subject: [PATCH] Do not try to copy pybind11_abseil status extension module
|
||||
|
||||
The module is already installed in the correct location. And even if not,
|
||||
it should be done as part of the pybind11_abseil build ...
|
||||
---
|
||||
cmake/python.cmake | 5 -----
|
||||
ortools/python/setup.py.in | 4 ----
|
||||
2 files changed, 9 deletions(-)
|
||||
|
||||
diff --git a/cmake/python.cmake b/cmake/python.cmake
|
||||
index 2112ceeb66..db15434303 100644
|
||||
--- a/cmake/python.cmake
|
||||
+++ b/cmake/python.cmake
|
||||
@@ -322,7 +322,6 @@
|
||||
@@ -326,7 +326,6 @@ file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/init/python/__init__.py CONTENT "")
|
||||
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/linear_solver/__init__.py CONTENT "")
|
||||
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/linear_solver/python/__init__.py CONTENT "")
|
||||
if(BUILD_MATH_OPT)
|
||||
@@ -8,17 +22,17 @@
|
||||
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/math_opt/__init__.py CONTENT "")
|
||||
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/math_opt/core/__init__.py CONTENT "")
|
||||
file(GENERATE OUTPUT ${PYTHON_PROJECT_DIR}/math_opt/core/python/__init__.py CONTENT "")
|
||||
@@ -635,9 +634,6 @@
|
||||
@@ -680,9 +679,6 @@ add_custom_command(
|
||||
COMMAND ${CMAKE_COMMAND} -E
|
||||
$<IF:$<BOOL:${BUILD_MATH_OPT}>,copy,true>
|
||||
$<TARGET_FILE:math_opt_pybind11> ${PYTHON_PROJECT}/math_opt/core/python
|
||||
$<TARGET_FILE:math_opt_io_pybind11> ${PYTHON_PROJECT}/math_opt/io/python
|
||||
- COMMAND ${CMAKE_COMMAND} -E
|
||||
- $<IF:$<BOOL:${BUILD_MATH_OPT}>,copy,true>
|
||||
- $<TARGET_FILE:status_py_extension_stub> ${PYTHON_PROJECT}/../pybind11_abseil
|
||||
COMMAND ${CMAKE_COMMAND} -E
|
||||
$<IF:$<TARGET_EXISTS:pdlp_pybind11>,copy,true>
|
||||
$<$<TARGET_EXISTS:pdlp_pybind11>:$<TARGET_FILE:pdlp_pybind11>> ${PYTHON_PROJECT}/pdlp/python
|
||||
@@ -696,7 +692,6 @@
|
||||
@@ -744,7 +740,6 @@ add_custom_command(
|
||||
COMMAND ${stubgen_EXECUTABLE} -p ortools.constraint_solver.pywrapcp --output .
|
||||
COMMAND ${stubgen_EXECUTABLE} -p ortools.linear_solver.pywraplp --output .
|
||||
COMMAND ${stubgen_EXECUTABLE} -p ortools.linear_solver.python.model_builder_helper --output .
|
||||
@@ -26,9 +40,11 @@
|
||||
COMMAND ${stubgen_EXECUTABLE} -p ortools.math_opt.core.python.solver --output .
|
||||
COMMAND ${stubgen_EXECUTABLE} -p ortools.pdlp.python.pdlp --output .
|
||||
COMMAND ${stubgen_EXECUTABLE} -p ortools.sat.python.cp_model_helper --output .
|
||||
diff --git a/ortools/python/setup.py.in b/ortools/python/setup.py.in
|
||||
index 0aeaa900ef..ae4fa07815 100644
|
||||
--- a/ortools/python/setup.py.in
|
||||
+++ b/ortools/python/setup.py.in
|
||||
@@ -83,10 +83,6 @@
|
||||
@@ -83,10 +83,6 @@ setup(
|
||||
'*.pyi',
|
||||
'py.typed'
|
||||
],
|
||||
@@ -37,5 +53,8 @@
|
||||
- '*.pyi'
|
||||
- ],
|
||||
'@PYTHON_PROJECT@.math_opt':['*.pyi'],
|
||||
'@PYTHON_PROJECT@.math_opt.python':['*.pyi'],
|
||||
'@PYTHON_PROJECT@.math_opt.core.python':[
|
||||
'$<TARGET_FILE_NAME:math_opt_pybind11>',
|
||||
--
|
||||
2.51.0
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
From 46e7d2cccd029a2c4215ce9b0c3bf72b2f2dd398 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
|
||||
Date: Thu, 2 Jan 2025 16:32:05 +0100
|
||||
Subject: [PATCH] Fix up broken CMake rules for bundled pybind stuff
|
||||
|
||||
Unfortunately, upstream only uses and tests the bundled code, and the
|
||||
unbundled cases are bitrotting.
|
||||
---
|
||||
cmake/system_deps.cmake | 1 +
|
||||
1 files changed, 1 insertion(+)
|
||||
|
||||
diff --git a/cmake/system_deps.cmake b/cmake/system_deps.cmake
|
||||
index d9ae923..0c176a8 100644
|
||||
--- a/cmake/system_deps.cmake
|
||||
+++ b/cmake/system_deps.cmake
|
||||
@@ -94,6 +94,7 @@ endif()
|
||||
|
||||
# Check language Dependencies
|
||||
if(BUILD_PYTHON)
|
||||
+ find_package(Python REQUIRED Interpreter Development.Module)
|
||||
if(NOT BUILD_pybind11 AND NOT TARGET pybind11::pybind11_headers)
|
||||
find_package(pybind11 REQUIRED)
|
||||
endif()
|
||||
--
|
||||
2.47.1
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
lib,
|
||||
callPackage,
|
||||
|
||||
abseil-cpp_202407,
|
||||
abseil-cpp_202505,
|
||||
bzip2,
|
||||
cbc,
|
||||
cmake,
|
||||
@@ -16,7 +16,7 @@
|
||||
glpk,
|
||||
highs,
|
||||
pkg-config,
|
||||
protobuf_29,
|
||||
protobuf_31,
|
||||
python3,
|
||||
re2,
|
||||
swig,
|
||||
@@ -32,12 +32,45 @@ let
|
||||
# protobuf. Do not un-pin these, even if you're upgrading them to
|
||||
# what might happen to be the latest version at the current moment;
|
||||
# future upgrades *will* break the build.
|
||||
abseil-cpp = abseil-cpp_202407;
|
||||
protobuf = protobuf_29.override { inherit abseil-cpp; };
|
||||
abseil-cpp = abseil-cpp_202505;
|
||||
protobuf = protobuf_31.override { inherit abseil-cpp; };
|
||||
python-protobuf = python3.pkgs.protobuf5.override { inherit protobuf; };
|
||||
pybind11-protobuf = callPackage ./pybind11-protobuf.nix {
|
||||
inherit (python3.pkgs) buildPythonPackage pybind11;
|
||||
|
||||
pybind11 = callPackage ./pybind11-2.13.6.nix {
|
||||
inherit (python3.pkgs)
|
||||
buildPythonPackage
|
||||
cmake
|
||||
ninja
|
||||
numpy
|
||||
pytestCheckHook
|
||||
pythonOlder
|
||||
setuptools
|
||||
;
|
||||
python = python3;
|
||||
};
|
||||
pybind11-abseil = python3.pkgs.pybind11-abseil.override {
|
||||
inherit abseil-cpp pybind11;
|
||||
};
|
||||
pybind11-protobuf = callPackage ./pybind11-protobuf.nix {
|
||||
inherit (python3.pkgs) buildPythonPackage;
|
||||
inherit pybind11;
|
||||
};
|
||||
# re2 must also use the same abseil version, else these two versions will conflict during linking
|
||||
_re2 = re2.override { inherit abseil-cpp; };
|
||||
|
||||
# 77a28070b9c4c83995ac6bbfa9544722ff3342ce renamed the scip cmake target(s) differently
|
||||
# to what upstream still calls it. Apply this patch to scipopt-scip.
|
||||
_scipopt-scip = scipopt-scip.overrideAttrs (old: {
|
||||
patches = old.patches or [ ] ++ [
|
||||
# from https://github.com/google/or-tools/commit/77a28070b9c4c83995ac6bbfa9544722ff3342ce#diff-c95174a817e73db366d414af1e329c1856f70e5158ed3994d43da88765ccc98f
|
||||
./scip.patch
|
||||
];
|
||||
# Their patch forgets to find_package() soplex, bring it back.
|
||||
postPatch = (old.postPatch or "") + ''
|
||||
substituteInPlace CMakeLists.txt \
|
||||
--replace-fail 'message(STATUS "Finding Soplex...")' 'find_package(SOPLEX CONFIG HINTS ''${SOPLEX_DIR})'
|
||||
'';
|
||||
});
|
||||
|
||||
# local revert of 58daf511687f191829238fc7f571e08dc9dedf56,
|
||||
# working around https://github.com/google/or-tools/issues/4911
|
||||
@@ -61,13 +94,13 @@ let
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "or-tools";
|
||||
version = "9.12";
|
||||
version = "9.14";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "google";
|
||||
repo = "or-tools";
|
||||
tag = "v${finalAttrs.version}";
|
||||
hash = "sha256-5rFeAK51+BfjIyu/5f5ptaKMD7Hd20yHa2Vj3O3PkLU=";
|
||||
hash = "sha256-FxKe3uY4L33mavwC2aanji3fY9dPqpkwVqi6PNjovSA=";
|
||||
};
|
||||
|
||||
patches = [
|
||||
@@ -78,11 +111,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
url = "https://build.opensuse.org/public/source/science/google-or-tools/0001-Revert-python-Fix-python-install-on-windows-breaks-L.patch?rev=19";
|
||||
hash = "sha256-BNB3KlgjpWcZtb9e68Jkc/4xC4K0c+Iisw0eS6ltYXE=";
|
||||
})
|
||||
(fetchpatch {
|
||||
name = "0001-Fix-up-broken-CMake-rules-for-bundled-pybind-stuff.patch";
|
||||
url = "https://build.opensuse.org/public/source/science/google-or-tools/0001-Fix-up-broken-CMake-rules-for-bundled-pybind-stuff.patch?rev=19";
|
||||
hash = "sha256-r38ZbRkEW1ZvJb0Uf56c0+HcnfouZZJeEYlIK7quSjQ=";
|
||||
})
|
||||
./0001-Fix-up-broken-CMake-rules-for-bundled-pybind-stuff.patch
|
||||
(fetchpatch {
|
||||
name = "math_opt-only-run-SCIP-tests-if-enabled.patch";
|
||||
url = "https://github.com/google/or-tools/commit/b5a2f8ac40dd4bfa4359c35570733171454ec72b.patch";
|
||||
@@ -112,6 +141,8 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
(lib.cmakeFeature "CMAKE_INSTALL_INCLUDEDIR" "include")
|
||||
(lib.cmakeFeature "CMAKE_INSTALL_LIBDIR" "lib")
|
||||
(lib.cmakeBool "FETCH_PYTHON_DEPS" false)
|
||||
# not packaged in nixpkgs
|
||||
(lib.cmakeBool "USE_fuzztest" false)
|
||||
(lib.cmakeBool "USE_GLPK" true)
|
||||
(lib.cmakeBool "USE_SCIP" withScip)
|
||||
(lib.cmakeFeature "Python3_EXECUTABLE" "${python3.pythonOnBuildForHost.interpreter}")
|
||||
@@ -149,14 +180,14 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
gtest
|
||||
_highs
|
||||
python3.pkgs.absl-py
|
||||
python3.pkgs.pybind11
|
||||
python3.pkgs.pybind11-abseil
|
||||
pybind11
|
||||
pybind11-abseil
|
||||
pybind11-protobuf
|
||||
python3.pkgs.pytest
|
||||
python3.pkgs.scipy
|
||||
python3.pkgs.setuptools
|
||||
python3.pkgs.wheel
|
||||
re2
|
||||
_re2
|
||||
zlib
|
||||
];
|
||||
propagatedBuildInputs = [
|
||||
@@ -170,7 +201,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
]
|
||||
++ lib.optionals withScip [
|
||||
# Needed for downstream cmake consumers to not need to set SCIP_ROOT explicitly
|
||||
scipopt-scip
|
||||
_scipopt-scip
|
||||
];
|
||||
|
||||
nativeCheckInputs = [
|
||||
@@ -183,6 +214,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
];
|
||||
|
||||
# some tests fail on aarch64-linux and hang on darwin
|
||||
# https://github.com/google/or-tools/issues/4746
|
||||
doCheck = stdenv.hostPlatform.isx86_64 && stdenv.hostPlatform.isLinux;
|
||||
|
||||
preCheck = ''
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
# This is pybind11 2.13.6 from an earlier nixpkgs version, with the
|
||||
# parts from https://github.com/google/or-tools/commit/7f29b27840436e19b6530d5c7f23eeadd819bd3e
|
||||
# applied.
|
||||
{
|
||||
stdenv,
|
||||
lib,
|
||||
buildPythonPackage,
|
||||
pythonOlder,
|
||||
fetchFromGitHub,
|
||||
cmake,
|
||||
ninja,
|
||||
setuptools,
|
||||
boost,
|
||||
eigen,
|
||||
python,
|
||||
catch2,
|
||||
numpy,
|
||||
pytestCheckHook,
|
||||
libxcrypt,
|
||||
makeSetupHook,
|
||||
}:
|
||||
let
|
||||
setupHook = makeSetupHook {
|
||||
name = "pybind11-setup-hook";
|
||||
substitutions = {
|
||||
out = placeholder "out";
|
||||
pythonInterpreter = python.pythonOnBuildForHost.interpreter;
|
||||
pythonIncludeDir = "${python}/include/python${python.pythonVersion}";
|
||||
pythonSitePackages = "${python}/${python.sitePackages}";
|
||||
};
|
||||
} ./pybind11-setup-hook.sh;
|
||||
in
|
||||
buildPythonPackage rec {
|
||||
pname = "pybind11";
|
||||
version = "2.13.6";
|
||||
pyproject = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "pybind";
|
||||
repo = "pybind11";
|
||||
tag = "v${version}";
|
||||
hash = "sha256-SNLdtrOjaC3lGHN9MAqTf51U9EzNKQLyTMNPe0GcdrU=";
|
||||
};
|
||||
|
||||
# https://github.com/google/or-tools/commit/7f29b27840436e19b6530d5c7f23eeadd819bd3e
|
||||
patches = [ ./pybind11.patch ];
|
||||
|
||||
build-system = [
|
||||
cmake
|
||||
ninja
|
||||
setuptools
|
||||
];
|
||||
|
||||
buildInputs = lib.optionals (pythonOlder "3.9") [ libxcrypt ];
|
||||
propagatedNativeBuildInputs = [ setupHook ];
|
||||
|
||||
dontUseCmakeBuildDir = true;
|
||||
|
||||
# Don't build tests if not needed, read the doInstallCheck value at runtime
|
||||
preConfigure = ''
|
||||
if [ -n "$doInstallCheck" ]; then
|
||||
cmakeFlagsArray+=("-DBUILD_TESTING=ON")
|
||||
fi
|
||||
'';
|
||||
|
||||
cmakeFlags = [
|
||||
"-DBoost_INCLUDE_DIR=${lib.getDev boost}/include"
|
||||
"-DCATCH_INCLUDE_DIR=${lib.getDev catch2}/include/catch2"
|
||||
"-DEIGEN3_INCLUDE_DIR=${lib.getDev eigen}/include/eigen3"
|
||||
]
|
||||
++ lib.optionals (python.isPy3k && !stdenv.cc.isClang) [ "-DPYBIND11_CXX_STANDARD=-std=c++17" ];
|
||||
|
||||
postBuild = ''
|
||||
# build tests
|
||||
make -j $NIX_BUILD_CORES
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
make install
|
||||
# Symlink the CMake-installed headers to the location expected by setuptools
|
||||
mkdir -p $out/include/${python.libPrefix}
|
||||
ln -sf $out/include/pybind11 $out/include/${python.libPrefix}/pybind11
|
||||
'';
|
||||
|
||||
nativeCheckInputs = [
|
||||
catch2
|
||||
numpy
|
||||
pytestCheckHook
|
||||
];
|
||||
|
||||
disabledTestPaths = [
|
||||
# require dependencies not available in nixpkgs
|
||||
"tests/test_embed/test_trampoline.py"
|
||||
"tests/test_embed/test_interpreter.py"
|
||||
# numpy changed __repr__ output of numpy dtypes
|
||||
"tests/test_numpy_dtypes.py"
|
||||
# no need to test internal packaging
|
||||
"tests/extra_python_package/test_files.py"
|
||||
# tests that try to parse setuptools stdout
|
||||
"tests/extra_setuptools/test_setuphelper.py"
|
||||
];
|
||||
|
||||
disabledTests = lib.optionals stdenv.hostPlatform.isDarwin [
|
||||
# expects KeyError, gets RuntimeError
|
||||
# https://github.com/pybind/pybind11/issues/4243
|
||||
"test_cross_module_exception_translator"
|
||||
];
|
||||
|
||||
postCheck = ''
|
||||
make cpptest
|
||||
'';
|
||||
|
||||
hardeningDisable = lib.optional stdenv.hostPlatform.isMusl "fortify";
|
||||
|
||||
meta = {
|
||||
homepage = "https://github.com/pybind/pybind11";
|
||||
changelog = "https://github.com/pybind/pybind11/blob/${src.rev}/docs/changelog.rst";
|
||||
description = "Seamless operability between C++11 and Python";
|
||||
mainProgram = "pybind11-config";
|
||||
longDescription = ''
|
||||
Pybind11 is a lightweight header-only library that exposes
|
||||
C++ types in Python and vice versa, mainly to create Python
|
||||
bindings of existing C++ code.
|
||||
'';
|
||||
license = lib.licenses.bsd3;
|
||||
maintainers = with lib.maintainers; [
|
||||
yuriaisaka
|
||||
dotlambda
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -4,22 +4,22 @@
|
||||
buildPythonPackage,
|
||||
fetchFromGitHub,
|
||||
cmake,
|
||||
abseil-cpp_202407,
|
||||
protobuf_29,
|
||||
abseil-cpp_202505,
|
||||
protobuf,
|
||||
pybind11,
|
||||
zlib,
|
||||
}:
|
||||
|
||||
buildPythonPackage {
|
||||
pname = "pybind11-protobuf";
|
||||
version = "0-unstable-2025-02-10";
|
||||
version = "0-unstable-2025-10-29";
|
||||
pyproject = false;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "pybind";
|
||||
repo = "pybind11_protobuf";
|
||||
rev = "f02a2b7653bc50eb5119d125842a3870db95d251";
|
||||
hash = "sha256-jlZcxQKYYYvTOGhk+0Sgtek4oKy6R1wDGiBOf2t+KiU=";
|
||||
rev = "4825dca68c8de73f5655fc50ce79c49c4d814652";
|
||||
hash = "sha256-SeIUyWLeThfBX3SljLdG7CbENdbuJG+X0+h/gn/ATWE=";
|
||||
};
|
||||
|
||||
patches = [
|
||||
@@ -28,11 +28,16 @@ buildPythonPackage {
|
||||
./add-install-target-for-cmake-builds.patch
|
||||
];
|
||||
|
||||
postPatch = ''
|
||||
substituteInPlace cmake/dependencies/CMakeLists.txt \
|
||||
--replace-fail 'find_package(protobuf 5.29.2 REQUIRED)' 'find_package(protobuf REQUIRED)'
|
||||
'';
|
||||
|
||||
nativeBuildInputs = [ cmake ];
|
||||
|
||||
buildInputs = [
|
||||
abseil-cpp_202407
|
||||
protobuf_29
|
||||
abseil-cpp_202505
|
||||
protobuf
|
||||
pybind11
|
||||
zlib
|
||||
];
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Tell the pybind11 CMake module where to find host platform Python. This is
|
||||
# required when cross-compiling.
|
||||
pybind11CMakeFlags () {
|
||||
cmakeFlagsArray+=(
|
||||
'-DPYBIND11_PYTHONLIBS_OVERWRITE=OFF'
|
||||
'-DPYTHON_EXECUTABLE=@pythonInterpreter@'
|
||||
'-DPYTHON_INCLUDE_DIR=@pythonIncludeDir@'
|
||||
'-DPYTHON_SITE_PACKAGES=@pythonSitePackages@'
|
||||
)
|
||||
}
|
||||
|
||||
preConfigureHooks+=(pybind11CMakeFlags)
|
||||
@@ -0,0 +1,452 @@
|
||||
diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h
|
||||
index 71bc5902..6a148e74 100644
|
||||
--- a/include/pybind11/stl.h
|
||||
+++ b/include/pybind11/stl.h
|
||||
@@ -11,10 +11,14 @@
|
||||
|
||||
#include "pybind11.h"
|
||||
#include "detail/common.h"
|
||||
+#include "detail/descr.h"
|
||||
+#include "detail/type_caster_base.h"
|
||||
|
||||
#include <deque>
|
||||
+#include <initializer_list>
|
||||
#include <list>
|
||||
#include <map>
|
||||
+#include <memory>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
@@ -35,6 +39,89 @@
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
|
||||
+//
|
||||
+// Begin: Equivalent of
|
||||
+// https://github.com/google/clif/blob/ae4eee1de07cdf115c0c9bf9fec9ff28efce6f6c/clif/python/runtime.cc#L388-L438
|
||||
+/*
|
||||
+The three `PyObjectTypeIsConvertibleTo*()` functions below are
|
||||
+the result of converging the behaviors of pybind11 and PyCLIF
|
||||
+(http://github.com/google/clif).
|
||||
+
|
||||
+Originally PyCLIF was extremely far on the permissive side of the spectrum,
|
||||
+while pybind11 was very far on the strict side. Originally PyCLIF accepted any
|
||||
+Python iterable as input for a C++ `vector`/`set`/`map` argument, as long as
|
||||
+the elements were convertible. The obvious (in hindsight) problem was that
|
||||
+any empty Python iterable could be passed to any of these C++ types, e.g. `{}`
|
||||
+was accepted for C++ `vector`/`set` arguments, or `[]` for C++ `map` arguments.
|
||||
+
|
||||
+The functions below strike a practical permissive-vs-strict compromise,
|
||||
+informed by tens of thousands of use cases in the wild. A main objective is
|
||||
+to prevent accidents and improve readability:
|
||||
+
|
||||
+- Python literals must match the C++ types.
|
||||
+
|
||||
+- For C++ `set`: The potentially reducing conversion from a Python sequence
|
||||
+ (e.g. Python `list` or `tuple`) to a C++ `set` must be explicit, by going
|
||||
+ through a Python `set`.
|
||||
+
|
||||
+- However, a Python `set` can still be passed to a C++ `vector`. The rationale
|
||||
+ is that this conversion is not reducing. Implicit conversions of this kind
|
||||
+ are also fairly commonly used, therefore enforcing explicit conversions
|
||||
+ would have an unfavorable cost : benefit ratio; more sloppily speaking,
|
||||
+ such an enforcement would be more annoying than helpful.
|
||||
+*/
|
||||
+
|
||||
+inline bool PyObjectIsInstanceWithOneOfTpNames(PyObject *obj,
|
||||
+ std::initializer_list<const char *> tp_names) {
|
||||
+ if (PyType_Check(obj)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ const char *obj_tp_name = Py_TYPE(obj)->tp_name;
|
||||
+ for (const auto *tp_name : tp_names) {
|
||||
+ if (std::strcmp(obj_tp_name, tp_name) == 0) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+inline bool PyObjectTypeIsConvertibleToStdVector(PyObject *obj) {
|
||||
+ if (PySequence_Check(obj) != 0) {
|
||||
+ return !PyUnicode_Check(obj) && !PyBytes_Check(obj);
|
||||
+ }
|
||||
+ return (PyGen_Check(obj) != 0) || (PyAnySet_Check(obj) != 0)
|
||||
+ || PyObjectIsInstanceWithOneOfTpNames(
|
||||
+ obj, {"dict_keys", "dict_values", "dict_items", "map", "zip"});
|
||||
+}
|
||||
+
|
||||
+inline bool PyObjectTypeIsConvertibleToStdSet(PyObject *obj) {
|
||||
+ return (PyAnySet_Check(obj) != 0) || PyObjectIsInstanceWithOneOfTpNames(obj, {"dict_keys"});
|
||||
+}
|
||||
+
|
||||
+inline bool PyObjectTypeIsConvertibleToStdMap(PyObject *obj) {
|
||||
+ if (PyDict_Check(obj)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Implicit requirement in the conditions below:
|
||||
+ // A type with `.__getitem__()` & `.items()` methods must implement these
|
||||
+ // to be compatible with https://docs.python.org/3/c-api/mapping.html
|
||||
+ if (PyMapping_Check(obj) == 0) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ PyObject *items = PyObject_GetAttrString(obj, "items");
|
||||
+ if (items == nullptr) {
|
||||
+ PyErr_Clear();
|
||||
+ return false;
|
||||
+ }
|
||||
+ bool is_convertible = (PyCallable_Check(items) != 0);
|
||||
+ Py_DECREF(items);
|
||||
+ return is_convertible;
|
||||
+}
|
||||
+
|
||||
+//
|
||||
+// End: Equivalent of clif/python/runtime.cc
|
||||
+//
|
||||
+
|
||||
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
|
||||
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
|
||||
template <typename T, typename U>
|
||||
@@ -66,17 +153,10 @@ private:
|
||||
}
|
||||
void reserve_maybe(const anyset &, void *) {}
|
||||
|
||||
-public:
|
||||
- bool load(handle src, bool convert) {
|
||||
- if (!isinstance<anyset>(src)) {
|
||||
- return false;
|
||||
- }
|
||||
- auto s = reinterpret_borrow<anyset>(src);
|
||||
- value.clear();
|
||||
- reserve_maybe(s, &value);
|
||||
- for (auto entry : s) {
|
||||
+ bool convert_iterable(const iterable &itbl, bool convert) {
|
||||
+ for (const auto &it : itbl) {
|
||||
key_conv conv;
|
||||
- if (!conv.load(entry, convert)) {
|
||||
+ if (!conv.load(it, convert)) {
|
||||
return false;
|
||||
}
|
||||
value.insert(cast_op<Key &&>(std::move(conv)));
|
||||
@@ -84,6 +164,29 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
+ bool convert_anyset(anyset s, bool convert) {
|
||||
+ value.clear();
|
||||
+ reserve_maybe(s, &value);
|
||||
+ return convert_iterable(s, convert);
|
||||
+ }
|
||||
+
|
||||
+public:
|
||||
+ bool load(handle src, bool convert) {
|
||||
+ if (!PyObjectTypeIsConvertibleToStdSet(src.ptr())) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (isinstance<anyset>(src)) {
|
||||
+ value.clear();
|
||||
+ return convert_anyset(reinterpret_borrow<anyset>(src), convert);
|
||||
+ }
|
||||
+ if (!convert) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ assert(isinstance<iterable>(src));
|
||||
+ value.clear();
|
||||
+ return convert_iterable(reinterpret_borrow<iterable>(src), convert);
|
||||
+ }
|
||||
+
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
if (!std::is_lvalue_reference<T>::value) {
|
||||
@@ -115,15 +218,10 @@ private:
|
||||
}
|
||||
void reserve_maybe(const dict &, void *) {}
|
||||
|
||||
-public:
|
||||
- bool load(handle src, bool convert) {
|
||||
- if (!isinstance<dict>(src)) {
|
||||
- return false;
|
||||
- }
|
||||
- auto d = reinterpret_borrow<dict>(src);
|
||||
+ bool convert_elements(const dict &d, bool convert) {
|
||||
value.clear();
|
||||
reserve_maybe(d, &value);
|
||||
- for (auto it : d) {
|
||||
+ for (const auto &it : d) {
|
||||
key_conv kconv;
|
||||
value_conv vconv;
|
||||
if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) {
|
||||
@@ -134,6 +232,25 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
+public:
|
||||
+ bool load(handle src, bool convert) {
|
||||
+ if (!PyObjectTypeIsConvertibleToStdMap(src.ptr())) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (isinstance<dict>(src)) {
|
||||
+ return convert_elements(reinterpret_borrow<dict>(src), convert);
|
||||
+ }
|
||||
+ if (!convert) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ auto items = reinterpret_steal<object>(PyMapping_Items(src.ptr()));
|
||||
+ if (!items) {
|
||||
+ throw error_already_set();
|
||||
+ }
|
||||
+ assert(isinstance<iterable>(items));
|
||||
+ return convert_elements(dict(reinterpret_borrow<iterable>(items)), convert);
|
||||
+ }
|
||||
+
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
dict d;
|
||||
@@ -166,13 +283,35 @@ struct list_caster {
|
||||
using value_conv = make_caster<Value>;
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
- if (!isinstance<sequence>(src) || isinstance<bytes>(src) || isinstance<str>(src)) {
|
||||
+ if (!PyObjectTypeIsConvertibleToStdVector(src.ptr())) {
|
||||
return false;
|
||||
}
|
||||
- auto s = reinterpret_borrow<sequence>(src);
|
||||
+ if (isinstance<sequence>(src)) {
|
||||
+ return convert_elements(src, convert);
|
||||
+ }
|
||||
+ if (!convert) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Designed to be behavior-equivalent to passing tuple(src) from Python:
|
||||
+ // The conversion to a tuple will first exhaust the generator object, to ensure that
|
||||
+ // the generator is not left in an unpredictable (to the caller) partially-consumed
|
||||
+ // state.
|
||||
+ assert(isinstance<iterable>(src));
|
||||
+ return convert_elements(tuple(reinterpret_borrow<iterable>(src)), convert);
|
||||
+ }
|
||||
+
|
||||
+private:
|
||||
+ template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
|
||||
+ void reserve_maybe(const sequence &s, Type *) {
|
||||
+ value.reserve(s.size());
|
||||
+ }
|
||||
+ void reserve_maybe(const sequence &, void *) {}
|
||||
+
|
||||
+ bool convert_elements(handle seq, bool convert) {
|
||||
+ auto s = reinterpret_borrow<sequence>(seq);
|
||||
value.clear();
|
||||
reserve_maybe(s, &value);
|
||||
- for (const auto &it : s) {
|
||||
+ for (const auto &it : seq) {
|
||||
value_conv conv;
|
||||
if (!conv.load(it, convert)) {
|
||||
return false;
|
||||
@@ -182,13 +321,6 @@ struct list_caster {
|
||||
return true;
|
||||
}
|
||||
|
||||
-private:
|
||||
- template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
|
||||
- void reserve_maybe(const sequence &s, Type *) {
|
||||
- value.reserve(s.size());
|
||||
- }
|
||||
- void reserve_maybe(const sequence &, void *) {}
|
||||
-
|
||||
public:
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
@@ -220,43 +352,87 @@ struct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc
|
||||
template <typename Type, typename Alloc>
|
||||
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
|
||||
|
||||
+template <typename ArrayType, typename V, size_t... I>
|
||||
+ArrayType vector_to_array_impl(V &&v, index_sequence<I...>) {
|
||||
+ return {{std::move(v[I])...}};
|
||||
+}
|
||||
+
|
||||
+// Based on https://en.cppreference.com/w/cpp/container/array/to_array
|
||||
+template <typename ArrayType, size_t N, typename V>
|
||||
+ArrayType vector_to_array(V &&v) {
|
||||
+ return vector_to_array_impl<ArrayType, V>(std::forward<V>(v), make_index_sequence<N>{});
|
||||
+}
|
||||
+
|
||||
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
|
||||
struct array_caster {
|
||||
using value_conv = make_caster<Value>;
|
||||
|
||||
private:
|
||||
- template <bool R = Resizable>
|
||||
- bool require_size(enable_if_t<R, size_t> size) {
|
||||
- if (value.size() != size) {
|
||||
- value.resize(size);
|
||||
+ std::unique_ptr<ArrayType> value;
|
||||
+
|
||||
+ template <bool R = Resizable, enable_if_t<R, int> = 0>
|
||||
+ bool convert_elements(handle seq, bool convert) {
|
||||
+ auto l = reinterpret_borrow<sequence>(seq);
|
||||
+ value.reset(new ArrayType{});
|
||||
+ // Using `resize` to preserve the behavior exactly as it was before PR #5305
|
||||
+ // For the `resize` to work, `Value` must be default constructible.
|
||||
+ // For `std::valarray`, this is a requirement:
|
||||
+ // https://en.cppreference.com/w/cpp/named_req/NumericType
|
||||
+ value->resize(l.size());
|
||||
+ size_t ctr = 0;
|
||||
+ for (const auto &it : l) {
|
||||
+ value_conv conv;
|
||||
+ if (!conv.load(it, convert)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ (*value)[ctr++] = cast_op<Value &&>(std::move(conv));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
- template <bool R = Resizable>
|
||||
- bool require_size(enable_if_t<!R, size_t> size) {
|
||||
- return size == Size;
|
||||
- }
|
||||
|
||||
-public:
|
||||
- bool load(handle src, bool convert) {
|
||||
- if (!isinstance<sequence>(src)) {
|
||||
+ template <bool R = Resizable, enable_if_t<!R, int> = 0>
|
||||
+ bool convert_elements(handle seq, bool convert) {
|
||||
+ auto l = reinterpret_borrow<sequence>(seq);
|
||||
+ if (l.size() != Size) {
|
||||
return false;
|
||||
}
|
||||
- auto l = reinterpret_borrow<sequence>(src);
|
||||
- if (!require_size(l.size())) {
|
||||
- return false;
|
||||
- }
|
||||
- size_t ctr = 0;
|
||||
- for (const auto &it : l) {
|
||||
+ // The `temp` storage is needed to support `Value` types that are not
|
||||
+ // default-constructible.
|
||||
+ // Deliberate choice: no template specializations, for simplicity, and
|
||||
+ // because the compile time overhead for the specializations is deemed
|
||||
+ // more significant than the runtime overhead for the `temp` storage.
|
||||
+ std::vector<Value> temp;
|
||||
+ temp.reserve(l.size());
|
||||
+ for (auto it : l) {
|
||||
value_conv conv;
|
||||
if (!conv.load(it, convert)) {
|
||||
return false;
|
||||
}
|
||||
- value[ctr++] = cast_op<Value &&>(std::move(conv));
|
||||
+ temp.emplace_back(cast_op<Value &&>(std::move(conv)));
|
||||
}
|
||||
+ value.reset(new ArrayType(vector_to_array<ArrayType, Size>(std::move(temp))));
|
||||
return true;
|
||||
}
|
||||
|
||||
+public:
|
||||
+ bool load(handle src, bool convert) {
|
||||
+ if (!PyObjectTypeIsConvertibleToStdVector(src.ptr())) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (isinstance<sequence>(src)) {
|
||||
+ return convert_elements(src, convert);
|
||||
+ }
|
||||
+ if (!convert) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Designed to be behavior-equivalent to passing tuple(src) from Python:
|
||||
+ // The conversion to a tuple will first exhaust the generator object, to ensure that
|
||||
+ // the generator is not left in an unpredictable (to the caller) partially-consumed
|
||||
+ // state.
|
||||
+ assert(isinstance<iterable>(src));
|
||||
+ return convert_elements(tuple(reinterpret_borrow<iterable>(src)), convert);
|
||||
+ }
|
||||
+
|
||||
template <typename T>
|
||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||
list l(src.size());
|
||||
@@ -272,12 +448,36 @@ public:
|
||||
return l.release();
|
||||
}
|
||||
|
||||
- PYBIND11_TYPE_CASTER(ArrayType,
|
||||
- const_name<Resizable>(const_name(""), const_name("Annotated["))
|
||||
- + const_name("list[") + value_conv::name + const_name("]")
|
||||
- + const_name<Resizable>(const_name(""),
|
||||
- const_name(", FixedSize(")
|
||||
- + const_name<Size>() + const_name(")]")));
|
||||
+ // Code copied from PYBIND11_TYPE_CASTER macro.
|
||||
+ // Intentionally preserving the behavior exactly as it was before PR #5305
|
||||
+ template <typename T_, enable_if_t<std::is_same<ArrayType, remove_cv_t<T_>>::value, int> = 0>
|
||||
+ static handle cast(T_ *src, return_value_policy policy, handle parent) {
|
||||
+ if (!src) {
|
||||
+ return none().release();
|
||||
+ }
|
||||
+ if (policy == return_value_policy::take_ownership) {
|
||||
+ auto h = cast(std::move(*src), policy, parent);
|
||||
+ delete src; // WARNING: Assumes `src` was allocated with `new`.
|
||||
+ return h;
|
||||
+ }
|
||||
+ return cast(*src, policy, parent);
|
||||
+ }
|
||||
+
|
||||
+ // NOLINTNEXTLINE(google-explicit-constructor)
|
||||
+ operator ArrayType *() { return &(*value); }
|
||||
+ // NOLINTNEXTLINE(google-explicit-constructor)
|
||||
+ operator ArrayType &() { return *value; }
|
||||
+ // NOLINTNEXTLINE(google-explicit-constructor)
|
||||
+ operator ArrayType &&() && { return std::move(*value); }
|
||||
+
|
||||
+ template <typename T_>
|
||||
+ using cast_op_type = movable_cast_op_type<T_>;
|
||||
+
|
||||
+ static constexpr auto name
|
||||
+ = const_name<Resizable>(const_name(""), const_name("Annotated[")) + const_name("list[")
|
||||
+ + value_conv::name + const_name("]")
|
||||
+ + const_name<Resizable>(
|
||||
+ const_name(""), const_name(", FixedSize(") + const_name<Size>() + const_name(")]"));
|
||||
};
|
||||
|
||||
template <typename Type, size_t Size>
|
||||
diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp
|
||||
index e7db8aaa..84bd4755 100644
|
||||
--- a/tests/test_stl.cpp
|
||||
+++ b/tests/test_stl.cpp
|
||||
@@ -193,6 +193,23 @@ TEST_SUBMODULE(stl, m) {
|
||||
m.def("cast_array", []() { return std::array<int, 2>{{1, 2}}; });
|
||||
m.def("load_array", [](const std::array<int, 2> &a) { return a[0] == 1 && a[1] == 2; });
|
||||
|
||||
+ struct NoDefaultCtor {
|
||||
+ explicit constexpr NoDefaultCtor(int val) : val{val} {}
|
||||
+ int val;
|
||||
+ };
|
||||
+
|
||||
+ struct NoDefaultCtorArray {
|
||||
+ explicit constexpr NoDefaultCtorArray(int i)
|
||||
+ : arr{{NoDefaultCtor(10 + i), NoDefaultCtor(20 + i)}} {}
|
||||
+ std::array<NoDefaultCtor, 2> arr;
|
||||
+ };
|
||||
+
|
||||
+ // test_array_no_default_ctor
|
||||
+ py::class_<NoDefaultCtor>(m, "NoDefaultCtor").def_readonly("val", &NoDefaultCtor::val);
|
||||
+ py::class_<NoDefaultCtorArray>(m, "NoDefaultCtorArray")
|
||||
+ .def(py::init<int>())
|
||||
+ .def_readwrite("arr", &NoDefaultCtorArray::arr);
|
||||
+
|
||||
// test_valarray
|
||||
m.def("cast_valarray", []() { return std::valarray<int>{1, 4, 9}; });
|
||||
m.def("load_valarray", [](const std::valarray<int> &v) {
|
||||
diff --git a/tests/test_stl.py b/tests/test_stl.py
|
||||
index 65fda54c..340cdc35 100644
|
||||
--- a/tests/test_stl.py
|
||||
+++ b/tests/test_stl.py
|
||||
@@ -48,6 +48,13 @@ def test_array(doc):
|
||||
)
|
||||
|
||||
|
||||
+def test_array_no_default_ctor():
|
||||
+ lst = m.NoDefaultCtorArray(3)
|
||||
+ assert [e.val for e in lst.arr] == [13, 23]
|
||||
+ lst.arr = m.NoDefaultCtorArray(4).arr
|
||||
+ assert [e.val for e in lst.arr] == [14, 24]
|
||||
+
|
||||
+
|
||||
def test_valarray(doc):
|
||||
"""std::valarray <-> list"""
|
||||
lst = m.cast_valarray()
|
||||
@@ -0,0 +1,145 @@
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 8492dc75..4c12a9bf 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -38,9 +38,11 @@ set(CPACK_PACKAGE_VENDOR "Zuse Institute Berlin")
|
||||
set(CPACK_PACKAGE_CONTACT "http://scipopt.org")
|
||||
include(CPack)
|
||||
|
||||
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
-set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
+if(CMAKE_PROJECT_NAME EQUAL "SCIP")
|
||||
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
+ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
+ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
+endif()
|
||||
|
||||
if(SCIPOptSuite_BINARY_DIR)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${SCIPOptSuite_BINARY_DIR}/bin)
|
||||
@@ -412,22 +414,11 @@ endif()
|
||||
#search the selected LP solver library
|
||||
message(STATUS "Finding Solver \"${LPS}\"")
|
||||
if(LPS STREQUAL "spx")
|
||||
- message(STATUS "Finding Soplex")
|
||||
- find_package(SOPLEX CONFIG HINTS ${SOPLEX_DIR})
|
||||
- if(NOT SOPLEX_FOUND)
|
||||
- # Utilities to automatically download missing dependencies
|
||||
- include(cmake/Dependencies.cmake)
|
||||
- find_or_download_package(
|
||||
- NAME SOPLEX
|
||||
- VERSION 7.0.1
|
||||
- URL https://github.com/scipopt/soplex/archive/refs/tags/release-701.tar.gz
|
||||
- URL_HASH SHA256=80cce994dcbe45fd52b60e31a3aeb5d2c60a7ddbaae495e0ce6bf58481675696
|
||||
- COMPONENTS soplex)
|
||||
- find_package(SOPLEX REQUIRED CONFIG HINTS _deps/local)
|
||||
- endif()
|
||||
- if(NOT SOPLEX_FOUND)
|
||||
+ message(STATUS "Finding Soplex...")
|
||||
+ if(NOT TARGET libsoplex-pic OR NOT TARGET libsoplex)
|
||||
message(FATAL_ERROR "Requested LP solver SoPlex not found.")
|
||||
endif()
|
||||
+ set(SOPLEX_FOUND TRUE)
|
||||
if (DEFINED SOPLEX_WITH_PAPILO)
|
||||
message(STATUS "SOPLEX links PAPILO")
|
||||
if((NOT SCIP_WITH_PAPILO)) # TODO not sure how to handle AUTOBUILD
|
||||
@@ -502,9 +493,9 @@ if(SOPLEX_FOUND)
|
||||
message(STATUS "Finding SOPLEX - found")
|
||||
# SoPlex headers can be directly included
|
||||
include_directories(${SOPLEX_INCLUDE_DIRS})
|
||||
- set(LPS_LIBRARIES ${SOPLEX_LIBRARIES})
|
||||
+ set(LPS_LIBRARIES libsoplex)
|
||||
if(SHARED)
|
||||
- set(LPS_PIC_LIBRARIES ${SOPLEX_PIC_LIBRARIES})
|
||||
+ set(LPS_PIC_LIBRARIES libsoplex-pic)
|
||||
else()
|
||||
set(LPS_PIC_LIBRARIES ${LPS_LIBRARIES})
|
||||
endif()
|
||||
@@ -514,7 +505,7 @@ if(SOPLEX_FOUND)
|
||||
set(lpi lpi/lpi_spx2.cpp)
|
||||
endif()
|
||||
else()
|
||||
- message(STATUS "Support SOPLEX: OFF")
|
||||
+ message(FATAL_ERROR "SOPLEX not found !")
|
||||
endif()
|
||||
|
||||
if(CLP_FOUND)
|
||||
diff --git a/scip-config.cmake.in b/scip-config.cmake.in
|
||||
index 559552f9..682ac40a 100644
|
||||
--- a/scip-config.cmake.in
|
||||
+++ b/scip-config.cmake.in
|
||||
@@ -1,17 +1,16 @@
|
||||
if(NOT TARGET libscip)
|
||||
- include("${CMAKE_CURRENT_LIST_DIR}/scip-targets.cmake")
|
||||
-endif()
|
||||
+ include(CMakeFindDependencyMacro)
|
||||
+ if(@ZIMPL_NEEDED@)
|
||||
+ find_dependency(ZIMPL REQUIRED NO_MODULE)
|
||||
+ endif()
|
||||
+ if(@SOPLEX_NEEDED@)
|
||||
+ find_dependency(SOPLEX REQUIRED NO_MODULE)
|
||||
+ endif()
|
||||
|
||||
-if(@ZIMPL_NEEDED@)
|
||||
- set(ZIMPL_DIR "@CONF_ZIMPL_DIR@")
|
||||
- find_package(ZIMPL QUIET CONFIG)
|
||||
-endif()
|
||||
-
|
||||
-if(@SOPLEX_NEEDED@)
|
||||
- set(SOPLEX_DIR "@CONF_SOPLEX_DIR@")
|
||||
- find_package(SOPLEX QUIET CONFIG)
|
||||
+ include("${CMAKE_CURRENT_LIST_DIR}/scip-targets.cmake")
|
||||
endif()
|
||||
|
||||
+# Legacy
|
||||
set(SCIP_LIBRARIES libscip)
|
||||
set(SCIP_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@")
|
||||
set(SCIP_FOUND TRUE)
|
||||
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
|
||||
index e6fda2d5..2d04b845 100644
|
||||
--- a/src/CMakeLists.txt
|
||||
+++ b/src/CMakeLists.txt
|
||||
@@ -1149,17 +1149,8 @@ install(TARGETS scip libscip EXPORT scip-targets
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
# Add all targets to the build-tree export set
|
||||
-export(TARGETS scip libscip
|
||||
- FILE "${PROJECT_BINARY_DIR}/scip-targets.cmake")
|
||||
-
|
||||
-# make soplex and zimpl dir absolute for the config file
|
||||
-if(SOPLEX_NEEDED)
|
||||
- get_filename_component(CONF_SOPLEX_DIR ${SOPLEX_DIR} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||
-endif()
|
||||
-
|
||||
-if(ZIMPL_NEEDED)
|
||||
- get_filename_component(CONF_ZIMPL_DIR ${ZIMPL_DIR} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||
-endif()
|
||||
+#export(TARGETS scip libscip
|
||||
+# FILE "${PROJECT_BINARY_DIR}/scip-targets.cmake")
|
||||
|
||||
# configure the config file for the build tree
|
||||
set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}")
|
||||
@@ -1175,18 +1166,16 @@ ${PROJECT_BINARY_DIR}/scip-config-version.cmake
|
||||
|
||||
#configure the config file for the install
|
||||
set(CONF_INCLUDE_DIRS "\${CMAKE_CURRENT_LIST_DIR}/../../../include")
|
||||
-if(SOPLEX_NEEDED)
|
||||
- set(CONF_SOPLEX_DIR "\${CMAKE_CURRENT_LIST_DIR}/../soplex")
|
||||
-endif()
|
||||
-if(ZIMPL_NEEDED)
|
||||
- set(CONF_ZIMPL_DIR "\${CMAKE_CURRENT_LIST_DIR}/../zimpl")
|
||||
-endif()
|
||||
configure_file(${PROJECT_SOURCE_DIR}/scip-config.cmake.in
|
||||
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/scip-config.cmake" @ONLY)
|
||||
|
||||
# install the targets of the scip export group and the config file so that other projects
|
||||
# can link easily against scip
|
||||
-install(EXPORT scip-targets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/scip)
|
||||
+install(EXPORT scip-targets
|
||||
+ NAMESPACE SCIP::
|
||||
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/scip
|
||||
+ COMPONENT Devel
|
||||
+)
|
||||
install(FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/scip-config.cmake"
|
||||
${PROJECT_BINARY_DIR}/scip-config-version.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/scip)
|
||||
Reference in New Issue
Block a user