diff --git a/recipes/xgboost/all/conandata.yml b/recipes/xgboost/all/conandata.yml new file mode 100644 index 0000000000000..21096c94b1919 --- /dev/null +++ b/recipes/xgboost/all/conandata.yml @@ -0,0 +1,11 @@ +sources: + "2.0.3": + xgboost: + url: "https://github.com/dmlc/xgboost/archive/refs/tags/v2.0.3.tar.gz" + sha256: "94e5deb27133459ec4172f3fed83971383366ad2a7d646b6f0b51f63484c5138" + dmlc-core: + url: "https://github.com/dmlc/dmlc-core/archive/ea21135fbb141ae103fb5fc960289b5601b468f2.zip" + sha256: "f5bc8789556752d268f0939d4dfd86288954b273e2e35b375649cd062d79c8ee" + gputreeshap: + url: "https://github.com/rapidsai/gputreeshap/archive/787259b412c18ab8d5f24bf2b8bd6a59ff8208f3.zip" + sha256: "071f9aacd0c55ac85059fe7b08768e2e410540e402c55594f7bdc5acd46e3fce" diff --git a/recipes/xgboost/all/conanfile.py b/recipes/xgboost/all/conanfile.py new file mode 100644 index 0000000000000..e54a2e2b185fd --- /dev/null +++ b/recipes/xgboost/all/conanfile.py @@ -0,0 +1,175 @@ +from conan import ConanFile +from conan.errors import ConanInvalidConfiguration +from conan.tools.build import check_min_cppstd, cross_building, stdcpp_library +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.env import VirtualBuildEnv +from conan.tools.files import copy, get, rm, rmdir, save +from conan.tools.microsoft import is_msvc_static_runtime +from conan.tools.scm import Version +import os + +required_conan_version = ">=1.56.0 <2 || >=2.0.6" + + +class XgboostConan(ConanFile): + name = "xgboost" + description = ("Scalable, Portable and Distributed Gradient Boosting (GBDT, GBRT or GBM) Library. " + "Runs on single machine, Hadoop, Spark, Dask, Flink and DataFlow") + license = "Apache-2.0" + url = "https://github.com/conan-io/conan-center-index" + homepage = "https://github.com/dmlc/xgboost" + topics = ("machine-learning", "boosting", "distributed-systems") + + package_type = "library" + settings = "os", "arch", "compiler", "build_type" + options = { + "shared": [True, False], + "fPIC": [True, False], + "openmp": [True, False], + "cuda": [True, False], + "nccl": [True, False], + "per_thread_default_stream": [True, False], + "plugin_rmm": [True, False], + "plugin_federated": [True, False], + "plugin_sycl": [True, False] + } + default_options = { + "shared": False, + "fPIC": True, + "openmp": True, + "cuda": False, + "nccl": False, + "per_thread_default_stream": True, + "plugin_rmm": False, + "plugin_federated": False, + "plugin_sycl": False, + } + options_description = { + "openmp": "Build with OpenMP support", + # CUDA + "cuda": "Build with GPU acceleration", + "nccl": "Build with NCCL to enable distributed GPU support", + "per_thread_default_stream": "Build with per-thread default stream (CUDA)", + # Plugins + "plugin_rmm": "Build with RAPIDS Memory Manager (RMM)", + "plugin_federated": "Build with Federated Learning", + "plugin_sycl": "SYCL plugin (requires Intel icpx compiler)", + } + + @property + def _min_cppstd(self): + return 17 + + @property + def _compilers_minimum_version(self): + # https://github.com/dmlc/xgboost/blob/v2.0.3/CMakeLists.txt#L17-L35 + return { + "apple-clang": "11", + "clang": "9", + "gcc": "8", + "msvc": "192", + "Visual Studio": "16", + } + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + if cross_building(self) or self.settings.os == "Windows": + del self.options.plugin_federated + if self.settings.compiler != "intel-cc": + del self.options.plugin_sycl + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + def layout(self): + cmake_layout(self, src_folder="src") + + def requirements(self): + if self.options.openmp: + self.requires("llvm-openmp/18.1.8") + if self.options.plugin_rmm: + self.requires("rmm/24.04.00") + if self.options.get_safe("plugin_federated"): + self.requires("grpc/1.54.3") + self.requires("protobuf/3.21.12") + + def validate(self): + if self.settings.compiler.cppstd: + check_min_cppstd(self, self._min_cppstd) + minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False) + if minimum_version and Version(self.settings.compiler.version) < minimum_version: + raise ConanInvalidConfiguration( + f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support." + ) + + # Checks from https://github.com/dmlc/xgboost/blob/v2.0.3/CMakeLists.txt#L92-L148 + if self.options.nccl and not self.options.cuda: + raise ConanInvalidConfiguration("`nccl` must be enabled with `cuda` option.") + if self.options.cuda and not self.options.plugin_rmm: + raise ConanInvalidConfiguration("`plugin_rmm` must be enabled with `cuda` option.") + if self.options.get_safe("plugin_federated") and not self.options.shared: + raise ConanInvalidConfiguration("Cannot build static lib with federated learning support") + + def build_requirements(self): + self.tool_requires("cmake/[>=3.18 <4]") + if self.options.get_safe("plugin_federated"): + self.tool_requires("protobuf/") + + def source(self): + get(self, **self.conan_data["sources"][self.version]["xgboost"], strip_root=True) + # TODO: unvendor + get(self, **self.conan_data["sources"][self.version]["dmlc-core"], strip_root=True, destination="dmlc-core") + get(self, **self.conan_data["sources"][self.version]["gputreeshap"], strip_root=True, destination="gputreeshap") + + def generate(self): + tc = CMakeToolchain(self) + tc.variables["USE_OPENMP"] = self.options.openmp + tc.variables["FORCE_SHARED_CRT"] = not is_msvc_static_runtime(self) + tc.variables["USE_CUDA"] = self.options.cuda + tc.variables["USE_NCCL"] = self.options.nccl + tc.variables["USE_PER_THREAD_DEFAULT_STREAM"] = self.options.per_thread_default_stream + tc.variables["PLUGIN_RMM"] = self.options.plugin_rmm + tc.variables["PLUGIN_FEDERATED"] = self.options.get_safe("plugin_federated", False) + tc.variables["PLUGIN_SYCL"] = self.options.get_safe("plugin_sycl", False) + tc.generate() + tc = CMakeDeps(self) + tc.generate() + venv = VirtualBuildEnv(self) + venv.generate() + + def _patch_sources(self): + # Don't build the 'xgboost' executable, + # which has been deprecated in the upcoming release anyway + save(self, os.path.join(self.source_folder, "CMakeLists.txt"), + "\nset_target_properties(runxgboost PROPERTIES EXCLUDE_FROM_ALL TRUE)\n", append=True) + + def build(self): + self._patch_sources() + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + copy(self, "LICENSE", self.source_folder, os.path.join(self.package_folder, "licenses")) + cmake = CMake(self) + cmake.install() + rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig")) + rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) + rm(self, "*.pdb", self.package_folder, recursive=True) + + def package_info(self): + self.cpp_info.set_property("cmake_file_name", "xgboost") + self.cpp_info.set_property("cmake_target_name", "xgboost::xgboost") + self.cpp_info.set_property("pkg_config_name", "xgboost") + + self.cpp_info.libs = ["xgboost"] + # TODO: unvendor dmlc-core + self.cpp_info.libs.append("dmlc") + + if self.settings.os in ["Linux", "FreeBSD"]: + self.cpp_info.system_libs.extend(["m", "pthread"]) + + # For the C API + if stdcpp_library(self): + self.cpp_info.system_libs.append(stdcpp_library(self)) diff --git a/recipes/xgboost/all/test_package/CMakeLists.txt b/recipes/xgboost/all/test_package/CMakeLists.txt new file mode 100644 index 0000000000000..83ad27be7b0b2 --- /dev/null +++ b/recipes/xgboost/all/test_package/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.15) +project(test_package LANGUAGES C) + +find_package(xgboost REQUIRED CONFIG) + +add_executable(${PROJECT_NAME} test_package.c) +target_link_libraries(${PROJECT_NAME} PRIVATE xgboost::xgboost) +target_compile_features(${PROJECT_NAME} PRIVATE c_std_99) diff --git a/recipes/xgboost/all/test_package/conanfile.py b/recipes/xgboost/all/test_package/conanfile.py new file mode 100644 index 0000000000000..ef5d7042163ec --- /dev/null +++ b/recipes/xgboost/all/test_package/conanfile.py @@ -0,0 +1,26 @@ +from conan import ConanFile +from conan.tools.build import can_run +from conan.tools.cmake import cmake_layout, CMake +import os + + +class TestPackageConan(ConanFile): + settings = "os", "arch", "compiler", "build_type" + generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv" + test_type = "explicit" + + def requirements(self): + self.requires(self.tested_reference_str) + + def layout(self): + cmake_layout(self) + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if can_run(self): + bin_path = os.path.join(self.cpp.build.bindir, "test_package") + self.run(bin_path, env="conanrun") diff --git a/recipes/xgboost/all/test_package/test_package.c b/recipes/xgboost/all/test_package/test_package.c new file mode 100644 index 0000000000000..51cbd52face5d --- /dev/null +++ b/recipes/xgboost/all/test_package/test_package.c @@ -0,0 +1,7 @@ +#include + +int main() { + int silent = 0; + DMatrixHandle dtrain; + XGDMatrixCreateFromFile("missing.txt", silent, &dtrain); +} diff --git a/recipes/xgboost/config.yml b/recipes/xgboost/config.yml new file mode 100644 index 0000000000000..7f57148a20478 --- /dev/null +++ b/recipes/xgboost/config.yml @@ -0,0 +1,3 @@ +versions: + "2.0.3": + folder: all