forked from firebase/firebase-ios-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpython_setup.cmake
170 lines (156 loc) · 6.31 KB
/
python_setup.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
include("${CMAKE_CURRENT_LIST_DIR}/firebase_utils.cmake")
# Sets up an isolated Python interpreter, installing required dependencies.
#
# This function does the following:
# 1. Finds a Python interpreter using the best-available built-in cmake
# mechanism do do so. This is referred to as the "host" interpreter.
# 2. Creates a Python virtualenv in the cmake binary directory using the
# host Python interpreter found in the previous step.
# 3. Locates the Python interpreter in the virtualenv and sets its path in
# the specified OUTVAR variable.
# 4. Runs `pip install` to install the specified required dependencies, if any,
# in the virtualenv.
#
# This function also writes "stamp files" into the virtualenv. These files
# are used to determine if the virtualenv is up-to-date from a previous cmake
# run or if it needs to be recreated from scratch. It will simply be re-used if
# possible.
#
# If any errors occur (e.g. cannot install one of the given requirements) then a
# fatal error is logged, causing the cmake processing to terminate.
#
# See https://docs.python.org/3/library/venv.html for details about virtualenv.
#
# Arguments:
# OUTVAR - The name of the variable into which to store the path of the
# Python executable from the virtualenv.
# KEY - A unique key to ensure isolation from other Python virtualenv
# environments created by this function. This value will be incorporated
# into the path of the virtualenv and incorporated into the name of the
# cmake cache variable that stores its path.
# REQUIREMENTS - (Optional) A list of Python packages to install in the
# virtualenv. These will be given as arguments to `pip install`.
#
# Example:
# include(python_setup)
# FirebaseSetupPythonInterpreter(
# OUTVAR MY_PYTHON_EXECUTABLE
# KEY ScanStuff
# REQUIREMENTS six absl-py
# )
# execute_process(COMMAND "${MY_PYTHON_EXECUTABLE}" scan_stuff.py)
function(FirebaseSetupPythonInterpreter)
cmake_parse_arguments(
PARSE_ARGV 0
ARG
"" # zero-value arguments
"OUTVAR;KEY" # single-value arguments
"REQUIREMENTS" # multi-value arguments
)
# Validate this function's arguments.
if("${ARG_OUTVAR}" STREQUAL "")
message(FATAL_ERROR "OUTVAR must be specified to ${CMAKE_CURRENT_FUNCTION}")
elseif("${ARG_KEY}" STREQUAL "")
message(FATAL_ERROR "KEY must be specified to ${CMAKE_CURRENT_FUNCTION}")
endif()
# Calculate the name of the cmake *cache* variable into which to store the
# path of the Python interpreter from the virtualenv.
set(CACHEVAR "FIREBASE_PYTHON_EXECUTABLE_${ARG_KEY}")
set(LOG_PREFIX "${CMAKE_CURRENT_FUNCTION}(${ARG_KEY})")
# Find a "host" Python interpreter using the best available mechanism.
if(${CMAKE_VERSION} VERSION_LESS "3.12")
include(FindPythonInterp)
set(DEFAULT_PYTHON_HOST_EXECUTABLE "${PYTHON_EXECUTABLE}")
else()
find_package(Python3 COMPONENTS Interpreter REQUIRED)
set(DEFAULT_PYTHON_HOST_EXECUTABLE "${Python3_EXECUTABLE}")
endif()
# Get the host Python interpreter on the host system to use.
set(
FIREBASE_PYTHON_HOST_EXECUTABLE
"${DEFAULT_PYTHON_HOST_EXECUTABLE}"
CACHE FILEPATH
"The Python interpreter on the host system to use"
)
# Check if the virtualenv is already up-to-date by examining the contents of
# its stamp files. The stamp files store the path of the host Python
# interpreter and the dependencies that were installed by pip. If both of
# these files exist and contain the same Python interpreter and dependencies
# then just re-use the virtualenv; otherwise, re-create it.
set(PYVENV_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pyvenv/${ARG_KEY}")
set(STAMP_FILE1 "${PYVENV_DIRECTORY}/cmake_firebase_python_stamp1.txt")
set(STAMP_FILE2 "${PYVENV_DIRECTORY}/cmake_firebase_python_stamp2.txt")
if(EXISTS "${STAMP_FILE1}" AND EXISTS "${STAMP_FILE2}")
file(READ "${STAMP_FILE1}" STAMP_FILE1_CONTENTS)
file(READ "${STAMP_FILE2}" STAMP_FILE2_CONTENTS)
if(
("${STAMP_FILE1_CONTENTS}" STREQUAL "${FIREBASE_PYTHON_HOST_EXECUTABLE}")
AND
("${STAMP_FILE2_CONTENTS}" STREQUAL "${ARG_REQUIREMENTS}")
)
set("${ARG_OUTVAR}" "$CACHE{${CACHEVAR}}" PARENT_SCOPE)
message(STATUS "${LOG_PREFIX}: Using Python interpreter: $CACHE{${CACHEVAR}}")
return()
endif()
endif()
# Create the virtualenv.
message(STATUS
"${LOG_PREFIX}: Creating Python virtualenv in ${PYVENV_DIRECTORY} "
"using ${FIREBASE_PYTHON_HOST_EXECUTABLE}"
)
file(REMOVE_RECURSE "${PYVENV_DIRECTORY}")
firebase_execute_process(
COMMAND
"${FIREBASE_PYTHON_HOST_EXECUTABLE}"
-m
venv
"${PYVENV_DIRECTORY}"
)
# Find the Python interpreter in the virtualenv.
find_program(
"${CACHEVAR}"
DOC "The Python interpreter to use for ${ARG_KEY}"
NAMES python3 python
PATHS "${PYVENV_DIRECTORY}"
PATH_SUFFIXES bin Scripts
NO_DEFAULT_PATH
)
if(NOT ${CACHEVAR})
message(FATAL_ERROR "Unable to find Python executable in ${PYVENV_DIRECTORY}")
else()
set(PYTHON_EXECUTABLE "$CACHE{${CACHEVAR}}")
message(STATUS "${LOG_PREFIX}: Found Python executable in virtualenv: ${PYTHON_EXECUTABLE}")
endif()
# Install the dependencies in the virtualenv, if any are requested.
if(NOT ("${ARG_REQUIREMENTS}" STREQUAL ""))
message(STATUS
"${LOG_PREFIX}: Installing Python dependencies into "
"${PYVENV_DIRECTORY}: ${ARG_REQUIREMENTS}"
)
firebase_execute_process(
COMMAND
"${PYTHON_EXECUTABLE}"
-m
pip
install
${ARG_REQUIREMENTS}
)
endif()
# Write the stamp files.
file(WRITE "${STAMP_FILE1}" "${FIREBASE_PYTHON_HOST_EXECUTABLE}")
file(WRITE "${STAMP_FILE2}" "${ARG_REQUIREMENTS}")
set("${ARG_OUTVAR}" "${PYTHON_EXECUTABLE}" PARENT_SCOPE)
endfunction(FirebaseSetupPythonInterpreter)