Skip to content

Commit 44accd1

Browse files
authored
Merge branch 'master' into gpu_linear_tree
2 parents 7d85909 + 59a3432 commit 44accd1

File tree

8 files changed

+116
-121
lines changed

8 files changed

+116
-121
lines changed

.ci/conda-envs/ci-core.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ joblib>=1.3.2
2323
matplotlib-base>=3.7.3
2424
numpy>=1.24.4
2525
pandas>2.0
26-
pyarrow>=6.0
26+
pyarrow-core>=6.0
2727
python-graphviz>=0.20.3
2828
scikit-learn>=1.3.2
2929
scipy>=1.1

.ci/test-python-latest.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ python -m pip install \
2222
'numpy>=2.0.0.dev0' \
2323
'matplotlib>=3.10.0.dev0' \
2424
'pandas>=3.0.0.dev0' \
25-
'scikit-learn>=1.6.dev0' \
25+
'scikit-learn==1.5.*' \
2626
'scipy>=1.15.0.dev0'
2727

2828
python -m pip install \

.github/workflows/r_package.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,7 @@ jobs:
268268
# * CRAN "additional checks": https://cran.r-project.org/web/checks/check_issue_kinds.html
269269
# * images: https://r-hub.github.io/containers/containers.html
270270
image:
271-
# clang16 should be re-enabled once it's fixed upstream
272-
# ref: https://github.com/microsoft/LightGBM/issues/6607
273-
#- clang16
271+
- clang16
274272
- clang17
275273
- clang18
276274
- clang19

CMakeLists.txt

Lines changed: 36 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ if(__INTEGRATE_OPENCL)
5959
message(STATUS "Building library with integrated OpenCL components")
6060
endif()
6161

62-
if(__BUILD_FOR_PYTHON OR __BUILD_FOR_R)
63-
# the Python and R package don't require the CLI
62+
if(__BUILD_FOR_PYTHON OR __BUILD_FOR_R OR USE_SWIG)
63+
# the SWIG wrapper, the Python and R package don't require the CLI
6464
set(BUILD_CLI OFF)
65-
# installing the R and Python package shouldn't place LightGBM's headers
65+
# installing the SWIG wrapper, the R and Python package shouldn't place LightGBM's headers
6666
# outside of where the package is installed
6767
set(INSTALL_HEADERS OFF)
6868
endif()
@@ -104,15 +104,16 @@ if(USE_SWIG)
104104
include_directories(JNI_INCLUDE_DIRS)
105105
include_directories($ENV{JAVA_HOME}/include)
106106
if(WIN32)
107-
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/com/microsoft/ml/lightgbm/windows/x86_64")
107+
set(LGBM_SWIG_DESTINATION_DIR "${CMAKE_CURRENT_BINARY_DIR}/com/microsoft/ml/lightgbm/windows/x86_64")
108108
include_directories($ENV{JAVA_HOME}/include/win32)
109109
elseif(APPLE)
110-
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/com/microsoft/ml/lightgbm/osx/x86_64")
110+
set(LGBM_SWIG_DESTINATION_DIR "${CMAKE_CURRENT_BINARY_DIR}/com/microsoft/ml/lightgbm/osx/x86_64")
111111
include_directories($ENV{JAVA_HOME}/include/darwin)
112112
else()
113-
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/com/microsoft/ml/lightgbm/linux/x86_64")
113+
set(LGBM_SWIG_DESTINATION_DIR "${CMAKE_CURRENT_BINARY_DIR}/com/microsoft/ml/lightgbm/linux/x86_64")
114114
include_directories($ENV{JAVA_HOME}/include/linux)
115115
endif()
116+
file(MAKE_DIRECTORY "${LGBM_SWIG_DESTINATION_DIR}")
116117
endif()
117118

118119
set(EIGEN_DIR "${PROJECT_SOURCE_DIR}/external_libs/eigen")
@@ -376,17 +377,6 @@ if(WIN32)
376377
endif()
377378

