10000 CI: add appveyor script to build Windows wheels by matthew-brett · Pull Request #6969 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

CI: add appveyor script to build Windows wheels #6969

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Win: build with a local freetype
Makes it possible to use the local freetype config option in setup.cfg.

Parts of this commit are from https://github.com/jbmohler/matplotlib-winbuild
  • Loading branch information
jankatins authored and matthew-brett committed Aug 25, 2016
commit affc50e369e1b99568f00cf8076fca857ff47ef0
32 changes: 32 additions & 0 deletions build_alllocal.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
:: This assumes you have installed all the dependencies via conda packages:
:: # create a new environment with the required packages
:: conda create -n "matplotlib_build" python=3.4 numpy python-dateutil pyparsing pytz tornado pyqt cycler tk libpng zlib freetype
:: activate matplotlib_build
:: # this package is only available in the conda-forge channel
:: conda install -c conda-forge msinttypes

set TARGET=bdist_wheel
IF [%1]==[] (
echo Using default target: %TARGET%
) else (
set TARGET=%1
echo Using user supplied target: %TARGET%
)

IF NOT DEFINED CONDA_DEFAULT_ENV (
echo No Conda env activated: you need to create a conda env with the right packages and activate it!
GOTO:eof
)

:: copy the libs which have "wrong" names
set LIBRARY_LIB=%CONDA_DEFAULT_ENV%\Library\lib
mkdir lib || cmd /c "exit /b 0"
copy %LIBRARY_LIB%\zlibstatic.lib lib\z.lib
copy %LIBRARY_LIB%\libpng_static.lib lib\png.lib

:: Make the header files and the rest of the static libs available during the build
:: CONDA_DEFAULT_ENV is a env variable which is set to the currently active environment path
set MPLBASEDIRLIST=%CONDA_DEFAULT_ENV%\Library\;.

:: build the target
python setup.py %TARGET%
228 changes: 228 additions & 0 deletions setup_external_compile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
"""
This file extracts and builds library dependencies libpng, zlib, & freetype2 on
MS Windows. It also extract tcl/tk for the header files.

There are four possible build targets -- one for each permutation of VS 2008,
2010 and 32/64 bit. This builds the configuration that matches the Python
install that is executing.

For Python 2.6, 2.7, 3.2:

- VS 2008, 32 bit -- Windows SDK v7.0
- VS 2008, 64 bit -- Windows SDK v7.0

< 10000 /td> For Python 3.3, 3.4:

- VS 2010, 32 bit -- Windows SDK v7.1
- VS 2010, 64 bit -- Windows SDK v7.1
"""

from __future__ import print_function, absolute_import
import sys
import platform
import os
import glob
import shutil
import zipfile
import tarfile
import distutils.msvc9compiler as msvc

def fixproj(project_file, bit_target):
"""
:param bit_target: one of 'Win32' or 'x64'
"""
with open(project_file, 'r') as fd:
content = '\n'.join(line.strip() for line in fd if line.strip())
content = content.replace('Win32', bit_target).replace('x64', bit_target)
with open(project_file, 'w') as fd:
fd.write(content)

def tar_extract(tar_file, target):
with tarfile.open(tar_file, 'r:gz') as tgz:
tgz.extractall(target)

def zip_extract(zip_file, target):
with zipfile.ZipFile(zip_file) as zf:
zf.extractall(target)

# Configuration selection & declaration:
DEPSSRC = os.path.join(os.path.dirname(os.path.normpath(__file__)), 'deps_source')
DEPSBUILD = os.path.join(os.path.dirname(os.path.normpath(__file__)), 'build')
X64 = platform.architecture()[0] == '64bit'
PYVER = sys.version_info[:2]
VS2010 = PYVER >= (3, 3)
# If not VS2010, then use VS2008

VCVARSALL = None

def prepare_build_cmd(build_cmd, **kwargs):
global VCVARSALL
if VCVARSALL == None:
candidate = msvc.find_vcvarsall(10.0 if VS2010 else 9.0)
if candidate == None:
raise RuntimeError('Microsoft VS {} required'.format('2010' if VS2010 else '2008'))
else:
VCVARSALL = candidate

return build_cmd.format(vcvarsall=VCVARSALL, xXX='x64' if X64 else 'x86', **kwargs)

def config_dir():
segment = 'msvcr{}-x{}'.format('100' if VS2010 else '90', '64' if X64 else '32')
return os.path.join(DEPSBUILD, segment)

def tcl_config_dir():
return os.path.join(config_dir(), 'tcl85', 'include')

