Skip to content

Commit cc00c47

Browse files
committed
make build script more paranoid about environment variables, especially with Conda (see JuliaPy/PyPlot#286)
1 parent 6cbb95b commit cc00c47

File tree

1 file changed

+49
-39
lines changed

1 file changed

+49
-39
lines changed

deps/build.jl

+49-39
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,40 @@
88
using Compat
99
import Conda
1010

11-
PYTHONIOENCODING = get(ENV, "PYTHONIOENCODING", nothing)
12-
PYTHONHOME = get(ENV, "PYTHONHOME", nothing)
1311
immutable UseCondaPython <: Exception end
1412

15-
try # save/restore environment vars
16-
17-
# set PYTHONIOENCODING when running python executable, so that
18-
# we get UTF-8 encoded text as output (this is not the default on Windows).
19-
ENV["PYTHONIOENCODING"] = "UTF-8"
13+
try # make sure deps.jl file is removed on error
2014

2115
#########################################################################
2216

23-
pyconfigvar(python::AbstractString, var::AbstractString) = chomp(readstring(`$python -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('$var'))"`))
17+
# Fix the environment for running `python`, and setts IO encoding to UTF-8.
18+
# If cmd is the Conda python, then additionally removes all PYTHON* and
19+
# CONDA* environment variables.
20+
function pythonenv(cmd::Cmd)
21+
env = copy(ENV)
22+
if dirname(cmd.exec[1]) == abspath(Conda.PYTHONDIR)
23+
pythonvars = Compat.UTF8String[]
24+
for var in keys(env)
25+
if startswith(var, "CONDA") || startswith(var, "PYTHON")
26+
push!(pythonvars, var)
27+
end
28+
end
29+
for var in pythonvars
30+
pop!(env, var)
31+
end
32+
end
33+
# set PYTHONIOENCODING when running python executable, so that
34+
# we get UTF-8 encoded text as output (this is not the default on Windows).
35+
env["PYTHONIOENCODING"] = "UTF-8"
36+
setenv(cmd, env)
37+
end
38+
39+
pyconfigvar(python::AbstractString, var::AbstractString) = chomp(readstring(pythonenv(`$python -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('$var'))"`)))
2440
pyconfigvar(python, var, default) = let v = pyconfigvar(python, var)
2541
v == "None" ? default : v
2642
end
2743

28-
pysys(python::AbstractString, var::AbstractString) = chomp(readstring(`$python -c "import sys; print(sys.$var)"`))
44+
pysys(python::AbstractString, var::AbstractString) = chomp(readstring(pythonenv(`$python -c "import sys; print(sys.$var)"`)))
2945

3046
#########################################################################
3147

@@ -58,24 +74,6 @@ function find_libpython(python::AbstractString)
5874

5975
error_strings = Compat.String[]
6076

61-
if !haskey(ENV, "PYTHONHOME")
62-
# PYTHONHOME tells python where to look for both pure python
63-
# and binary modules. When it is set, it replaces both
64-
# `prefix` and `exec_prefix` and we thus need to set it to
65-
# both in case they differ. This is also what the
66-
# documentation recommends. However, they are documented
67-
# to always be the same on Windows, where it causes
68-
# problems if we try to include both.
69-
ENV["PYTHONHOME"] = is_windows() ? exec_prefix : pysys(python, "prefix") * ":" * exec_prefix
70-
# Unfortunately, setting PYTHONHOME screws up Canopy's Python distro?
71-
try
72-
run(pipeline(`$python -c "import site"`, stdout=DevNull, stderr=DevNull))
73-
catch e
74-
push!(error_strings, string("$python -c \"import site\" ==> ", e))
75-
pop!(ENV, "PYTHONHOME")
76-
end
77-
end
78-
7977
# TODO: other paths? python-config output? pyconfigvar("LDFLAGS")?
8078

8179
# find libpython (we hope):
@@ -133,13 +131,13 @@ function find_libpython(python::AbstractString)
133131
134132
The python executable we tried was $python (= version $v);
135133
the library names we tried were $libs
136-
and the library paths we tried were $libpaths
137-
""")
134+
and the library paths we tried were $libpaths""")
138135
end
139136

140137
#########################################################################
141138

142139
include("depsutils.jl")
140+
143141
#########################################################################
144142

145143
const python = try
@@ -179,8 +177,26 @@ end
179177
const (libpython, libpy_name) = find_libpython(python)
180178
const programname = pysys(python, "executable")
181179

180+
# Get PYTHONHOME, either from the environment or from Python
181+
# itself (if it is not in the environment or if we are using Conda)
182+
PYTHONHOME = if !haskey(ENV, "PYTHONHOME") || use_conda
183+
# PYTHONHOME tells python where to look for both pure python
184+
# and binary modules. When it is set, it replaces both
185+
# `prefix` and `exec_prefix` and we thus need to set it to
186+
# both in case they differ. This is also what the
187+
# documentation recommends. However, they are documented
188+
# to always be the same on Windows, where it causes
189+
# problems if we try to include both.
190+
exec_prefix = pysys(python, "exec_prefix")
191+
is_windows() ? exec_prefix : pysys(python, "prefix") * ":" * exec_prefix
192+
else
193+
ENV["PYTHONHOME"]
194+
end
195+
182196
# cache the Python version as a Julia VersionNumber
183-
const pyversion = convert(VersionNumber, split(Py_GetVersion(libpython))[1])
197+
const pyversion = withenv("PYTHONHOME"=>PYTHONHOME) do
198+
convert(VersionNumber, split(Py_GetVersion(libpython))[1])
199+
end
184200

185201
info("PyCall is using $python (Python $pyversion) at $programname, libpython = $libpy_name")
186202

@@ -196,8 +212,6 @@ wstringconst(s) =
196212
string("wstring(\"", escape_string(s), "\")") :
197213
string("Base.cconvert(Cwstring, \"", escape_string(s), "\")")
198214

199-
PYTHONHOMEENV = get(ENV, "PYTHONHOME", "")
200-
201215
# we write configuration files only if they change, both
202216
# to prevent unnecessary recompilation and to minimize
203217
# problems in the unlikely event of read-only directories.
@@ -216,8 +230,8 @@ writeifchanged("deps.jl", """
216230
const pyprogramname = "$(escape_string(programname))"
217231
const wpyprogramname = $(wstringconst(programname))
218232
const pyversion_build = $(repr(pyversion))
219-
const PYTHONHOME = "$(escape_string(PYTHONHOMEENV))"
220-
const wPYTHONHOME = $(wstringconst(PYTHONHOMEENV))
233+
const PYTHONHOME = "$(escape_string(PYTHONHOME))"
234+
const wPYTHONHOME = $(wstringconst(PYTHONHOME))
221235
222236
"True if we are using the Python distribution in the Conda package."
223237
const conda = $use_conda
@@ -233,10 +247,6 @@ catch
233247
# remove deps.jl (if it exists) on an error, so that PyCall will
234248
# not load until it is properly configured.
235249
isfile("deps.jl") && rm("deps.jl")
236-
237-
finally # restore env vars
238-
239-
PYTHONIOENCODING != nothing ? (ENV["PYTHONIOENCODING"] = PYTHONIOENCODING) : pop!(ENV, "PYTHONIOENCODING")
240-
PYTHONHOME != nothing ? (ENV["PYTHONHOME"] = PYTHONHOME) : pop!(ENV, "PYTHONHOME", "")
250+
rethrow()
241251

242252
end

0 commit comments

Comments
 (0)