Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[python] [setup] improving installation #880

Merged
merged 33 commits into from Sep 8, 2017
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a5cfbda
disabled logs from compilers; fixed #874
Sep 1, 2017
5285ba4
fixed safe clear_fplder
Sep 1, 2017
7ed297e
added windows folder to manifest.in
Sep 1, 2017
7d3d3f1
added windows folder to build
Sep 1, 2017
f527e75
added library path
Sep 1, 2017
0dd47b9
added compilation with MSBuild from .sln-file
Sep 1, 2017
cf0355f
fixed unknown PlatformToolset returns exitcode 0
Sep 1, 2017
56e98ae
hotfix
Sep 1, 2017
72d57a2
updated Readme
Sep 2, 2017
c426442
removed return
Sep 2, 2017
d98b822
added installation with mingw test to appveyor
Sep 2, 2017
05dbbbe
let's test appveyor with both VS 2015 and VS 2017; but MinGW isn't in…
Sep 2, 2017
478468b
fixed built-in name 'file'
Sep 2, 2017
fa07c5e
simplified appveyor
Sep 2, 2017
1631fa1
removed excess data_files
Sep 2, 2017
0668aa7
fixed unreadable paths
Sep 2, 2017
4031d3b
separated exceptions for cmake and mingw
Sep 3, 2017
d6fdb92
refactored silent_call
Sep 3, 2017
f4e149f
don't create artifacts with VS 2015 and mingw
Sep 3, 2017
c1814e8
be more precise with python versioning in Travis
Sep 3, 2017
541b2e5
removed unnecessary if statement
Sep 4, 2017
2c04458
added classifiers for PyPI and python versions badge
Sep 4, 2017
ef28139
Merge branch 'master' into pip
StrikerRUS Sep 4, 2017
17f6400
changed python version in travis
Sep 4, 2017
cc8c212
Merge branch 'master' into pip
StrikerRUS Sep 5, 2017
9d7fa73
Merge branch 'master' into pip
Sep 5, 2017
ab8f81c
added support of scikit-learn 0.18.x
Sep 5, 2017
a4d90f4
added more python versions to Travis
Sep 5, 2017
710d8d7
added more python versions to Appveyor
Sep 5, 2017
8364407
reduced number of tests in Travis
Sep 6, 2017
749761e
Merge branch 'master' into pip
Sep 6, 2017
30e83a4
Travis trick is not needed anymore
Sep 6, 2017
27d19a3
attempt to fix according to https://github.com/Microsoft/LightGBM/pul…
Sep 8, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions python-package/MANIFEST.in
Expand Up @@ -5,5 +5,6 @@ recursive-include lightgbm *.py *.txt *.so
recursive-include lightgbm/Release *.dll
recursive-include lightgbm/include *
recursive-include lightgbm/src *
global-exclude *.pyo
global-exclude *.pyc
recursive-include lightgbm/windows LightGBM.sln LightGBM.vcxproj LightGBM.vcxproj.filters
recursive-include lightgbm/windows/x64/DLL *.dll
global-exclude *.py[co]
60 changes: 36 additions & 24 deletions python-package/README.rst
Expand Up @@ -3,7 +3,6 @@ LightGBM Python Package

|PyPI version|


Installation
------------

Expand All @@ -16,63 +15,76 @@ For Mac OS X users, gcc with OpenMP support must be installed first. Refer to `w

Note: 32-bit python is not supported. Please install 64-bit version.

Install from pip
''''''''''''''''
Install from `PyPI <https://pypi.python.org/pypi/lightgbm>`_ using ``pip``
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
For Windows users, `VC runtime <https://go.microsoft.com/fwlink/?LinkId=746572>`_ is needed if Visual Studio (2013, 2015 or 2017) is not installed.

Install `wheel <http://pythonwheels.com>`_ via ``pip install wheel`` first. After that download the wheel file and install from it:

.. code:: sh

pip install lightgbm

Install `wheel <http://pythonwheels.com>`_ via ``pip install wheel`` first. For Windows user, `VC runtime <https://go.microsoft.com/fwlink/?LinkId=746572>`_ is needed if Visual Studio (2013, 2015 or 2017) is not installed.
Build from sources
******************

.. code:: sh

``pip install lightgbm``
pip install --no-binary :all: lightgbm

For Linux and Mac OS X users, installation from sources requires installed `CMake <https://cmake.org/>`_.

