build-python.sh 12 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
#     --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.
51
52
53
#     --no-isolation
#                                   Assume all build and install dependencies are already installed,
#                                   don't go to the internet to get them.
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
92
93
94
#     --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 #
    ############################
95
96
97
98
99
    --boost-dir|--boost-dir=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        BOOST_DIR="${1#*=}"
100
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.Boost_DIR='${BOOST_DIR}'"
101
        ;;
102
103
104
105
106
    --boost-include-dir|--boost-include-dir=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        BOOST_INCLUDE_DIR="${1#*=}"
107
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.Boost_INCLUDE_DIR='${BOOST_INCLUDE_DIR}'"
108
109
110
111
112
113
        ;;
    --boost-librarydir|--boost-librarydir=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        BOOST_LIBRARY_DIR="${1#*=}"
114
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.BOOST_LIBRARYDIR='${BOOST_LIBRARY_DIR}'"
115
116
117
118
119
120
        ;;
    --boost-root|--boost-root=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        BOOST_ROOT="${1#*=}"
121
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.Boost_ROOT='${BOOST_ROOT}'"
122
123
124
125
126
127
        ;;
    --opencl-include-dir|--opencl-include-dir=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        OPENCL_INCLUDE_DIR="${1#*=}"
128
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.OpenCL_INCLUDE_DIR='${OPENCL_INCLUDE_DIR}'"
129
130
131
132
133
134
        ;;
    --opencl-library|--opencl-library=*)
        if [[ "$1" != *=* ]];
            then shift;
        fi
        OPENCL_LIBRARY="${1#*=}"
135
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.OpenCL_LIBRARY='${OPENCL_LIBRARY}'"
136
137
138
139
140
        ;;
    #########
    # flags #
    #########
    --bit32)
141
142
143
        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}'."
144
145
        ;;
    --cuda)
146
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_CUDA=ON"
147
148
        ;;
    --gpu)
149
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_GPU=ON"
150
151
        ;;
    --hdfs)
152
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_HDFS=ON"
153
154
        ;;
    --integrated-opencl)
155
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.__INTEGRATE_OPENCL=ON"
156
157
        ;;
    --mingw)
158
159
160
        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"
161
162
        ;;
    --mpi)
163
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_MPI=ON"
164
        ;;
165
166
167
168
    --no-isolation)
        BUILD_ARGS="${BUILD_ARGS} --no-isolation"
        PIP_INSTALL_ARGS="${PIP_INSTALL_ARGS} --no-build-isolation"
        ;;
169
    --nomp)
170
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_OPENMP=OFF"
171
172
173
174
175
        ;;
    --precompile)
        PRECOMPILE="true"
        ;;
    --time-costs)
176
        BUILD_ARGS="${BUILD_ARGS} --config-setting=cmake.define.USE_TIMETAG=ON"
177
178
179
180
181
182
183
184
185
186
187
188
        ;;
    --user)
        PIP_INSTALL_ARGS="${PIP_INSTALL_ARGS} --user"
        ;;
    *)
        echo "invalid argument '${1}'"
        exit -1
        ;;
  esac
  shift
done

189
190
pip install --prefer-binary 'build>=0.10.0'

191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# 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

208
209
210
211
212
213
    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
214
215
216
217
218
219
220
221

    # 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 #
    ######################
222
    mkdir -p ./lightgbm-python/external_libs/fast_double_parser
223
224
    cp \
        external_libs/fast_double_parser/CMakeLists.txt \
225
        ./lightgbm-python/external_libs/fast_double_parser/CMakeLists.txt
226
227
    cp \
        external_libs/fast_double_parser/LICENSE* \
228
        ./lightgbm-python/external_libs/fast_double_parser/
229

230
    mkdir -p ./lightgbm-python/external_libs/fast_double_parser/include/
231
232
    cp \
        external_libs/fast_double_parser/include/fast_double_parser.h \
233
        ./lightgbm-python/external_libs/fast_double_parser/include/
234
235
236
237

    #######
    # fmt #
    #######
238
    mkdir -p ./lightgbm-python/external_libs/fmt
239
240
    cp \
        external_libs/fast_double_parser/CMakeLists.txt \
241
        ./lightgbm-python/external_libs/fmt/CMakeLists.txt
242
243
    cp \
        external_libs/fmt/LICENSE* \
244
        ./lightgbm-python/external_libs/fmt/
245

246
    mkdir -p ./lightgbm-python/external_libs/fmt/include/fmt
247
248
    cp \
        external_libs/fmt/include/fmt/*.h \
249
        ./lightgbm-python/external_libs/fmt/include/fmt/
250
251
252
253

    #########
    # Eigen #
    #########
254
    mkdir -p ./lightgbm-python/external_libs/eigen/Eigen
255
256
    cp \
        external_libs/eigen/CMakeLists.txt \
257
        ./lightgbm-python/external_libs/eigen/CMakeLists.txt
258
259
260
261
262

    modules="Cholesky Core Dense Eigenvalues Geometry Householder Jacobi LU QR SVD"
    for eigen_module in ${modules}; do
        cp \
            external_libs/eigen/Eigen/${eigen_module} \
263
            ./lightgbm-python/external_libs/eigen/Eigen/${eigen_module}
264
        if [ ${eigen_module} != "Dense" ]; then
265
            mkdir -p ./lightgbm-python/external_libs/eigen/Eigen/src/${eigen_module}/
266
267
268
            cp \
                -R \
                external_libs/eigen/Eigen/src/${eigen_module}/* \
269
                ./lightgbm-python/external_libs/eigen/Eigen/src/${eigen_module}/
270
271
272
        fi
    done

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

279
    mkdir -p ./lightgbm-python/external_libs/eigen/Eigen/plugins
280
281
282
    cp \
        -R \
        external_libs/eigen/Eigen/src/plugins \
283
        ./lightgbm-python/external_libs/eigen/Eigen/src/plugins/
284
285
286
287

    ###################
    # compute (Boost) #
    ###################
288
    mkdir -p ./lightgbm-python/external_libs/compute
289
290
291
    cp \
        -R \
        external_libs/compute/include \
292
        ./lightgbm-python/external_libs/compute/include/
293
294
295
296
297
298
299
300
301
}

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
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
328
329
330
331
332
333
334
        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
335
336
337
338
339
340
341
342
343
    else
        BUILD_SDIST="false"
        BUILD_WHEEL="true"
    fi
fi

if test "${BUILD_SDIST}" = true; then
    echo "--- building sdist ---"
    rm -f ../dist/*.tar.gz
344
345
346
    python -m build \
        --sdist \
        --outdir ../dist \
347
        ${BUILD_ARGS} \
348
        .
349
350
351
fi

if test "${BUILD_WHEEL}" = true; then
352
    echo "--- building wheel ---"
353
    rm -f ../dist/*.whl || true
354
355
356
357
358
    python -m build \
        --wheel \
        --outdir ../dist \
        ${BUILD_ARGS} \
        .
359
360
361
362
363
364
365
366
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} \
367
        --force-reinstall \
368
        --no-cache-dir \
369
370
371
372
373
374
375
        --find-links=. \
        lightgbm
    cd ../
fi

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