Commit 678efb91 authored by Gigg, Martyn Anthony's avatar Gigg, Martyn Anthony Committed by Peterson, Peter
Browse files

Generate sitecustomize.py in binary dir

setuptools no longer installs a site,py to bootstrap the sys.path
so we use the recommended approach of installing a sitecustomize file
for the build.
The custom setup.py build classes have been removed as they complicate
the build setup vs just using gitignore. Future changes in setuptools
and pip will remove the option to build out of source anyway...
parent fdabe055
......@@ -100,6 +100,18 @@
"OSX_INSTALL_RPATH": "+",
"LINUX_INSTALL_RPATH": "+"
}
},
"add_python_package": {
"kwargs": {
"EGGLINKNAME": 1,
"INSTALL_LIB_DIRS": "+",
"INSTALL_BIN_DIR": 1,
"EXCLUDE_ON_INSTALL": "+"
},
"flags": [
"EXECUTABLE",
"GENERATE_SITECUSTOMIZE"
]
}
},
"always_wrap": [],
......
......@@ -108,9 +108,14 @@ if(APPLE)
else()
set(_install_lib_dirs "${SITE_PACKAGES}")
endif()
add_python_package(
PythonInterface EGGLINKNAME mantid INSTALL_LIB_DIRS ${_install_lib_dirs}
PythonInterface
EGGLINKNAME mantid
INSTALL_LIB_DIRS ${_install_lib_dirs}
GENERATE_SITECUSTOMIZE
)
set_property(TARGET PythonInterface PROPERTY FOLDER "MantidFramework/Python")
add_dependencies(
PythonInterface
......@@ -150,7 +155,11 @@ add_subdirectory(test)
# Python algorithms
mtd_install_dirs(
DIRECTORY plugins/
INSTALL_DIRS ${PLUGINS_DIR}/python ${WORKBENCH_PLUGINS_DIR}/python
EXCLUDE "*.pyc"
DIRECTORY
plugins/
INSTALL_DIRS
${PLUGINS_DIR}/python
${WORKBENCH_PLUGINS_DIR}/python
EXCLUDE
"*.pyc"
)
......@@ -6,15 +6,13 @@
# & Institut Laue - Langevin
# SPDX - License - Identifier: GPL - 3.0 +
# This file is part of the mantid workbench.
import os
from setuptools import find_packages, setup
@SETUPTOOLS_BUILD_COMMANDS_DEF@
# The most basic setup possible to be able to use setup.py develop
# The most basic setup possible to be able to use pip develop/install
setup(
name='mantid',
version='@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@@VERSION_TWEAK_PY@',
version=os.environ['MANTID_VERSION_STR'],
packages=find_packages(exclude=['*.test', 'plugins*']),
package_data={'': ['*.ui']},
@SETUPTOOLS_BUILD_COMMANDS_USE@
)
# ##############################################################################
# Configure required dependencies if necessary
# ##############################################################################
if(MSVC)
if(MSVC AND NOT CONDA_BUILD)
# Git LFS does not work properly with <= 1.9
find_package(Git 1.9.5 REQUIRED)
find_package(GitLFS REQUIRED)
......@@ -15,7 +15,7 @@ if(MSVC)
set(THIRD_PARTY_GIT_URL
"https://github.com/mantidproject/thirdparty-msvc2015.git"
)
set(THIRD_PARTY_GIT_SHA1 913585ad3212c6fa6bd6f9c54cde473fa171ff54)
set(THIRD_PARTY_GIT_SHA1 0a4c81cb2a6809125867022d2d5320c22075a0c6)
set(THIRD_PARTY_DIR ${EXTERNAL_ROOT}/src/ThirdParty)
# Generates a script to do the clone/update in tmp
set(_project_name ThirdParty)
......@@ -115,8 +115,8 @@ if(MSVC)
# Add to the path so that cmake can configure correctly without the user
# having to do it
set(ENV{PATH} "${THIRD_PARTY_BIN};$ENV{PATH}")
# Set PATH for custom command or target build steps. Avoids the need to
# make external PATH updates
# Set PATH for custom command or target build steps. Avoids the need to make
# external PATH updates
set(CMAKE_MSVCIDE_RUN_PATH ${THIRD_PARTY_BIN})
# Set variables to help CMake find components
......@@ -127,7 +127,20 @@ if(MSVC)
set(BOOST_INCLUDEDIR "${CMAKE_INCLUDE_PATH}")
set(BOOST_LIBRARYDIR "${CMAKE_LIBRARY_PATH}")
set(Boost_NO_SYSTEM_PATHS TRUE)
elseif(MSVC AND CONDA_BUILD)
# Print out where we are looking for 3rd party stuff
set(Python_FIND_REGISTRY NEVER)
# used in later parts for MSVC to bundle Python
set(MSVC_PYTHON_EXECUTABLE_DIR $ENV{CONDA_PREFIX})
set(THIRD_PARTY_BIN
"$ENV{CONDA_PREFIX}/Library/bin;$ENV{CONDA_PREFIX}/Library/lib;${MSVC_PYTHON_EXECUTABLE_DIR}"
)
# Add to the path so that cmake can configure correctly without the user
# having to do it
set(ENV{PATH} "${THIRD_PARTY_BIN};$ENV{PATH}")
# Set PATH for custom command or target build steps. Avoids the need to make
# external PATH updates
set(CMAKE_MSVCIDE_RUN_PATH ${THIRD_PARTY_BIN})
else()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# Homebrew adds qt4 here and we require it to be unlinked from /usr/local to
......@@ -166,12 +179,28 @@ endfunction()
# Find python interpreter
set(MINIMUM_PYTHON_VERSION 3.6)
find_package(Python ${MINIMUM_PYTHON_VERSION} REQUIRED
COMPONENTS Interpreter Development NumPy)
# If anything external uses find_package(PythonInterp) then make sure it finds the correct version and executable
set(Python3_ROOT_DIR $ENV{CONDA_PREFIX})
find_package(
Python ${MINIMUM_PYTHON_VERSION} REQUIRED COMPONENTS Interpreter Development
NumPy
)
# If anything external uses find_package(PythonInterp) then make sure it finds
# the correct version and executable
set(PYTHON_EXECUTABLE ${Python_EXECUTABLE})
set(Python_ADDITIONAL_VERSIONS ${Python_VERSION_MAJOR}.${Python_VERSION_MINOR})
# Search for the pythonw executable if it has not already been found Will only
# look in the folder containing the current python.exe
if(NOT Python_W_EXECUTABLE)
get_filename_component(Python_Binary_Dir ${PYTHON_EXECUTABLE} DIRECTORY)
find_program(
Python_W_EXECUTABLE
PATHS ${Python_Binary_Dir}
NAMES pythonw
NO_DEFAULT_PATH
)
endif()
# Handle switching between previously configured Python verions
if(Python_INCLUDE_DIR
AND NOT Python_INCLUDE_DIR MATCHES
......@@ -180,5 +209,19 @@ if(Python_INCLUDE_DIR
message(
STATUS "Python version has changed. Clearing previous Python configuration."
)
unset_cached_Python_variables()
unset_cached_python_variables()
endif()
# What version of setuptools are we using?
execute_process(
COMMAND ${Python_EXECUTABLE} -c
"import setuptools;print(setuptools.__version__)"
RESULT_VARIABLE _setuptools_version_check_result
OUTPUT_VARIABLE Python_SETUPTOOLS_VERSION
ERROR_VARIABLE _setuptools_version_check_error
)
if(NOT _setuptools_version_check_result EQUAL 0)
message(FATAL_ERROR "Unable to determine setuptools version:\n"
" ${_setuptools_version_check_error}"
)
endif()
# Defines functions to help deal with python packages
# ~~~
# Function to create links to python packages in the source tree
# Function to create links to python packages from the source tree
# to the binary tree. It expects a setup.py to be found in
# ${CMAKE_CURRENT_SOURCE_DIR}/setup.py
# Optional keyword arguments:
# - EXECUTABLE: If this option provided then it is assumed the package contains a
# startup script and this is installed in the package bin
......@@ -12,62 +14,22 @@
# - INSTALL_BIN_DIR: Destination for an executable to be installed
# - EXCLUDE_ON_INSTALL: Specifies a regex of files to exclude from the install
# - command
# - GENERATE_SITECUSTOMIZE: If provided then generate a sitecustomize
# file in the egg link directory
# ~~~
function(
add_python_package
pkg_name
)
function(add_python_package pkg_name)
# Create a setup.py file if necessary
set(_setup_py ${CMAKE_CURRENT_SOURCE_DIR}/setup.py)
set(_setup_py_build_root ${CMAKE_CURRENT_BINARY_DIR})
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in")
set(
SETUPTOOLS_BUILD_COMMANDS_DEF
"def patch_setuptools_command(cmd_cls_name):
import importlib
cmd_module = importlib.import_module('setuptools.command.' + cmd_cls_name)
setuptools_command_cls = getattr(cmd_module, cmd_cls_name)
class CustomCommand(setuptools_command_cls):
user_options = setuptools_command_cls.user_options[:]
boolean_options = setuptools_command_cls.boolean_options[:]
def finalize_options(self):
self.build_lib = '${_setup_py_build_root}/build'
setuptools_command_cls.finalize_options(self)
return CustomCommand
CustomBuildPy = patch_setuptools_command('build_py')
CustomInstall = patch_setuptools_command('install')
CustomInstallLib = patch_setuptools_command('install_lib')
"
)
set(
SETUPTOOLS_BUILD_COMMANDS_USE
"cmdclass={'build_py': CustomBuildPy, 'install': CustomInstall, 'install-lib': CustomInstallLib }"
)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in
${_setup_py}
@ONLY
)
endif()
set(_egg_link_dir ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR})
# Create variables for additional arguments
_configure_setup_py(${_setup_py} ${_setup_py_build_root})
cmake_parse_arguments(
_parsed_arg
"EXECUTABLE"
"EGGLINKNAME;EXCLUDE_FROM_INSTALL;INSTALL_BIN_DIR"
"INSTALL_LIB_DIRS"
_parsed_arg "EXECUTABLE;GENERATE_SITECUSTOMIZE"
"EGGLINKNAME;EXCLUDE_FROM_INSTALL;INSTALL_BIN_DIR" "INSTALL_LIB_DIRS"
${ARGN}
)
# If a custom egg-link name was specified use that for the link
if(_parsed_arg_EGGLINKNAME)
set(_egg_link ${_egg_link_dir}/${_parsed_arg_EGGLINKNAME}.egg-link)
else()
......@@ -92,34 +54,36 @@ CustomInstallLib = patch_setuptools_command('install_lib')
# create the developer setup which just creates a pth file rather than copying
# things over
set(
_outputs
${_egg_link}
${_startup_script}
${_startup_exe}
set(_outputs ${_egg_link} ${_startup_script} ${_startup_exe})
set(_version_str
${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_TWEAK_PY}
)
add_custom_command(
OUTPUT ${_outputs}
COMMAND
${CMAKE_COMMAND}
-E
env
PYTHONPATH=${_egg_link_dir}
${Python_EXECUTABLE}
${_setup_py}
develop
--install-dir
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}
--script-dir
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}
${CMAKE_COMMAND} -E env PYTHONPATH=${_egg_link_dir}
MANTID_VERSION_STR=${_version_str} ${Python_EXECUTABLE} ${_setup_py}
develop --install-dir ${_egg_link_dir} --script-dir ${_egg_link_dir}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${_setup_py}
)
add_custom_target(
${pkg_name}
ALL
DEPENDS ${_outputs}
# Generate a sitecustomize.py file in the egg link directory as setuptools no
# longer generates site.py for v>=49.0.0
if(_parsed_arg_GENERATE_SITECUSTOMIZE AND Python_SETUPTOOLS_VERSION
VERSION_GREATER_EQUAL 49.0.0
)
add_custom_command(
OUTPUT ${_egg_link_dir}/sitecustomize.py
COMMAND ${CMAKE_COMMAND} -DSITECUSTOMIZE_DIR=${_egg_link_dir} -P
${CMAKE_MODULE_PATH}/WriteSiteCustomize.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${_setup_py} ${CMAKE_MODULE_PATH}/WriteSiteCustomize.cmake
)
list(APPEND _outputs ${_egg_link_dir}/sitecustomize.py)
endif()
add_custom_target(${pkg_name} ALL DEPENDS ${_outputs})
# setuptools by default wants to build into a directory called 'build'
# relative the to the working directory. We have overridden commands in
......@@ -128,47 +92,70 @@ CustomInstallLib = patch_setuptools_command('install_lib')
# --install-lib=lib removes any of the platform/distribution specific install
# directories so we can have a flat structure
install(
CODE
"execute_process(COMMAND ${Python_EXECUTABLE} ${_setup_py} install -O1 --single-version-externally-managed --root=${_setup_py_build_root}/install --install-scripts=bin --install-lib=lib WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})"
CODE "execute_process(COMMAND ${Python_EXECUTABLE} ${_setup_py} install -O1 --single-version-externally-managed --root=${_setup_py_build_root}/install --install-scripts=bin --install-lib=lib WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})"
)
# Registers the "installed" components with CMake so it will carry them over
if(_parsed_arg_EXCLUDE_FROM_INSTALL)
foreach(
_dest
${_parsed_arg_INSTALL_LIB_DIRS}
)
foreach(_dest ${_parsed_arg_INSTALL_LIB_DIRS})
install(
DIRECTORY ${_setup_py_build_root}/install/lib/
DESTINATION ${_dest}
PATTERN
"test"
EXCLUDE
REGEX
"${_parsed_arg_EXCLUDE_FROM_INSTALL}"
EXCLUDE
PATTERN "test" EXCLUDE
REGEX "${_parsed_arg_EXCLUDE_FROM_INSTALL}" EXCLUDE
)
endforeach()
else()
foreach(
_dest
${_parsed_arg_INSTALL_LIB_DIRS}
)
foreach(_dest ${_parsed_arg_INSTALL_LIB_DIRS})
install(
DIRECTORY ${_setup_py_build_root}/install/lib/
DESTINATION ${_dest}
PATTERN
"test"
EXCLUDE
PATTERN "test" EXCLUDE
)
endforeach()
endif()
# install the generated executable
if(_parsed_arg_EXECUTABLE AND _parsed_arg_INSTALL_BIN_DIR)
install(
PROGRAMS ${_setup_py_build_root}/install/bin/${pkg_name}
DESTINATION ${_parsed_arg_INSTALL_BIN_DIR}
)
install(PROGRAMS ${_setup_py_build_root}/install/bin/${pkg_name}
DESTINATION ${_parsed_arg_INSTALL_BIN_DIR}
)
endif()
endfunction()
# ~~~
# Function to generate a setup.py from a template. It is assumed the template
# resides at ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in.
# The generated file injects custom build commands to:
# - ensure setup build/install ends up in the binary tree and not source
# - inject a sitecustomize file in the egg-link directory if one does not
# exist
# ~~~
function(_configure_setup_py target build_root)
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in")
message(
FATAL_ERROR
"Unable to generate setup.py. ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in not found."
)
endif()
# # ~~~ set(SETUPTOOLS_BUILD_COMMANDS_DEF "class
# CustomBuildDir(setuptools_command_cls): user_options =
# setuptools_command_cls.user_options[:] boolean_options =
# setuptools_command_cls.boolean_options[:]
# def finalize_options(self): self.build_lib = '${build_root}/build'
# setuptools_command_cls.finalize_options(self)
# def patch_setuptools_command(cmd_cls_name, CommandCls): import importlib
# cmd_module = importlib.import_module('setuptools.command.' + cmd_cls_name)
# setuptools_command_cls = getattr(cmd_module, cmd_cls_name) return CommandCls
# CustomBuildPy = patch_setuptools_command('build_py') CustomInstall =
# patch_setuptools_command('install') CustomInstallLib =
# patch_setuptools_command('install_lib') " ) # ~~~
# set(SETUPTOOLS_BUILD_COMMANDS_USE "cmdclass={'build_py': CustomBuildPy,
# 'install': CustomInstall, 'install-lib': CustomInstallLib }" )
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in ${target} @ONLY)
endfunction()
# CMake script to generate a Python sitecustomize.py file at build time It is
# intended to be used via cmake -P (script mode)
file(
WRITE ${SITECUSTOMIZE_DIR}/sitecustomize.py
"
import site
site.addsitedir('${SITECUSTOMIZE_DIR}')
"
)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment