1
+ # No 3rd-party modules here, see "3rd-party" note below
1
2
import io , os , os .path , sys , runpy , subprocess , re , sysconfig
2
3
3
- import pip , pip .vcs .git
4
-
5
4
6
5
def main ():
7
6
os .chdir (os .path .dirname (os .path .abspath (__file__ )))
8
7
9
- build_contrib = get_build_contrib ()
8
+ # Only import 3rd-party modules after having installed all the build dependencies:
9
+ # any of them, or their dependencies, can be updated during that process,
10
+ # leading to version conflicts
11
+ numpy_version = get_or_install ("numpy" , "1.11.3" if sys .version_info [:2 ] >= (3 , 6 ) else "1.11.1" )
12
+ get_or_install ("scikit-build" )
13
+ import skbuild
14
+ if os .path .isdir ('.git' ):
15
+ import pip .vcs .git
16
+ pip .vcs .git .Git ().update_submodules ('.' )
17
+ del pip
18
+
10
19
11
- # in case of sdist
12
- if os .path .isdir ('./.git' ): pip .vcs .git .Git ().update_submodules ('.' )
20
+ # https://stackoverflow.com/questions/1405913/python-32bit-or-64bit-mode
21
+ x64 = sys .maxsize > 2 ** 32
22
+
23
+ build_contrib = get_build_contrib ()
13
24
14
25
package_name = "opencv-contrib-python" if build_contrib else "opencv-python"
15
26
long_description = io .open ('README_CONTRIB.rst' if build_contrib else 'README.rst' , encoding = "utf-8" ).read ()
16
27
package_version = get_opencv_version ()
17
- numpy_version = get_or_install ( "numpy" , "1.11.3" if sys . version_info [: 2 ] >= ( 3 , 6 ) else "1.11.1" )
28
+
18
29
package_data = \
19
30
{'cv2' :
20
31
['*%s' % sysconfig .get_config_var ('SO' )] + (['*.dll' ] if os .name == 'nt' else []) +
@@ -25,26 +36,33 @@ def main():
25
36
# Path regexes with forward slashes relative to CMake install dir.
26
37
rearrange_cmake_output_data = \
27
38
{'cv2' :
28
- [r'bin/opencv_ffmpeg\d{3}%s\.dll' %
29
- # https://stackoverflow.com/questions/1405913/python-32bit-or-64bit-mode
30
- ('_64' if sys .maxsize > 2 ** 32 else '' ),
31
- 'python/[^/]+/[^/]+/cv2%s' % sysconfig .get_config_var ('SO' )]
32
-
39
+ sum ([
40
+ ([r'bin/opencv_ffmpeg\d{3}%s\.dll' %
41
+ ('_64' if x64 else '' )] if os .name == 'nt' else []
42
+ ),
43
+ # In Windows, in python/X.Y/<arch>/; in Linux, in just python/X.Y/. What gives?
44
+ ['python/([^/]+)/{1,2}cv2%(arch)s%(ext)s' % {
45
+ 'arch' : (('\\ .cp%d%d-[^.]+' % sys .version_info [:2 ])
46
+ if sys .version_info [:2 ] >= (3 , 5 ) else '' ),
47
+ 'ext' : re .escape (sysconfig .get_config_var ('SO' ))
48
+ }
49
+ ]
50
+ ],[])
33
51
}
34
52
# Files in sourcetree outside package dir that should be copied to package.
35
53
# Raw paths relative to sourcetree root.
36
54
files_outside_package_dir = \
37
55
{'cv2' :
38
- ['LICENSE.txt' , 'LICENSE-3RD-PARTY.txt' ]
39
- }
56
+ ['LICENSE.txt' , 'LICENSE-3RD-PARTY.txt' ]
57
+ }
40
58
41
- cmake_source_dir = "opencv"
59
+ cmake_source_dir = "opencv"
42
60
cmake_args = ([
43
- "-G" , "Visual Studio 14" + (" Win64" if sys .maxsize > 2 ** 32 else '' ),
44
- "-T" , "v140_xp" if sys .version_info [:2 ] <= (3 , 4 ) else "v140"
61
+ "-G" , "Visual Studio 14" + (" Win64" if x64 else '' )
45
62
] if os .name == 'nt' else []) + \
46
63
[
47
64
# No need to specify Python paths, skbuild takes care of that
65
+ "-DPYTHON%d_EXECUTABLE=%s" % (sys .version_info [0 ], sys .executable ),
48
66
"-DBUILD_opencv_python%d=ON" % sys .version_info [0 ],
49
67
# Otherwise, opencv scripts would want to install `.pyd' right into site-packages,
50
68
# and skbuild bails out on seeing that
@@ -56,16 +74,18 @@ def main():
56
74
"-DBUILD_PERF_TESTS=OFF" ,
57
75
"-DBUILD_DOCS=OFF"
58
76
] + \
59
- ([ "-DOPENCV_EXTRA_MODULES_PATH=" + "opencv_contrib/modules" ] if build_contrib else [])
77
+ ([ "-DOPENCV_EXTRA_MODULES_PATH=" + os .path .abspath ("opencv_contrib/modules" ) ]
78
+ if build_contrib else [])
79
+
60
80
81
+ # ABI config variables are introduced in PEP 425
61
82
if sys .version_info [:2 ] < (3 , 2 ):
62
83
import warnings
63
- # ABI config variables are introduced in PEP 425
64
- warnings . filterwarnings ( 'ignore' , r"Config variable '[^']+' is unset, Python ABI tag may be incorrect" ,
84
+ warnings . filterwarnings ( 'ignore' , r"Config variable '[^']+' is unset, "
85
+ r" Python ABI tag may be incorrect" ,
65
86
category = RuntimeWarning )
87
+ del warnings
66
88
67
- get_or_install ("scikit-build" )
68
- import skbuild
69
89
70
90
# works via side effect
71
91
RearrangeCMakeOutput (rearrange_cmake_output_data ,
@@ -108,6 +128,7 @@ def main():
108
128
cmake_source_dir = cmake_source_dir ,
109
129
)
110
130
131
+
111
132
class RearrangeCMakeOutput (object ):
112
133
"""Patch SKBuild logic to only take files related to the Python package
113
134
and construct a file hierarchy that SKBuild expects (see below)"""
@@ -117,7 +138,7 @@ class RearrangeCMakeOutput(object):
117
138
# into an instance method on attr assignment
118
139
import argparse
119
140
wraps = argparse .Namespace (
120
- _classify_files = None )
141
+ _classify_files = None )
121
142
del argparse
122
143
123
144
package_paths_re = None
@@ -163,17 +184,21 @@ def _classify_files_override(self, install_paths,
163
184
cmake_install_reldir )
164
185
install_relpaths = [os .path .relpath (p , cmake_install_dir ) for p in install_paths ]
165
186
fslash_install_relpaths = [p .replace (os .path .sep , '/' ) for p in install_relpaths ]
166
- relpaths_zip = zip (fslash_install_relpaths , install_relpaths )
187
+ relpaths_zip = list (zip (fslash_install_relpaths , install_relpaths ))
188
+ del install_relpaths , fslash_install_relpaths
189
+
167
190
final_install_relpaths = []
168
191
169
192
print ("Copying files from CMake output" )
170
193
for package_name , relpaths_re in cls .package_paths_re .items ():
171
194
package_dest_reldir = package_name .replace ('.' , os .path .sep )
172
195
for relpath_re in relpaths_re :
196
+ found = False
173
197
r = re .compile (relpath_re + '$' )
174
198
for fslash_relpath , relpath in relpaths_zip :
175
199
m = r .match (fslash_relpath )
176
200
if not m : continue
201
+ found = True
177
202
new_install_relpath = os .path .join (
178
203
package_dest_reldir ,
179
204
os .path .basename (relpath ))
@@ -183,9 +208,11 @@ def _classify_files_override(self, install_paths,
183
208
hide_listing = False )
184
209
final_install_relpaths .append (new_install_relpath )
185
210
del m , fslash_relpath , new_install_relpath
186
- del r
211
+ else :
212
+ if not found : raise Exception ("Not found: '%s'" % relpath_re )
213
+ del r , found
187
214
188
- del fslash_install_relpaths , install_relpaths , relpaths_zip
215
+ del relpaths_zip
189
216
190
217
print ("Copying files from non-default sourcetree locations" )
191
218
for package_name , paths in cls .files_outside_package .items ():
@@ -250,15 +277,21 @@ def get_build_contrib():
250
277
251
278
252
279
def get_or_install (name , version = None ):
253
- """If numpy is already installed, build against it. If not, install"""
280
+ """If a package is already installed, build against it. If not, install"""
281
+ # Do not import 3rd-party modules into the current process
282
+ import json
283
+ js_packages = json .loads (
284
+ subprocess .check_output (
285
+ [sys .executable , "-m" , "pip" , "list" , "--format=json" ])
286
+ .decode ('ascii' )) #valid names & versions are ASCII as per PEP 440
254
287
try :
255
- [package ] = (package for package in pip . get_installed_distributions ()
256
- if package . key == name )
288
+ [package ] = (package for package in js_packages
289
+ if package [ 'name' ] == name )
257
290
except ValueError :
258
291
install_packages ("%s==%s" % (name , version ) if version else name )
259
292
return version
260
293
else :
261
- return package . version
294
+ return package [ ' version' ]
262
295
263
296
264
297
# This creates a list which is empty but returns a length of 1.
0 commit comments