Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coin-cbc: migrate, add v2.10.11, apply autoreconf, use OpenBLAS, add GLPK support #23536

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions recipes/coin-cbc/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
sources:
"2.10.11":
url: "https://github.com/coin-or/Cbc/archive/releases/2.10.11.tar.gz"
sha256: "1fb591dd88336fdaf096b8e42e46111e41671a5eb85d4ee36e45baff1678bd33"
"2.10.5":
url: "https://github.com/coin-or/Cbc/archive/releases/2.10.5.tar.gz"
sha256: "cc44c1950ff4615e7791d7e03ea34318ca001d3cac6dc3f7f5ee392459ce6719"
patches:
"2.10.11":
- patch_file: "patches/0002-pthreads4w.patch"
"2.10.5":
- patch_file: "patches/0001-no-pkg-config-check.patch"
base_path: "source_subfolder"
- patch_file: "patches/0002-pthreads4w.patch"
base_path: "source_subfolder"
235 changes: 128 additions & 107 deletions recipes/coin-cbc/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.files import rename, get, apply_conandata_patches, rmdir, mkdir
from conan.tools.build import cross_building
from conan.tools.scm import Version
from conans import AutoToolsBuildEnvironment, tools
from contextlib import contextmanager
import os
import shutil

required_conan_version = ">=1.47.0"
from conan import ConanFile
from conan.tools.env import VirtualBuildEnv
from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get, mkdir, rename, rmdir
from conan.tools.gnu import Autotools, AutotoolsToolchain, PkgConfigDeps
from conan.tools.layout import basic_layout
from conan.tools.microsoft import is_msvc, msvc_runtime_flag, unix_path, check_min_vs

required_conan_version = ">=1.53.0"


class CoinCbcConan(ConanFile):
name = "coin-cbc"
description = "COIN-OR Branch-and-Cut solver"
topics = ("clp", "simplex", "solver", "linear", "programming")
license = "EPL-2.0"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/coin-or/Clp"
license = ("EPL-2.0",)
settings = "os", "arch", "build_type", "compiler"
homepage = "https://github.com/coin-or/Cbc"
topics = ("cbc", "branch-and-cut", "solver", "linear", "programming")

package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
Expand All @@ -28,145 +31,163 @@ class CoinCbcConan(ConanFile):
"fPIC": True,
"parallel": False,
}
generators = "pkg_config"

_autotools = None

@property
def _source_subfolder(self):
return "source_subfolder"

@property
def _build_subfolder(self):
return "build_subfolder"
def _settings_build(self):
return getattr(self, "settings_build", self.settings)

def export_sources(self):
for patch in self.conan_data.get("patches", {}).get(self.version, []):
self.copy(patch["patch_file"])
export_conandata_patches(self)

def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC

def configure(self):
if self.options.shared:
del self.options.fPIC

def requirements(self):
self.requires("coin-utils/2.11.4")
self.requires("coin-osi/0.108.6")
self.requires("coin-clp/1.17.6")
self.requires("coin-cgl/0.60.3")
if self.settings.compiler == "Visual Studio" and self.options.parallel:
self.requires("pthreads4w/3.0.0")
self.options.rm_safe("fPIC")

@property
def _settings_build(self):
return getattr(self, "settings_build", self.settings)
def layout(self):
basic_layout(self, src_folder="src")

@property
def _user_info_build(self):
return getattr(self, "user_info_build", self.deps_user_info)
def requirements(self):
self.requires("coin-utils/2.11.11")
self.requires("coin-osi/0.108.10")
self.requires("coin-clp/1.17.9", transitive_headers=True, transitive_libs=True)
self.requires("coin-cgl/0.60.8")
Copy link
Contributor

@oleurodecision oleurodecision Dec 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't coin-cgl configured with transitive headers too ?

include/coin/CbcLinked.hpp:#include "CglStored.hpp"
include/coin/CbcCutSubsetModifier.hpp:#include "CglCutGenerator.hpp"
include/coin/CbcCutModifier.hpp:#include "CglCutGenerator.hpp"
include/coin/CbcCutGenerator.hpp:#include "CglCutGenerator.hpp"

