forked from JuliaPy/PyCall.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstartup.jl
139 lines (129 loc) · 5.31 KB
/
startup.jl
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
# Finding python. This is slightly complicated in order to support using PyCall
# from libjulia. We check if python symbols are present in the current process
# and if so do not use the deps.jl file, getting everything we need from the
# current process instead.
proc_handle = unsafe_load(cglobal(:jl_exe_handle, Ptr{Cvoid}))
struct Dl_info
dli_fname::Ptr{UInt8}
dli_fbase::Ptr{Cvoid}
dli_sname::Ptr{UInt8}
dli_saddr::Ptr{Cvoid}
end
EnumProcessModules(hProcess, lphModule, cb, lpcbNeeded) =
ccall(:K32EnumProcessModules, stdcall, Bool,
(Ptr{Cvoid}, Ptr{Ptr{Cvoid}}, UInt32, Ptr{UInt32}),
hProcess, lphModule, cb, lpcbNeeded)
symbols_present = false
@static if Compat.Sys.iswindows()
lpcbneeded = Ref{UInt32}()
proc_handle = ccall(:GetCurrentProcess, stdcall, Ptr{Cvoid}, ())
handles = Vector{Ptr{Cvoid}}(undef, 20)
if EnumProcessModules(proc_handle, handles, sizeof(handles), lpcbneeded) == 0
resize!(handles, div(lpcbneeded[],sizeof(Ptr{Cvoid})))
EnumProcessModules(proc_handle, handles, sizeof(handles), lpcbneeded)
end
# Try to find python if it's in the current process
for handle in handles
sym = ccall(:GetProcAddress, stdcall, Ptr{Cvoid},
(Ptr{Cvoid}, Ptr{UInt8}), handle, "Py_GetVersion")
sym != C_NULL || continue
global symbols_present = true
global libpy_handle = handle
break
end
else
global symbols_present = hassym(proc_handle, :Py_GetVersion)
end
if !symbols_present
# Python not present. Use deps.jl
const depfile = joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")
isfile(depfile) || error("PyCall not properly installed. Please run Pkg.build(\"PyCall\")")
include(depfile) # generated by Pkg.build("PyCall")
# Only to be used at top-level - pointer will be invalid after reload
libpy_handle = Libdl.dlopen(libpython, Libdl.RTLD_LAZY|Libdl.RTLD_DEEPBIND|Libdl.RTLD_GLOBAL)
# need SetPythonHome to avoid warning, #299
Py_SetPythonHome(libpy_handle, PYTHONHOME, wPYTHONHOME, pyversion_build)
else
@static if Compat.Sys.iswindows()
pathbuf = Vector{UInt16}(undef, 1024)
ret = ccall(:GetModuleFileNameW, stdcall, UInt32,
(Ptr{Cvoid}, Ptr{UInt16}, UInt32),
libpy_handle, pathbuf, length(pathbuf))
@assert ret != 0
libname = String(Base.transcode(UInt8, pathbuf[1:findfirst(pathbuf, 0)-1]))
if (Libdl.dlopen_e(libname) != C_NULL)
const libpython = libname
else
const libpython = nothing
end
else
libpy_handle = proc_handle
# Now determine the name of the python library that these symbols are from
some_address_in_libpython = Libdl.dlsym(libpy_handle, :Py_GetVersion)
some_address_in_main_exe = Libdl.dlsym(proc_handle, Compat.Sys.isapple() ? :_mh_execute_header : :main)
dlinfo1 = Ref{Dl_info}()
dlinfo2 = Ref{Dl_info}()
ccall(:dladdr, Cint, (Ptr{Cvoid}, Ptr{Dl_info}), some_address_in_libpython,
dlinfo1)
ccall(:dladdr, Cint, (Ptr{Cvoid}, Ptr{Dl_info}), some_address_in_main_exe,
dlinfo2)
if dlinfo1[].dli_fbase == dlinfo2[].dli_fbase
const libpython = nothing
else
const libpython = unsafe_string(dlinfo1[].dli_fname)
end
end
# If we're not in charge, assume the user is installing necessary python
# libraries rather than messing with their configuration
const conda = false
end
const pyversion = vparse(split(Py_GetVersion(libpy_handle))[1])
# PyUnicode_* may actually be a #define for another symbol, so
# we cache the correct dlsym
const PyUnicode_AsUTF8String =
findsym(libpy_handle, :PyUnicode_AsUTF8String, :PyUnicodeUCS4_AsUTF8String, :PyUnicodeUCS2_AsUTF8String)
const PyUnicode_DecodeUTF8 =
findsym(libpy_handle, :PyUnicode_DecodeUTF8, :PyUnicodeUCS4_DecodeUTF8, :PyUnicodeUCS2_DecodeUTF8)
# Python 2/3 compatibility: cache symbols for renamed functions
if hassym(libpy_handle, :PyString_FromStringAndSize)
const PyString_FromStringAndSize = :PyString_FromStringAndSize
const PyString_AsStringAndSize = :PyString_AsStringAndSize
const PyString_Size = :PyString_Size
const PyString_Type = :PyString_Type
else
const PyString_FromStringAndSize = :PyBytes_FromStringAndSize
const PyString_AsStringAndSize = :PyBytes_AsStringAndSize
const PyString_Size = :PyBytes_Size
const PyString_Type = :PyBytes_Type
end
# hashes changed from long to intptr_t in Python 3.2
const Py_hash_t = pyversion < v"3.2" ? Clong : Int
# whether to use unicode for strings by default, ala Python 3
const pyunicode_literals = pyversion >= v"3.0"
if libpython == nothing
macro pysym(func)
esc(func)
end
macro pyglobal(name)
:(cglobal($(esc(name))))
end
macro pyglobalobj(name)
:(cglobal($(esc(name)), PyObject_struct))
end
macro pyglobalobjptr(name)
:(unsafe_load(cglobal($(esc(name)), Ptr{PyObject_struct})))
end
else
macro pysym(func)
:(($(esc(func)), libpython))
end
macro pyglobal(name)
:(cglobal(($(esc(name)), libpython)))
end
macro pyglobalobj(name)
:(cglobal(($(esc(name)), libpython), PyObject_struct))
end
macro pyglobalobjptr(name)
:(unsafe_load(cglobal(($(esc(name)), libpython), Ptr{PyObject_struct})))
end
end