build-python.sh 11.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/sh

# [description]
#
#     Prepare a source distribution (sdist) or built distribution (wheel)
#     of the Python package, and optionally install it.
#
# [usage]
#
#     # build sdist and put it in dist/
#     sh ./build-python.sh sdist
#
#     # build wheel and put it in dist/
#     sh ./build-python.sh bdist_wheel [OPTIONS]
#
#     # compile lib_lightgbm and install the Python package wrapping it
#     sh ./build-python.sh install [OPTIONS]
#
#     # install the Python package using a pre-compiled lib_lightgbm
#     # (assumes lib_lightgbm.{dll,so} is located at the root of the repo)
#     sh ./build-python.sh install --precompile
#
# [options]
#
25
26
#     --boost-dir=FILEPATH
#                                   Directory with Boost package configuration file.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#     --boost-include-dir=FILEPATH
#                                   Directory containing Boost headers.
#     --boost-librarydir=FILEPATH
#                                   Preferred Boost library directory.
#     --boost-root=FILEPATH
#                                   Boost preferred installation prefix.
#     --opencl-include-dir=FILEPATH
#                                   OpenCL include directory.
#     --opencl-library=FILEPATH
#                                   Path to OpenCL library.
#     --bit32
#                                   Compile 32-bit version.
#     --cuda
#                                   Compile CUDA version.
#     --gpu
#                                   Compile GPU version.
#     --hdfs
#                                   Compile HDFS version.
#     --integrated-opencl
#                                   Compile integrated OpenCL version.
#     --mingw
#                                   Compile with MinGW.
#     --mpi
#                                   Compile MPI version.
#     --nomp
#                                   Compile version without OpenMP support.
#     --precompile
#                                   Use precompiled library.
#                                   Only used with 'install' command.
#     --time-costs
#                                   Output time costs for different internal routines.
#     --user
#                                   Install into user-specific instead of global site-packages directory.
#                                   Only used with 'install' command.

set -e -u

echo "building lightgbm"

# Default values of arguments
INSTALL="false"
BUILD_SDIST="false"
BUILD_WHEEL="false"

PIP_INSTALL_ARGS=""
BUILD_ARGS=""
PRECOMPILE="false"

while [ $# -gt 0 ]; do
  case "$1" in
    ############################
    # sub-commands of setup.py #
    ############################
    install)
      INSTALL="true"
      ;;
    sdist)
      BUILD_SDIST="true"
      ;;
    bdist_wheel)
      BUILD_WHEEL="true"
      ;;
    ############################
    # customized library paths #
    ############################
92
93
94
95
96
    --boost-dir|--boost-dir=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        BOOST_DIR="${1#*=}"
97
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.Boost_DIR='${BOOST_DIR}'"
98
        ;;
99
100
101
102
103
    --boost-include-dir|--boost-include-dir=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        BOOST_INCLUDE_DIR="${1#*=}"
104
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.Boost_INCLUDE_DIR='${BOOST_INCLUDE_DIR}'"
105
106
107
108
109
110
        ;;
    --boost-librarydir|--boost-librarydir=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        BOOST_LIBRARY_DIR="${1#*=}"
111
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.BOOST_LIBRARYDIR='${BOOST_LIBRARY_DIR}'"
112
113
114
115
116
117
        ;;
    --boost-root|--boost-root=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        BOOST_ROOT="${1#*=}"
118
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.Boost_ROOT='${BOOST_ROOT}'"
119
120
121
122
123
124
        ;;
    --opencl-include-dir|--opencl-include-dir=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        OPENCL_INCLUDE_DIR="${1#*=}"
125
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.OpenCL_INCLUDE_DIR='${OPENCL_INCLUDE_DIR}'"
126
127
128
129
130
131
        ;;
    --opencl-library|--opencl-library=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        OPENCL_LIBRARY="${1#*=}"
132
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.OpenCL_LIBRARY='${OPENCL_LIBRARY}'"
133
134
135
136
137
        ;;
    #########
    # flags #
    #########
    --bit32)
138
139
140
        export CMAKE_GENERATOR="Visual Studio 17 2022"
        export CMAKE_GENERATOR_PLATFORM="Win32"
        echo "[INFO] Attempting to build 32-bit version of LightGBM, which is only supported on Windows with generator '${CMAKE_GENERATOR}'."