self.requires("glpk/4.48")
self.requires("openblas/0.3.28")
if is_msvc(self) and self.options.parallel:
self.requires("pthreads4w/3.0.0")

# TODO: add support for:
# self.requires("metis/5.2.1")
# self.requires("coin-mumps/3.0.5")
# TODO: add support for: Nauty, ASL, DyLP, Vol, Cplex, Gurobi, Highs, Mosek, Soplex, Xpress

def build_requirements(self):
self.tool_requires("gnu-config/cci.20201022")
self.tool_requires("pkgconf/1.7.4")
if self._settings_build.os == "Windows" and not tools.get_env("CONAN_BASH_PATH"):
self.tool_requires("msys2/cci.latest")
if self.settings.compiler == "Visual Studio":
self.tool_requires("automake/1.16.5")

def validate(self):
if self.settings.os == "Windows" and self.options.shared:
raise ConanInvalidConfiguration("coin-cbc does not support shared builds on Windows")
# FIXME: This issue likely comes from very old autotools versions used to produce configure.
if hasattr(self, "settings_build") and cross_building(self) and self.options.shared:
raise ConanInvalidConfiguration("coin-cbc shared not supported yet when cross-building")
self.tool_requires("coin-buildtools/0.8.11")
self.tool_requires("gnu-config/cci.20210814")
if not self.conf.get("tools.gnu:pkg_config", check_type=str):
self.tool_requires("pkgconf/[>=2.2 <3]")
if self._settings_build.os == "Windows":
self.win_bash = True
if not self.conf.get("tools.microsoft.bash:path", check_type=str):
self.tool_requires("msys2/cci.latest")

def source(self):
get(self, **self.conan_data["sources"][self.version],
strip_root=True, destination=self._source_subfolder)

@contextmanager
def _build_context(self):
if self.settings.compiler == "Visual Studio":
with tools.vcvars(self.settings):
env = {
"CC": "{} cl -nologo".format(tools.unix_path(self._user_info_build["automake"].compile)),
"CXX": "{} cl -nologo".format(tools.unix_path(self._user_info_build["automake"].compile)),
"LD": "{} link -nologo".format(tools.unix_path(self._user_info_build["automake"].compile)),
"AR": "{} lib".format(tools.unix_path(self._user_info_build["automake"].ar_lib)),
}
with tools.environment_append(env):
yield
else:
yield

def _configure_autotools(self):
if self._autotools:
return self._autotools
self._autotools = AutoToolsBuildEnvironment(self, win_bash=tools.os_info.is_windows)
self._autotools.libs = []
get(self, **self.conan_data["sources"][self.version], strip_root=True)

def generate(self):
env = VirtualBuildEnv(self)
env.generate()

tc = PkgConfigDeps(self)
tc.generate()

def _add_pkg_config_alias(src_name, dst_name):
shutil.copy(os.path.join(self.generators_folder, f"{src_name}.pc"),
os.path.join(self.generators_folder, f"{dst_name}.pc"))

_add_pkg_config_alias("openblas", "coinblas")
_add_pkg_config_alias("openblas", "coinlapack")
_add_pkg_config_alias("glpk", "coinglpk")

