@@ -124,6 +124,7 @@ def get_win32_compiler():
124
124
"""
125
125
Determine the compiler being used on win32.
126
126
"""
127
+ # TODO: rewrite to use distutils
127
128
# Used to determine mingw32 or msvc
128
129
# This is pretty bad logic, someone know a better way?
129
130
for v in sys .argv :
@@ -151,7 +152,8 @@ def has_include_file(include_dirs, filename):
151
152
directories in `include_dirs`.
152
153
"""
153
154
if sys .platform == 'win32' :
154
- include_dirs += os .environ .get ('INCLUDE' , '.' ).split (';' )
155
+ include_dirs = list (include_dirs )
156
+ include_dirs += os .environ .get ('INCLUDE' , '.' ).split (os .pathsep )
155
157
for dir in include_dirs :
156
158
if os .path .exists (os .path .join (dir , filename )):
157
159
return True
@@ -180,10 +182,14 @@ def get_base_dirs():
180
182
return os .environ .get ('MPLBASEDIRLIST' ).split (os .pathsep )
181
183
182
184
win_bases = ['win32_static' , ]
183
- # on conda windows, we also add the <installdir >\Library of the local interpreter ,
185
+ # on conda windows, we also add the <conda_env_dir >\Library,
184
186
# as conda installs libs/includes there
185
- if os .getenv ('CONDA_DEFAULT_ENV' ):
186
- win_bases .append (os .path .join (os .getenv ('CONDA_DEFAULT_ENV' ), "Library" ))
187
+ # env var names mess: https://github.com/conda/conda/issues/2312
188
+ conda_env_path = os .getenv ('CONDA_PREFIX' ) # conda >= 4.1
189
+ if not conda_env_path :
190
+ conda_env_path = os .getenv ('CONDA_DEFAULT_ENV' ) # conda < 4.1
191
+ if conda_env_path and os .path .isdir (conda_env_path ):
192
+ win_bases .append (os .path .join (conda_env_path , "Library" ))
187
193
188
194
basedir_map = {
189
195
'win32' : win_bases ,
@@ -541,11 +547,16 @@ def _check_for_pkg_config(self, package, include_file, min_version=None,
541
547
542
548
return 'version %s' % version
543
549
544
- def do_custom_build (self ):
550
+ def do_custom_build (self , cmd ):
545
551
"""
546
552
If a package needs to do extra custom things, such as building a
547
553
third-party library, before building an extension, it should
548
554
override this method.
555
+
556
+ Parameters
557
+ ----------
558
+ cmd : distutils.command.build_ext
559
+ The 'build_ext' instance
549
560
"""
550
561
pass
551
562
@@ -1088,19 +1099,24 @@ def version_from_header(self):
1088
1099
patch = value
1089
1100
return '.' .join ([major , minor , patch ])
1090
1101
1102
+ def get_local_freetype_path (self , version = LOCAL_FREETYPE_VERSION ):
1103
+ return os .path .join ('build' , 'freetype-{0}' .format (version ))
1104
+
1105
+ def get_local_freetype_lib_path (self , version = LOCAL_FREETYPE_VERSION ):
1106
+ if sys .platform == 'win32' :
1107
+ libfreetype = 'libfreetype.lib'
1108
+ else :
1109
+ libfreetype = 'libfreetype.a'
1110
+
1111
+ src_path = self .get_local_freetype_path (version )
1112
+ return os .path .join (src_path , 'objs' , '.libs' , libfreetype )
1113
+
1091
1114
def add_flags (self , ext ):
1092
1115
if options .get ('local_freetype' ):
1093
- src_path = os .path .join (
1094
- 'build' , 'freetype-{0}' .format (LOCAL_FREETYPE_VERSION ))
1095
- # Statically link to the locally-built freetype.
1096
- # This is certainly broken on Windows.
1116
+ src_path = self .get_local_freetype_path ()
1117
+ # link to the locally-built freetype.
1097
1118
ext .include_dirs .insert (0 , os .path .join (src_path , 'include' ))
1098
- if sys .platform == 'win32' :
1099
- libfreetype = 'libfreetype.lib'
1100
- else :
1101
- libfreetype = 'libfreetype.a'
1102
- ext .extra_objects .insert (
1103
- 0 , os .path .join (src_path , 'objs' , '.libs' , libfreetype ))
1119
+ ext .extra_objects .insert (0 , self .get_local_freetype_lib_path ())
1104
1120
ext .define_macros .append (('FREETYPE_BUILD_TYPE' , 'local' ))
1105
1121
else :
1106
1122
pkg_config .setup_extension (
@@ -1111,26 +1127,21 @@ def add_flags(self, ext):
1111
1127
'lib/freetype2/include/freetype2' ],
1112
1128
default_library_dirs = [
1113
1129
'freetype2/lib' ],
1114
- default_libraries = ['freetype' , 'z' ])
1130
+ default_libraries = ['freetype' ])
1115
1131
ext .define_macros .append (('FREETYPE_BUILD_TYPE' , 'system' ))
1116
1132
1117
- def do_custom_build (self ):
1118
- # We're using a system freetype
1133
+ def do_custom_build (self , cmd ):
1119
1134
if not options .get ('local_freetype' ):
1135
+ # We're using a system freetype
1120
1136
return
1121
1137
1122
- src_path = os .path .join (
1123
- 'build' , 'freetype-{0}' .format (LOCAL_FREETYPE_VERSION ))
1124
-
1125
- # We've already built freetype
1126
- if sys .platform == 'win32' :
1127
- libfreetype = 'libfreetype.lib'
1128
- else :
1129
- libfreetype = 'libfreetype.a'
1130
-
1131
- if os .path .isfile (os .path .join (src_path , 'objs' , '.libs' , libfreetype )):
1138
+ libdir = os .path .dirname (self .get_local_freetype_lib_path ())
1139
+ if os .path .isfile (self .get_local_freetype_lib_path ()):
1140
+ # We've already built freetype
1141
+ # TODO: This will prevent x86/x64 debug/release switch
1132
1142
return
1133
1143
1144
+ src_path = self .get_local_freetype_path ()
1134
1145
tarball = 'freetype-{0}.tar.gz' .format (LOCAL_FREETYPE_VERSION )
1135
1146
tarball_path = os .path .join ('build' , tarball )
1136
1147
try :
@@ -1217,40 +1228,72 @@ def do_custom_build(self):
1217
1228
subprocess .check_call (
1218
1229
[cflags + 'make' ], shell = True , cwd = src_path )
1219
1230
else :
1220
- # compilation on windows
1221
- FREETYPE_BUILD_CMD = """\
1222
- call "%ProgramFiles%\\ Microsoft SDKs\\ Windows\\ v7.0\\ Bin\\ SetEnv.Cmd" /Release /{xXX} /xp
1223
- call "{vcvarsall}" {xXX}
1224
- set MSBUILD=C:\\ Windows\\ Microsoft.NET\\ Framework\\ v4.0.30319\\ MSBuild.exe
1225
- rd /S /Q %FREETYPE%\\ objs
1226
- %MSBUILD% %FREETYPE%\\ builds\\ windows\\ {vc20xx}\\ freetype.sln /t:Clean;Build /p:Configuration="{config}";Platform={WinXX}
1227
- echo Build completed, moving result"
1228
- :: move to the "normal" path for the unix builds...
1229
- mkdir %FREETYPE%\\ objs\\ .libs
1230
- :: REMINDER: fix when changing the version
1231
- copy %FREETYPE%\\ objs\\ {vc20xx}\\ {xXX}\\ freetype261.lib %FREETYPE%\\ objs\\ .libs\\ libfreetype.lib
1232
- if errorlevel 1 (
1233
- rem This is a py27 version, which has a different location for the lib file :-/
1234
- copy %FREETYPE%\\ objs\\ win32\\ {vc20xx}\\ freetype261.lib %FREETYPE%\\ objs\\ .libs\\ libfreetype.lib
1235
- )
1236
- """
1237
- from setup_external_compile import fixproj , prepare_build_cmd , VS2010 , X64 , tar_extract
1238
- # Note: freetype has no build profile for 2014, so we don't bother...
1239
- vc = 'vc2010' if VS2010 else 'vc2008'
1240
- WinXX = 'x64' if X64 else 'Win32'
1231
+ assert cmd .compiler .compiler_type == 'msvc' , (
1232
+ 'Support for other compilers is not implemented' )
1233
+
1234
+ #from distutils.spawn import find_executable
1235
+ from distutils .msvccompiler import get_build_version
1236
+ from setup_external_compile import fixproj , X64 , tar_extract
1237
+
1238
+ if not cmd .compiler .initialized :
1239
+ cmd .compiler .initialize ()
1240
+
1241
+ vc = {9 : 'vc2005' , 11 : 'vc2010' }[min (int (get_build_version ()), 11 )]
1242
+ ftproj = os .path .join (src_path , 'builds' , 'windows' , vc , 'freetype' )
1243
+
1244
+ vc_config = 'Debug' if cmd .debug else 'Release'
1245
+ #vc_config += '|x64' if X64 else '|Win32'
1246
+ vc_platform = 'x64' if X64 else 'x86'
1247
+
1241
1248
tar_extract (tarball_path , "build" )
1242
- # This is only false for py2.7, even on py3.5...
1243
- if not VS2010 :
1244
- fixproj (os .path .join (src_path , 'builds' , 'windows' , vc , 'freetype.sln' ), WinXX )
1245
- fixproj (os .path .join (src_path , 'builds' , 'windows' , vc , 'freetype.vcproj' ), WinXX )
1246
1249
1247
- cmdfile = os .path .join ("build" , 'build_freetype.cmd' )
1248
- with open (cmdfile , 'w' ) as cmd :
1249
- cmd .write (prepare_build_cmd (FREETYPE_BUILD_CMD , vc20xx = vc , WinXX = WinXX ,
1250
- config = 'Release' if VS2010 else 'LIB Release' ))
1250
+ if not cmd .compiler .initialized :
1251
+ cmd .compiler .initialize ()
1251
1252
1252
- os .environ ['FREETYPE' ] = src_path
1253
- subprocess .check_call ([cmdfile ], shell = True )
1253
+ def spawn (command ):
1254
+ command = list (command )
1255
+ if hasattr (cmd .compiler , 'find_exe' ):
1256
+ executable = cmd .compiler .find_exe (command [0 ])
1257
+ if not executable :
1258
+ raise ValueError ("Couldn't find %s" % executable )
1259
+ return cmd .compiler .spawn ([executable ] + command [1 :])
1260
+ else :
1261
+ return cmd .compiler .spawn (command )
1262
+
1263
+ if get_build_version () < 11.0 :
1264
+ vc_config = 'LIB ' + vc_config
1265
+ # monkey-patch project files, because
1266
+ # vc2005 and vc2008 have only Win32 targets
1267
+ # TODO: fix `win32` output dir to `x64`?
1268
+ fixproj (ftproj + '.sln' , vc_platform )
1269
+ fixproj (ftproj + '.vcproj' , vc_platform )
1270
+ spawn (['vcbuild' , ftproj + '.sln' , '/M' , '/time' ,
1271
+ '/platform:{}' .format (vc_platform ),
1272
+ '{config}|{platform}' .format (config = vc_config ,
1273
+ platform = 'x64' if X64 else 'Win32' )
1274
+ ])
1275
+ postfix = '_D' if cmd .debug else ''
1276
+ builddir = os .path .join (src_path , 'objs' , 'win32' , vc )
1277
+ else :
1278
+ spawn (['msbuild' , ftproj + '.sln' , '/m' , '/t:Clean;Build' ,
1279
+ '/toolsversion:{}' .format (get_build_version ()),
1280
+ ('/p:Configuration="{config}"'
1281
+ ';Platform={platform}'
1282
+ ';VisualStudioVersion={version}'
1283
+ ';ToolsVersion={version}'
1284
+ ';PlatformToolset=v{toolset:d}'
1285
+ ).format (config = vc_config , platform = vc_platform ,
1286
+ version = get_build_version (),
1287
+ toolset = int (get_build_version () * 10 )),
1288
+ ])
1289
+ postfix = 'd' if cmd .debug else ''
1290
+ builddir = os .path .join (src_path , 'objs' , vc , vc_platform )
1291
+
1292
+ verstr = LOCAL_FREETYPE_VERSION .replace ('.' , '' )
1293
+ buildname = 'freetype{0}{1}.lib' .format (verstr , postfix )
1294
+ buildpath = os .path .join (builddir , buildname )
1295
+ assert os .path .isfile (buildpath )
1296
+ os .renames (buildpath , self .get_local_freetype_lib_path ())
1254
1297
1255
1298
1256
1299
class FT2Font (SetupPackage ):
@@ -1267,6 +1310,23 @@ def get_extension(self):
1267
1310
Numpy ().add_flags (ext )
1268
1311
return ext
1269
1312
1313
+ def do_custom_build (self , cmd ):
1314
+ if cmd .compiler .compiler_type != 'msvc' :
1315
+ return
1316
+
1317
+ if not cmd .compiler .initialized :
1318
+ cmd .compiler .initialize ()
1319
+
1320
+ # TODO: What about compiler pathes?
1321
+ if not has_include_file (cmd .compiler .include_dirs , 'stdint.h' ):
1322
+ if os .getenv ('CONDA_DEFAULT_ENV' ):
1323
+ # TODO: spawn conda install msinttypes?
1324
+ pass
1325
+ else :
1326
+ # TODO: download from https://code.google.com/p/msinttypes/
1327
+ #cmd.compiler.add_include_dir(...)
1328
+ pass
1329
+
1270
1330
1271
1331
class Png (SetupPackage ):
1272
1332
name = "png"
@@ -1300,13 +1360,24 @@ def check(self):
1300
1360
raise
1301
1361
1302
1362
def get_extension (self ):
1363
+ # TODO: implement a dynamic/static linking switch
1364
+ zlib = 'z' if sys .platform != 'win32' else 'zlibstatic'
1365
+ if sys .platform != 'win32' :
1366
+ png = 'png'
1367
+ zlib = 'z'
1368
+ elif os .getenv ('CONDA_DEFAULT_ENV' ):
1369
+ # libpng in conda copies versioned lib to unversioned
1370
+ png = 'libpng_static'
1371
+ else :
1372
+ # TODO: there is no good solution with our build system
1373
+ png = 'libpng16_static'
1303
1374
sources = [
1304
1375
'src/_png.cpp' ,
1305
1376
'src/mplutils.cpp'
1306
1377
]
1307
1378
ext = make_extension ('matplotlib._png' , sources )
1308
1379
pkg_config .setup_extension (
1309
- ext , 'libpng' , default_libraries = [' png' , 'z' ],
1380
+ ext , 'libpng' , default_libraries = [png , zlib ],
1310
1381
alt_exec = 'libpng-config --ldflags' )
1311
1382
Numpy ().add_flags (ext )
1312
1383
return ext
0 commit comments