378379
if(MSVC)
379-
set(
380-
variables
381-
CMAKE_C_FLAGS_DEBUG
382-
CMAKE_C_FLAGS_MINSIZEREL
383-
CMAKE_C_FLAGS_RELEASE
384-
CMAKE_C_FLAGS_RELWITHDEBINFO
385-
CMAKE_CXX_FLAGS_DEBUG
386-
CMAKE_CXX_FLAGS_MINSIZEREL
387-
CMAKE_CXX_FLAGS_RELEASE
388-
CMAKE_CXX_FLAGS_RELWITHDEBINFO
389-
)
390380
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /MP")
391381
if(__BUILD_FOR_R)
392382
# MSVC does not like this commit:
@@ -553,84 +543,41 @@ if(USE_SWIG)
553543
OUTPUT_NAME "lib_lightgbm_swig"
554544
)
555545
if(WIN32)
546+
set(LGBM_SWIG_LIB_DESTINATION_PATH "${LGBM_SWIG_DESTINATION_DIR}/lib_lightgbm_swig.dll")
556547
if(MINGW OR CYGWIN)
557-
add_custom_command(
558-
TARGET _lightgbm_swig
559-
POST_BUILD
560-
COMMAND "${Java_JAVAC_EXECUTABLE}" -d . java/*.java
561-
COMMAND
562-
"${CMAKE_COMMAND}"
563-
-E
564-
copy_if_different
565-
"${PROJECT_SOURCE_DIR}/lib_lightgbm.dll"
566-
com/microsoft/ml/lightgbm/windows/x86_64
567-
COMMAND
568-
"${CMAKE_COMMAND}"
569-
-E
570-
copy_if_different
571-
"${PROJECT_SOURCE_DIR}/lib_lightgbm_swig.dll"
572-
com/microsoft/ml/lightgbm/windows/x86_64
573-
COMMAND "${Java_JAR_EXECUTABLE}" -cf lightgbmlib.jar com
574-
)
548+
set(LGBM_LIB_SOURCE_PATH "${PROJECT_SOURCE_DIR}/lib_lightgbm.dll")
549+
set(LGBM_SWIG_LIB_SOURCE_PATH "${PROJECT_SOURCE_DIR}/lib_lightgbm_swig.dll")
575550
else()
576-
add_custom_command(
577-
TARGET _lightgbm_swig
578-
POST_BUILD
579-
COMMAND "${Java_JAVAC_EXECUTABLE}" -d . java/*.java
580-
COMMAND
581-
"${CMAKE_COMMAND}"
582-
-E
583-
copy_if_different
584-
"${PROJECT_SOURCE_DIR}/Release/lib_lightgbm.dll"
585-
com/microsoft/ml/lightgbm/windows/x86_64
586-
COMMAND
587-
"${CMAKE_COMMAND}"
588-
-E
589-
copy_if_different
590-
"${PROJECT_SOURCE_DIR}/Release/lib_lightgbm_swig.dll"
591-
com/microsoft/ml/lightgbm/windows/x86_64
592-
COMMAND "${Java_JAR_EXECUTABLE}" -cf lightgbmlib.jar com
593-
)
551+
set(LGBM_LIB_SOURCE_PATH "${PROJECT_SOURCE_DIR}/Release/lib_lightgbm.dll")
552+
set(LGBM_SWIG_LIB_SOURCE_PATH "${PROJECT_SOURCE_DIR}/Release/lib_lightgbm_swig.dll")
594553
endif()
595554
elseif(APPLE)
596-
add_custom_command(
597-
TARGET _lightgbm_swig
598-
POST_BUILD
599-
COMMAND "${Java_JAVAC_EXECUTABLE}" -d . java/*.java
600-
COMMAND
601-
"${CMAKE_COMMAND}"
602-
-E
603-
copy_if_different
604-
"${PROJECT_SOURCE_DIR}/lib_lightgbm.dylib"
605-
com/microsoft/ml/lightgbm/osx/x86_64
606-
COMMAND
607-
"${CMAKE_COMMAND}"
608-
-E
609-
copy_if_different
610-
"${PROJECT_SOURCE_DIR}/lib_lightgbm_swig.jnilib"
611-
com/microsoft/ml/lightgbm/osx/x86_64/lib_lightgbm_swig.dylib
612-
COMMAND "${Java_JAR_EXECUTABLE}" -cf lightgbmlib.jar com
613-
)
555+
set(LGBM_LIB_SOURCE_PATH "${PROJECT_SOURCE_DIR}/lib_lightgbm.dylib")
556+
set(LGBM_SWIG_LIB_SOURCE_PATH "${PROJECT_SOURCE_DIR}/lib_lightgbm_swig.jnilib")
557+
set(LGBM_SWIG_LIB_DESTINATION_PATH "${LGBM_SWIG_DESTINATION_DIR}/lib_lightgbm_swig.dylib")
614558
else()
615-
add_custom_command(
616-
TARGET _lightgbm_swig
617-
POST_BUILD
618-
COMMAND "${Java_JAVAC_EXECUTABLE}" -d . java/*.java
619-
COMMAND
620-
"${CMAKE_COMMAND}"
621-
-E
622-
copy_if_different
623-
"${PROJECT_SOURCE_DIR}/lib_lightgbm.so"
624-
com/microsoft/ml/lightgbm/linux/x86_64
625-
COMMAND
626-
"${CMAKE_COMMAND}"
627-
-E
628-
copy_if_different
629-
"${PROJECT_SOURCE_DIR}/lib_lightgbm_swig.so"
630-
com/microsoft/ml/lightgbm/linux/x86_64
631-
COMMAND "${Java_JAR_EXECUTABLE}" -cf lightgbmlib.jar com
632-
)
559+
set(LGBM_LIB_SOURCE_PATH "${PROJECT_SOURCE_DIR}/lib_lightgbm.so")
560+
set(LGBM_SWIG_LIB_SOURCE_PATH "${PROJECT_SOURCE_DIR}/lib_lightgbm_swig.so")
561+
set(LGBM_SWIG_LIB_DESTINATION_PATH "${LGBM_SWIG_DESTINATION_DIR}/lib_lightgbm_swig.so")
633562
endif()
563+
add_custom_command(
564+
TARGET _lightgbm_swig
565+
POST_BUILD
566+
COMMAND "${Java_JAVAC_EXECUTABLE}" -d . java/*.java
567+
COMMAND
568+
"${CMAKE_COMMAND}"
569+
-E
570+
copy_if_different
571+
"${LGBM_LIB_SOURCE_PATH}"
572+
"${LGBM_SWIG_DESTINATION_DIR}"
573+
COMMAND
574+
"${CMAKE_COMMAND}"
575+
-E
576+
copy_if_different
577+
"${LGBM_SWIG_LIB_SOURCE_PATH}"
578+
"${LGBM_SWIG_LIB_DESTINATION_PATH}"
579+
COMMAND "${Java_JAR_EXECUTABLE}" -cf lightgbmlib.jar com
580+
)
634581
endif()
635582

636583
if(USE_MPI)

docs/FAQ.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,49 @@ Detailed description of conflicts between multiple OpenMP instances is provided
206206

207207
If this is not your case, then you should find conflicting OpenMP library installations on your own and leave only one of them.
208208

209+
17. Loading LightGBM fails like: ``cannot allocate memory in static TLS block``
210+
-------------------------------------------------------------------------------
211+
212+
When loading LightGBM, you may encounter errors like the following.
213+
214+
.. code-block:: console
215+
216+
lib/libgomp.so.1: cannot allocate memory in static TLS block
217+
218+
This most commonly happens on aarch64 Linux systems.
219+
220+
``gcc``'s OpenMP library (``libgomp.so``) tries to allocate a small amount of static thread-local storage ("TLS")
221+
when it's dynamically loaded.
222+
223+
That error can happen when the loader isn't able to find a large enough block of memory.
224+
225+
On aarch64 Linux, processes and loaded libraries share the same pool of static TLS,
226+
which makes such failures more likely. See these discussions:
227+
228+
* https://bugzilla.redhat.com/show_bug.cgi?id=1722181#c6
229+
* https://gcc.gcc.gnu.narkive.com/vOXMQqLA/failure-to-dlopen-libgomp-due-to-static-tls-data
230+
231+
If you are experiencing this issue when using the ``lightgbm`` Python package, try upgrading
232+
to at least ``v4.6.0``.
233+
234+
For older versions of the Python package, or for other LightGBM APIs, this issue can
235+
often be avoided by loading ``libgomp.so.1``. That can be done directly by setting environment
236+
variable ``LD_PRELOAD``, like this:
237+
238+
.. code-block:: console
239+
240+
export LD_PRELOAD=/root/miniconda3/envs/test-env/lib/libgomp.so.1
241+
242+
It can also be done indirectly by changing the order that other libraries are loaded
243+
into processes, which varies by programming language and application type.
244+
245+
For more details, see these discussions:
246+
247+
* https://github.com/microsoft/LightGBM/pull/6654#issuecomment-2352014275
248+
* https://github.com/microsoft/LightGBM/issues/6509
249+
* https://maskray.me/blog/2021-02-14-all-about-thread-local-storage
250+
* https://bugzilla.redhat.com/show_bug.cgi?id=1722181#c6
251+
209252
------
210253

211254
R-package

python-package/lightgbm/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
from pathlib import Path
88

9+
# .basic is intentionally loaded as early as possible, to dlopen() lib_lightgbm.{dll,dylib,so}
10+
# and its dependencies as early as possible
911
from .basic import Booster, Dataset, Sequence, register_logger
1012
from .callback import EarlyStopException, early_stopping, log_evaluation, record_evaluation, reset_parameter
1113
from .engine import CVBooster, cv, train

python-package/lightgbm/basic.py

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
# coding: utf-8
22
"""Wrapper for C API of LightGBM."""
33

4+
# This import causes lib_lightgbm.{dll,dylib,so} to be loaded.
5+
# It's intentionally done here, as early as possible, to avoid issues like
6+
# "libgomp.so.1: cannot allocate memory in static TLS block" on aarch64 Linux.
7+
#
8+
# For details, see the "cannot allocate memory in static TLS block" entry in docs/FAQ.rst.
9+
from .libpath import _LIB # isort: skip
10+
411
import abc
512
import ctypes
613
import inspect
@@ -37,7 +44,6 @@
3744
pd_DataFrame,
3845
pd_Series,
3946
)
40-
from .libpath import find_lib_path
4147

4248
if TYPE_CHECKING:
4349
from typing import Literal
@@ -160,6 +166,12 @@
160166
_MULTICLASS_OBJECTIVES = {"multiclass", "multiclassova", "multiclass_ova", "ova", "ovr", "softmax"}
161167

162168

169+
class LightGBMError(Exception):
170+
"""Error thrown by LightGBM."""
171+
172+
pass
173+
174+
163175
def _is_zero(x: float) -> bool:
164176
return -ZERO_THRESHOLD <= x <= ZERO_THRESHOLD
165177

@@ -259,26 +271,13 @@ def _log_callback(msg: bytes) -> None:
259271
_log_native(str(msg.decode("utf-8")))
260272

261273

262-
def _load_lib() -> ctypes.CDLL:
263-
"""Load LightGBM library."""
264-
lib_path = find_lib_path()
265-
lib = ctypes.cdll.LoadLibrary(lib_path[0])
266-
lib.LGBM_GetLastError.restype = ctypes.c_char_p
274+
# connect the Python logger to logging in lib_lightgbm
275+
if not environ.get("LIGHTGBM_BUILD_DOC", False):
276+
_LIB.LGBM_GetLastError.restype = ctypes.c_char_p
267277
callback = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
268-
lib.callback = callback(_log_callback) # type: ignore[attr-defined]
269-
if lib.LGBM_RegisterLogCallback(lib.callback) != 0:
270-
raise LightGBMError(lib.LGBM_GetLastError().decode("utf-8"))
271-
return lib
272-
273-
274-
# we don't need lib_lightgbm while building docs
275-
_LIB: ctypes.CDLL
276-
if environ.get("LIGHTGBM_BUILD_DOC", False):
277-
from unittest.mock import Mock # isort: skip
278-
279-
_LIB = Mock(ctypes.CDLL) # type: ignore
280-
else:
281-
_LIB = _load_lib()
278+
_LIB.callback = callback(_log_callback) # type: ignore[attr-defined]
279+
if _LIB.LGBM_RegisterLogCallback(_LIB.callback) != 0:
280+
raise LightGBMError(_LIB.LGBM_GetLastError().decode("utf-8"))
282281

283282

284283
_NUMERIC_TYPES = (int, float, bool)
@@ -552,12 +551,6 @@ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
552551
self.path.unlink()
553552

554553

555-
class LightGBMError(Exception):
556-
"""Error thrown by LightGBM."""
557-
558-
pass
559-
560-
561554
# DeprecationWarning is not shown by default, so let's create our own with higher level
562555
# ref: https://peps.python.org/pep-0565/#additional-use-case-for-futurewarning
563556
class LGBMDeprecationWarning(FutureWarning):

python-package/lightgbm/libpath.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
# coding: utf-8
22
"""Find the path to LightGBM dynamic library files."""
33

4+
import ctypes
5+
from os import environ
46
from pathlib import Path
57
from platform import system
68
from typing import List
79

810
__all__: List[str] = []
911

1012

11-
def find_lib_path() -> List[str]:
13+
def _find_lib_path() -> List[str]:
1214
"""Find the path to LightGBM library files.
1315
1416
Returns
@@ -35,3 +37,13 @@ def find_lib_path() -> List[str]:
3537
dll_path_joined = "\n".join(map(str, dll_path))
3638
raise Exception(f"Cannot find lightgbm library file in following paths:\n{dll_path_joined}")
3739
return lib_path
40+
41+
42+
# we don't need lib_lightgbm while building docs
43+
_LIB: ctypes.CDLL
44+
if environ.get("LIGHTGBM_BUILD_DOC", False):
45+
from unittest.mock import Mock # isort: skip
46+
47+
_LIB = Mock(ctypes.CDLL) # type: ignore
48+
else:
49+
_LIB = ctypes.cdll.LoadLibrary(_find_lib_path()[0])

0 commit comments

Comments
 (0)