tc = AutotoolsToolchain(self)
yes_no = lambda v: "yes" if v else "no"
configure_args = [
"--enable-shared={}".format(yes_no(self.options.shared)),
"--enable-cbc-parallel={}".format(yes_no(self.options.parallel)),
"--without-blas",
"--without-lapack",
tc.configure_args += [
f"--enable-cbc-parallel={yes_no(self.options.parallel)}",
"--with-blas=BUILD",
"--with-lapack=BUILD",
"--with-glpk=BUILD",
# Only used for sample data
"--without-netlib",
"--without-sample",
"--without-miplib3",
"--disable-dependency-linking",
"F77=unavailable",
]
if self.settings.compiler == "Visual Studio":
self._autotools.cxx_flags.append("-EHsc")
configure_args.append(f"--enable-msvc={self.settings.compiler.runtime}")
if Version(self.settings.compiler.version) >= 12:
self._autotools.flags.append("-FS")
if is_msvc(self):
tc.extra_cxxflags.append("-EHsc")
tc.configure_args.append(f"--enable-msvc={msvc_runtime_flag(self)}")
if check_min_vs(self, "180", raise_invalid=False):
tc.extra_cflags.append("-FS")
tc.extra_cxxflags.append("-FS")
if self.options.parallel:
configure_args.append("--with-pthreadsw32-lib={}".format(tools.unix_path(os.path.join(self.deps_cpp_info["pthreads4w"].lib_paths[0], self.deps_cpp_info["pthreads4w"].libs[0] + ".lib"))))
configure_args.append("--with-pthreadsw32-incdir={}".format(tools.unix_path(self.deps_cpp_info["pthreads4w"].include_paths[0])))
self._autotools.configure(configure_dir=os.path.join(self.source_folder, self._source_subfolder), args=configure_args)
return self._autotools
pthreads4w_info = self.dependencies["pthreads4w"].cpp_info
pthreads_path = os.path.join(pthreads4w_info.libdir, pthreads4w_info.libs[0] + ".lib")
tc.configure_args.append(f"--with-pthreadsw32-lib={unix_path(self, pthreads_path)}")
tc.configure_args.append(f"--with-pthreadsw32-incdir={unix_path(self, pthreads4w_info.includedir)}")
tc.generate()

env = tc.environment()
if is_msvc(self):
automake_conf = self.dependencies.build["automake"].conf_info
compile_wrapper = unix_path(self, automake_conf.get("user.automake:compile-wrapper", check_type=str))
ar_wrapper = unix_path(self, automake_conf.get("user.automake:lib-wrapper", check_type=str))
env.define("CC", f"{compile_wrapper} cl -nologo")
env.define("CXX", f"{compile_wrapper} cl -nologo")
env.define("LD", "link -nologo")
env.define("AR", f"{ar_wrapper} lib")
env.define("NM", "dumpbin -symbols")
env.vars(self).save_script("conanbuild_msvc")
if self._settings_build.os == "Windows":
env.define("PKG_CONFIG_PATH", self.generators_folder)
tc.generate(env)

def build(self):
apply_conandata_patches(self)
shutil.copy(self._user_info_build["gnu-config"].CONFIG_SUB,
os.path.join(self._source_subfolder, "config.sub"))
shutil.copy(self._user_info_build["gnu-config"].CONFIG_GUESS,
os.path.join(self._source_subfolder, "config.guess"))
with self._build_context():
autotools = self._configure_autotools()
autotools.make()
copy(self, "*", os.path.join(self.dependencies.build["coin-buildtools"].package_folder, "res"),
os.path.join(self.source_folder, "BuildTools"))
copy(self, "*", os.path.join(self.dependencies.build["coin-buildtools"].package_folder, "res"),
os.path.join(self.source_folder, "Cbc", "BuildTools"))
for gnu_config in [
self.conf.get("user.gnu-config:config_guess", check_type=str),
self.conf.get("user.gnu-config:config_sub", check_type=str),
]:
config_folder = os.path.join(self.source_folder, "config")
copy(self, os.path.basename(gnu_config), src=os.path.dirname(gnu_config), dst=config_folder)
autotools = Autotools(self)
autotools.autoreconf()
autotools.configure()
autotools.make()

def package(self):
self.copy("LICENSE", src=self._source_subfolder, dst="licenses")
copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
# Installation script expects include/coin to already exist
mkdir(self, os.path.join(self.package_folder, "include", "coin"))
with self._build_context():
autotools = self._configure_autotools()
autotools.install()
autotools = Autotools(self)
autotools.install()

for l in ("CbcSolver", "Cbc", "OsiCbc"):
os.unlink(f"{self.package_folder}/lib/lib{l}.la")
if self.settings.compiler == "Visual Studio":
rename(self,
f"{self.package_folder}/lib/lib{l}.a",
f"{self.package_folder}/lib/{l}.lib")
if is_msvc(self):
rename(self, f"{self.package_folder}/lib/lib{l}.a", f"{self.package_folder}/lib/{l}.lib")

rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
rmdir(self, os.path.join(self.package_folder, "share"))

def package_info(self):
self.cpp_info.components["libcbc"].set_property("pkg_config_name", "cbc")
self.cpp_info.components["libcbc"].libs = ["CbcSolver", "Cbc"]
self.cpp_info.components["libcbc"].includedirs.append(os.path.join("include", "coin"))
self.cpp_info.components["libcbc"].requires = ["coin-clp::osi-clp", "coin-utils::coin-utils", "coin-osi::coin-osi", "coin-cgl::coin-cgl"]
self.cpp_info.components["libcbc"].names["pkg_config"] = "cbc"
self.cpp_info.components["libcbc"].requires = [
"coin-clp::osi-clp",
"coin-utils::coin-utils",
"coin-osi::coin-osi",
"coin-cgl::coin-cgl",
"openblas::openblas",
"glpk::glpk",
]
if self.settings.os in ["Linux", "FreeBSD"] and self.options.parallel:
self.cpp_info.components["libcbc"].system_libs.append("pthread")
if self.settings.os in ["Windows"] and self.options.parallel:
self.cpp_info.components["libcbc"].requires.append("pthreads4w::pthreads4w")

self.cpp_info.components["osi-cbc"].set_property("pkg_config_name", "osi-cbc")
self.cpp_info.components["osi-cbc"].libs = ["OsiCbc"]
self.cpp_info.components["osi-cbc"].requires = ["libcbc"]
self.cpp_info.components["osi-cbc"].names["pkg_config"] = "osi-cbc"

# TODO: remove in conan v2
bin_path = os.path.join(self.package_folder, "bin")
self.output.info("Appending PATH environment variable: {}".format(bin_path))
self.env_info.PATH.append(bin_path)
13 changes: 0 additions & 13 deletions recipes/coin-cbc/all/patches/0001-no-pkg-config-check.patch

This file was deleted.

14 changes: 7 additions & 7 deletions recipes/coin-cbc/all/patches/0002-pthreads4w.patch
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
--- a/Cbc/configure
+++ b/Cbc/configure
@@ -30970,7 +30970,7 @@ cat >>confdefs.h <<\_ACEOF
#define CBC_THREAD 1
_ACEOF

--- a/Cbc/configure.ac
+++ b/Cbc/configure.ac
@@ -179,7 +179,7 @@
if test "$enable_cbc_parallel" = yes; then
# Define the preprocessor macro
AC_DEFINE([CBC_THREAD],[1],[Define to 1 if the SMP version of Cbc should be compiled])
- if test $coin_cxx_is_cl = true ;
+ if test "${with_pthreadsw32_lib+set}" = set ;
then
# TODO we should check whether the library works and pthread.h is indeed there

AC_ARG_WITH(pthreadsw32-lib,
22 changes: 12 additions & 10 deletions recipes/coin-cbc/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
cmake_minimum_required(VERSION 3.1)
project(test_package)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
cmake_minimum_required(VERSION 3.15)
project(test_package LANGUAGES CXX)

include(FindPkgConfig)

pkg_check_modules(OsiCbc REQUIRED IMPORTED_TARGET osi-cbc)

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::OsiCbc)
# The transitive 'coinutils' is added explicitly to work around the linked library order otherwise being:
# OsiCbc CbcSolver Cbc bz2 z OsiCommonTests Osi Cgl ClpSolver Clp OsiClp CoinUtils
# which causes CoinUtils to not find bz2 and z symbols.
pkg_check_modules(OsiCbc REQUIRED IMPORTED_TARGET osi-cbc coinutils)
add_executable(${PROJECT_NAME}_pkgconfig test_package.cpp)
target_link_libraries(${PROJECT_NAME}_pkgconfig PRIVATE PkgConfig::OsiCbc)

find_package(coin-cbc CONFIG REQUIRED)
add_executable(${PROJECT_NAME}_cmake test_package.cpp)
target_link_libraries(${PROJECT_NAME}_cmake PRIVATE coin-cbc::coin-cbc)
Loading