141
142
        ;;
    --cuda)
143
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_CUDA=ON"
144
145
        ;;
    --gpu)
146
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_GPU=ON"
147
148
        ;;
    --hdfs)
149
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_HDFS=ON"
150
151
        ;;
    --integrated-opencl)
152
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.__INTEGRATE_OPENCL=ON"
153
154
        ;;
    --mingw)
155
156
157
        export CMAKE_GENERATOR='MinGW Makefiles'
        # ref: https://stackoverflow.com/a/45104058/3986677
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.CMAKE_SH=CMAKE_SH-NOTFOUND"
158
159
        ;;
    --mpi)
160
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_MPI=ON"
161
162
        ;;
    --nomp)
163
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_OPENMP=OFF"
164
165
166
167
168
        ;;
    --precompile)
        PRECOMPILE="true"
        ;;
    --time-costs)
169
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_TIMETAG=ON"
170
171
172
173
174
175
176
177
178
179
180
181
        ;;
    --user)
        PIP_INSTALL_ARGS="${PIP_INSTALL_ARGS} --user"
        ;;
    *)
        echo "invalid argument '${1}'"
        exit -1
        ;;
  esac
  shift
done

182
183
pip install --prefer-binary 'build>=0.10.0'

184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# create a new directory that just contains the files needed
# to build the Python package
create_isolated_source_dir() {
    rm -rf \
        ./lightgbm-python \
        ./lightgbm \
        ./python-package/build \
        ./python-package/build_cpp \
        ./python-package/compile \
        ./python-package/dist \
        ./python-package/lightgbm.egg-info

    cp -R ./python-package ./lightgbm-python

    cp LICENSE ./lightgbm-python/
    cp VERSION.txt ./lightgbm-python/lightgbm/VERSION.txt

201
202
203
204
205
206
    cp -R ./cmake ./lightgbm-python
    cp CMakeLists.txt ./lightgbm-python
    cp -R ./include ./lightgbm-python
    cp -R ./src ./lightgbm-python
    cp -R ./swig ./lightgbm-python
    cp -R ./windows ./lightgbm-python
207
208
209
210
211
212
213
214

    # include only specific files from external_libs, to keep the package
    # small and avoid redistributing code with licenses incompatible with
    # LightGBM's license

    ######################
    # fast_double_parser #
    ######################
215
    mkdir -p ./lightgbm-python/external_libs/fast_double_parser
216
217
    cp \
        external_libs/fast_double_parser/CMakeLists.txt \
218
        ./lightgbm-python/external_libs/fast_double_parser/CMakeLists.txt
219
220
    cp \
        external_libs/fast_double_parser/LICENSE* \
221
        ./lightgbm-python/external_libs/fast_double_parser/
222

223
    mkdir -p ./lightgbm-python/external_libs/fast_double_parser/include/
224
225
    cp \
        external_libs/fast_double_parser/include/fast_double_parser.h \
226
        ./lightgbm-python/external_libs/fast_double_parser/include/
227
228
229
230

    #######
    # fmt #
    #######
231
    mkdir -p ./lightgbm-python/external_libs/fmt
232
233
    cp \
        external_libs/fast_double_parser/CMakeLists.txt \
234
        ./lightgbm-python/external_libs/fmt/CMakeLists.txt
235
236
    cp \
        external_libs/fmt/LICENSE* \
237
        ./lightgbm-python/external_libs/fmt/
238

239
    mkdir -p ./lightgbm-python/external_libs/fmt/include/fmt
240
241
    cp \
        external_libs/fmt/include/fmt/*.h \
242
        ./lightgbm-python/external_libs/fmt/include/fmt/
243
244
245
246

    #########
    # Eigen #
    #########
247
    mkdir -p ./lightgbm-python/external_libs/eigen/Eigen
248
249
    cp \
        external_libs/eigen/CMakeLists.txt \
250
        ./lightgbm-python/external_libs/eigen/CMakeLists.txt
251
252
253
254
255

    modules="Cholesky Core Dense Eigenvalues Geometry Householder Jacobi LU QR SVD"
    for eigen_module in ${modules}; do
        cp \
            external_libs/eigen/Eigen/${eigen_module} \
256
            ./lightgbm-python/external_libs/eigen/Eigen/${eigen_module}
257
        if [ ${eigen_module} != "Dense" ]; then
258
            mkdir -p ./lightgbm-python/external_libs/eigen/Eigen/src/${eigen_module}/
259
260
261
            cp \
                -R \
                external_libs/eigen/Eigen/src/${eigen_module}/* \
262
                ./lightgbm-python/external_libs/eigen/Eigen/src/${eigen_module}/
263
264
265
        fi
    done

266
    mkdir -p ./lightgbm-python/external_libs/eigen/Eigen/misc
267
268
269
    cp \
        -R \
        external_libs/eigen/Eigen/src/misc \
270
        ./lightgbm-python/external_libs/eigen/Eigen/src/misc/
271

272
    mkdir -p ./lightgbm-python/external_libs/eigen/Eigen/plugins
273
274
275
    cp \
        -R \
        external_libs/eigen/Eigen/src/plugins \
276
        ./lightgbm-python/external_libs/eigen/Eigen/src/plugins/
277
278
279
280

    ###################
    # compute (Boost) #
    ###################
281
    mkdir -p ./lightgbm-python/external_libs/compute
282
283
284
    cp \
        -R \
        external_libs/compute/include \
285
        ./lightgbm-python/external_libs/compute/include/
286
287
288
289
290
291
292
293
294
}

create_isolated_source_dir

cd ./lightgbm-python

# installation involves building the wheel + `pip install`-ing it
if test "${INSTALL}" = true; then
    if test "${PRECOMPILE}" = true; then
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
        BUILD_SDIST=true
        BUILD_WHEEL=false
        BUILD_ARGS=""
        rm -rf \
            ./cmake \
            ./CMakeLists.txt \
            ./external_libs \
            ./include \
            ./src \
            ./swig \
            ./windows
        # use regular-old setuptools for these builds, to avoid
        # trying to recompile the shared library
        sed -i.bak -e '/start:build-system/,/end:build-system/d' pyproject.toml
        echo '[build-system]' >> ./pyproject.toml
        echo 'requires = ["setuptools"]' >> ./pyproject.toml
        echo 'build-backend = "setuptools.build_meta"' >> ./pyproject.toml
        echo "" >> ./pyproject.toml
        echo "recursive-include lightgbm *.dll *.so" > ./MANIFEST.in
        echo "" >> ./MANIFEST.in
        mkdir -p ./lightgbm/lib
        if test -f ../lib_lightgbm.so; then
            echo "found pre-compiled lib_lightgbm.so"
            cp ../lib_lightgbm.so ./lightgbm/lib/lib_lightgbm.so
        elif test -f ../Release/lib_lightgbm.dll; then
            echo "found pre-compiled Release/lib_lightgbm.dll"
            cp ../Release/lib_lightgbm.dll ./lightgbm/lib/lib_lightgbm.dll
        elif test -f ../windows/x64/DLL/lib_lightgbm.dll; then
            echo "found pre-compiled windows/x64/DLL/lib_lightgbm.dll"
            cp ../windows/x64/DLL/lib_lightgbm.dll ./lightgbm/lib/lib_lightgbm.dll
            cp ../windows/x64/DLL/lib_lightgbm.lib ./lightgbm/lib/lib_lightgbm.lib
        fi
        rm -f ./*.bak
328
329
330
331
332
333
334
335
336
    else
        BUILD_SDIST="false"
        BUILD_WHEEL="true"
    fi
fi

if test "${BUILD_SDIST}" = true; then
    echo "--- building sdist ---"
    rm -f ../dist/*.tar.gz
337
338
339
340
    python -m build \
        --sdist \
        --outdir ../dist \
        .
341
342
343
fi

if test "${BUILD_WHEEL}" = true; then
344
    echo "--- building wheel ---"
345
    rm -f ../dist/*.whl || true
346
347
348
349
350
    python -m build \
        --wheel \
        --outdir ../dist \
        ${BUILD_ARGS} \
        .
351
352
353
354
355
356
357
358
fi

if test "${INSTALL}" = true; then
    echo "--- installing lightgbm ---"
    # ref for use of '--find-links': https://stackoverflow.com/a/52481267/3986677
    cd ../dist
    pip install \
        ${PIP_INSTALL_ARGS} \
359
        --force-reinstall \
360
361
362
363
364
365
366
        --find-links=. \
        lightgbm
    cd ../
fi

echo "cleaning up"
rm -rf ./lightgbm-python