source: wkhtmltox/trunk/fuentes/scripts/build.py @ 51

Last change on this file since 51 was 51, checked in by mabarracus, 4 years ago

wip

  • Property svn:executable set to *
File size: 48.8 KB
Line 
1#!/usr/bin/env python
2#
3# Copyright 2014 wkhtmltopdf authors
4#
5# This file is part of wkhtmltopdf.
6#
7# wkhtmltopdf is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Lesser General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# wkhtmltopdf is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU Lesser General Public License
18# along with wkhtmltopdf.  If not, see <http:#www.gnu.org/licenses/>.
19
20# --------------------------------------------------------------- CONFIGURATION
21
22PROJECT_SETUP = {
23    'name':         'wkhtmltox',
24    'description':  'convert HTML to PDF and various image formats using QtWebkit',
25    'license':      'LGPLv3',
26    'maintainer':   'Ashish Kulkarni <kulkarni.ashish@gmail.com>',
27    'url':          'http://wkhtmltopdf.org/'
28}
29
30BUILDERS = {
31    'source-tarball':        'source_tarball',
32    'msvc2013-win32':        'msvc',
33    'msvc2013-win64':        'msvc',
34    'setup-mingw-w64':       'setup_mingw_w64',
35    'setup-schroot-generic': 'setup_schroot',
36    'setup-schroot-centos7': 'setup_schroot',
37    'setup-schroot-wheezy':  'setup_schroot',
38    'setup-schroot-jessie':  'setup_schroot',
39    'setup-schroot-trusty':  'setup_schroot',
40    'setup-schroot-precise': 'setup_schroot',
41    'update-all-schroots':   'update_schroot',
42    'linux-generic-i386':    'linux_generic',
43    'linux-generic-amd64':   'linux_generic',
44    'centos7-amd64':         'linux_schroot',
45    'wheezy-i386':           'linux_schroot',
46    'wheezy-amd64':          'linux_schroot',
47    'jessie-i386':           'linux_schroot',
48    'jessie-amd64':          'linux_schroot',
49    'trusty-i386':           'linux_schroot',
50    'trusty-amd64':          'linux_schroot',
51    'precise-i386':          'linux_schroot',
52    'precise-amd64':         'linux_schroot',
53    'mingw-w64-cross-win32': 'mingw64_cross',
54    'mingw-w64-cross-win64': 'mingw64_cross',
55    'posix-local':           'posix_local',
56    'osx-cocoa-x86-64':      'osx',
57    'osx-carbon-i386':       'osx'
58}
59
60QT_CONFIG = {
61    'common' : [
62        '-opensource',
63        '-confirm-license',
64        '-fast',
65        '-release',
66        '-static',
67        '-graphicssystem raster',
68        '-webkit',
69        '-exceptions',              # required by XmlPatterns
70        '-xmlpatterns',             # required for TOC support
71        '-system-zlib',
72        '-system-libpng',
73        '-system-libjpeg',
74        '-no-libmng',
75        '-no-libtiff',
76        '-no-accessibility',
77        '-no-stl',
78        '-no-qt3support',
79        '-no-phonon',
80        '-no-phonon-backend',
81        '-no-opengl',
82        '-no-declarative',
83        '-no-script',
84        '-no-scripttools',
85        '-no-sql-ibase',
86        '-no-sql-mysql',
87        '-no-sql-odbc',
88        '-no-sql-psql',
89        '-no-sql-sqlite',
90        '-no-sql-sqlite2',
91        '-no-mmx',
92        '-no-3dnow',
93        '-no-sse',
94        '-no-sse2',
95        '-no-multimedia',
96        '-nomake demos',
97        '-nomake docs',
98        '-nomake examples',
99        '-nomake tools',
100        '-nomake tests',
101        '-nomake translations'
102    ],
103
104    'msvc': [
105        '-mp',
106        '-qt-style-windows',
107        '-qt-style-cleanlooks',
108        '-no-style-windowsxp',
109        '-no-style-windowsvista',
110        '-no-style-plastique',
111        '-no-style-motif',
112        '-no-style-cde',
113        '-openssl-linked'           # static linkage for OpenSSL
114    ],
115
116    'posix': [
117        '-silent',                  # perform a silent build
118        '-xrender',                 # xrender support is required
119        '-largefile',
120        '-iconv',                   # iconv support is required for text codecs
121        '-openssl',                 # load OpenSSL binaries at runtime
122        '-no-javascript-jit',       # can cause crashes/excess memory usage
123        '-no-rpath',
124        '-no-dbus',
125        '-no-nis',
126        '-no-cups',
127        '-no-pch',
128        '-no-gtkstyle',
129        '-no-nas-sound',
130        '-no-sm',
131        '-no-xshape',
132        '-no-xinerama',
133        '-no-xcursor',
134        '-no-xfixes',
135        '-no-xrandr',
136        '-no-mitshm',
137        '-no-xinput',
138        '-no-xkb',
139        '-no-glib',
140        '-no-gstreamer',
141        '-no-icu',
142        '-no-openvg',
143        '-no-xsync',
144        '-no-audio-backend',
145        '-no-sse3',
146        '-no-ssse3',
147        '-no-sse4.1',
148        '-no-sse4.2',
149        '-no-avx',
150        '-no-neon'
151    ],
152
153    'mingw-w64-cross' : [
154        '-silent',                  # perform a silent build
155        '-openssl-linked',          # static linkage for OpenSSL
156        '-no-reduce-exports',
157        '-no-rpath',
158        '-xplatform win32-g++-4.6'
159    ],
160
161    'osx': [
162        '-silent',                  # perform a silent build
163        '-no-framework',
164        '-no-dwarf2',
165        '-xrender',                 # xrender support is required
166        '-openssl',                 # load OpenSSL binaries at runtime
167        '-largefile',
168        '-no-rpath'
169    ]
170}
171
172LINUX_SCHROOT_SETUP = {
173    'wheezy': {
174        'title'             : 'Debian Wheezy',
175        'packaging_tool'    : 'apt',
176        'build_arch'        : ['amd64', 'i386'],
177        'compression'       : 'xz',
178        'runtime_packages'  : 'libc6 libstdc++6 zlib1g libpng12-0 libjpeg62 '\
179                              'libssl1.0.0 libfreetype6 libicu48 fontconfig '\
180                              'libx11-6 libxext6 libxrender1 libxcb1 xfonts-base xfonts-75dpi',
181        'build_packages'    : 'xz-utils ruby python perl gperf bison flex git '\
182                              'zlib1g-dev libpng12-dev libjpeg62-dev libssl-dev libfreetype6-dev libicu-dev libfontconfig1-dev '\
183                              'libx11-dev libxext-dev libxrender-dev libxcb1-dev',
184        'debootstrap'       : ('wheezy', 'http://ftp.us.debian.org/debian/', """
185                                    deb http://ftp.debian.org/debian/ wheezy         main contrib non-free
186                                    deb http://ftp.debian.org/debian/ wheezy-updates main contrib non-free
187                                    deb http://security.debian.org/   wheezy/updates main contrib non-free""")
188    },
189    'jessie': {
190        'title'             : 'Debian Jessie',
191        'packaging_tool'    : 'apt',
192        'build_arch'        : ['amd64', 'i386'],
193        'compression'       : 'xz',
194        'runtime_packages'  : 'libc6 libstdc++6 zlib1g libpng12-0 libjpeg62-turbo '\
195                              'libssl1.0.0 libfreetype6 libicu52 fontconfig '\
196                              'libx11-6 libxext6 libxrender1 libxcb1 xfonts-base xfonts-75dpi',
197        'build_packages'    : 'xz-utils ruby python perl gperf bison flex git '\
198                              'zlib1g-dev libpng12-dev libjpeg62-turbo-dev libssl-dev libfreetype6-dev libicu-dev libfontconfig1-dev '\
199                              'libx11-dev libxext-dev libxrender-dev libxcb1-dev',
200        'debootstrap'       : ('jessie', 'http://ftp.us.debian.org/debian/', """
201                                    deb http://ftp.debian.org/debian/ jessie         main contrib non-free
202                                    deb http://ftp.debian.org/debian/ jessie-updates main contrib non-free
203                                    deb http://security.debian.org/   jessie/updates main contrib non-free""")
204    },
205    'trusty': {
206        'title'             : 'Ubuntu Trusty',
207        'packaging_tool'    : 'apt',
208        'build_arch'        : ['amd64', 'i386'],
209        'compression'       : 'xz',
210        'runtime_packages'  : 'libc6 libstdc++6 zlib1g libpng12-0 libjpeg-turbo8 '\
211                              'libssl1.0.0 libfreetype6 libicu52 fontconfig '\
212                              'libx11-6 libxext6 libxrender1 libxcb1 xfonts-base xfonts-75dpi',
213        'build_packages'    : 'xz-utils ruby python perl gperf bison flex git '\
214                              'zlib1g-dev libpng12-dev libjpeg-turbo8-dev libssl-dev libfreetype6-dev libicu-dev libfontconfig1-dev '\
215                              'libx11-dev libxext-dev libxrender-dev libxcb1-dev',
216        'debootstrap'       : ('trusty', 'http://archive.ubuntu.com/ubuntu/', """
217                                    deb http://archive.ubuntu.com/ubuntu/ trusty          main restricted universe multiverse
218                                    deb http://archive.ubuntu.com/ubuntu/ trusty-updates  main restricted universe multiverse
219                                    deb http://archive.ubuntu.com/ubuntu/ trusty-security main restricted universe multiverse""")
220    },
221    'precise': {
222        'title'             : 'Ubuntu Precise',
223        'packaging_tool'    : 'apt',
224        'build_arch'        : ['amd64', 'i386'],
225        'compression'       : 'xz',
226        'runtime_packages'  : 'libc6 libstdc++6 zlib1g libpng12-0 libjpeg-turbo8 '\
227                              'libssl1.0.0 libfreetype6 libicu48 fontconfig '\
228                              'libx11-6 libxext6 libxrender1 libxcb1 xfonts-base xfonts-75dpi',
229        'build_packages'    : 'xz-utils ruby python perl gperf bison flex git '\
230                              'zlib1g-dev libpng12-dev libjpeg-turbo8-dev libssl-dev libfreetype6-dev libicu-dev libfontconfig1-dev '\
231                              'libx11-dev libxext-dev libxrender-dev libxcb1-dev',
232        'debootstrap'       : ('precise', 'http://archive.ubuntu.com/ubuntu/', """
233                                    deb http://archive.ubuntu.com/ubuntu/ precise          main restricted universe multiverse
234                                    deb http://archive.ubuntu.com/ubuntu/ precise-updates  main restricted universe multiverse
235                                    deb http://archive.ubuntu.com/ubuntu/ precise-security main restricted universe multiverse""")
236    },
237    'generic': {
238        'title'             : 'Generic (based on CentOS 6)',
239        'packaging_tool'    : 'yum',
240        'build_arch'        : ['amd64', 'i386'],
241        'compression'       : 'bzip2',
242        'wrapper_command'   : 'scl enable devtoolset-3 python27 -- ',
243        'runtime_packages'  : 'glibc libstdc++ zlib openssl freetype fontconfig '\
244                              'libX11 libXext libXrender xorg-x11-fonts-Type1 xorg-x11-fonts-75dpi',
245        'build_packages'    : 'scl-utils devtoolset-3-gcc-c++ python27 ruby perl git make gzip diffutils gperf bison flex '\
246                              'zlib-devel openssl-devel freetype-devel fontconfig-devel '\
247                              'libX11-devel libXrender-devel libXext-devel',
248        'rinse'             : ('centos-6', """
249[slc6-scl]
250name=Scientific Linux CERN (SLC6) - SCL addons
251baseurl=http://linuxsoft.cern.ch/cern/scl/slc6X/$basearch/yum/scl/
252gpgcheck=0
253enabled=1
254""")},
255    'centos7': {
256        'title'             : 'CentOS 7',
257        'packaging_tool'    : 'yum',
258        'build_arch'        : ['amd64'],
259        'compression'       : 'xz',
260        'runtime_packages'  : 'glibc libstdc++ zlib libpng libjpeg openssl freetype icu fontconfig '\
261                              'libX11 libXext libXrender xorg-x11-fonts-Type1 xorg-x11-fonts-75dpi',
262        'build_packages'    : 'gcc gcc-c++ binutils python ruby perl git make diffutils gperf bison flex '\
263                              'zlib-devel libpng-devel libjpeg-turbo-devel openssl-devel freetype-devel libicu-devel fontconfig-devel '\
264                              'libX11-devel libXrender-devel libXext-devel',
265        'rinse'             : ('centos-7', '')
266    }
267}
268
269DEPENDENT_LIBS = {
270    'openssl': {
271        'order' : 1,
272        'url'   : 'https://openssl.org/source/openssl-1.0.2e.tar.gz',
273        'sha1'  : '2c5691496761cb18f98476eefa4d35c835448fb6',
274        'build' : {
275            'msvc*-win32*': {
276                'result': ['include/openssl/ssl.h', 'lib/ssleay32.lib', 'lib/libeay32.lib'],
277                'replace': [('util/pl/VC-32.pl', ' /MT', ' %(cflags)s')],
278                'commands': [
279                    'perl Configure --openssldir=%(destdir)s VC-WIN32 no-asm',
280                    'ms\\do_ms.bat',
281                    'nmake /f ms\\nt.mak install'],
282            },
283            'msvc*-win64*': {
284                'result': ['include/openssl/ssl.h', 'lib/ssleay32.lib', 'lib/libeay32.lib'],
285                'replace': [('util/pl/VC-32.pl', ' /MT', ' %(cflags)s')],
286                'commands': [
287                    'perl Configure --openssldir=%(destdir)s VC-WIN64A',
288                    'ms\\do_win64a.bat',
289                    'nmake /f ms\\nt.mak install']
290            },
291            'mingw-w64-cross-win*': {
292                'result': ['include/openssl/ssl.h', 'lib/libssl.a', 'lib/libcrypto.a'],
293                'commands': [
294                    'perl Configure --openssldir=%(destdir)s --cross-compile-prefix=%(mingw_w64)s- no-shared no-asm mingw64',
295                    'make',
296                    'make install_sw']
297            }
298        }
299    },
300
301    'zlib': {
302        'order' : 2,
303        'url'   : 'http://downloads.sourceforge.net/libpng/zlib-1.2.8.tar.gz',
304        'sha1'  : 'a4d316c404ff54ca545ea71a27af7dbc29817088',
305        'build' : {
306            'msvc*': {
307                'result': {
308                    'include/zlib.h' : 'zlib.h',
309                    'include/zconf.h': 'zconf.h',
310                    'lib/zdll.lib'   : 'zlib.lib'
311                },
312                'replace':  [('win32/Makefile.msc', '-MD', '%(cflags)s')],
313                'commands': ['nmake /f win32/Makefile.msc zlib.lib']
314            },
315            'mingw-w64-cross-win*': {
316                'result': {
317                    'include/zlib.h' : 'zlib.h',
318                    'include/zconf.h': 'zconf.h',
319                    'lib/libz.a'     : 'libz.a'
320                },
321                'replace':  [('win32/Makefile.gcc', 'PREFIX =', 'PREFIX = %(mingw_w64)s-')],
322                'commands': ['make -f win32/Makefile.gcc']
323            }
324        }
325    },
326
327    'libpng': {
328        'order' : 3,
329        'url' : 'http://downloads.sourceforge.net/libpng/libpng-1.2.56.tar.gz',
330        'sha1': '9619a20e1bfc34edfbc4931a632a2d6a2c8a9fbc',
331        'build' : {
332            'msvc*': {
333                'result': {
334                    'include/png.h'       : 'png.h',
335                    'include/pngconf.h'   : 'pngconf.h',
336                    'lib/libpng.lib'      : 'libpng.lib'
337                },
338                'replace': [
339                    ('scripts/makefile.vcwin32', '-I..\\zlib', '-I..\\deplibs\\include'),
340                    ('scripts/makefile.vcwin32', '..\\zlib\\zlib.lib', '..\\deplibs\\lib\\zdll.lib'),
341                    ('scripts/makefile.vcwin32', '-MD', '%(cflags)s')],
342                'commands': ['nmake /f scripts/makefile.vcwin32 libpng.lib']
343            },
344            'mingw-w64-cross-win*': {
345                'result': {
346                    'include/png.h'       : 'png.h',
347                    'include/pngconf.h'   : 'pngconf.h',
348                    'lib/libpng.a'        : 'libpng.a'
349                },
350                'replace': [
351                    ('scripts/makefile.gcc', 'ZLIBINC = ../zlib', 'ZLIBINC = %(destdir)s/include'),
352                    ('scripts/makefile.gcc', 'ZLIBLIB = ../zlib', 'ZLIBLIB = %(destdir)s/lib'),
353                    ('scripts/makefile.gcc', 'CC = gcc', 'CC = %(mingw_w64)s-gcc'),
354                    ('scripts/makefile.gcc', 'AR_RC = ar', 'AR_RC = %(mingw_w64)s-ar'),
355                    ('scripts/makefile.gcc', 'RANLIB = ranlib', 'RANLIB = %(mingw_w64)s-ranlib')],
356                'commands': ['make -f scripts/makefile.gcc libpng.a']
357            },
358            'osx-carbon-i386': {
359                'result': ['include/png.h', 'include/pngconf.h', 'lib/libpng.a'],
360                'commands': [
361                    'CFLAGS="-arch i386" ./configure --disable-shared --prefix=%(destdir)s',
362                    'make install']
363            },
364            'osx-cocoa-x86-64': {
365                'result': ['include/png.h', 'include/pngconf.h', 'lib/libpng.a'],
366                'commands': [
367                    'CFLAGS="-arch x86_64" ./configure --disable-shared --prefix=%(destdir)s',
368                    'make install']
369            },
370            'linux-generic-*': {
371                'result': ['include/png.h', 'include/pngconf.h', 'lib/libpng.a'],
372                'commands': [
373                    'CFLAGS="-fPIC" ./configure --disable-shared --enable-static --prefix=%(destdir)s',
374                    'make install']
375            }
376        }
377    },
378
379    'libjpeg': {
380        'order' : 4,
381        'url' : 'http://ijg.org/files/jpegsrc.v9b.tar.gz',
382        'sha1': '15dd867617a88abd07573e06a86ace9bdb998ac2',
383        'build' : {
384            'msvc*': {
385                'result': {
386                    'include/jpeglib.h' : 'jpeglib.h',
387                    'include/jmorecfg.h': 'jmorecfg.h',
388                    'include/jerror.h'  : 'jerror.h',
389                    'include/jconfig.h' : 'jconfig.h',
390                    'lib/libjpeg.lib'   : 'libjpeg.lib'
391                },
392                'replace':  [('makefile.vc', '!include <win32.mak>', ''),
393                             ('makefile.vc', '$(cc)', 'cl'),
394                             ('makefile.vc', '$(cflags) $(cdebug) $(cvars)', '-c -nologo -D_CRT_SECURE_NO_DEPRECATE %(cflags)s -O2 -W3')],
395                'commands': [
396                    'copy /y jconfig.vc jconfig.h',
397                    'nmake /f makefile.vc libjpeg.lib']
398            },
399            'mingw-w64-cross-win*': {
400                'result': ['include/jpeglib.h', 'include/jmorecfg.h', 'include/jerror.h', 'include/jconfig.h', 'lib/libjpeg.a'],
401                'commands': [
402                    './configure --host=%(mingw_w64)s --disable-shared --prefix=%(destdir)s',
403                    'make install']
404            },
405            'osx-carbon-i386': {
406                'result': ['include/jpeglib.h', 'include/jmorecfg.h', 'include/jerror.h', 'include/jconfig.h', 'lib/libjpeg.a'],
407                'commands': [
408                    'CFLAGS="-arch i386" ./configure --disable-shared --prefix=%(destdir)s',
409                    'make install']
410            },
411            'osx-cocoa-x86-64': {
412                'result': ['include/jpeglib.h', 'include/jmorecfg.h', 'include/jerror.h', 'include/jconfig.h', 'lib/libjpeg.a'],
413                'commands': [
414                    'CFLAGS="-arch x86_64" ./configure --disable-shared --prefix=%(destdir)s',
415                    'make install']
416            },
417            'linux-generic-*': {
418                'result': ['include/jpeglib.h', 'include/jmorecfg.h', 'include/jerror.h', 'include/jconfig.h', 'lib/libjpeg.a'],
419                'commands': [
420                    'CFLAGS="-fPIC" ./configure --disable-shared --enable-static --prefix=%(destdir)s',
421                    'make install']
422            }
423        }
424    },
425
426    'xz': {
427        'order' : 5,
428        'url' : 'http://tukaani.org/xz/xz-5.2.2.tar.gz',
429        'sha1': '14663612422ab61386673be78fbb2556f50a1f08',
430        'build' : {
431            'osx*': {
432                'result': ['bin/xz'],
433                'commands': [
434                    'CFLAGS="-arch i386 -mmacosx-version-min=10.6" ./configure --disable-nls --enable-small --disable-shared --disable-threads --prefix=%(destdir)s',
435                    'make -C src/liblzma', 'make -C src/xz', 'make install-strip']
436            }
437        }
438    }
439}
440
441EXCLUDE_SRC_TARBALL = [
442    'qt/config.profiles*',
443    'qt/demos*',
444    'qt/dist*',
445    'qt/doc*',
446    'qt/examples*',
447    'qt/imports*',
448    'qt/templates*',
449    'qt/tests*',
450    'qt/translations*',
451    'qt/util*',
452    'qt/lib/fonts*',
453    'qt/src/3rdparty/*ChangeLog*',
454    'qt/src/3rdparty/ce-compat*',
455    'qt/src/3rdparty/clucene*',
456    'qt/src/3rdparty/fonts*',
457    'qt/src/3rdparty/freetype*',
458    'qt/src/3rdparty/javascriptcore*',
459    'qt/src/3rdparty/libgq*',
460    'qt/src/3rdparty/libmng*',
461    'qt/src/3rdparty/libtiff*',
462    'qt/src/3rdparty/patches*',
463    'qt/src/3rdparty/phonon*',
464    'qt/src/3rdparty/pixman*',
465    'qt/src/3rdparty/powervr*',
466    'qt/src/3rdparty/ptmalloc*',
467    'qt/src/3rdparty/s60*',
468    'qt/src/3rdparty/wayland*'
469]
470
471# --------------------------------------------------------------- HELPERS
472
473import os, sys, platform, subprocess, shutil, re, fnmatch, multiprocessing, urllib, hashlib, tarfile
474
475from os.path import exists
476
477if platform.system() == 'Windows':
478    try:
479        import winreg
480    except ImportError:
481        import _winreg as winreg
482    CPU_COUNT = max(2, multiprocessing.cpu_count()-1)   # leave one CPU free
483else:
484    CPU_COUNT = max(2, multiprocessing.cpu_count())
485
486def rchop(s, e):
487    if s.endswith(e):
488        return s[:-len(e)]
489    return s
490
491def message(msg):
492    sys.stdout.write(msg)
493    sys.stdout.flush()
494
495def error(msg):
496    message(msg+'\n')
497    sys.exit(1)
498
499def shell(cmd):
500    ret = os.system(cmd)
501    if ret != 0:
502        error("%s\ncommand failed: exit code %d" % (cmd, ret))
503
504def chroot_shell(name, cmd):
505    distro  = get_chroot_list().get(name)
506    wrapper = LINUX_SCHROOT_SETUP.get(distro, {}).get('wrapper_command', '')
507    ret = os.system('schroot -c wkhtmltox-%s -- %s%s ' % (name, wrapper, cmd))
508    if ret != 0:
509        error("command inside chroot failed: exit code %d" % ret)
510
511def get_output(*cmd):
512    try:
513        return subprocess.check_output(cmd, stderr=subprocess.STDOUT).strip()
514    except:
515        return None
516
517def rmdir(path):
518    if exists(path):
519        if platform.system() == 'Windows':
520            shell('attrib -R %s\* /S' % path)
521        shutil.rmtree(path)
522
523def mkdir_p(path):
524    if not exists(path):
525        os.makedirs(path)
526
527def get_registry_value(key, value=None):
528    for mask in [0, winreg.KEY_WOW64_64KEY, winreg.KEY_WOW64_32KEY]:
529        try:
530            reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key, 0, winreg.KEY_READ | mask)
531            return winreg.QueryValueEx(reg_key, value)[0]
532        except WindowsError:
533            pass
534    return None
535
536def get_version(basedir):
537    mkdir_p(basedir)
538    text = open(os.path.join(basedir, '..', 'VERSION'), 'r').read()
539    if '-' not in text:
540        return (text, text)
541    version = text[:text.index('-')]
542    os.chdir(os.path.join(basedir, '..'))
543    hash = get_output('git', 'rev-parse', '--short', 'HEAD')
544    if not hash:
545        return (text, version)
546    return ('%s-%s' % (text, hash), version)
547
548def nsis_version(ver):
549    while ver.count('.') < 3:
550        ver += '.0'
551    return ver
552
553def qt_config(key, *opts):
554    input, output = [], []
555    input.extend(QT_CONFIG['common'])
556    input.extend(QT_CONFIG[key])
557    input.extend(opts)
558    cfg = os.environ.get('WKHTMLTOX_QT_CONFIG')
559    if cfg:
560        input.extend(cfg.split())
561    for arg in input:
562        if not arg.startswith('remove:-'):
563            output.append(arg)
564        elif arg[1+arg.index(':'):] in output:
565            output.remove(arg[1+arg.index(':'):])
566    return ' '.join(output)
567
568def fpm_params(cfg, ver):
569    setup  = LINUX_SCHROOT_SETUP[cfg[:cfg.index('-')]]
570    output = '--force --prefix /usr/local --category utils -s dir -C dist'
571    for key in PROJECT_SETUP:
572        output += ' --%s "%s"' % (key, PROJECT_SETUP[key])
573
574    output += ' --version "%s"' % ver
575    output += ' --package ../%s-%s_linux-%s' % (PROJECT_SETUP['name'], ver, cfg)
576    if setup['packaging_tool'] == 'apt':
577        output += '.deb -t deb --deb-compression %s' % setup['compression']
578        output += ' --provides wkhtmltopdf --conflicts wkhtmltopdf --replaces wkhtmltopdf'
579    elif setup['packaging_tool'] == 'yum':
580        output += '.rpm -t rpm --rpm-compression %s --epoch 1' % setup['compression']
581
582    for depend in setup['runtime_packages'].split():
583        output += ' --depends %s' % depend
584
585    output += ' .'
586    return output
587
588def download_file(url, sha1, dir):
589    name = url.split('/')[-1]
590    loc  = os.path.join(dir, name)
591    if os.path.exists(loc):
592        hash = hashlib.sha1(open(loc, 'rb').read()).hexdigest()
593        if hash == sha1:
594            return loc
595        os.remove(loc)
596        message('Checksum mismatch for %s, re-downloading.\n' % name)
597    def hook(cnt, bs, total):
598        pct = int(cnt*bs*100/total)
599        message("\rDownloading: %s [%d%%]" % (name, pct))
600    urllib.urlretrieve(url, loc, reporthook=hook)
601    message("\r")
602    hash = hashlib.sha1(open(loc, 'rb').read()).hexdigest()
603    if hash != sha1:
604        os.remove(loc)
605        error('Checksum mismatch for %s, aborting.' % name)
606    message("\rDownloaded: %s [checksum OK]\n" % name)
607    return loc
608
609def download_tarball(url, sha1, dir, name):
610    loc = download_file(url, sha1, dir)
611    tar = tarfile.open(loc)
612    sub = tar.getnames()[0]
613    if '/' in sub:
614        sub = sub[:sub.index('/')]
615    src = os.path.join(dir, sub)
616    tgt = os.path.join(dir, name)
617    rmdir(src)
618    tar.extractall(dir)
619    rmdir(tgt)
620    os.rename(src, tgt)
621    return tgt
622
623def _is_compiled(dst, loc):
624    present = True
625    for name in loc['result']:
626        if isinstance(name, tuple):
627            present = present and bool([n for n in name if exists(os.path.join(dst, n))])
628        else:
629            present = present and exists(os.path.join(dst, name))
630    return present
631
632def build_deplibs(config, basedir, **kwargs):
633    mkdir_p(os.path.join(basedir, config))
634
635    dstdir = os.path.join(basedir, config, 'deplibs')
636    vars   = {'destdir': dstdir }
637    vars.update(kwargs)
638    for lib in sorted(DEPENDENT_LIBS, key=lambda x: DEPENDENT_LIBS[x]['order']):
639        cfg = None
640        for key in DEPENDENT_LIBS[lib]['build']:
641            if fnmatch.fnmatch(config, key):
642                cfg = key
643
644        if not cfg or _is_compiled(dstdir, DEPENDENT_LIBS[lib]['build'][cfg]):
645            continue
646
647        build_cfg = DEPENDENT_LIBS[lib]['build'][cfg]
648        message('========== building: %s\n' % lib)
649        srcdir = download_tarball(DEPENDENT_LIBS[lib]['url'], DEPENDENT_LIBS[lib]['sha1'],
650                                  basedir, os.path.join(config, lib))
651
652        for location, source, target in build_cfg.get('replace', []):
653            data = open(os.path.join(srcdir, location), 'r').read()
654            open(os.path.join(srcdir, location), 'w').write(data.replace(source, target % vars))
655
656        os.chdir(srcdir)
657        for command in build_cfg['commands']:
658            shell(command % vars)
659        if not type(build_cfg['result']) is list:
660            for target in build_cfg['result']:
661                mkdir_p(os.path.dirname(os.path.join(dstdir, target)))
662                shutil.copy(build_cfg['result'][target], os.path.join(dstdir, target))
663        os.chdir(dstdir)
664        if not _is_compiled(dstdir, build_cfg):
665            error("Unable to compile %s for your system, aborting." % lib)
666
667        rmdir(srcdir)
668
669def build_qt(qtdir, make_cmd, configure_cmd):
670    configured = ''
671    if exists(os.path.join(qtdir, 'configured')):
672        configured = open(os.path.join(qtdir, 'configured'), 'r').read()
673    if not 'qt' in configured or not exists(qtdir):
674        mkdir_p(qtdir)
675        os.chdir(qtdir)
676        shell(configure_cmd)
677        open(os.path.join(qtdir, 'configured'), 'a').write('qt\n')
678    os.chdir(qtdir)
679    shell(make_cmd)
680
681def check_running_on_debian():
682    if not sys.platform.startswith('linux') or not exists('/etc/apt/sources.list') or platform.architecture()[0] != '64bit':
683        error('This can only be run on a 64-bit Debian/Ubuntu distribution, aborting.')
684
685    if os.geteuid() != 0:
686        error('This script must be run as root.')
687
688def install_packages(*names):
689    inst = get_output('dpkg-query', '--show', '--showformat', '${Package}\n').split('\n')
690    miss = [name for name in names if name not in inst]
691
692    if miss:
693        shell('apt-get update')
694        shell('apt-get install --assume-yes %s' % (' '.join(miss)))
695
696def get_chroot_list():
697    prefix = 'chroot:wkhtmltox-'
698    result = {}
699    for line in get_output('schroot', '--list').split('\n'):
700        if not line.startswith(prefix):
701            continue
702        name = line[len(prefix):]
703        for distro in LINUX_SCHROOT_SETUP:
704            if 'chroot_alias' in LINUX_SCHROOT_SETUP[distro]:
705                if name == LINUX_SCHROOT_SETUP[distro]['chroot_alias']:
706                    result[name] = distro
707                continue
708            for arch in LINUX_SCHROOT_SETUP[distro]['build_arch']:
709                if name == '%s-%s' % (distro, arch):
710                    result[name] = distro
711    return result
712
713# --------------------------------------------------------------- Linux chroot
714
715def check_setup_schroot(config):
716    check_running_on_debian()
717    login = os.environ.get('SUDO_USER') or get_output('logname')
718    if not login or login == 'root':
719        error('Unable to determine the login for which schroot access is to be given.')
720
721def build_setup_schroot(config, basedir):
722    install_packages('git', 'debootstrap', 'schroot', 'rinse', 'debian-archive-keyring',
723                     'build-essential', 'ruby', 'ruby-dev', 'libffi-dev', 'tar', 'xz-utils')
724    if not get_output('which', 'fpm'):
725        shell('gem install -V fpm -N')
726
727    login  = os.environ.get('SUDO_USER') or get_output('logname')
728    target = config.split('-', 2)[2]
729    distro = LINUX_SCHROOT_SETUP.get(target)
730    allenv = get_chroot_list()
731
732    for arch in distro['build_arch']:
733        alias    = distro.get('chroot_alias', '%s-%s' % (target, arch))
734        base_dir = os.environ.get('WKHTMLTOX_CHROOT') or '/var/chroot'
735        root_dir = os.path.join(base_dir, 'wkhtmltox-%s' % alias)
736        pkg_list = '%s %s' % (distro['build_packages'], distro.get('runtime_packages', ''))
737        chroot   = (arch == 'i386' and 'linux32 chroot' or 'chroot')
738
739        if alias in allenv:
740            message('******************* %s (skipped)\n' % alias)
741            continue
742
743        message('******************* %s\n' % alias)
744        os.system('umount %s/proc 2>/dev/null' % root_dir)
745        os.system('umount %s/sys  2>/dev/null' % root_dir)
746        rmdir(root_dir)
747        mkdir_p(root_dir)
748
749        def do_setup(*cmds):
750            shell('mount -t proc  proc  %s/proc' % root_dir)
751            shell('mount -t sysfs sysfs %s/sys'  % root_dir)
752            for cmd in cmds:
753                shell('%s %s %s' % (chroot, root_dir, cmd))
754            shell('umount %s/proc' % root_dir)
755            shell('umount %s/sys'  % root_dir)
756
757        if distro['packaging_tool'] == 'apt':
758            cfg = distro['debootstrap']
759            shell('debootstrap --arch=%s --variant=buildd %s %s %s' % (arch, cfg[0], root_dir, cfg[1]))
760
761            open(os.path.join(root_dir, 'etc/apt/sources.list'), 'w').write(cfg[2])
762            open(os.path.join(root_dir, 'usr/sbin/policy-rc.d'), 'w').write("#!/bin/bash\nexit 101\n")
763            do_setup('chmod a+x /usr/sbin/policy-rc.d',         # hack for Ubuntu Precise
764                     'apt-get update',
765                     'apt-get dist-upgrade --assume-yes',
766                     'apt-get install --assume-yes %s' % pkg_list)
767        elif distro['packaging_tool'] == 'yum':
768            rinse = (arch == 'i386' and 'linux32 rinse' or 'rinse')
769            rinse_distro, extra_repos = distro['rinse']
770            shell('%s --arch %s --distribution %s --directory %s' % (rinse, arch, rinse_distro, root_dir))
771
772            if arch == 'amd64':
773                open(os.path.join(root_dir, 'etc/yum.conf'), 'a').write('exclude = *.i?86\n')
774
775            if extra_repos:
776                open(os.path.join(root_dir, 'etc/yum.repos.d/wkhtmltopdf.repo'), 'w').write(extra_repos)
777
778            do_setup('yum clean all', 'yum update -y', 'yum install -y %s' % pkg_list)
779
780        open('/etc/schroot/chroot.d/wkhtmltox', 'a').write("""
781[wkhtmltox-%(alias)s]
782type=directory
783directory=%(dir)s
784description=%(title)s for wkhtmltox
785users=%(login)s
786root-users=root
787%(personality)s""" % { 'alias': alias, 'dir': root_dir, 'title': distro['title'], 'login': login,
788                       'personality': (arch == 'i386' and 'personality=linux32\n' or '\n') })
789
790def check_update_schroot(config):
791    check_running_on_debian()
792    if not get_chroot_list():
793        error('Unable to determine the list of available schroots.')
794
795def build_update_schroot(config, basedir):
796    for name, distro in get_chroot_list().iteritems():
797        message('******************* %s\n' % name)
798        tool = LINUX_SCHROOT_SETUP[distro]['packaging_tool']
799        if tool == 'apt':
800            chroot_shell(name, 'apt-get update')
801            chroot_shell(name, 'apt-get dist-upgrade --assume-yes')
802        elif tool == 'yum':
803            chroot_shell(name, 'yum update -y')
804
805def check_setup_mingw_w64(config):
806    check_running_on_debian()
807
808def build_setup_mingw_w64(config, basedir):
809    install_packages('build-essential', 'mingw-w64', 'nsis', 'perl', 'git', 'ruby', 'gperf', 'bison', 'flex')
810
811def check_source_tarball(config):
812    if not get_output('git', 'rev-parse', '--short', 'HEAD'):
813        error("This can only be run inside a git checkout.")
814
815    if not exists(os.path.join(os.getcwd(), 'qt', '.git')):
816        error("Please initialize and download the Qt submodule before running this.")
817
818def _filter_tar(info):
819    name = info.name[1+info.name.index('/'):]
820    if name.endswith('.git') or [p for p in EXCLUDE_SRC_TARBALL if fnmatch.fnmatch(name, p)]:
821        return None
822
823    info.uid   = info.gid   = 1000
824    info.uname = info.gname = 'wkhtmltopdf'
825    return info
826
827def build_source_tarball(config, basedir):
828    version, simple_version = get_version(basedir)
829    root_dir = os.path.realpath(os.path.join(basedir, '..'))
830    os.chdir(os.path.join(root_dir, 'qt'))
831    shell('git clean -fdx')
832    shell('git reset --hard HEAD')
833    os.chdir(root_dir)
834    shell('git clean -fdx')
835    shell('git reset --hard HEAD')
836    shell('git submodule update')
837    open('VERSION', 'w').write(version)
838    with tarfile.open('wkhtmltox-%s.tar.bz2' % version, 'w:bz2') as tar:
839        tar.add('.', 'wkhtmltox-%s/' % version, filter=_filter_tar)
840    shell('git reset --hard HEAD')
841
842# --------------------------------------------------------------- MSVC (2013 only)
843
844MSVC_LOCATION = {
845    'msvc2013': 'VS120COMNTOOLS'
846}
847MSVC_RUNTIME = {
848    'msvc2013-win32': ('df7f0a73bfa077e483e51bfb97f5e2eceedfb6a3', 'http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x86.exe'),
849    'msvc2013-win64': ('8bf41ba9eef02d30635a10433817dbb6886da5a2', 'http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x64.exe')
850}
851
852def check_msvc(config):
853    version, arch = rchop(config, '-dbg').split('-')
854    env_var = MSVC_LOCATION[version]
855    if not env_var in os.environ:
856        error("%s does not seem to be installed." % version)
857
858    vcdir = os.path.join(os.environ[env_var], '..', '..', 'VC')
859    if not exists(os.path.join(vcdir, 'vcvarsall.bat')):
860        error("%s: unable to find vcvarsall.bat" % version)
861
862    if arch == 'win32' and not exists(os.path.join(vcdir, 'bin', 'cl.exe')):
863        error("%s: unable to find the x86 compiler" % version)
864
865    if arch == 'win64' and not exists(os.path.join(vcdir, 'bin', 'amd64', 'cl.exe')) \
866                       and not exists(os.path.join(vcdir, 'bin', 'x86_amd64', 'cl.exe')):
867        error("%s: unable to find the amd64 compiler" % version)
868
869    perl = get_output('perl', '-V')
870    if not perl or 'perl5' not in perl:
871        error("perl does not seem to be installed.")
872
873    nsis = get_registry_value(r'SOFTWARE\NSIS')
874    if not nsis or not exists(os.path.join(nsis, 'makensis.exe')):
875        error("NSIS does not seem to be installed.")
876
877def build_msvc(config, basedir):
878    msvc, arch = rchop(config, '-dbg').split('-')
879    vcdir = os.path.join(os.environ[MSVC_LOCATION[msvc]], '..', '..', 'VC')
880    vcarg = 'x86'
881    if arch == 'win64':
882        if exists(os.path.join(vcdir, 'bin', 'amd64', 'cl.exe')):
883            vcarg = 'amd64'
884        else:
885            vcarg = 'x86_amd64'
886
887    python = sys.executable
888    process = subprocess.Popen('("%s" %s>nul)&&"%s" -c "import os, sys; sys.stdout.write(repr(dict(os.environ)))"' % (
889        os.path.join(vcdir, 'vcvarsall.bat'), vcarg, python), stdout=subprocess.PIPE, shell=True)
890    stdout, _ = process.communicate()
891    exitcode = process.wait()
892    if exitcode != 0:
893        error("%s: unable to initialize the environment" % msvc)
894
895    os.environ.update(eval(stdout.strip()))
896
897    version, simple_version = get_version(basedir)
898    cflags  = config.endswith('-dbg') and '/MDd /Zi' or '/MD'
899    build_deplibs(config, basedir, cflags=cflags)
900
901    sha1, url = MSVC_RUNTIME[rchop(config, '-dbg')]
902    shutil.copy(download_file(url, sha1, basedir), os.path.join(basedir, config, 'vcredist.exe'))
903
904    libdir = os.path.join(basedir, config, 'deplibs')
905    qtdir  = os.path.join(basedir, config, 'qt')
906    mkdir_p(qtdir)
907
908    configure_args = qt_config('msvc',
909        '-I %s\\include' % libdir,
910        '-L %s\\lib' % libdir,
911        'OPENSSL_LIBS="-L%s\\\\lib -lssleay32 -llibeay32 -lUser32 -lAdvapi32 -lGdi32 -lCrypt32"' % libdir.replace('\\', '\\\\'))
912
913    build_qt(qtdir, 'nmake', '%s\\..\\qt\\configure.exe %s' % (basedir, configure_args))
914
915    appdir = os.path.join(basedir, config, 'app')
916    mkdir_p(appdir)
917    os.chdir(appdir)
918    rmdir('bin')
919    mkdir_p('bin')
920
921    os.environ['WKHTMLTOX_VERSION'] = version
922
923    shell('%s\\bin\\qmake %s\\..\\wkhtmltopdf.pro' % (qtdir, basedir))
924    shell('nmake')
925
926    makensis = os.path.join(get_registry_value(r'SOFTWARE\NSIS'), 'makensis.exe')
927    os.chdir(os.path.join(basedir, '..'))
928    shell('"%s" /DVERSION=%s /DSIMPLE_VERSION=%s /DTARGET=%s /DMSVC /DARCH=%s wkhtmltox.nsi' % \
929            (makensis, version, nsis_version(simple_version), config, arch))
930
931# ------------------------------------------------ MinGW-W64 Cross Environment
932
933MINGW_W64_PREFIX = {
934    'mingw-w64-cross-win32' : 'i686-w64-mingw32',
935    'mingw-w64-cross-win64' : 'x86_64-w64-mingw32',
936}
937
938def check_mingw64_cross(config):
939    shell('%s-gcc --version' % MINGW_W64_PREFIX[rchop(config, '-dbg')])
940
941def build_mingw64_cross(config, basedir):
942    version, simple_version = get_version(basedir)
943    build_deplibs(config, basedir, mingw_w64=MINGW_W64_PREFIX.get(rchop(config, '-dbg')))
944
945    libdir = os.path.join(basedir, config, 'deplibs')
946    qtdir  = os.path.join(basedir, config, 'qt')
947
948    configure_args = qt_config('mingw-w64-cross',
949        '--prefix=%s'   % qtdir,
950        '-I%s/include'  % libdir,
951        '-L%s/lib'      % libdir,
952        '-device-option CROSS_COMPILE=%s-' % MINGW_W64_PREFIX[rchop(config, '-dbg')])
953
954    os.environ['OPENSSL_LIBS'] = '-lssl -lcrypto -L%s/lib -lws2_32 -lgdi32 -lcrypt32' % libdir
955
956    mkdir_p(qtdir)
957    os.chdir(qtdir)
958
959    build_qt(qtdir, 'make -j%d' % CPU_COUNT,
960        '%s/../qt/configure %s' % (basedir, configure_args))
961
962    appdir = os.path.join(basedir, config, 'app')
963    mkdir_p(appdir)
964    os.chdir(appdir)
965    shell('rm -f bin/*')
966
967    # set up cross compiling prefix correctly
968    os.environ['WKHTMLTOX_VERSION'] = version
969    shell('%s/bin/qmake -set CROSS_COMPILE %s-' % (qtdir, MINGW_W64_PREFIX[rchop(config, '-dbg')]))
970    shell('%s/bin/qmake -spec win32-g++-4.6 %s/../wkhtmltopdf.pro' % (qtdir, basedir))
971    shell('make')
972    shutil.copy('bin/libwkhtmltox0.a', 'bin/wkhtmltox.lib')
973    shell('rm -f bin/lib*.dll')
974    for dll in ['libgcc_s_sjlj-1.dll', 'libgcc_s_seh-1.dll', 'libstdc++-6.dll']:
975        dll_path = get_output('dpkg', '-S', dll)
976        if dll_path:
977            for line in dll_path.split('\n'):
978                loc = line[1+line.index(':'):].strip()
979                if exists(loc) and MINGW_W64_PREFIX[rchop(config, '-dbg')] in loc and '-posix' not in loc:
980                    shell('cp %s bin/' % loc)
981
982    os.chdir(os.path.join(basedir, '..'))
983    shell('makensis -DVERSION=%s -DSIMPLE_VERSION=%s -DTARGET=%s -DMINGW -DARCH=%s wkhtmltox.nsi' % \
984            (version, nsis_version(simple_version), config, rchop(config, '-dbg').split('-')[-1]))
985
986# -------------------------------------------------- Linux schroot environment
987
988def check_linux_schroot(config):
989    chroot_shell(rchop(config, '-dbg'), 'gcc --version')
990
991def build_linux_schroot(config, basedir):
992    os.chdir(os.path.realpath(os.path.join(basedir, '..')))
993    chroot_shell(rchop(config, '-dbg'), 'python scripts/build.py %s -chroot-build' % ' '.join(sys.argv[1:]))
994
995    version, simple_version = get_version(basedir)
996    os.chdir(os.path.join(basedir, config))
997    shell('fpm %s' % fpm_params(config, version))
998
999def chroot_build_linux_schroot(config, basedir):
1000    version, simple_version = get_version(basedir)
1001
1002    qtdir  = os.path.join(basedir, config, 'qt')
1003    mkdir_p(qtdir)
1004
1005    build_qt(qtdir, 'make -j%d' % CPU_COUNT,
1006        '%s/../qt/configure %s' % (basedir, qt_config('posix', '--prefix=%s' % qtdir)))
1007
1008    app    = os.path.join(basedir, config, 'app')
1009    dist   = os.path.join(basedir, config, 'dist')
1010    mkdir_p(app)
1011    mkdir_p(dist)
1012    os.chdir(app)
1013    shell('rm -f bin/*')
1014
1015    os.environ['WKHTMLTOX_VERSION'] = version
1016    os.environ['XZ_OPT']            = '-9'
1017    shell('%s/bin/qmake %s/../wkhtmltopdf.pro' % (qtdir, basedir))
1018    shell('make install INSTALL_ROOT=%s' % dist)
1019
1020def check_linux_generic(config):
1021    chroot_env = ('amd64' in config) and 'generic-amd64' or 'generic-i386'
1022    chroot_shell(chroot_env, 'gcc --version')
1023
1024def build_linux_generic(config, basedir):
1025    chroot_env = ('amd64' in config) and 'generic-amd64' or 'generic-i386'
1026    os.chdir(os.path.realpath(os.path.join(basedir, '..')))
1027    chroot_shell(chroot_env, 'python scripts/build.py %s -chroot-build' % ' '.join(sys.argv[1:]))
1028
1029    version, simple_version = get_version(basedir)
1030    os.chdir(os.path.join(basedir, config))
1031    shell('XZ_OPT=-9 tar Jcf ../%s-%s_%s.tar.xz wkhtmltox/' % (PROJECT_SETUP['name'], version, config))
1032
1033def chroot_build_linux_generic(config, basedir):
1034    version, simple_version = get_version(basedir)
1035    build_deplibs(config, basedir)
1036
1037    libdir = os.path.join(basedir, config, 'deplibs')
1038    qtdir  = os.path.join(basedir, config, 'qt')
1039    mkdir_p(qtdir)
1040
1041    configure_args = qt_config('posix',
1042        '--prefix=%s'   % qtdir,
1043        '-I%s/include'  % libdir,
1044        '-L%s/lib'      % libdir,
1045        '-DOPENSSL_NO_SSL2')
1046    build_qt(qtdir, 'make -j%d' % CPU_COUNT, '%s/../qt/configure %s' % (basedir, configure_args))
1047
1048    app    = os.path.join(basedir, config, 'app')
1049    dist   = os.path.join(basedir, config, 'wkhtmltox')
1050
1051    mkdir_p(app)
1052    rmdir(dist)
1053    mkdir_p(dist)
1054
1055    os.chdir(app)
1056    shell('rm -f bin/*')
1057
1058    os.environ['WKHTMLTOX_VERSION'] = version
1059    shell('%s/bin/qmake %s/../wkhtmltopdf.pro' % (qtdir, basedir))
1060    shell('make install INSTALL_ROOT=%s' % dist)
1061
1062# -------------------------------------------------- POSIX local environment
1063
1064def check_posix_local(config):
1065    pass
1066
1067def build_posix_local(config, basedir):
1068    version, simple_version = get_version(basedir)
1069
1070    app    = os.path.join(basedir, config, 'app')
1071    qt     = os.path.join(basedir, config, 'qt')
1072    dist   = os.path.join(basedir, config, 'wkhtmltox-%s' % version)
1073    make   = get_output('which', 'gmake') and 'gmake' or 'make'
1074
1075    mkdir_p(qt)
1076    mkdir_p(app)
1077
1078    rmdir(dist)
1079    mkdir_p(os.path.join(dist, 'bin'))
1080    mkdir_p(os.path.join(dist, 'include', 'wkhtmltox'))
1081    mkdir_p(os.path.join(dist, 'lib'))
1082
1083    build_qt(qt, '%s -j%d' % (make, CPU_COUNT),
1084        '%s/../qt/configure %s' % (basedir, qt_config('posix', '--prefix=%s' % qt)))
1085
1086    os.chdir(app)
1087    shell('rm -f bin/*')
1088    os.environ['WKHTMLTOX_VERSION'] = version
1089    shell('../qt/bin/qmake ../../../wkhtmltopdf.pro')
1090    shell('%s -j%d' % (make, CPU_COUNT))
1091    shell('cp bin/wkhtmlto* ../wkhtmltox-%s/bin' % version)
1092    shell('cp -P bin/libwkhtmltox*.so.* ../wkhtmltox-%s/lib' % version)
1093    shell('cp ../../../include/wkhtmltox/*.h ../wkhtmltox-%s/include/wkhtmltox' % version)
1094    shell('cp ../../../include/wkhtmltox/dll*.inc ../wkhtmltox-%s/include/wkhtmltox' % version)
1095
1096    os.chdir(os.path.join(basedir, config))
1097    shell('tar -c -v -f ../wkhtmltox-%s_local-%s.tar wkhtmltox-%s/' % (version, platform.node(), version))
1098    shell('xz --compress --force --verbose -9 ../wkhtmltox-%s_local-%s.tar' % (version, platform.node()))
1099
1100# --------------------------------------------------------------- OS X
1101
1102OSXPKG_IDENTIFIER = 'org.wkhtmltopdf'
1103OSXPKG_PREFIX     = '/usr/local/share/wkhtmltox-installer'
1104
1105def check_osx(config):
1106    if not platform.system() == 'Darwin' or not platform.mac_ver()[0]:
1107        error('This can only be run on a OS X system!')
1108
1109    if not get_output('xcode-select', '--print-path'):
1110        error('Xcode is not installed, aborting.')
1111
1112    if not get_output('which', 'fpm'):
1113        error('Please install fpm by running "sudo gem install fpm --no-ri --no-rdoc"')
1114
1115def build_osx(config, basedir):
1116    version, simple_version = get_version(basedir)
1117    build_deplibs(config, basedir)
1118
1119    osxver    = platform.mac_ver()[0][:platform.mac_ver()[0].rindex('.')]
1120    framework = config.split('-')[1]
1121    if osxver == '10.6':
1122        osxcfg = '-%s -platform macx-g++42' % framework
1123    else:
1124        osxcfg = '-%s -platform unsupported/macx-clang' % framework
1125
1126    flags = ''
1127    if framework == 'carbon' and osxver != '10.6':
1128        for item in ['CFLAGS', 'CXXFLAGS']:
1129            flags += '"QMAKE_%s += %s" ' % (item, '-fvisibility=hidden -fvisibility-inlines-hidden')
1130
1131    def get_dir(name):
1132        return os.path.join(basedir, config, name)
1133
1134    configure_args = qt_config('osx', osxcfg,
1135        '--prefix=%s'   % get_dir('qt'),
1136        '-I %s/include' % get_dir('deplibs'),
1137        '-L %s/lib'     % get_dir('deplibs'))
1138
1139    rmdir(get_dir('dist'))
1140    rmdir(get_dir('pkg'))
1141    mkdir_p(get_dir('qt'))
1142    mkdir_p(get_dir('app'))
1143    mkdir_p(get_dir('pkg'))
1144
1145    build_qt(get_dir('qt'), 'make -j%d' % CPU_COUNT, '../../../qt/configure %s' % configure_args)
1146
1147    os.chdir(get_dir('app'))
1148    shell('rm -f bin/*')
1149    os.environ['WKHTMLTOX_VERSION'] = version
1150    shell('../qt/bin/qmake %s ../../../wkhtmltopdf.pro' % flags)
1151    shell('make -j%d' % CPU_COUNT)
1152
1153    if osxver not in ['10.6', '10.7']:
1154        for item in ['wkhtmltoimage', 'wkhtmltopdf', 'libwkhtmltox.%s.dylib' % simple_version]:
1155            shell(' '.join([
1156                'install_name_tool', '-change',
1157                '/System/Library/Frameworks/CoreText.framework/Versions/A/CoreText',
1158                '/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreText.framework/CoreText',
1159                'bin/'+item]))
1160
1161    shell('make install INSTALL_ROOT=%s' % get_dir('dist'))
1162
1163    def _osx_tar(info):
1164        info.uid   = info.gid   = 0
1165        info.uname = 'root'
1166        info.gname = 'wheel'
1167        return info
1168
1169    # create tarball for application and copy xz
1170    os.chdir(get_dir('dist'))
1171    with tarfile.open('../pkg/app.tar', 'w') as tar:
1172        tar.add('.', './', filter=_osx_tar)
1173    xz = os.path.join(get_dir('deplibs'), 'bin', 'xz')
1174    shell('%s --compress --force --verbose -9 ../pkg/app.tar' % xz)
1175    shutil.copy(xz, '../pkg/')
1176
1177    with open('../pkg/uninstall-wkhtmltox', 'w') as f:
1178        os.chmod('../pkg/uninstall-wkhtmltox', 0o755)
1179        f.write("""#!/bin/bash
1180if [ "$(id -u)" != "0" ]; then
1181   echo "This script must be run as sudo uninstall-wkhtmltox" 1>&2
1182   exit 1
1183fi
1184cd /usr/local
1185if which pkgutil >/dev/null; then
1186    pkgutil --forget %s.%s
1187fi
1188""" % (OSXPKG_IDENTIFIER, PROJECT_SETUP['name']))
1189        for root, dirs, files in os.walk(get_dir('dist')):
1190            for file in files:
1191                f.write('echo REMOVE /usr/local/%(name)s && rm -f %(name)s\n' % { 'name': os.path.relpath(os.path.join(root, file)) })
1192        f.write('echo REMOVE /usr/local/include/wkhtmltox && rm -df /usr/local/include/wkhtmltox\n')
1193        f.write('echo REMOVE /usr/local/bin/uninstall-wkhtmltox && rm -f /usr/local/bin/uninstall-wkhtmltox')
1194
1195    open('../extract.sh', 'w').write("""#!/bin/bash
1196TGTDIR=/usr/local
1197BASEDIR=%s
1198cd $BASEDIR
1199./xz --decompress app.tar.xz
1200cd $TGTDIR
1201tar oxf $BASEDIR/app.tar
1202mv $BASEDIR/uninstall-wkhtmltox $TGTDIR/bin
1203rm -fr $BASEDIR
1204""" % OSXPKG_PREFIX)
1205
1206    os.chdir(os.path.join(basedir, config))
1207    fpm_args = '--force --prefix %s --category utils -s dir -C pkg' % OSXPKG_PREFIX
1208    for key in PROJECT_SETUP:
1209        fpm_args += ' --%s "%s"' % (key, PROJECT_SETUP[key])
1210    fpm_args += ' --osxpkg-identifier-prefix "%s" --version "%s"' % (OSXPKG_IDENTIFIER, version)
1211    fpm_args += ' -t osxpkg --package ../%s-%s_%s.pkg' % (PROJECT_SETUP['name'], version, config)
1212    fpm_args += ' --after-install extract.sh .'
1213    shell('fpm %s' % fpm_args)
1214
1215# --------------------------------------------------------------- command line
1216
1217def usage(exit_code=2):
1218    message("Usage: scripts/build.py <target> [-clean] [-debug]\n\nThe supported targets are:\n")
1219    opts = list(BUILDERS.keys())
1220    opts.sort()
1221    for opt in opts:
1222        message('* %s\n' % opt)
1223    sys.exit(exit_code)
1224
1225def main():
1226    rootdir = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
1227    basedir = os.path.join(rootdir, 'static-build')
1228    if len(sys.argv) == 1:
1229        usage(0)
1230
1231    config = sys.argv[1]
1232    if config not in BUILDERS:
1233        usage()
1234
1235    for arg in sys.argv[2:]:
1236        if not arg in ['-clean', '-debug', '-chroot-build']:
1237            usage()
1238
1239    final_config = config
1240    if '-debug' in sys.argv[2:]:
1241        final_config += '-dbg'
1242        QT_CONFIG['common'].extend(['remove:-release', 'remove:-webkit', '-debug', '-webkit-debug'])
1243
1244    if '-clean' in sys.argv[2:]:
1245        rmdir(os.path.join(basedir, final_config))
1246
1247    os.chdir(rootdir)
1248    if '-chroot-build' in sys.argv[2:]:
1249        globals()['chroot_build_%s' % BUILDERS[config]](final_config, basedir)
1250        return
1251
1252    globals()['check_%s' % BUILDERS[config]](final_config)
1253    globals()['build_%s' % BUILDERS[config]](final_config, basedir)
1254
1255if __name__ == '__main__':
1256    main()
Note: See TracBrowser for help on using the repository browser.