def build_tcl():
inclib = config_dir()
tcl_inclib = tcl_config_dir()
if not os.path.exists(tcl_inclib):
os.makedirs(tcl_inclib)
tcl_inclib_x11 = os.path.join(tcl_inclib, 'X11')
if not os.path.exists(tcl_inclib_x11):
os.makedirs(tcl_inclib_x11)

distfile = os.path.join(DEPSSRC, 'tcl8513-src.zip')
compfile = os.path.join(tcl_inclib, 'tcl.h')
if not os.path.exists(compfile) or os.path.getmtime(distfile) > os.path.getmtime(compfile):
zip_extract(distfile, DEPSBUILD)
targetdir = os.path.join(DEPSBUILD, 'tcl8.5.13')
headers = glob.glob(os.path.join(targetdir, 'generic', '*.h'))
for filename in headers:
shutil.copy(filename, tcl_inclib)

distfile = os.path.join(DEPSSRC, 'tk8513-src.zip')
compfile = os.path.join(tcl_inclib, 'tk.h')
if not os.path.exists(compfile) or os.path.getmtime(distfile) > os.path.getmtime(compfile):
zip_extract(distfile, DEPSBUILD)
targetdir = os.path.join(DEPSBUILD, 'tk8.5.13')
headers = glob.glob(os.path.join(targetdir, 'generic', '*.h'))
for filename in headers:
shutil.copy(filename, tcl_inclib)
headers = glob.glob(os.path.join(targetdir, 'xlib', 'X11', '*.*'))
for filename in headers:
shutil.copy(filename, tcl_inclib_x11)

ZLIB_BUILD_CMD = """\
@ECHO OFF
REM call "%ProgramFiles%\\Microsoft SDKs\\Windows\\v7.0\\Bin\\SetEnv.Cmd" /Release /{xXX} /xp
call "{vcvarsall}" {xXX}

cd /D %ZLIB%
nmake -f win32\\Makefile.msc clean
nmake -f win32\\Makefile.msc
copy /Y /B *.dll %INCLIB%
copy /Y /B *.lib %INCLIB%
copy /Y /B zlib.lib %INCLIB%\\z.lib
copy /Y /B zlib.h %INCLIB%
copy /Y /B zconf.h %INCLIB%
"""

def build_zlib():
inclib = config_dir()
if not os.path.exists(inclib):
os.makedirs(inclib)

distfile = os.path.join(DEPSSRC, 'zlib128.zip')
compfile = os.path.join(inclib, 'z.lib')
if os.path.exists(compfile) and os.path.getmtime(distfile) < os.path.getmtime(compfile):
# already built
return

10000 zip_extract(distfile, DEPSBUILD)

cmdfile = os.path.join(DEPSBUILD, 'build_zlib.cmd')
with open(cmdfile, 'w') as cmd:
cmd.write(prepare_build_cmd(ZLIB_BUILD_CMD))

os.environ['INCLIB'] = inclib
os.environ['ZLIB'] = os.path.join(DEPSBUILD, 'zlib-1.2.8')
os.system(cmdfile)

LIBPNG_BUILD_CMD = """\
@ECHO OFF
REM call "%ProgramFiles%\\Microsoft SDKs\\Windows\\v7.0\\Bin\\SetEnv.Cmd" /Release /{xXX} /xp
call "{vcvarsall}" {xXX}
set CMAKE="cmake.exe"

set BUILDDIR=%LIBPNG%-build
rd /S /Q %BUILDDIR%
%CMAKE% -G"NMake Makefiles" -H%LIBPNG% -B%BUILDDIR% ^
-DCMAKE_BUILD_TYPE=Release ^
-DZLIB_INCLUDE_DIR=%INCLIB% ^
-DZLIB_LIBRARY:FILEPATH=%INCLIB%\\zlib.lib ^
-DPNG_STATIC=ON ^
-DPNG_SHARED=OFF
copy /Y /B %BUILDDIR%\\pnglibconf.h %INCLIB%
copy /Y /B %LIBPNG%\\png.h %INCLIB%
copy /Y /B %LIBPNG%\\pngconf.h %INCLIB%
cd %BUILDDIR%
nmake -f Makefile
REM It's a static lib -- no *.dll in sight!
REM copy /Y /B *.dll %INCLIB%
copy /Y /B *.lib %INCLIB%
copy /Y /B libpng16_static.lib %INCLIB%\\png.lib
"""

def build_libpng():
inclib = config_dir()
if not os.path.exists(inclib):
os.mkdir(inclib)

distfile = os.path.join(DEPSSRC, 'libpng-1.6.7.tar.gz')
compfile = os.path.join(inclib, 'png.lib')
if os.path.exists(compfile) and os.path.getmtime(distfile) < os.path.getmtime(compfile):
# already built
return

