CMakeLists.txt 23.4 KB
Newer Older
1
2
3
4
5
6
option(USE_MPI "Enable MPI-based distributed learning" OFF)
option(USE_OPENMP "Enable OpenMP" ON)
option(USE_GPU "Enable GPU-accelerated training" OFF)
option(USE_SWIG "Enable SWIG to generate Java API" OFF)
option(USE_HDFS "Enable HDFS support (EXPERIMENTAL)" OFF)
option(USE_TIMETAG "Set to ON to output time costs" OFF)
7
option(USE_CUDA "Enable CUDA-accelerated training " OFF)
8
9
10
option(USE_DEBUG "Set to ON for Debug mode" OFF)
option(USE_SANITIZER "Use santizer flags" OFF)
set(
11
12
13
14
15
16
17
  ENABLED_SANITIZERS
  "address" "leak" "undefined"
  CACHE
  STRING
  "Semicolon separated list of sanitizer names, e.g., 'address;leak'. \
Supported sanitizers are address, leak, undefined and thread."
)
18
option(BUILD_CLI "Build the 'lightbgm' command-line interface in addition to lib_lightgbm" ON)
19
20
option(BUILD_CPP_TEST "Build C++ tests with Google Test" OFF)
option(BUILD_STATIC_LIB "Build static library" OFF)
21
22
option(INSTALL_HEADERS "Install headers to CMAKE_INSTALL_PREFIX (e.g. '/usr/local/include')" ON)
option(__BUILD_FOR_PYTHON "Set to ON if building lib_lightgbm for use with the Python package" OFF)
23
24
option(__BUILD_FOR_R "Set to ON if building lib_lightgbm for use with the R package" OFF)
option(__INTEGRATE_OPENCL "Set to ON if building LightGBM with the OpenCL ICD Loader and its dependencies included" OFF)
25

26
cmake_minimum_required(VERSION 3.18)
Guolin Ke's avatar
Guolin Ke committed
27

28
29
30
31
32
33
34
35
# If using Visual Studio generators, always target v10.x of the Windows SDK.
# Doing this avoids lookups that could fall back to very old versions, e.g. by finding
# outdated registry entries.
# ref: https://cmake.org/cmake/help/latest/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.html
if(CMAKE_GENERATOR MATCHES "Visual Studio")
    set(CMAKE_SYSTEM_VERSION 10.0 CACHE INTERNAL "target Windows SDK version" FORCE)
endif()

36
project(lightgbm LANGUAGES C CXX)
Guolin Ke's avatar
Guolin Ke committed
37

38
39
40
41
42
43
44
if(BUILD_CPP_TEST)
  set(CMAKE_CXX_STANDARD 14)
else()
  set(CMAKE_CXX_STANDARD 11)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)

45
46
47
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")

#-- Sanitizer
48
if(USE_SANITIZER)
49
50
  if(MSVC)
    message(FATAL_ERROR "Sanitizers are not supported with MSVC.")
51
  endif()
52
53
  include(cmake/Sanitizer.cmake)
  enable_sanitizers("${ENABLED_SANITIZERS}")
54
endif()
55

56
57
58
59
60
61
if(__INTEGRATE_OPENCL)
  set(__INTEGRATE_OPENCL ON CACHE BOOL "" FORCE)
  set(USE_GPU OFF CACHE BOOL "" FORCE)
  message(STATUS "Building library with integrated OpenCL components")
endif()

62
63
64
65
66
67
68
69
if(__BUILD_FOR_PYTHON OR __BUILD_FOR_R)
    # the Python and R package don't require the CLI
    set(BUILD_CLI OFF)
    # installing the R and Python package shouldn't place LightGBM's headers
    # outside of where the package is installed
    set(INSTALL_HEADERS OFF)
endif()

Qiwei Ye's avatar
Qiwei Ye committed
70
71
72
73
74
75
76
77
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
  if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.2")
    message(FATAL_ERROR "Insufficient gcc version")
  endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
  if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.8")
    message(FATAL_ERROR "Insufficient Clang version")
  endif()
78
79
80
81
82
83
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
  if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.1.0")
    message(FATAL_ERROR "Insufficient AppleClang version")
  endif()
elseif(MSVC)
  if(MSVC_VERSION LESS 1900)
84
85
86
87
    message(
      FATAL_ERROR
      "The compiler ${CMAKE_CXX_COMPILER} doesn't support required C++11 features. Please use a newer MSVC."
    )