Install source package from pip
*******************************
For Mac OS X users, you need to specify compilers by runnig ``export CXX=g++-7 CC=gcc-7`` first.

``pip install --no-binary :all: lightgbm``
For Windows users, Visual Studio (or `MS Build <https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017>`_) is needed. If you get any errors during installation, you may need to install `CMake <https://cmake.org/>`_ (version 3.8 or higher).

Build GPU version
~~~~~~~~~~~~~~~~~

Note: Installation from source package require installing `CMake <https://cmake.org/>`_ first.
.. code:: sh

For Windows user, Visual Studio (or `MS Build <https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017>`_) is needed, and `CMake <https://cmake.org/>`_ must be version 3.8 or higher.
pip install lightgbm --install-option=--gpu

For OSX user, you need to run ```export CXX=g++-7 CC=gcc-7``` before running ```pip install ... ```.
For Windows users, `CMake <https://cmake.org/>`_ (version 3.8 or higher) is strongly required in this case.

Install GPU version:
Note: Boost and OpenCL are needed: details for installation can be found in `gpu-support <https://github.com/Microsoft/LightGBM/wiki/Installation-Guide#with-gpu-support>`_. You need to add ``OpenCL_INCLUDE_DIR`` to the environmental variable **'PATH'** and export ``BOOST_ROOT`` before installation.

``pip install lightgbm --install-option=--gpu``
Build with MinGW-w64 on Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Note: Boost and OpenCL are needed: details for installation can be found in `gpu-support <https://github.com/Microsoft/LightGBM/wiki/Installation-Guide#with-gpu-support>`_. Need to add OpenCL_INCLUDE_DIR to PATH and export BOOST_ROOT before installation.
.. code:: sh

Install with MinGW on Windows:
pip install lightgbm --install-option=--mingw

``pip install lightgbm --install-option=--mingw``
Note: `CMake <https://cmake.org/>`_ and `MinGW-w64 <https://mingw-w64.org/>`_ should be installed first.

Install from GitHub
'''''''''''''''''''

Installation from GitHub require installing `CMake <https://cmake.org/>`_ first.
For Linux and Mac OS X users, installation from GitHub requires installed `CMake <https://cmake.org/>`_.

For Windows user, Visual Studio (or `MS Build <https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017>`_) is needed, and `CMake <https://cmake.org/>`_ must be version 3.8 or higher.
For Windows users, Visual Studio (or `MS Build <https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017>`_) is needed. If you get any errors during installation and there is the warning ``WARNING:LightGBM:Compilation with MSBuild from existing solution file failed.`` in the log, you should install `CMake <https://cmake.org/>`_ (version 3.8 or higher).

.. code:: sh

git clone --recursive https://github.com/Microsoft/LightGBM
git clone --recursive https://github.com/Microsoft/LightGBM.git
cd LightGBM/python-package
# export CXX=g++-7 CC=gcc-7 # for OSX
# export CXX=g++-7 CC=gcc-7 # for Mac OS X users only
python setup.py install

``sudo`` (or administrator rights in Windows) may is needed to perform ``python setup.py install``.
Note: ``sudo`` (or administrator rights in Windows) may be needed to perform the command.

Use ``python setup.py install --mingw`` to use MinGW in Windows.
Run ``python setup.py install --mingw`` if you want to use MinGW-w64 on Windows instead of Visual Studio. `CMake <https://cmake.org/>`_ and `MinGW-w64 <https://mingw-w64.org/>`_ should be installed first.

Use ``python setup.py install --gpu`` to enable GPU support. Boost and OpenCL are needed: details for installation can be found in `gpu-support <https://github.com/Microsoft/LightGBM/wiki/Installation-Guide#with-gpu-support>`_.
Run ``python setup.py install --gpu`` to enable GPU support. For Windows users, `CMake <https://cmake.org/>`_ (version 3.8 or higher) is strongly required in this case. Boost and OpenCL are needed: details for installation can be found in `gpu-support <https://github.com/Microsoft/LightGBM/wiki/Installation-Guide#with-gpu-support>`_.

If you get any errors during installation or due to any other reason, you may want to build dynamic library from sources by any method you prefer (see `Installation-Guide <https://github.com/Microsoft/LightGBM/wiki/Installation-Guide>`_) and then run ``python setup.py install --precompile``.

Examples
--------