tar_extract(distfile, DEPSBUILD)

cmdfile = os.path.join(DEPSBUILD, 'build_libpng.cmd')
with open(cmdfile, 'w') as cmd:
cmd.write(prepare_build_cmd(LIBPNG_BUILD_CMD))

os.environ['INCLIB'] = inclib
os.environ['LIBPNG'] = os.path.join(DEPSBUILD, 'libpng-1.6.7')
os.system(cmdfile)

FREETYPE_VERSION = '2.4.11'

FREETYPE_BUILD_CMD = """\
@ECHO OFF
REM call "%ProgramFiles%\\Microsoft SDKs\\Windows\\v7.0\\Bin\\SetEnv.Cmd" /Release /{xXX} /xp
call "{vcvarsall}" {xXX}
set MSBUILD=C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe

rd /S /Q %FREETYPE%\\objs
%MSBUILD% %FREETYPE%\\builds\\win32\\{vc20xx}\\freetype.sln /t:Clean;Build /p:Configuration="{config}";Platform={WinXX}
xcopy /Y /E /Q %FREETYPE%\\include %INCLIB%
xcopy /Y /E /Q %FREETYPE%\\objs\\win32\\{vc20xx} %INCLIB%
copy /Y /B %FREETYPE%\\objs\\win32\\{vc20xx}\\*.lib %INCLIB%\\freetype.lib
"""

def build_freetype():
inclib = config_dir()
if not os.path.exists(inclib):
os.mkdir(inclib)

distfile = os.path.join(DEPSSRC, 'ft2411.zip')
compfile = os.path.join(inclib, 'freetype.lib')
if os.path.exists(compfile) and os.path.getmtime(distfile) < os.path.getmtime(compfile):
# already built
return

vc = 'vc2010' if VS2010 else 'vc2008'
WinXX = 'x64' if X64 else 'Win32'

zip_extract(distfile, DEPSBUILD)
ft_dir = os.path.join(DEPSBUILD, 'freetype-2.4.11')
fixproj(os.path.join(ft_dir, 'builds', 'win32', vc, 'freetype.sln'), WinXX)
fixproj(os.path.join(ft_dir, 'builds', 'win32', vc, 'freetype.{}'.format('vcxproj' if VS2010 else 'vcproj')), WinXX)

cmdfile = os.path.join(DEPSBUILD, 'build_freetype.cmd')
with open(cmdfile, 'w') as cmd:
cmd.write(prepare_build_cmd(FREETYPE_BUILD_CMD, vc20xx=vc, WinXX=WinXX, config='Release' if VS2010 else 'LIB Release'))

os.environ['INCLIB'] = inclib
os.environ['FREETYPE'] = ft_dir
os.system(cmdfile)
75 changes: 58 additions & 17 deletions setupext.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ def _get_xdg_cache_dir():

# This is the version of FreeType to use when building a local
# version. It must match the value in
# lib/matplotlib.__init__.py
# lib/matplotlib.__init__.py and also needs to be changed below in the
# embedded windows build script (grep for "REMINDER" in this file)
LOCAL_FREETYPE_VERSION = '2.6.1'
# md5 hash of the freetype tarball
LOCAL_FREETYPE_HASH = '348e667d728c597360e4a87c16556597'
Expand Down Expand Up @@ -171,16 +172,16 @@ def get_base_dirs():
"""
if options['basedirlist']:
return options['basedirlist']

if os.environ.get('MPLBASEDIRLIST'):
return os.environ.get('MPLBASEDIRLIST').split(os.pathsep)

win_bases = ['win32_static', ]
# on conda windows, we also add the <installdir>\Library of the local interperter,
# on conda windows, we also add the <installdir>\Library of the local interperter,
# as conda installs libs/includes there
if os.getenv('CONDA_DEFAULT_ENV'):
win_bases.append(os.path.join(os.getenv('CONDA_DEFAULT_ENV'), "Library"))

basedir_map = {
'win32': win_bases,
'darwin': ['/usr/local/', '/usr', '/usr/X11',
Expand All @@ -198,7 +199,7 @@ def get_include_dirs():
"""
include_dirs = [os.path.join(d, 'include') for d in get_base_dirs()]
if sys.platform != 'win32':
# gcc includes this dir automatically, so also look for headers in
# gcc includes this dir automatically, so also look for headers in
# these dirs
include_dirs.extend(
os.environ.get('CPLUS_INCLUDE_PATH', '').split(os.pathsep))
Expand Down Expand Up @@ -1010,8 +1011,12 @@ def add_flags(self, ext):
# Statically link to the locally-built freetype.
# This is certainly broken on Windows.
ext.include_dirs.insert(0, os.path.join(src_path, 'include'))
if sys.platform == 'win32':
libfreetype = 'libfreetype.lib'
else:
libfreetype = 'libfreetype.a'
ext.extra_objects.insert(
0, os.path.join(src_path, 'objs', '.libs', 'libfreetype.a'))
0, os.path.join(src_path, 'objs', '.libs', libfreetype))
ext.define_macros.append(('FREETYPE_BUILD_TYPE', 'local'))
else:
pkg_config.setup_extension(
Expand All @@ -1034,8 +1039,12 @@ def do_custom_build(self):
'build', 'freetype-{0}'.format(LOCAL_FREETYPE_VERSION))

