Skip to content

Commit

Permalink
(#18759) lightgbm: migrate to Conan v2, add v4.0.0
Browse files Browse the repository at this point in the history
* lightgbm: migrate to Conan v2, add v4.0.0

* lightgbm: enable llvm-openmp

* lightgbm: bump version

* lightgbm: unvendor Eigen fully

* lightgbm: bump llvm-openmp, export OpenMP flags correctly

* lightgbm: restore patches for the Clang OpenMP support fix

* lightgbm: simplify patching

* lightgbm: add -fopenmp to linker flags

* lightgbm: disable openmp on apple-clang for Conan v1
  • Loading branch information
valgur authored Dec 4, 2023
1 parent 162359b commit 4524ed6
Show file tree
Hide file tree
Showing 12 changed files with 163 additions and 89 deletions.
23 changes: 18 additions & 5 deletions recipes/lightgbm/all/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
cmake_minimum_required(VERSION 3.1)
project(cmake_wrapper)
cmake_minimum_required(VERSION 3.15)
project(cmake_wrapper LANGUAGES CXX)

include(conanbuildinfo.cmake)
conan_basic_setup(KEEP_RPATHS)
find_package(Eigen3 REQUIRED CONFIG)
find_package(fast_double_parser REQUIRED CONFIG)
find_package(fmt REQUIRED CONFIG)

add_subdirectory("source_subfolder")
add_subdirectory(src)

if(_MAJOR_VERSION GREATER_EQUAL 4)
set(TARGETS lightgbm_objs lightgbm_capi_objs)
set(VISIBILITY PRIVATE)
else()
set(TARGETS lightgbm _lightgbm)
set(VISIBILITY "")
endif()

foreach(target ${TARGETS})
target_link_libraries(${target} ${VISIBILITY} Eigen3::Eigen fast_double_parser::fast_double_parser fmt::fmt)
endforeach()
29 changes: 17 additions & 12 deletions recipes/lightgbm/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
sources:
"3.3.2":
url: "https://github.com/microsoft/LightGBM/archive/refs/tags/v3.3.2.tar.gz"
sha256: "d7c0f842e94165578d5a0c046ca942838d1574149f98c84400ce511239d17b9f"
"4.1.0":
url: "https://github.com/microsoft/LightGBM/archive/refs/tags/v4.1.0.tar.gz"
sha256: "eb896dc21c7afec95d10327777f6e77163b5bcd35f6ce5d152e6feefbe3328a5"
"3.3.5":
url: "https://github.com/microsoft/LightGBM/archive/refs/tags/v3.3.5.tar.gz"
sha256: "16fb9e299ced37be5ac69dd510e7323337e623019c9c578628c43b285f764be7"
patches:
"3.3.2":
- patch_file: "patches/0001-fix-includes.patch"
base_path: "source_subfolder"
- patch_file: "patches/0002-fix-openmp-clang.patch"
base_path: "source_subfolder"
url: "https://github.com/microsoft/LightGBM/archive/refs/tags/v3.3.2.tar.gz"
sha256: "d7c0f842e94165578d5a0c046ca942838d1574149f98c84400ce511239d17b9f"
patches:
"4.1.0":
- patch_file: "patches/4.1.0-0001-fix-openmp-clang.patch"
patch_type: "portability"
patch_description: "Fix OpenMP support for Clang"
"3.3.5":
- patch_file: "patches/0001-fix-includes.patch"
base_path: "source_subfolder"
- patch_file: "patches/0003-fix-openmp-clang.patch"
base_path: "source_subfolder"
- patch_file: "patches/3.3.5-0001-fix-openmp-clang.patch"
patch_type: "portability"
patch_description: "Fix OpenMP support for Clang"
"3.3.2":
- patch_file: "patches/3.3.2-0001-fix-openmp-clang.patch"
patch_type: "portability"
patch_description: "Fix OpenMP support for Clang"
112 changes: 70 additions & 42 deletions recipes/lightgbm/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,82 +1,107 @@
from conans import CMake, ConanFile, tools
import os

from conan import ConanFile, conan_version
from conan.tools.apple import is_apple_os
from conan.tools.build import check_min_cppstd
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
from conan.tools.files import copy, get, replace_in_file, export_conandata_patches, apply_conandata_patches
from conan.tools.microsoft import is_msvc
import functools
from conan.tools.scm import Version

required_conan_version = ">=1.33.0"
required_conan_version = ">=1.53.0"


class LightGBMConan(ConanFile):
name = "lightgbm"
description = "A fast, distributed, high performance gradient boosting (GBT, GBDT, GBRT, GBM or MART) framework based on decision tree algorithms, used for ranking, classification and many other machine learning tasks."
topics = ("machine-learning", "boosting")
description = (
"A fast, distributed, high performance gradient boosting "
"(GBT, GBDT, GBRT, GBM or MART) framework based on decision tree algorithms, "
"used for ranking, classification and many other machine learning tasks."
)
license = "MIT"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/microsoft/LightGBM"
license = "MIT"
topics = ("machine-learning", "boosting")

package_type = "library"
settings = "os", "arch", "compiler", "build_type"
exports_sources = ["CMakeLists.txt", "patches/**"]
generators = "cmake", "cmake_find_package"
options = {
"shared": [True, False],
"fPIC": [True, False],
"with_openmp": [True, False]
"with_openmp": [True, False],
}
default_options = {
"shared": False,
"fPIC": True,
"with_openmp": True
"with_openmp": True,
}

@property
def _source_subfolder(self):
return "source_subfolder"
def export_sources(self):
copy(self, "CMakeLists.txt", self.recipe_folder, self.export_sources_folder)
export_conandata_patches(self)

def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
if conan_version.major == 1 and self.settings.compiler == "apple-clang":
# https://github.com/conan-io/conan-center-index/pull/18759#issuecomment-1817470331
del self.options.with_openmp

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

def layout(self):
cmake_layout(self, src_folder="src")

def requirements(self):
self.requires("eigen/3.4.0")
self.requires("fast_double_parser/0.6.0")
self.requires("fmt/9.0.0")
if self.options.with_openmp and self.settings.compiler in ("clang", "apple-clang"):
self.requires("llvm-openmp/11.1.0")
self.requires("fast_double_parser/0.7.0", transitive_headers=True, transitive_libs=True)
self.requires("fmt/10.1.1", transitive_headers=True, transitive_libs=True)
if self.options.get_safe("with_openmp") and self.settings.compiler in ["clang", "apple-clang"]:
self.requires("llvm-openmp/17.0.4", transitive_headers=True, transitive_libs=True)

def validate(self):
if self.settings.compiler.get_safe("cppstd"):
tools.check_min_cppstd(self, 11)
check_min_cppstd(self, 11)

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

def generate(self):
tc = CMakeToolchain(self)
tc.cache_variables["BUILD_STATIC_LIB"] = not self.options.shared
tc.cache_variables["USE_DEBUG"] = self.settings.build_type in ["Debug", "RelWithDebInfo"]
tc.cache_variables["USE_OPENMP"] = self.options.get_safe("with_openmp", False)
tc.cache_variables["BUILD_CLI"] = False
if is_apple_os(self):
tc.cache_variables["APPLE_OUTPUT_DYLIB"] = True
tc.variables["_MAJOR_VERSION"] = Version(self.version).major
tc.generate()
tc = CMakeDeps(self)
tc.generate()

def _patch_sources(self):
for patch in self.conan_data.get("patches", {}).get(self.version, []):
tools.patch(**patch)

@functools.lru_cache(1)
def _configure_cmake(self):
cmake = CMake(self)
cmake.definitions["BUILD_STATIC_LIB"] = not self.options.shared
cmake.definitions["USE_DEBUG"] = self.settings.build_type == "Debug"
cmake.definitions["USE_OPENMP"] = self.options.with_openmp
if self.settings.os == "Macos":
cmake.definitions["APPLE_OUTPUT_DYLIB"] = True
cmake.configure()
return cmake
apply_conandata_patches(self)
# Fix vendored dependency includes
common_h = os.path.join(self.source_folder, "include", "LightGBM", "utils", "common.h")
for lib in ["fmt", "fast_double_parser"]:
replace_in_file(self, common_h, f"../../../external_libs/{lib}/include/", "")
# Unvendor Eigen3
replace_in_file(self, os.path.join(self.source_folder, "CMakeLists.txt"),
"include_directories(${EIGEN_DIR})", "")

def build(self):
self._patch_sources()
cmake = self._configure_cmake()
cmake = CMake(self)
cmake.configure(build_script_folder=self.source_path.parent)
cmake.build()

def package(self):
self.copy("LICENSE", dst="licenses", src=self._source_subfolder)
cmake = self._configure_cmake()
copy(self, "LICENSE",
dst=os.path.join(self.package_folder, "licenses"),
src=self.source_folder)
cmake = CMake(self)
cmake.install()

def package_info(self):
Expand All @@ -90,16 +115,19 @@ def package_info(self):
self.cpp_info.libs = ["lib_lightgbm"] if is_msvc(self) else ["_lightgbm"]
if self.settings.os == "Windows":
self.cpp_info.system_libs.extend(["ws2_32", "iphlpapi"])
elif self.settings.os == "Linux":
elif self.settings.os in ["Linux", "FreeBSD"]:
self.cpp_info.system_libs.append("pthread")
if not self.options.shared and self.options.with_openmp:

# OpenMP preprocessor directives are used in a number of public headers, such as:
# https://github.com/microsoft/LightGBM/blob/master/include/LightGBM/tree.h#L188
if self.options.get_safe("with_openmp"):
openmp_flags = []
if is_msvc(self):
openmp_flags = ["-openmp"]
elif self.settings.compiler == "gcc":
openmp_flags = ["-fopenmp"]
elif self.settings.compiler in ("clang", "apple-clang"):
elif self.settings.compiler in ["clang", "apple-clang"]:
openmp_flags = ["-Xpreprocessor", "-fopenmp"]
else:
openmp_flags = []
self.cpp_info.cxxflags.extend(openmp_flags)
self.cpp_info.exelinkflags.extend(openmp_flags)
self.cpp_info.sharedlinkflags.extend(openmp_flags)
16 changes: 0 additions & 16 deletions recipes/lightgbm/all/patches/0001-fix-includes.patch

This file was deleted.

11 changes: 11 additions & 0 deletions recipes/lightgbm/all/patches/4.1.0-0001-fix-openmp-clang.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -526,7 +526,7 @@
endif()

if(USE_OPENMP)
- if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang|AppleClang")
target_link_libraries(lightgbm_objs PUBLIC OpenMP::OpenMP_CXX)
# c_api headers also includes OpenMP headers, thus compiling
# lightgbm_capi_objs needs include directory for OpenMP.
9 changes: 3 additions & 6 deletions recipes/lightgbm/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
cmake_minimum_required(VERSION 3.1)
project(test_package)
cmake_minimum_required(VERSION 3.15)
project(test_package LANGUAGES CXX)

include("${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
conan_basic_setup(TARGETS)

find_package(LightGBM CONFIG REQUIRED)
find_package(LightGBM REQUIRED CONFIG)

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} LightGBM::LightGBM)
Expand Down
23 changes: 16 additions & 7 deletions recipes/lightgbm/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
from conans import ConanFile, CMake, tools
from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.cmake import cmake_layout, CMake
import os


class LightGBMTestConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake", "cmake_find_package_multi"
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 not tools.cross_building(self):
bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)
if can_run(self):
bin_path = os.path.join(self.cpp.build.bindir, "test_package")
self.run(bin_path, env="conanrun")
8 changes: 8 additions & 0 deletions recipes/lightgbm/all/test_v1_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.15)
project(test_package)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../test_package/
${CMAKE_CURRENT_BINARY_DIR}/test_package/)
17 changes: 17 additions & 0 deletions recipes/lightgbm/all/test_v1_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from conans import ConanFile, CMake, tools
import os


class LightGBMTestConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake", "cmake_find_package_multi"

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if not tools.cross_building(self):
bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)
4 changes: 3 additions & 1 deletion recipes/lightgbm/config.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
versions:
"3.3.2":
"4.1.0":
folder: all
"3.3.5":
folder: all
"3.3.2":
folder: all

0 comments on commit 4524ed6

Please sign in to comment.