Skip to content

Commit 2046d72

Browse files
committed
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.
1 parent 891e25b commit 2046d72

File tree

2 files changed

+25
-167
lines changed

2 files changed

+25
-167
lines changed

lldb/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
cmake_minimum_required(VERSION 3.4.3)
2+
if(CMAKE_SYSTEM_NAME STREQUAL Windows)
3+
cmake_minimum_required(VERSION 3.13)
4+
endif()
25

36
if(POLICY CMP0075)
47
cmake_policy(SET CMP0075 NEW)

lldb/cmake/modules/LLDBConfig.cmake

Lines changed: 22 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -138,184 +138,39 @@ if (LLDB_ENABLE_LIBEDIT)
138138
set(CMAKE_EXTRA_INCLUDE_FILES)
139139
endif()
140140

141-
# On Windows, we can't use the normal FindPythonLibs module that comes with CMake,
142-
# for a number of reasons.
143-
# 1) Prior to MSVC 2015, it is only possible to embed Python if python itself was
144-
# compiled with an identical version (and build configuration) of MSVC as LLDB.
145-
# The standard algorithm does not take into account the differences between
146-
# a binary release distribution of python and a custom built distribution.
147-
# 2) From MSVC 2015 and onwards, it is only possible to use Python 3.5 or later.
148-
# 3) FindPythonLibs queries the registry to locate Python, and when looking for a
149-
# 64-bit version of Python, since cmake.exe is a 32-bit executable, it will see
150-
# a 32-bit view of the registry. As such, it is impossible for FindPythonLibs to
151-
# locate 64-bit Python libraries.
152-
# This function is designed to address those limitations. Currently it only partially
153-
# addresses them, but it can be improved and extended on an as-needed basis.
154-
function(find_python_libs_windows_helper LOOKUP_DEBUG OUT_EXE_PATH_VARNAME OUT_LIB_PATH_VARNAME OUT_DLL_PATH_VARNAME OUT_VERSION_VARNAME)
155-
if(LOOKUP_DEBUG)
156-
set(POSTFIX "_d")
157-
else()
158-
set(POSTFIX "")
159-
endif()
160-
161-
file(TO_CMAKE_PATH "${PYTHON_HOME}/python${POSTFIX}.exe" PYTHON_EXE)
162-
file(TO_CMAKE_PATH "${PYTHON_HOME}/libs/${PYTHONLIBS_BASE_NAME}${POSTFIX}.lib" PYTHON_LIB)
163-
file(TO_CMAKE_PATH "${PYTHON_HOME}/${PYTHONLIBS_BASE_NAME}${POSTFIX}.dll" PYTHON_DLL)
164-
165-
foreach(component PYTHON_EXE;PYTHON_LIB;PYTHON_DLL)
166-
if(NOT EXISTS ${${component}})
167-
message(WARNING "Unable to find ${component}")
168-
unset(${component})
169-
endif()
170-
endforeach()
171-
172-
if (NOT PYTHON_EXE OR NOT PYTHON_LIB OR NOT PYTHON_DLL)
173-
message(WARNING "Unable to find all Python components. Python support will be disabled for this build.")
174-
set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE)
175-
return()
176-
endif()
177-
178-
# Find the version of the Python interpreter.
179-
execute_process(COMMAND "${PYTHON_EXE}" -c
180-
"import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))"
181-
OUTPUT_VARIABLE PYTHON_VERSION_OUTPUT
182-
RESULT_VARIABLE PYTHON_VERSION_RESULT
183-
ERROR_QUIET)
184-
185-
if(PYTHON_VERSION_RESULT)
186-
message(WARNING "Unable to retrieve Python executable version")
187-
set(PYTHON_VERSION_OUTPUT "")
188-
endif()
189-
190-
set(${OUT_EXE_PATH_VARNAME} ${PYTHON_EXE} PARENT_SCOPE)
191-
set(${OUT_LIB_PATH_VARNAME} ${PYTHON_LIB} PARENT_SCOPE)
192-
set(${OUT_DLL_PATH_VARNAME} ${PYTHON_DLL} PARENT_SCOPE)
193-
set(${OUT_VERSION_VARNAME} ${PYTHON_VERSION_OUTPUT} PARENT_SCOPE)
194-
endfunction()
195-
196-
function(find_python_libs_windows)
197-
if ("${PYTHON_HOME}" STREQUAL "")
198-
message(WARNING "LLDB embedded Python on Windows requires specifying a value for PYTHON_HOME. Python support disabled.")
199-
set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE)
200-
return()
201-
endif()
202-
203-
file(TO_CMAKE_PATH "${PYTHON_HOME}/Include" PYTHON_INCLUDE_DIR)
204-
205-
if(EXISTS "${PYTHON_INCLUDE_DIR}/patchlevel.h")
206-
file(STRINGS "${PYTHON_INCLUDE_DIR}/patchlevel.h" python_version_str
207-
REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"")
208-
string(REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"+]+)[+]?\".*" "\\1"
209-
PYTHONLIBS_VERSION_STRING "${python_version_str}")
210-
message(STATUS "Found Python library version ${PYTHONLIBS_VERSION_STRING}")
211-
string(REGEX REPLACE "([0-9]+)[.]([0-9]+)[.][0-9]+" "python\\1\\2" PYTHONLIBS_BASE_NAME "${PYTHONLIBS_VERSION_STRING}")
212-
unset(python_version_str)
213-
else()
214-
message(WARNING "Unable to find ${PYTHON_INCLUDE_DIR}/patchlevel.h, Python installation is corrupt.")
215-
message(WARNING "Python support will be disabled for this build.")
216-
set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE)
217-
return()
218-
endif()
219-
220-
file(TO_CMAKE_PATH "${PYTHON_HOME}" PYTHON_HOME)
221-
# TODO(compnerd) when CMake Policy `CMP0091` is set to NEW, we should use
222-
# if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES MultiThreadedDebug)
223-
if(NOT DEFINED CMAKE_BUILD_TYPE)
224-
# Multi-target generator was selected (like Visual Studio or Xcode) where no concrete build type was passed
225-
# Lookup for both debug and release python installations
226-
find_python_libs_windows_helper(TRUE PYTHON_DEBUG_EXE PYTHON_DEBUG_LIB PYTHON_DEBUG_DLL PYTHON_DEBUG_VERSION_STRING)
227-
find_python_libs_windows_helper(FALSE PYTHON_RELEASE_EXE PYTHON_RELEASE_LIB PYTHON_RELEASE_DLL PYTHON_RELEASE_VERSION_STRING)
228-
if(NOT LLDB_ENABLE_PYTHON)
229-
set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE)
230-
return()
231-
endif()
232-
233-
# We should have been found both debug and release python here
234-
# Now check that their versions are equal
235-
if(NOT PYTHON_DEBUG_VERSION_STRING STREQUAL PYTHON_RELEASE_VERSION_STRING)
236-
message(FATAL_ERROR "Python versions for debug (${PYTHON_DEBUG_VERSION_STRING}) and release (${PYTHON_RELEASE_VERSION_STRING}) are different."
237-
"Python installation is corrupted")
238-
endif ()
239-
240-
set(PYTHON_EXECUTABLE $<$<CONFIG:Debug>:${PYTHON_DEBUG_EXE}>$<$<NOT:$<CONFIG:Debug>>:${PYTHON_RELEASE_EXE}>)
241-
set(PYTHON_LIBRARY $<$<CONFIG:Debug>:${PYTHON_DEBUG_LIB}>$<$<NOT:$<CONFIG:Debug>>:${PYTHON_RELEASE_LIB}>)
242-
set(PYTHON_DLL $<$<CONFIG:Debug>:${PYTHON_DEBUG_DLL}>$<$<NOT:$<CONFIG:Debug>>:${PYTHON_RELEASE_DLL}>)
243-
set(PYTHON_VERSION_STRING ${PYTHON_RELEASE_VERSION_STRING})
244-
else()
245-
# Lookup for concrete python installation depending on build type
246-
if (CMAKE_BUILD_TYPE STREQUAL Debug)
247-
set(LOOKUP_DEBUG_PYTHON TRUE)
248-
else()
249-
set(LOOKUP_DEBUG_PYTHON FALSE)
250-
endif()
251-
find_python_libs_windows_helper(${LOOKUP_DEBUG_PYTHON} PYTHON_EXECUTABLE PYTHON_LIBRARY PYTHON_DLL PYTHON_VERSION_STRING)
252-
if(NOT LLDB_ENABLE_PYTHON)
253-
set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE)
254-
return()
255-
endif()
256-
endif()
257-
258-
if(PYTHON_VERSION_STRING)
259-
string(REPLACE "." ";" PYTHON_VERSION_PARTS "${PYTHON_VERSION_STRING}")
260-
list(GET PYTHON_VERSION_PARTS 0 PYTHON_VERSION_MAJOR)
261-
list(GET PYTHON_VERSION_PARTS 1 PYTHON_VERSION_MINOR)
262-
list(GET PYTHON_VERSION_PARTS 2 PYTHON_VERSION_PATCH)
263-
else()
264-
unset(PYTHON_VERSION_MAJOR)
265-
unset(PYTHON_VERSION_MINOR)
266-
unset(PYTHON_VERSION_PATCH)
267-
endif()
268-
269-
# Set the same variables as FindPythonInterp and FindPythonLibs.
270-
set(PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}" CACHE PATH "")
271-
set(PYTHON_LIBRARY "${PYTHON_LIBRARY}" CACHE PATH "")
272-
set(PYTHON_DLL "${PYTHON_DLL}" CACHE PATH "")
273-
set(PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}" CACHE PATH "")
274-
set(PYTHONLIBS_VERSION_STRING "${PYTHONLIBS_VERSION_STRING}" PARENT_SCOPE)
275-
set(PYTHON_VERSION_STRING "${PYTHON_VERSION_STRING}" PARENT_SCOPE)
276-
set(PYTHON_VERSION_MAJOR "${PYTHON_VERSION_MAJOR}" PARENT_SCOPE)
277-
set(PYTHON_VERSION_MINOR "${PYTHON_VERSION_MINOR}" PARENT_SCOPE)
278-
set(PYTHON_VERSION_PATCH "${PYTHON_VERSION_PATCH}" PARENT_SCOPE)
279-
280-
message(STATUS "LLDB Found PythonExecutable: ${PYTHON_EXECUTABLE} (${PYTHON_VERSION_STRING})")
281-
message(STATUS "LLDB Found PythonLibs: ${PYTHON_LIBRARY} (${PYTHONLIBS_VERSION_STRING})")
282-
message(STATUS "LLDB Found PythonDLL: ${PYTHON_DLL}")
283-
message(STATUS "LLDB Found PythonIncludeDirs: ${PYTHON_INCLUDE_DIR}")
284-
endfunction(find_python_libs_windows)
285-
286-
# Call find_python_libs_windows ahead of the rest of the python configuration.
287-
# It's possible that it won't find a python installation and will then set
288-
# LLDB_ENABLE_PYTHON to OFF.
289-
if (LLDB_ENABLE_PYTHON AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
290-
find_python_libs_windows()
291-
endif()
292-
293141
if (LLDB_ENABLE_PYTHON)
294142
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
143+
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
144+
if(Python3_VERSION VERSION_LESS 3.5)
145+
message(SEND_ERROR "Python 3.5 or newer is required (found: ${Python3_VERSION}")
146+
endif()
147+
set(PYTHON_LIBRARY ${Python3_LIBRARIES})
148+
include_directories(${Python3_INCLUDE_DIRS})
149+
295150
if (NOT LLDB_RELOCATABLE_PYTHON)
296151
file(TO_CMAKE_PATH "${PYTHON_HOME}" LLDB_PYTHON_HOME)
297152
endif()
298153
else()
299154
find_package(PythonInterp REQUIRED)
300155
find_package(PythonLibs REQUIRED)
301-
endif()
302156

303-
if (NOT CMAKE_CROSSCOMPILING)
304-
string(REPLACE "." ";" pythonlibs_version_list ${PYTHONLIBS_VERSION_STRING})
305-
list(GET pythonlibs_version_list 0 pythonlibs_major)
306-
list(GET pythonlibs_version_list 1 pythonlibs_minor)
307-
308-
# Ignore the patch version. Some versions of macOS report a different patch
309-
# version for the system provided interpreter and libraries.
310-
if (NOT PYTHON_VERSION_MAJOR VERSION_EQUAL pythonlibs_major OR
311-
NOT PYTHON_VERSION_MINOR VERSION_EQUAL pythonlibs_minor)
312-
message(FATAL_ERROR "Found incompatible Python interpreter (${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})"
313-
" and Python libraries (${pythonlibs_major}.${pythonlibs_minor})")
157+
if (NOT CMAKE_CROSSCOMPILING)
158+
string(REPLACE "." ";" pythonlibs_version_list ${PYTHONLIBS_VERSION_STRING})
159+
list(GET pythonlibs_version_list 0 pythonlibs_major)
160+
list(GET pythonlibs_version_list 1 pythonlibs_minor)
161+
162+
# Ignore the patch version. Some versions of macOS report a different patch
163+
# version for the system provided interpreter and libraries.
164+
if (NOT PYTHON_VERSION_MAJOR VERSION_EQUAL pythonlibs_major OR
165+
NOT PYTHON_VERSION_MINOR VERSION_EQUAL pythonlibs_minor)
166+
message(FATAL_ERROR "Found incompatible Python interpreter (${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})"
167+
" and Python libraries (${pythonlibs_major}.${pythonlibs_minor})")
168+
endif()
314169
endif()
315-
endif()
316170

317-
if (PYTHON_INCLUDE_DIR)
318-
include_directories(${PYTHON_INCLUDE_DIR})
171+
if (PYTHON_INCLUDE_DIR)
172+
include_directories(${PYTHON_INCLUDE_DIR})
173+
endif()
319174
endif()
320175
endif()
321176

0 commit comments

Comments
 (0)