@@ -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
@@ -1094,19 +1105,24 @@ def version_from_header(self):
1094
1105
patch = value
1095
1106
return '.' .join ([major , minor , patch ])
1096
1107
1108
+ def get_local_freetype_path (self , version = LOCAL_FREETYPE_VERSION ):
1109
+ return os .path .join ('build' , 'freetype-{0}' .format (version ))
1110
+
1111
+ def get_local_freetype_lib_path (self , version = LOCAL_FREETYPE_VERSION ):
1112
+ if sys .platform == 'win32' :
1113
+ libfreetype = 'libfreetype.lib'
1114
+ else :
1115
+ libfreetype = 'libfreetype.a'
1116
+
1117
+ src_path = self .get_local_freetype_path (version )
1118
+ return os .path .join (src_path , 'objs' , '.libs' , libfreetype )
1119
+
1097
1120
def add_flags (self , ext ):
1098
1121
if options .get ('local_freetype' ):
1099
- src_path = os .path .join (
1100
- 'build' , 'freetype-{0}' .format (LOCAL_FREETYPE_VERSION ))
1101
- # Statically link to the locally-built freetype.
1102
- # This is certainly broken on Windows.
1122
+ src_path = self .get_local_freetype_path ()
1123
+ # link to the locally-built freetype.
1103
1124
ext .include_dirs .insert (0 , os .path .join (src_path , 'include' ))
1104
- if sys .platform == 'win32' :
1105
- libfreetype = 'libfreetype.lib'
1106
- else :
1107
- libfreetype = 'libfreetype.a'
1108
- ext .extra_objects .insert (
1109
- 0 , os .path .join (src_path , 'objs' , '.libs' , libfreetype ))
1125
+ ext .extra_objects .insert (0 , self .get_local_freetype_lib_path ())
1110
1126
ext .define_macros .append (('FREETYPE_BUILD_TYPE' , 'local' ))
1111
1127
else :
1112
1128
pkg_config .setup_extension (
@@ -1117,26 +1133,21 @@ def add_flags(self, ext):
1117
1133
'lib/freetype2/include/freetype2' ],
1118
1134
default_library_dirs = [
1119
1135
'freetype2/lib' ],
1120
- default_libraries = ['freetype' , 'z' ])
1136
+ default_libraries = ['freetype' ])
1121
1137
ext .define_macros .append (('FREETYPE_BUILD_TYPE' , 'system' ))
1122
1138
1123
- def do_custom_build (self ):
1124
- # We're using a system freetype
1139
+ def do_custom_build (self , cmd ):
1125
1140
if not options .get ('local_freetype' ):
1141
+ # We're using a system freetype
1126
1142
return
1127
1143
1128
- src_path = os .path .join (
1129
- 'build' , 'freetype-{0}' .format (LOCAL_FREETYPE_VERSION ))
1130
-
1131
- # We've already built freetype
1132
- if sys .platform == 'win32' :
1133
- libfreetype = 'libfreetype.lib'
1134
- else :
1135
- libfreetype = 'libfreetype.a'
1136
-
1137
- if os .path .isfile (os .path .join (src_path , 'objs' , '.libs' , libfreetype )):
1144
+ libdir = os .path .dirname (self .get_local_freetype_lib_path ())
1145
+ if os .path .isfile (self .get_local_freetype_lib_path ()):
1146
+ # We've already built freetype
1147
+ # TODO: This will prevent x86/x64 debug/release switch
1138
1148
return
1139
1149
1150
+ src_path = self .get_local_freetype_path ()
1140
1151
tarball = 'freetype-{0}.tar.gz' .format (LOCAL_FREETYPE_VERSION )
1141
1152
tarball_path = os .path .join ('build' , tarball )
1142
1153
try :
@@ -1223,40 +1234,71 @@ def do_custom_build(self):
1223
1234
subprocess .check_call (
1224
1235
[cflags + 'make' ], shell = True , cwd = src_path )
1225
1236
else :
1226
- # compilation on windows
1227
- FREETYPE_BUILD_CMD = """\
1228
- call "%ProgramFiles%\\ Microsoft SDKs\\ Windows\\ v7.0\\ Bin\\ SetEnv.Cmd" /Release /{xXX} /xp
1229
- call "{vcvarsall}" {xXX}
1230
- set MSBUILD=C:\\ Windows\\ Microsoft.NET\\ Framework\\ v4.0.30319\\ MSBuild.exe
1231
- rd /S /Q %FREETYPE%\\ objs
1232
- %MSBUILD% %FREETYPE%\\ builds\\ windows\\ {vc20xx}\\ freetype.sln /t:Clean;Build /p:Configuration="{config}";Platform={WinXX}
1233
- echo Build completed, moving result"
1234
- :: move to the "normal" path for the unix builds...
1235
- mkdir %FREETYPE%\\ objs\\ .libs
1236
- :: REMINDER: fix when changing the version
1237
- copy %FREETYPE%\\ objs\\ {vc20xx}\\ {xXX}\\ freetype261.lib %FREETYPE%\\ objs\\ .libs\\ libfreetype.lib
1238
- if errorlevel 1 (
1239
- rem This is a py27 version, which has a different location for the lib file :-/
1240
- copy %FREETYPE%\\ objs\\ win32\\ {vc20xx}\\ freetype261.lib %FREETYPE%\\ objs\\ .libs\\ libfreetype.lib
1241
- )
1242
- """
1243
- from setup_external_compile import fixproj , prepare_build_cmd , VS2010 , X64 , tar_extract
1244
- # Note: freetype has no build profile for 2014, so we don't bother...
1245
- vc = 'vc2010' if VS2010 else 'vc2008'
1246
- WinXX = 'x64' if X64 else 'Win32'
1237
+ assert cmd .compiler .compiler_type == 'msvc' , (
1238
+ 'Support for other compilers is not implemented' )
1239
+
1240
+ from distutils .msvccompiler import get_build_version
1241
+ from setup_external_compile import fixproj , X64 , tar_extract
1242
+
1243
+ if not cmd .compiler .initialized :
1244
+ cmd .compiler .initialize ()
1245
+
1246
+ # NOTE: need change on upgrade of local freetype to newer versions
1247
+ vc = {9 : 'vc2005' , 11 : 'vc2010' }[min (int (get_build_version ()), 11 )]
1248
+ ftproj = os .path .join (src_path , 'builds' , 'windows' , vc , 'freetype' )
1249
+
1250
+ vc_config = 'Debug' if cmd .debug else 'Release'
1251
+ vc_platform = 'x64' if X64 else 'x86'
1252
+
1247
1253
tar_extract (tarball_path , "build" )
1248
- # This is only false for py2.7, even on py3.5...
1249
- if not VS2010 :
1250
- fixproj (os .path .join (src_path , 'builds' , 'windows' , vc , 'freetype.sln' ), WinXX )
1251
- fixproj (os .path .join (src_path , 'builds' , 'windows' , vc , 'freetype.vcproj' ), WinXX )
1252
1254
1253
- cmdfile = os .path .join ("build" , 'build_freetype.cmd' )
1254
- with open (cmdfile , 'w' ) as cmd :
1255
- cmd .write (prepare_build_cmd (FREETYPE_BUILD_CMD , vc20xx = vc , WinXX = WinXX ,
1256
- config = 'Release' if VS2010 else 'LIB Release' ))
1255
+ if not cmd .compiler .initialized :
1256
+ cmd .compiler .initialize ()
1257
1257
1258
- os .environ ['FREETYPE' ] = src_path
1259
- subprocess .check_call ([cmdfile ], shell = True )
1258
+ def spawn (command ):
1259
+ command = list (command )
1260
+ if hasattr (cmd .compiler , 'find_exe' ):
1261
+ executable = cmd .compiler .find_exe (command [0 ])
1262
+ if not executable :
1263
+ raise ValueError ("Couldn't find %s" % command [0 ])
1264
+ return cmd .compiler .spawn ([executable ] + command [1 :])
1265
+ else :
1266
+ return cmd .compiler .spawn (command )
1267
+
1268
+ if get_build_version () < 11.0 :
1269
+ vc_config = 'LIB ' + vc_config
1270
+ # monkey-patch project files, because
1271
+ # vc2005 and vc2008 have only Win32 targets
1272
+ # TODO: fix `win32` output dir to `x64`?
1273
+ fixproj (ftproj + '.sln' , vc_platform )
1274
+ fixproj (ftproj + '.vcproj' , vc_platform )
1275
+ spawn (['vcbuild' , ftproj + '.sln' , '/M' , '/time' ,
1276
+ '/platform:{}' .format (vc_platform ),
1277
+ '{config}|{platform}' .format (config = vc_config ,
1278
+ platform = 'x64' if X64 else 'Win32' )
1279
+ ])
1280
+ postfix = '_D' if cmd .debug else ''
1281
+ builddir = os .path .join (src_path , 'objs' , 'win32' , vc )
1282
+ else :
1283
+ spawn (['msbuild' , ftproj + '.sln' , '/m' , '/t:Clean;Build' ,
1284
+ '/toolsversion:{}' .format (get_build_version ()),
1285
+ ('/p:Configuration="{config}"'
1286
+ ';Platform={platform}'
1287
+ ';VisualStudioVersion={version}'
1288
+ ';ToolsVersion={version}'
1289
+ ';PlatformToolset=v{toolset:d}'
1290
+ ).format (config = vc_config , platform = vc_platform ,
1291
+ version = get_build_version (),
1292
+ toolset = int (get_build_version () * 10 )),
1293
+ ])
1294
+ postfix = 'd' if cmd .debug else ''
1295
+ builddir = os .path .join (src_path , 'objs' , vc , vc_platform )
1296
+
1297
+ verstr = LOCAL_FREETYPE_VERSION .replace ('.' , '' )
1298
+ buildname = 'freetype{0}{1}.lib' .format (verstr , postfix )
1299
+ buildpath = os .path .join (builddir , buildname )
1300
+ assert os .path .isfile (buildpath )
1301
+ os .renames (buildpath , self .get_local_freetype_lib_path ())
1260
1302
1261
1303
1262
1304
class FT2Font (SetupPackage ):
@@ -1273,6 +1315,23 @@ def get_extension(self):
1273
1315
Numpy ().add_flags (ext )
1274
1316
return ext
1275
1317
1318
+ def do_custom_build (self , cmd ):
1319
+ if cmd .compiler .compiler_type != 'msvc' :
1320
+ return
1321
+
1322
+ if not cmd .compiler .initialized :
1323
+ cmd .compiler .initialize ()
1324
+
1325
+ # TODO: What about compiler pathes?
1326
+ if not has_include_file (cmd .compiler .include_dirs , 'stdint.h' ):
1327
+ if os .getenv ('CONDA_DEFAULT_ENV' ):
1328
+ # TODO: spawn conda install msinttypes?
1329
+ pass
1330
+ else :
1331
+ # TODO: download from https://code.google.com/p/msinttypes/
1332
+ #cmd.compiler.add_include_dir(...)
1333
+ pass
1334
+
1276
1335
1277
1336
class Png (SetupPackage ):
1278
1337
name = "png"
@@ -1306,13 +1365,24 @@ def check(self):
1306
1365
raise
1307
1366
1308
1367
def get_extension (self ):
1368
+ # TODO: implement a dynamic/static linking switch
1369
+ zlib = 'z' if sys .platform != 'win32' else 'zlibstatic'
1370
+ if sys .platform != 'win32' :
1371
+ png = 'png'
1372
+ zlib = 'z'
1373
+ elif os .getenv ('CONDA_DEFAULT_ENV' ):
1374
+ # libpng in conda copies versioned lib to unversioned
1375
+ png = 'libpng_static'
1376
+ else :
1377
+ # TODO: there is no good solution with our build system
1378
+ png = 'libpng16_static'
1309
1379
sources = [
1310
1380
'src/_png.cpp' ,
1311
1381
'src/mplutils.cpp'
1312
1382
]
1313
1383
ext = make_extension ('matplotlib._png' , sources )
1314
1384
pkg_config .setup_extension (
1315
- ext , 'libpng' , default_libraries = [' png' , 'z' ],
1385
+ ext , 'libpng' , default_libraries = [png , zlib ],
1316
1386
alt_exec = 'libpng-config --ldflags' )
1317
1387
Numpy ().add_flags (ext )
1318
1388
return ext
0 commit comments