From 2046d72e91670114625c87e122db6e013ba089d5 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Sun, 22 Dec 2019 13:57:46 -0800 Subject: [PATCH] build: improve python checks for Windows Require a newer CMake on Windows to use the Python3 support that is packaged in CMake. This version is able to check both 32-bit and 64-bit versions and will setup everything properly without the user needing to specify PYTHON_HOME. This enables building lldb's python bindings on Windows under Azure's CI again. --- lldb/CMakeLists.txt | 3 + lldb/cmake/modules/LLDBConfig.cmake | 189 +++++------------------------------- 2 files changed, 25 insertions(+), 167 deletions(-) diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index ff3d8ae..6170ab6 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -1,4 +1,7 @@ cmake_minimum_required(VERSION 3.4.3) +if(CMAKE_SYSTEM_NAME STREQUAL Windows) + cmake_minimum_required(VERSION 3.13) +endif() if(POLICY CMP0075) cmake_policy(SET CMP0075 NEW) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index c34ef76..e1da76c 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -138,184 +138,39 @@ if (LLDB_ENABLE_LIBEDIT) set(CMAKE_EXTRA_INCLUDE_FILES) endif() -# On Windows, we can't use the normal FindPythonLibs module that comes with CMake, -# for a number of reasons. -# 1) Prior to MSVC 2015, it is only possible to embed Python if python itself was -# compiled with an identical version (and build configuration) of MSVC as LLDB. -# The standard algorithm does not take into account the differences between -# a binary release distribution of python and a custom built distribution. -# 2) From MSVC 2015 and onwards, it is only possible to use Python 3.5 or later. -# 3) FindPythonLibs queries the registry to locate Python, and when looking for a -# 64-bit version of Python, since cmake.exe is a 32-bit executable, it will see -# a 32-bit view of the registry. As such, it is impossible for FindPythonLibs to -# locate 64-bit Python libraries. -# This function is designed to address those limitations. Currently it only partially -# addresses them, but it can be improved and extended on an as-needed basis. -function(find_python_libs_windows_helper LOOKUP_DEBUG OUT_EXE_PATH_VARNAME OUT_LIB_PATH_VARNAME OUT_DLL_PATH_VARNAME OUT_VERSION_VARNAME) - if(LOOKUP_DEBUG) - set(POSTFIX "_d") - else() - set(POSTFIX "") - endif() - - file(TO_CMAKE_PATH "${PYTHON_HOME}/python${POSTFIX}.exe" PYTHON_EXE) - file(TO_CMAKE_PATH "${PYTHON_HOME}/libs/${PYTHONLIBS_BASE_NAME}${POSTFIX}.lib" PYTHON_LIB) - file(TO_CMAKE_PATH "${PYTHON_HOME}/${PYTHONLIBS_BASE_NAME}${POSTFIX}.dll" PYTHON_DLL) - - foreach(component PYTHON_EXE;PYTHON_LIB;PYTHON_DLL) - if(NOT EXISTS ${${component}}) - message(WARNING "Unable to find ${component}") - unset(${component}) - endif() - endforeach() - - if (NOT PYTHON_EXE OR NOT PYTHON_LIB OR NOT PYTHON_DLL) - message(WARNING "Unable to find all Python components. Python support will be disabled for this build.") - set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE) - return() - endif() - - # Find the version of the Python interpreter. - execute_process(COMMAND "${PYTHON_EXE}" -c - "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))" - OUTPUT_VARIABLE PYTHON_VERSION_OUTPUT - RESULT_VARIABLE PYTHON_VERSION_RESULT - ERROR_QUIET) - - if(PYTHON_VERSION_RESULT) - message(WARNING "Unable to retrieve Python executable version") - set(PYTHON_VERSION_OUTPUT "") - endif() - - set(${OUT_EXE_PATH_VARNAME} ${PYTHON_EXE} PARENT_SCOPE) - set(${OUT_LIB_PATH_VARNAME} ${PYTHON_LIB} PARENT_SCOPE) - set(${OUT_DLL_PATH_VARNAME} ${PYTHON_DLL} PARENT_SCOPE) - set(${OUT_VERSION_VARNAME} ${PYTHON_VERSION_OUTPUT} PARENT_SCOPE) -endfunction() - -function(find_python_libs_windows) - if ("${PYTHON_HOME}" STREQUAL "") - message(WARNING "LLDB embedded Python on Windows requires specifying a value for PYTHON_HOME. Python support disabled.") - set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE) - return() - endif() - - file(TO_CMAKE_PATH "${PYTHON_HOME}/Include" PYTHON_INCLUDE_DIR) - - if(EXISTS "${PYTHON_INCLUDE_DIR}/patchlevel.h") - file(STRINGS "${PYTHON_INCLUDE_DIR}/patchlevel.h" python_version_str - REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"") - string(REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"+]+)[+]?\".*" "\\1" - PYTHONLIBS_VERSION_STRING "${python_version_str}") - message(STATUS "Found Python library version ${PYTHONLIBS_VERSION_STRING}") - string(REGEX REPLACE "([0-9]+)[.]([0-9]+)[.][0-9]+" "python\\1\\2" PYTHONLIBS_BASE_NAME "${PYTHONLIBS_VERSION_STRING}") - unset(python_version_str) - else() - message(WARNING "Unable to find ${PYTHON_INCLUDE_DIR}/patchlevel.h, Python installation is corrupt.") - message(WARNING "Python support will be disabled for this build.") - set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE) - return() - endif() - - file(TO_CMAKE_PATH "${PYTHON_HOME}" PYTHON_HOME) - # TODO(compnerd) when CMake Policy `CMP0091` is set to NEW, we should use - # if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES MultiThreadedDebug) - if(NOT DEFINED CMAKE_BUILD_TYPE) - # Multi-target generator was selected (like Visual Studio or Xcode) where no concrete build type was passed - # Lookup for both debug and release python installations - find_python_libs_windows_helper(TRUE PYTHON_DEBUG_EXE PYTHON_DEBUG_LIB PYTHON_DEBUG_DLL PYTHON_DEBUG_VERSION_STRING) - find_python_libs_windows_helper(FALSE PYTHON_RELEASE_EXE PYTHON_RELEASE_LIB PYTHON_RELEASE_DLL PYTHON_RELEASE_VERSION_STRING) - if(NOT LLDB_ENABLE_PYTHON) - set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE) - return() - endif() - - # We should have been found both debug and release python here - # Now check that their versions are equal - if(NOT PYTHON_DEBUG_VERSION_STRING STREQUAL PYTHON_RELEASE_VERSION_STRING) - message(FATAL_ERROR "Python versions for debug (${PYTHON_DEBUG_VERSION_STRING}) and release (${PYTHON_RELEASE_VERSION_STRING}) are different." - "Python installation is corrupted") - endif () - - set(PYTHON_EXECUTABLE $<$:${PYTHON_DEBUG_EXE}>$<$>:${PYTHON_RELEASE_EXE}>) - set(PYTHON_LIBRARY $<$:${PYTHON_DEBUG_LIB}>$<$>:${PYTHON_RELEASE_LIB}>) - set(PYTHON_DLL $<$:${PYTHON_DEBUG_DLL}>$<$>:${PYTHON_RELEASE_DLL}>) - set(PYTHON_VERSION_STRING ${PYTHON_RELEASE_VERSION_STRING}) - else() - # Lookup for concrete python installation depending on build type - if (CMAKE_BUILD_TYPE STREQUAL Debug) - set(LOOKUP_DEBUG_PYTHON TRUE) - else() - set(LOOKUP_DEBUG_PYTHON FALSE) - endif() - find_python_libs_windows_helper(${LOOKUP_DEBUG_PYTHON} PYTHON_EXECUTABLE PYTHON_LIBRARY PYTHON_DLL PYTHON_VERSION_STRING) - if(NOT LLDB_ENABLE_PYTHON) - set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE) - return() - endif() - endif() - - if(PYTHON_VERSION_STRING) - string(REPLACE "." ";" PYTHON_VERSION_PARTS "${PYTHON_VERSION_STRING}") - list(GET PYTHON_VERSION_PARTS 0 PYTHON_VERSION_MAJOR) - list(GET PYTHON_VERSION_PARTS 1 PYTHON_VERSION_MINOR) - list(GET PYTHON_VERSION_PARTS 2 PYTHON_VERSION_PATCH) - else() - unset(PYTHON_VERSION_MAJOR) - unset(PYTHON_VERSION_MINOR) - unset(PYTHON_VERSION_PATCH) - endif() - - # Set the same variables as FindPythonInterp and FindPythonLibs. - set(PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}" CACHE PATH "") - set(PYTHON_LIBRARY "${PYTHON_LIBRARY}" CACHE PATH "") - set(PYTHON_DLL "${PYTHON_DLL}" CACHE PATH "") - set(PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}" CACHE PATH "") - set(PYTHONLIBS_VERSION_STRING "${PYTHONLIBS_VERSION_STRING}" PARENT_SCOPE) - set(PYTHON_VERSION_STRING "${PYTHON_VERSION_STRING}" PARENT_SCOPE) - set(PYTHON_VERSION_MAJOR "${PYTHON_VERSION_MAJOR}" PARENT_SCOPE) - set(PYTHON_VERSION_MINOR "${PYTHON_VERSION_MINOR}" PARENT_SCOPE) - set(PYTHON_VERSION_PATCH "${PYTHON_VERSION_PATCH}" PARENT_SCOPE) - - message(STATUS "LLDB Found PythonExecutable: ${PYTHON_EXECUTABLE} (${PYTHON_VERSION_STRING})") - message(STATUS "LLDB Found PythonLibs: ${PYTHON_LIBRARY} (${PYTHONLIBS_VERSION_STRING})") - message(STATUS "LLDB Found PythonDLL: ${PYTHON_DLL}") - message(STATUS "LLDB Found PythonIncludeDirs: ${PYTHON_INCLUDE_DIR}") -endfunction(find_python_libs_windows) - -# Call find_python_libs_windows ahead of the rest of the python configuration. -# It's possible that it won't find a python installation and will then set -# LLDB_ENABLE_PYTHON to OFF. -if (LLDB_ENABLE_PYTHON AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") - find_python_libs_windows() -endif() - if (LLDB_ENABLE_PYTHON) if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") + find_package(Python3 COMPONENTS Interpreter Development REQUIRED) + if(Python3_VERSION VERSION_LESS 3.5) + message(SEND_ERROR "Python 3.5 or newer is required (found: ${Python3_VERSION}") + endif() + set(PYTHON_LIBRARY ${Python3_LIBRARIES}) + include_directories(${Python3_INCLUDE_DIRS}) + if (NOT LLDB_RELOCATABLE_PYTHON) file(TO_CMAKE_PATH "${PYTHON_HOME}" LLDB_PYTHON_HOME) endif() else() find_package(PythonInterp REQUIRED) find_package(PythonLibs REQUIRED) - endif() - if (NOT CMAKE_CROSSCOMPILING) - string(REPLACE "." ";" pythonlibs_version_list ${PYTHONLIBS_VERSION_STRING}) - list(GET pythonlibs_version_list 0 pythonlibs_major) - list(GET pythonlibs_version_list 1 pythonlibs_minor) - - # Ignore the patch version. Some versions of macOS report a different patch - # version for the system provided interpreter and libraries. - if (NOT PYTHON_VERSION_MAJOR VERSION_EQUAL pythonlibs_major OR - NOT PYTHON_VERSION_MINOR VERSION_EQUAL pythonlibs_minor) - message(FATAL_ERROR "Found incompatible Python interpreter (${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})" - " and Python libraries (${pythonlibs_major}.${pythonlibs_minor})") + if (NOT CMAKE_CROSSCOMPILING) + string(REPLACE "." ";" pythonlibs_version_list ${PYTHONLIBS_VERSION_STRING}) + list(GET pythonlibs_version_list 0 pythonlibs_major) + list(GET pythonlibs_version_list 1 pythonlibs_minor) + + # Ignore the patch version. Some versions of macOS report a different patch + # version for the system provided interpreter and libraries. + if (NOT PYTHON_VERSION_MAJOR VERSION_EQUAL pythonlibs_major OR + NOT PYTHON_VERSION_MINOR VERSION_EQUAL pythonlibs_minor) + message(FATAL_ERROR "Found incompatible Python interpreter (${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})" + " and Python libraries (${pythonlibs_major}.${pythonlibs_minor})") + endif() endif() - endif() - if (PYTHON_INCLUDE_DIR) - include_directories(${PYTHON_INCLUDE_DIR}) + if (PYTHON_INCLUDE_DIR) + include_directories(${PYTHON_INCLUDE_DIR}) + endif() endif() endif() -- 2.7.4