Refer to the walk through examples in `python-guide folder <https://github.com/Microsoft/LightGBM/tree/master/examples/python-guide>`_.


Troubleshooting
---------------

Expand Down
3 changes: 2 additions & 1 deletion python-package/lightgbm/libpath.py
Expand Up @@ -19,6 +19,7 @@ def find_lib_path():
dll_path = [curr_path, os.path.join(curr_path, '../../'), os.path.join(curr_path, '../../lib/')]
if os.name == 'nt':
dll_path.append(os.path.join(curr_path, './Release/'))
dll_path.append(os.path.join(curr_path, './windows/x64/DLL/'))
dll_path.append(os.path.join(curr_path, '../../Release/'))
dll_path.append(os.path.join(curr_path, '../../windows/x64/DLL/'))
dll_path = [os.path.join(p, 'lib_lightgbm.dll') for p in dll_path]
Expand All @@ -27,5 +28,5 @@ def find_lib_path():
lib_path = [p for p in dll_path if os.path.exists(p) and os.path.isfile(p)]
if not lib_path:
dll_path = [os.path.realpath(p) for p in dll_path]
raise Exception('Cannot find lightgbm Library in following paths: ' + ','.join(dll_path))
raise Exception('Cannot find lightgbm library in following paths: ' + '\n'.join(dll_path))
return lib_path
101 changes: 70 additions & 31 deletions python-package/setup.py
Expand Up @@ -4,9 +4,11 @@
from __future__ import absolute_import

import distutils
import logging
import os
import shutil
import struct
import subprocess
import sys

from setuptools import find_packages, setup
Expand All @@ -22,7 +24,7 @@ def find_lib():
exec(compile(open(libpath_py, "rb").read(), libpath_py, 'exec'), libpath, libpath)

LIB_PATH = [os.path.relpath(path, CURRENT_DIR) for path in libpath['find_lib_path']()]
print("Install lib_lightgbm from: %s" % LIB_PATH)
logging.info("Installing lib_lightgbm from: %s" % LIB_PATH)
return LIB_PATH


Expand All @@ -40,20 +42,31 @@ def copy_files_helper(folder_name):
if not os.path.isfile('./_IS_SOURCE_PACKAGE.txt'):
copy_files_helper('include')
copy_files_helper('src')
copy_files_helper('windows')
if use_gpu:
copy_files_helper('compute')
distutils.file_util.copy_file("../CMakeLists.txt", "./lightgbm/")
distutils.file_util.copy_file("../LICENSE", "./")


def clear_path(path):
contents = os.listdir(path)
for file in contents:
file_path = os.path.join(path, file)
if os.path.isfile(file_path):
os.remove(file_path)
else:
shutil.rmtree(file_path)
if os.path.isdir(path):
contents = os.listdir(path)
for file in contents:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

look like file is a built-in, can you help rename it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wxchan Sure.

file_path = os.path.join(path, file)
if os.path.isfile(file_path):
os.remove(file_path)
else:
shutil.rmtree(file_path)


def silent_call(cmd):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not so sure about what's this function for, why makes it silent?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wxchan This PR was conceived as fix to #874

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@StrikerRUS ok, got it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this function be designed like def silent_call(cmd, raise_error=True, error_msg='')? In this case, if cmake_cmd fails, you don't need to call make_cmd then.

Copy link
Collaborator Author

@StrikerRUS StrikerRUS Sep 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wxchan
It already has described behavior. In case of any error it returns 1 and you should just check returned value.

Do you mean that I should change this code

status = silent_call(cmake_cmd + ["-G", "MinGW Makefiles"])
status += silent_call(["mingw32-make.exe", "_lightgbm"])
if status != 0:
    raise Exception('Please install CMake and MinGW first')

to

status = silent_call(cmake_cmd + ["-G", "MinGW Makefiles"])
if status != 0:
    raise Exception('Please install CMake first')
status = silent_call(["mingw32-make.exe", "_lightgbm"])
if status != 0:
    raise Exception('Please install MinGW first')

?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I think it's better, and you can move raise Exception into function to avoid duplicates, but it's trivial, up to you.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wxchan Moving raising Exception into the function will cause dozens of try/except into the main code and will make code messy.

Copy link
Contributor

@wxchan wxchan Sep 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't sth like below work? why need try/except in main code? not sure, LGTM now, it's up to you.