# We've already built freetype
if os.path.isfile(
os.path.join(src_path, 'objs', '.libs', 'libfreetype.a')):
if sys.platform == 'win32':
libfreetype = 'libfreetype.lib'
else:
libfreetype = 'libfreetype.a'

if os.path.isfile(os.path.join(src_path, 'objs', '.libs', libfreetype)):
return

tarball = 'freetype-{0}.tar.gz'.format(LOCAL_FREETYPE_VERSION)
Expand Down Expand Up @@ -1107,15 +1116,47 @@ def do_custom_build(self):
"{0} does not match expected hash.".format(tarball))

print("Building {0}".format(tarball))
cflags = 'CFLAGS="{0} -fPIC" '.format(os.environ.get('CFLAGS', ''))

subprocess.check_call(
['tar', 'zxf', tarball], cwd='build')
subprocess.check_call(
[cflags + './configure --with-zlib=no --with-bzip2=no '
'--with-png=no --with-harfbuzz=no'], shell=True, cwd=src_path)
subprocess.check_call(
[cflags + 'make'], shell=True, cwd=src_path)
if sys.platform != 'win32':
# compilation on all other platforms than windows
cflags = 'CFLAGS="{0} -fPIC" '.format(os.environ.get('CFLAGS', ''))

subprocess.check_call(
['tar', 'zxf', tarball], cwd='build')
subprocess.check_call(
[cflags + './configure --with-zlib=no --with-bzip2=no '
'--with-png=no --with-harfbuzz=no'], shell=True, cwd=src_path)
subprocess.check_call(
[cflags + 'make'], shell=True, cwd=src_path)
else:
# compilation on windows
FREETYPE_BUILD_CMD = """\
call "%ProgramFiles%\\Microsoft SDKs\\Windows\\v7.0\\Bin\\SetEnv.Cmd" /Release /{xXX} /xp
call "{vcvarsall}" {xXX}
set MSBUILD=C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe
rd /S /Q %FREETYPE%\\objs
%MSBUILD% %FREETYPE%\\builds\\windows\\{vc20xx}\\freetype.sln /t:Clean;Build /p:Configuration="{config}";Platform={WinXX}
:: move to the "normal" path for the unix builds...
mkdir %FREETYPE%\\objs\\.libs
:: REMINDER: fix when changing the version
copy %FREETYPE%\\objs\\{vc20xx}\\{xXX}\\freetype261.lib %FREETYPE%\\objs\\.libs\\libfreetype.lib
"""
from setup_external_compile import fixproj, prepare_build_cmd, VS2010, X64, tar_extract
vc = 'vc2010' if VS2010 else 'vc2008'
vc = 'vc2010' if VS2010 else 'vc2008'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is broken on Python 3.5, which uses VS2015. Better raise an Exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build seems to be working : https://ci.appveyor.com/project/mdboom/matplotlib/build/1.0.2436/job/akufhhatuycx8tps - is it not running this block?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you got lucky with linking a static library built with VS2010 into a DLL otherwise built with VS2015.

WinXX = 'x64' if X64 else 'Win32'
tar_extract(tarball_path, "build")

#fixproj(os.path.join(src_path, 'builds', 'windows', vc, 'freetype.sln'), WinXX)
#fixproj(os.path.join(src_path, 'builds', 'windows', vc, 'freetype.{}'.format(
# 'vcxproj' if VS2010 else 'vcproj')), WinXX)

cmdfile = os.path.join("build", 'build_freetype.cmd')
with open(cmdfile, 'w') as cmd:
cmd.write(prepare_build_cmd(FREETYPE_BUILD_CMD, vc20xx=vc, WinXX=WinXX,
config='Release' if VS2010 else 'LIB Release'))

os.environ['FREETYPE'] = src_path
subprocess.check_call([cmdfile], shell=True)


class FT2Font(SetupPackage):
Expand Down
< 2937 /turbo-frame>
0