88
  endif()
89
endif()
Guolin Ke's avatar
Guolin Ke committed
90

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
if(USE_SWIG)
  find_package(SWIG REQUIRED)
  find_package(Java REQUIRED)
  find_package(JNI REQUIRED)
  include(UseJava)
  include(UseSWIG)
  set(SWIG_CXX_EXTENSION "cxx")
  set(SWIG_EXTRA_LIBRARIES "")
  set(SWIG_JAVA_EXTRA_FILE_EXTENSIONS ".java" "JNI.java")
  set(SWIG_MODULE_JAVA_LANGUAGE "JAVA")
  set(SWIG_MODULE_JAVA_SWIG_LANGUAGE_FLAG "java")
  set(CMAKE_SWIG_OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/java")
  include_directories(Java_INCLUDE_DIRS)
  include_directories(JNI_INCLUDE_DIRS)
  include_directories($ENV{JAVA_HOME}/include)
106
  if(WIN32)
107
      file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/com/microsoft/ml/lightgbm/windows/x86_64")
108
      include_directories($ENV{JAVA_HOME}/include/win32)
109
  elseif(APPLE)
110
      file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/com/microsoft/ml/lightgbm/osx/x86_64")
111
      include_directories($ENV{JAVA_HOME}/include/darwin)
112
  else()
113
      file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/com/microsoft/ml/lightgbm/linux/x86_64")
114
115
      include_directories($ENV{JAVA_HOME}/include/linux)
  endif()
116
endif()
117

118
set(EIGEN_DIR "${PROJECT_SOURCE_DIR}/external_libs/eigen")
119
120
include_directories(${EIGEN_DIR})

121
# See https://gitlab.com/libeigen/eigen/-/blob/master/COPYING.README
122
add_definitions(-DEIGEN_MPL2_ONLY)
123
add_definitions(-DEIGEN_DONT_PARALLELIZE)
124

125
126
127
128
129
130
set(FAST_DOUBLE_PARSER_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/external_libs/fast_double_parser/include")
include_directories(${FAST_DOUBLE_PARSER_INCLUDE_DIR})

set(FMT_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/external_libs/fmt/include")
include_directories(${FMT_INCLUDE_DIR})

131
if(__BUILD_FOR_R)
132
133
134
135
136
    find_package(LibR REQUIRED)
    message(STATUS "LIBR_EXECUTABLE: ${LIBR_EXECUTABLE}")
    message(STATUS "LIBR_INCLUDE_DIRS: ${LIBR_INCLUDE_DIRS}")
    message(STATUS "LIBR_CORE_LIBRARY: ${LIBR_CORE_LIBRARY}")
    include_directories(${LIBR_INCLUDE_DIRS})
137
    add_definitions(-DLGB_R_BUILD)
138
endif()
139

140
if(USE_TIMETAG)
141
    add_definitions(-DTIMETAG)
142
endif()
143

Guolin Ke's avatar
Guolin Ke committed
144
if(USE_DEBUG)
145
    add_definitions(-DDEBUG)
146
endif()
Guolin Ke's avatar
Guolin Ke committed
147

Guolin Ke's avatar
Guolin Ke committed
148
if(USE_MPI)
Guolin Ke's avatar
Guolin Ke committed
149
    find_package(MPI REQUIRED)
150
    add_definitions(-DUSE_MPI)
Guolin Ke's avatar
Guolin Ke committed
151
else()
152
    add_definitions(-DUSE_SOCKET)
153
endif()
Guolin Ke's avatar
Guolin Ke committed
154

155
if(USE_CUDA)
156
    set(CMAKE_CUDA_HOST_COMPILER "${CMAKE_CXX_COMPILER}")
157
    enable_language(CUDA)
158
    set(USE_OPENMP ON CACHE BOOL "CUDA requires OpenMP" FORCE)
159
endif()
160

161
if(USE_OPENMP)
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    if(APPLE)
        find_package(OpenMP)
        if(NOT OpenMP_FOUND)
            # libomp 15.0+ from brew is keg-only, so have to search in other locations.
            # See https://github.com/Homebrew/homebrew-core/issues/112107#issuecomment-1278042927.
            execute_process(COMMAND brew --prefix libomp
                            OUTPUT_VARIABLE HOMEBREW_LIBOMP_PREFIX
                            OUTPUT_STRIP_TRAILING_WHITESPACE)
            set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp -I${HOMEBREW_LIBOMP_PREFIX}/include")
            set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I${HOMEBREW_LIBOMP_PREFIX}/include")
            set(OpenMP_C_LIB_NAMES omp)
            set(OpenMP_CXX_LIB_NAMES omp)
            set(OpenMP_omp_LIBRARY ${HOMEBREW_LIBOMP_PREFIX}/lib/libomp.dylib)
            find_package(OpenMP REQUIRED)
        endif()
    else()
        find_package(OpenMP REQUIRED)
    endif()
180
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
181
endif()
Guolin Ke's avatar
Guolin Ke committed
182

183
if(USE_GPU)
184
    set(BOOST_COMPUTE_HEADER_DIR ${PROJECT_SOURCE_DIR}/external_libs/compute/include)
185
    include_directories(${BOOST_COMPUTE_HEADER_DIR})
186
187
    find_package(OpenCL REQUIRED)
    include_directories(${OpenCL_INCLUDE_DIRS})
188
    message(STATUS "OpenCL include directory: " ${OpenCL_INCLUDE_DIRS})
189
    if(WIN32)
Guolin Ke's avatar
Guolin Ke committed
190
191
        set(Boost_USE_STATIC_LIBS ON)
    endif()
192
    find_package(Boost 1.56.0 COMPONENTS filesystem system REQUIRED)
193
    if(WIN32)
194
        # disable autolinking in boost
195
        add_definitions(-DBOOST_ALL_NO_LIB)
196
    endif()
Guolin Ke's avatar
Guolin Ke committed
197
    include_directories(${Boost_INCLUDE_DIRS})
198
    add_definitions(-DUSE_GPU)
199
endif()
200

201
if(__INTEGRATE_OPENCL)
202
203
204
    if(APPLE)
        message(FATAL_ERROR "Integrated OpenCL build is not available on macOS")
    else()
205
        include(cmake/IntegratedOpenCL.cmake)
206
        add_definitions(-DUSE_GPU)
207
208
    endif()
endif()
209

210
if(USE_CUDA)
211
212
    find_package(CUDAToolkit 11.0 REQUIRED)
    include_directories(${CUDAToolkit_INCLUDE_DIRS})
213
    set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler=${OpenMP_CXX_FLAGS} -Xcompiler=-fPIC -Xcompiler=-Wall")
214

215
216
    # reference for mapping of CUDA toolkit component versions to supported architectures ("compute capabilities"):
    # https://en.wikipedia.org/wiki/CUDA#GPUs_supported
217
218
219
    set(CUDA_ARCHS "60" "61" "62" "70" "75")
    if(CUDA_VERSION VERSION_GREATER_EQUAL "110")
        list(APPEND CUDA_ARCHS "80")
220
    endif()
221
222
    if(CUDA_VERSION VERSION_GREATER_EQUAL "111")
        list(APPEND CUDA_ARCHS "86")
223
    endif()
224
225
    if(CUDA_VERSION VERSION_GREATER_EQUAL "115")
        list(APPEND CUDA_ARCHS "87")
226
    endif()
227
228
229
    if(CUDA_VERSION VERSION_GREATER_EQUAL "118")
        list(APPEND CUDA_ARCHS "89")
        list(APPEND CUDA_ARCHS "90")
230
    endif()
231
232
    list(POP_BACK CUDA_ARCHS CUDA_LAST_SUPPORTED_ARCH)
    list(APPEND CUDA_ARCHS "${CUDA_LAST_SUPPORTED_ARCH}+PTX")
233
    if(USE_DEBUG)
234
      set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -g")
235
    else()
236
      set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -O3 -lineinfo")
237
238
239
    endif()
    message(STATUS "CMAKE_CUDA_FLAGS: ${CMAKE_CUDA_FLAGS}")

240
    add_definitions(-DUSE_CUDA)
241

242
    if(NOT DEFINED CMAKE_CUDA_STANDARD)
243
244
245
246
      set(CMAKE_CUDA_STANDARD 11)
      set(CMAKE_CUDA_STANDARD_REQUIRED ON)
    endif()

247
248
249
250
    set(
      BASE_DEFINES
      -DPOWER_FEATURE_WORKGROUPS=12
      -DUSE_CONSTANT_BUF=0
251
    )
252
253
254
255
    set(
      ALLFEATS_DEFINES
      ${BASE_DEFINES}
      -DENABLE_ALL_FEATURES
256
    )
257
258
259
260
    set(
      FULLDATA_DEFINES
      ${ALLFEATS_DEFINES}
      -DIGNORE_INDICES
261
262
263
264
265
266
267
268
    )

    message(STATUS "ALLFEATS_DEFINES: ${ALLFEATS_DEFINES}")
    message(STATUS "FULLDATA_DEFINES: ${FULLDATA_DEFINES}")

    function(add_histogram hsize hname hadd hconst hdir)
      add_library(histo${hsize}${hname} OBJECT src/treelearner/kernels/histogram${hsize}.cu)
      set_target_properties(histo${hsize}${hname} PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
269
      set_target_properties(histo${hsize}${hname} PROPERTIES CUDA_ARCHITECTURES ${CUDA_ARCHS})
270
271
272
273
274
      if(hadd)
        list(APPEND histograms histo${hsize}${hname})
        set(histograms ${histograms} PARENT_SCOPE)
      endif()
      target_compile_definitions(
275
276
        histo${hsize}${hname}
        PRIVATE
277
278
279
280
281
        -DCONST_HESSIAN=${hconst}
        ${hdir}
      )
    endfunction()

282
    foreach(hsize _16_64_256)
283
284
285
286
287
288
289
      add_histogram("${hsize}" "_sp_const" "True" "1" "${BASE_DEFINES}")
      add_histogram("${hsize}" "_sp" "True" "0" "${BASE_DEFINES}")
      add_histogram("${hsize}" "-allfeats_sp_const" "False" "1" "${ALLFEATS_DEFINES}")
      add_histogram("${hsize}" "-allfeats_sp" "False" "0" "${ALLFEATS_DEFINES}")
      add_histogram("${hsize}" "-fulldata_sp_const" "True" "1" "${FULLDATA_DEFINES}")
      add_histogram("${hsize}" "-fulldata_sp" "True" "0" "${FULLDATA_DEFINES}")
    endforeach()
290
endif()
291

292
if(USE_HDFS)
James Lamb's avatar
James Lamb committed
293
294
295
296
297
298
    message(
      DEPRECATION
      "HDFS support in LightGBM is deprecated, and will be removed in a future release.\
      See https://github.com/microsoft/LightGBM/issues/6436.
      "
    )
299
300
301
302
    find_package(JNI REQUIRED)
    find_path(HDFS_INCLUDE_DIR hdfs.h REQUIRED)
    find_library(HDFS_LIB NAMES hdfs REQUIRED)
    include_directories(${HDFS_INCLUDE_DIR})
303
304
    add_definitions(-DUSE_HDFS)
    set(HDFS_CXX_LIBRARIES ${HDFS_LIB} ${JAVA_JVM_LIBRARY})
305
endif()
306

307
308
309
310
311
312
313
314
315
316
317
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include <xmmintrin.h>
int main() {
  int a = 0;
  _mm_prefetch(&a, _MM_HINT_NTA);
  return 0;
}
" MM_PREFETCH)

if(${MM_PREFETCH})
318
  message(STATUS "Using _mm_prefetch")
319
  add_definitions(-DMM_PREFETCH)
320
321
endif()

322
323
324
325
326
327
328
329
330
331
332
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include <mm_malloc.h>
int main() {
  char *a = (char*)_mm_malloc(8, 16);
  _mm_free(a);
  return 0;
}
" MM_MALLOC)

if(${MM_MALLOC})
333
  message(STATUS "Using _mm_malloc")
334
  add_definitions(-DMM_MALLOC)
335
336
endif()

Guolin Ke's avatar
Guolin Ke committed
337
if(UNIX OR MINGW OR CYGWIN)
338
  set(
339
    CMAKE_CXX_FLAGS
340
    "${CMAKE_CXX_FLAGS} -pthread -Wextra -Wall -Wno-ignored-attributes -Wno-unknown-pragmas -Wno-return-type"
341
  )
342
343
344
345
346
347
348
  if(MINGW)
    # ignore this warning: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95353
    set(
      CMAKE_CXX_FLAGS
      "${CMAKE_CXX_FLAGS} -Wno-stringop-overflow"
    )
  endif()
349
  if(USE_DEBUG)
350
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0")
351
  else()
352
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
353
354
  endif()
  if(USE_SWIG)
355
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
356
357
  endif()
  if(NOT USE_OPENMP)
358
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas -Wno-unused-private-field")
359
360
  endif()
  if(__BUILD_FOR_R AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
361
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-cast-function-type")
362
  endif()
Guolin Ke's avatar
Guolin Ke committed
363
364
endif()

Nikita Titov's avatar
Nikita Titov committed
365
if(WIN32 AND MINGW)
366
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++")
Nikita Titov's avatar
Nikita Titov committed
367
368
endif()

369
370
371
372
373
374
375
376
377
378
379
380
# Check if inet_pton is already available, to avoid conflicts with the implementation in LightGBM.
# As of 2022, MinGW started including a definition of inet_pton.
if(WIN32)
  include(CheckSymbolExists)
  list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32")
  check_symbol_exists(inet_pton "ws2tcpip.h" WIN_INET_PTON_FOUND)
  if(WIN_INET_PTON_FOUND)
    add_definitions(-DWIN_HAS_INET_PTON)
  endif()
  list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "ws2_32")
endif()

Guolin Ke's avatar
Guolin Ke committed
381
if(MSVC)
382
    set(
383
      variables
Guolin Ke's avatar
Guolin Ke committed
384
385
386
387
388
389
390
391
392
        CMAKE_C_FLAGS_DEBUG
        CMAKE_C_FLAGS_MINSIZEREL
        CMAKE_C_FLAGS_RELEASE
        CMAKE_C_FLAGS_RELWITHDEBINFO
        CMAKE_CXX_FLAGS_DEBUG
        CMAKE_CXX_FLAGS_MINSIZEREL
        CMAKE_CXX_FLAGS_RELEASE
        CMAKE_CXX_FLAGS_RELWITHDEBINFO
    )
393
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /MP")
394
395
396
397
398
399
400
    if(__BUILD_FOR_R)
        # MSVC does not like this commit:
        # https://github.com/wch/r-source/commit/fb52ac1a610571fcb8ac92d886b9fefcffaa7d48
        #
        # and raises "error C3646: 'private_data_c': unknown override specifier"
        add_definitions(-DR_LEGACY_RCOMPLEX)
    endif()
Guolin Ke's avatar
Guolin Ke committed
401
    if(USE_DEBUG)
402
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Od")
Guolin Ke's avatar
Guolin Ke committed
403
    else()
404
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /O2 /Ob2 /Oi /Ot /Oy")
Guolin Ke's avatar
Guolin Ke committed
405
    endif()
Guolin Ke's avatar
Guolin Ke committed
406
else()
407
408
409
    if(NOT BUILD_STATIC_LIB)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
    endif()
Guolin Ke's avatar
Guolin Ke committed
410
    if(NOT USE_DEBUG)
411
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -funroll-loops")
Guolin Ke's avatar
Guolin Ke committed
412
    endif()
413
endif()
Guolin Ke's avatar
Guolin Ke committed
414

415
set(LightGBM_HEADER_DIR ${PROJECT_SOURCE_DIR}/include)
Guolin Ke's avatar
Guolin Ke committed
416

417
418
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
Guolin Ke's avatar
Guolin Ke committed
419

420
include_directories(${LightGBM_HEADER_DIR})
Guolin Ke's avatar
Guolin Ke committed
421
422
423

if(USE_MPI)
  include_directories(${MPI_CXX_INCLUDE_PATH})
424
endif()
Guolin Ke's avatar
Guolin Ke committed
425

426
427
428
429
430
431
432
433
434
file(
    GLOB
    SOURCES
      src/boosting/*.cpp
      src/io/*.cpp
      src/metric/*.cpp
      src/objective/*.cpp
      src/network/*.cpp
      src/treelearner/*.cpp
435
      src/utils/*.cpp
436
437
438
439
)
file(
    GLOB
    LGBM_CUDA_SOURCES
440
      src/treelearner/*.cu
441
442
      src/boosting/cuda/*.cpp
      src/boosting/cuda/*.cu
443
444
      src/metric/cuda/*.cpp
      src/metric/cuda/*.cu
445
446
      src/objective/cuda/*.cpp
      src/objective/cuda/*.cu
447
448
449
450
451
452
      src/treelearner/cuda/*.cpp
      src/treelearner/cuda/*.cu
      src/io/cuda/*.cu
      src/io/cuda/*.cpp
      src/cuda/*.cpp
      src/cuda/*.cu
Guolin Ke's avatar
Guolin Ke committed
453
454
)

455
456
457
458
if(USE_CUDA)
  list(APPEND SOURCES ${LGBM_CUDA_SOURCES})
endif()

459
460
add_library(lightgbm_objs OBJECT ${SOURCES})

461
462
463
464
if(BUILD_CLI)
    add_executable(lightgbm src/main.cpp src/application/application.cpp)
    target_link_libraries(lightgbm PRIVATE lightgbm_objs)
endif()
465

466
set(API_SOURCES "src/c_api.cpp")
467
468
# Only build the R part of the library if building for
# use with the R package
469
if(__BUILD_FOR_R)
470
  list(APPEND API_SOURCES "src/lightgbm_R.cpp")
471
endif()
472

473
474
add_library(lightgbm_capi_objs OBJECT ${API_SOURCES})

475
if(BUILD_STATIC_LIB)
476
  add_library(_lightgbm STATIC)
477
else()
478
  add_library(_lightgbm SHARED)
479
endif()
480
481
482
483
484
485
486
487
488
489
490

# R expects libraries of the form <project>.{dll,dylib,so}, not lib_<project>.{dll,dylib,so}
if(__BUILD_FOR_R)
  set_target_properties(
    _lightgbm
    PROPERTIES
      PREFIX ""
      OUTPUT_NAME "lightgbm"
  )
endif()

491
# LightGBM headers include openmp, cuda, R etc. headers,
492
493
# thus PUBLIC is required for building _lightgbm_swig target.
target_link_libraries(_lightgbm PUBLIC lightgbm_capi_objs lightgbm_objs)
494

495
if(MSVC AND NOT __BUILD_FOR_R)
496
  set_target_properties(_lightgbm PROPERTIES OUTPUT_NAME "lib_lightgbm")
497
endif()
498

499
500
if(USE_SWIG)
  set_property(SOURCE swig/lightgbmlib.i PROPERTY CPLUSPLUS ON)
501
  list(APPEND swig_options -package com.microsoft.ml.lightgbm)
502
  set_property(SOURCE swig/lightgbmlib.i PROPERTY SWIG_FLAGS "${swig_options}")
503
  swig_add_library(_lightgbm_swig LANGUAGE java SOURCES swig/lightgbmlib.i)
504
  swig_link_libraries(_lightgbm_swig _lightgbm)
505
  # needed to ensure Linux build does not have lib prefix specified twice, e.g. liblib_lightgbm_swig
506
  set_target_properties(_lightgbm_swig PROPERTIES PREFIX "")
507
  # needed in some versions of CMake for VS and MinGW builds to ensure output dll has lib prefix
508
509
510
  set_target_properties(_lightgbm_swig PROPERTIES OUTPUT_NAME "lib_lightgbm_swig")
  if(WIN32)
    if(MINGW OR CYGWIN)
511
512
513
        add_custom_command(
            TARGET _lightgbm_swig
            POST_BUILD
514
            COMMAND "${Java_JAVAC_EXECUTABLE}" -d . java/*.java
515
516
517
518
519
520
521
522
523
524
525
526
527
528
            COMMAND
              "${CMAKE_COMMAND}"
              -E
              copy_if_different
              "${PROJECT_SOURCE_DIR}/lib_lightgbm.dll"
              com/microsoft/ml/lightgbm/windows/x86_64
            COMMAND
              "${CMAKE_COMMAND}"
              -E
              copy_if_different
              "${PROJECT_SOURCE_DIR}/lib_lightgbm_swig.dll"
              com/microsoft/ml/lightgbm/windows/x86_64
            COMMAND "${Java_JAR_EXECUTABLE}" -cf lightgbmlib.jar com
        )
529
    else()
530
531
532
        add_custom_command(
            TARGET _lightgbm_swig
            POST_BUILD
533
            COMMAND "${Java_JAVAC_EXECUTABLE}" -d . java/*.java
534
535
536
537
538
539
540
541
542
543
544
545
            COMMAND
              "${CMAKE_COMMAND}"
              -E
              copy_if_different
              "${PROJECT_SOURCE_DIR}/Release/lib_lightgbm.dll"
              com/microsoft/ml/lightgbm/windows/x86_64
            COMMAND
              "${CMAKE_COMMAND}"
              -E
              copy_if_different
              "${PROJECT_SOURCE_DIR}/Release/lib_lightgbm_swig.dll"
              com/microsoft/ml/lightgbm/windows/x86_64
546
547
            COMMAND "${Java_JAR_EXECUTABLE}" -cf lightgbmlib.jar com
        )
548
    endif()
549
  elseif(APPLE)
550
551
552
553
554
    add_custom_command(
        TARGET _lightgbm_swig
        POST_BUILD
        COMMAND "${Java_JAVAC_EXECUTABLE}" -d . java/*.java
        COMMAND
555
556
557
558
559
560
561
562
563
          "${CMAKE_COMMAND}"
          -E
          copy_if_different
          "${PROJECT_SOURCE_DIR}/lib_lightgbm.dylib"
          com/microsoft/ml/lightgbm/osx/x86_64
        COMMAND
          "${CMAKE_COMMAND}"
          -E
          copy_if_different
564
565
566
567
          "${PROJECT_SOURCE_DIR}/lib_lightgbm_swig.jnilib"
          com/microsoft/ml/lightgbm/osx/x86_64/lib_lightgbm_swig.dylib
        COMMAND "${Java_JAR_EXECUTABLE}" -cf lightgbmlib.jar com
    )
568
  else()
569
570
571
572
    add_custom_command(
        TARGET _lightgbm_swig
        POST_BUILD
        COMMAND "${Java_JAVAC_EXECUTABLE}" -d . java/*.java
573
574
575
576
577
578
        COMMAND
          "${CMAKE_COMMAND}"
          -E
          copy_if_different
          "${PROJECT_SOURCE_DIR}/lib_lightgbm.so"
          com/microsoft/ml/lightgbm/linux/x86_64
579
580
        COMMAND "${Java_JAR_EXECUTABLE}" -cf lightgbmlib.jar com
    )
581
  endif()
582
endif()
Guolin Ke's avatar
Guolin Ke committed
583
584

if(USE_MPI)
585
  target_link_libraries(lightgbm_objs PUBLIC ${MPI_CXX_LIBRARIES})
586
endif()
Guolin Ke's avatar
Guolin Ke committed
587

fanliwen's avatar
fanliwen committed
588
if(USE_OPENMP)
589
590
591
592
593
594
595
596
597
598
  if(CMAKE_CXX_COMPILER_ID STREQUAL "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.
    # Specifying OpenMP in target_link_libraries will get include directory
    # requirements for compilation.
    # This uses CMake's Transitive Usage Requirements. Refer to CMake doc:
    # https://cmake.org/cmake/help/v3.16/manual/cmake-buildsystem.7.html#transitive-usage-requirements
    target_link_libraries(lightgbm_capi_objs PUBLIC OpenMP::OpenMP_CXX)
  endif()
599
endif()
fanliwen's avatar
fanliwen committed
600

601
if(USE_GPU)
602
  target_link_libraries(lightgbm_objs PUBLIC ${OpenCL_LIBRARY} ${Boost_LIBRARIES})
603
endif()
604

605
if(__INTEGRATE_OPENCL)
606
  # targets OpenCL and Boost are added in IntegratedOpenCL.cmake
607
  add_dependencies(lightgbm_objs OpenCL Boost)
608
  # variables INTEGRATED_OPENCL_* are set in IntegratedOpenCL.cmake
609
610
  target_include_directories(lightgbm_objs PRIVATE ${INTEGRATED_OPENCL_INCLUDES})
  target_compile_definitions(lightgbm_objs PRIVATE ${INTEGRATED_OPENCL_DEFINITIONS})
611
  target_link_libraries(lightgbm_objs PUBLIC ${INTEGRATED_OPENCL_LIBRARIES} ${CMAKE_DL_LIBS})
612
613
endif()

614
if(USE_CUDA)
615
616
  set_target_properties(lightgbm_objs PROPERTIES CUDA_ARCHITECTURES ${CUDA_ARCHS})
  set_target_properties(_lightgbm PROPERTIES CUDA_ARCHITECTURES ${CUDA_ARCHS})
617
  if(BUILD_CLI)
618
    set_target_properties(lightgbm PROPERTIES CUDA_ARCHITECTURES ${CUDA_ARCHS})
619
  endif()
620

621
622
  set_target_properties(lightgbm_objs PROPERTIES CUDA_SEPARABLE_COMPILATION ON)

623
624
  # Device linking is not supported for object libraries.
  # Thus we have to specify them on final targets.
625
626
627
  if(BUILD_CLI)
    set_target_properties(lightgbm PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS ON)
  endif()
628
  set_target_properties(_lightgbm PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS ON)
629
630
631
632

  # histograms are list of object libraries. Linking object library to other
  # object libraries only gets usage requirements, the linked objects won't be
  # used. Thus we have to call target_link_libraries on final targets here.
633
634
635
  if(BUILD_CLI)
    target_link_libraries(lightgbm PRIVATE ${histograms})
  endif()
636
  target_link_libraries(_lightgbm PRIVATE ${histograms})
637
endif()
638

639
if(USE_HDFS)
640
  target_link_libraries(lightgbm_objs PUBLIC ${HDFS_CXX_LIBRARIES})
641
endif()
642

643
644
if(WIN32)
    if(MINGW OR CYGWIN)
645
      target_link_libraries(lightgbm_objs PUBLIC ws2_32 iphlpapi)
646
647
    endif()
endif()
Guolin Ke's avatar
Guolin Ke committed
648

649
if(__BUILD_FOR_R)
650
651
  # utils/log.h and capi uses R headers, thus both object libraries need to link
  # with R lib.
652
  if(MSVC)
653
    set(R_LIB ${LIBR_MSVC_CORE_LIBRARY})
654
  else()
655
    set(R_LIB ${LIBR_CORE_LIBRARY})
656
  endif()
657
658
  target_link_libraries(lightgbm_objs PUBLIC ${R_LIB})
  target_link_libraries(lightgbm_capi_objs PUBLIC ${R_LIB})
659
endif()
660

661
662
663
664
665
666
667
668
669
#-- Google C++ tests
if(BUILD_CPP_TEST)
  find_package(GTest CONFIG)
  if(NOT GTEST_FOUND)
    message(STATUS "Did not find Google Test in the system root. Fetching Google Test now...")
    include(FetchContent)
    FetchContent_Declare(
      googletest
      GIT_REPOSITORY https://github.com/google/googletest.git
670
      GIT_TAG        v1.14.0
671
672
673
674
    )
    FetchContent_MakeAvailable(googletest)
    add_library(GTest::GTest ALIAS gtest)
  endif()
675
676
677
678

  set(LightGBM_TEST_HEADER_DIR ${PROJECT_SOURCE_DIR}/tests/cpp_tests)
  include_directories(${LightGBM_TEST_HEADER_DIR})

679
680
  file(GLOB CPP_TEST_SOURCES tests/cpp_tests/*.cpp)
  if(MSVC)
June Liu's avatar
June Liu committed
681
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /permissive-")
682
683
684
685
686
687
688
689
690
691
692
693
    set(
      CompilerFlags
        CMAKE_CXX_FLAGS
        CMAKE_CXX_FLAGS_DEBUG
        CMAKE_CXX_FLAGS_RELEASE
        CMAKE_C_FLAGS
        CMAKE_C_FLAGS_DEBUG
        CMAKE_C_FLAGS_RELEASE
    )
    foreach(CompilerFlag ${CompilerFlags})
      string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
    endforeach()
694
  endif()
695
  add_executable(testlightgbm ${CPP_TEST_SOURCES})
696
  target_link_libraries(testlightgbm PRIVATE lightgbm_objs lightgbm_capi_objs GTest::GTest)
697
698
endif()

699
700
701
702
703
704
705
if(BUILD_CLI)
    install(
      TARGETS lightgbm
      RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
    )
endif()

706
707
708
709
if(__BUILD_FOR_PYTHON)
    set(CMAKE_INSTALL_PREFIX "lightgbm")
endif()

710
install(
711
  TARGETS _lightgbm
712
713
714
715
  RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
  LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
  ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
)
716

717
if(INSTALL_HEADERS)
718
719
720
721
722
723
724
725
726
727
728
729
730
    install(
      DIRECTORY ${LightGBM_HEADER_DIR}/LightGBM
      DESTINATION ${CMAKE_INSTALL_PREFIX}/include
    )
    install(
      FILES ${FAST_DOUBLE_PARSER_INCLUDE_DIR}/fast_double_parser.h
      DESTINATION ${CMAKE_INSTALL_PREFIX}/include/LightGBM/utils
    )
    install(
      DIRECTORY ${FMT_INCLUDE_DIR}/
      DESTINATION ${CMAKE_INSTALL_PREFIX}/include/LightGBM/utils
      FILES_MATCHING PATTERN "*.h"
    )
731
endif()