def silent_call(cmd, raise_error=True, error_msg='')
	try:
		// do sth
		return 0
	except:
		if raise_error:
			raise Exception(error_msg)
		return 1

silent_call(cmake_cmd, error_msg='Please install CMake first')

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wxchan It seems you are right! raise_error will help to deal with such situation
if status == 0 and os.path.exists(lib_path):

try:
with open(os.devnull, "w") as shut_up:
subprocess.check_output(cmd, stderr=shut_up)
return 0
except Exception:
return 1


def compile_cpp(use_mingw=False, use_gpu=False):
Expand All @@ -63,33 +76,56 @@ def compile_cpp(use_mingw=False, use_gpu=False):
os.makedirs("build_cpp")
os.chdir("build_cpp")

cmake_cmd = "cmake "
build_cmd = "make _lightgbm"
logger.info("Starting to compile the library.")

cmake_cmd = ["cmake", "../lightgbm/"]
if use_gpu:
cmake_cmd += " -DUSE_GPU=ON "
cmake_cmd.append("-DUSE_GPU=ON")
if os.name == "nt":
if use_mingw:
cmake_cmd += " -G \"MinGW Makefiles\" "
os.system(cmake_cmd + " ../lightgbm/")
build_cmd = "mingw32-make.exe _lightgbm"
logger.info("Starting to compile with CMake and MinGW.")
status = silent_call(cmake_cmd + ["-G", "MinGW Makefiles"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name status is a little confusing, can it be succeed or fail or sth like this? (I don't read through all codes because I am not sure about those VS install logic).

Copy link
Collaborator Author

@StrikerRUS StrikerRUS Sep 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wxchan Will exitcode be OK?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ignore this.

status += silent_call(["mingw32-make.exe", "_lightgbm"])
if status != 0:
raise Exception('Please install CMake and MinGW first')
else:
vs_versions = ["Visual Studio 15 2017 Win64", "Visual Studio 14 2015 Win64", "Visual Studio 12 2013 Win64"]
try_vs = 1
for vs in vs_versions:
tmp_cmake_cmd = "%s -G \"%s\"" % (cmake_cmd, vs)
try_vs = os.system(tmp_cmake_cmd + " ../lightgbm/")
if try_vs == 0:
cmake_cmd = tmp_cmake_cmd
break
else:
clear_path("./")
if try_vs != 0:
raise Exception('Please install Visual Studio or MS Build first')

build_cmd = "cmake --build . --target _lightgbm --config Release"
print("Start to compile library.")
os.system(cmake_cmd + " ../lightgbm/")
os.system(build_cmd)
status = 1
lib_path = "../lightgbm/windows/x64/DLL/lib_lightgbm.dll"
if not use_gpu:
logger.info("Starting to compile with MSBuild from existing solution file.")
platform_toolsets = ("v141", "v140", "v120")
for pt in platform_toolsets:
status = silent_call(["MSBuild", "../lightgbm/windows/LightGBM.sln",
"/p:Configuration=DLL",
"/p:Platform=x64",
"/p:PlatformToolset={0}".format(pt)])
if status == 0 and os.path.exists(lib_path):
break
else:
clear_path("../lightgbm/windows/x64")
if status != 0 or not os.path.exists(lib_path):
logger.warning("Compilation with MSBuild from existing solution file failed.")
if status != 0 or not os.path.exists(lib_path):
vs_versions = ("Visual Studio 15 2017 Win64", "Visual Studio 14 2015 Win64", "Visual Studio 12 2013 Win64")
for vs in vs_versions:
logger.info("Starting to compile with %s." % vs)
status = silent_call(cmake_cmd + ["-G", vs])
if status == 0:
break
else:
clear_path("./")
if status != 0:
raise Exception('Please install Visual Studio or MS Build first')

status = silent_call(["cmake", "--build", ".", "--target", "_lightgbm", "--config", "Release"])
if status != 0:
raise Exception('Please install CMake first')
else: # Linux, Darwin (OS X), etc.
logger.info("Starting to compile with CMake.")
status = silent_call(cmake_cmd)
status += silent_call(["make", "_lightgbm"])
if status != 0:
raise Exception('Please install CMake first')
os.chdir("..")


Expand Down Expand Up @@ -154,6 +190,9 @@ def run(self):

sys.path.insert(0, '.')

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('LightGBM')

setup(name='lightgbm',
version=version,
description='LightGBM Python Package',
Expand Down