mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
Use the new auto-build infrastructure for creating calibre installers
This commit is contained in:
parent
7bce30a9db
commit
37cd0c56e5
@ -18,12 +18,14 @@ __all__ = [
|
||||
'pypi_register', 'pypi_upload', 'upload_to_server',
|
||||
'upload_installers',
|
||||
'upload_user_manual', 'upload_demo', 'reupload',
|
||||
'linux32', 'linux64', 'linux', 'linux_freeze',
|
||||
'osx32_freeze', 'osx', 'rsync', 'push',
|
||||
'win32_freeze', 'win32', 'win64', 'win',
|
||||
'stage1', 'stage2', 'stage3', 'stage4', 'stage5', 'publish', 'publish_betas',
|
||||
'linux', 'linux32', 'linux64', 'win', 'win32', 'win64', 'osx',
|
||||
]
|
||||
|
||||
from setup.installers import Linux, Win, OSX, Linux32, Linux64, Win32, Win64
|
||||
linux, linux32, linux64 = Linux(), Linux32(), Linux64()
|
||||
win, win32, win64 = Win(), Win32(), Win64()
|
||||
osx = OSX()
|
||||
|
||||
from setup.translations import POT, GetTranslations, Translations, ISO639, ISO3166
|
||||
pot = POT()
|
||||
@ -81,29 +83,6 @@ upload_to_server = UploadToServer()
|
||||
upload_installers = UploadInstallers()
|
||||
reupload = ReUpload()
|
||||
|
||||
from setup.installer import Rsync, Push
|
||||
rsync = Rsync()
|
||||
push = Push()
|
||||
|
||||
from setup.installer.linux import Linux, Linux32, Linux64
|
||||
linux = Linux()
|
||||
linux32 = Linux32()
|
||||
linux64 = Linux64()
|
||||
from setup.installer.linux.freeze2 import LinuxFreeze
|
||||
linux_freeze = LinuxFreeze()
|
||||
|
||||
from setup.installer.osx import OSX
|
||||
osx = OSX()
|
||||
from setup.installer.osx.app.main import OSX32_Freeze
|
||||
osx32_freeze = OSX32_Freeze()
|
||||
|
||||
from setup.installer.windows import Win, Win32, Win64
|
||||
win = Win()
|
||||
win32 = Win32()
|
||||
win64 = Win64()
|
||||
from setup.installer.windows.freeze import Win32Freeze
|
||||
win32_freeze = Win32Freeze()
|
||||
|
||||
from setup.pypi import PyPIRegister, PyPIUpload
|
||||
pypi_register = PyPIRegister()
|
||||
pypi_upload = PyPIUpload()
|
||||
|
@ -1,233 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import subprocess, os, time, socket
|
||||
|
||||
from setup import Command, installer_name
|
||||
from setup.build_environment import BUILD_HOST, PROJECT
|
||||
|
||||
BASE_RSYNC = ['rsync', '-av', '--delete', '--force']
|
||||
EXCLUDES = []
|
||||
for x in [
|
||||
'/src/calibre/plugins', '/manual', '/translations', '/build', '/dist', '/imgsrc',
|
||||
'/format_docs', '/.build-cache', '.bzr', '.git', '.build', '.svn', '*.pyc',
|
||||
'*.pyo', '*.swp', '*.swo', '*.pyj-cached'
|
||||
]:
|
||||
EXCLUDES.extend(['--exclude', ('/calibre' + x) if x.startswith('/') else x])
|
||||
SAFE_EXCLUDES = ['"%s"' % x if '*' in x else x for x in EXCLUDES]
|
||||
|
||||
|
||||
def get_rsync_pw():
|
||||
return open(os.environ['PENV'] + '/buildbot'
|
||||
).read().decode('utf-8').partition(':')[-1].strip()
|
||||
|
||||
|
||||
def is_vm_running(name):
|
||||
qname = '"%s"' % name
|
||||
try:
|
||||
lines = subprocess.check_output('VBoxManage list runningvms'.split()
|
||||
).decode('utf-8').splitlines()
|
||||
except Exception:
|
||||
time.sleep(1)
|
||||
lines = subprocess.check_output('VBoxManage list runningvms'.split()
|
||||
).decode('utf-8').splitlines()
|
||||
for line in lines:
|
||||
if line.startswith(qname):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_host_reachable(name, timeout=1):
|
||||
try:
|
||||
socket.create_connection((name, 22), timeout).close()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
class Rsync(Command):
|
||||
|
||||
description = 'Sync source tree from development machine'
|
||||
|
||||
SYNC_CMD = ' '.join(
|
||||
BASE_RSYNC + SAFE_EXCLUDES +
|
||||
['rsync://buildbot@{host}/work/{project}', '..']
|
||||
)
|
||||
|
||||
def run(self, opts):
|
||||
cmd = self.SYNC_CMD.format(host=BUILD_HOST, project=PROJECT)
|
||||
env = dict(os.environ)
|
||||
env['RSYNC_PASSWORD'] = get_rsync_pw()
|
||||
self.info(cmd)
|
||||
subprocess.check_call(cmd, shell=True, env=env)
|
||||
|
||||
|
||||
def push(host, vmname, available):
|
||||
if vmname is None:
|
||||
hostname = host.partition(':')[0].partition('@')[-1]
|
||||
ok = is_host_reachable(hostname)
|
||||
else:
|
||||
ok = is_vm_running(vmname)
|
||||
if ok:
|
||||
available[vmname or host] = True
|
||||
rcmd = BASE_RSYNC + EXCLUDES + ['.', host]
|
||||
print('\n\nPushing to:', vmname or host, '\n')
|
||||
subprocess.check_call(rcmd, stdout=open(os.devnull, 'wb'))
|
||||
|
||||
|
||||
class Push(Command):
|
||||
|
||||
description = 'Push code to another host'
|
||||
|
||||
def run(self, opts):
|
||||
from threading import Thread
|
||||
threads, available = {}, {}
|
||||
for host, vmname in {
|
||||
r'Owner@winxp:/cygdrive/c/Documents\ and\ Settings/Owner/calibre':
|
||||
'winxp',
|
||||
'kovid@ox:calibre': None,
|
||||
r'kovid@win7:/cygdrive/c/Users/kovid/calibre': 'Windows 7',
|
||||
'kovid@win7-x64:calibre': 'win7-x64',
|
||||
'kovid@tiny:calibre': None,
|
||||
'kovid@getafix:calibre-src': None,
|
||||
}.iteritems():
|
||||
threads[vmname or host] = thread = Thread(
|
||||
target=push, args=(host, vmname, available)
|
||||
)
|
||||
thread.start()
|
||||
while threads:
|
||||
for name, thread in tuple(threads.iteritems()):
|
||||
thread.join(0.01)
|
||||
if not thread.is_alive():
|
||||
if available.get(name, False):
|
||||
print('\n\n', name, 'done')
|
||||
threads.pop(name)
|
||||
|
||||
|
||||
class VMInstaller(Command):
|
||||
|
||||
INSTALLER_EXT = None
|
||||
VM_NAME = None
|
||||
FREEZE_COMMAND = None
|
||||
FREEZE_TEMPLATE = 'python setup.py {freeze_command}'
|
||||
SHUTDOWN_CMD = ['sudo', 'shutdown', '-h', 'now']
|
||||
IS_64_BIT = False
|
||||
|
||||
BUILD_PREFIX = ['#!/bin/sh', 'export CALIBRE_BUILDBOT=1']
|
||||
BUILD_RSYNC = [
|
||||
'mkdir -p ~/build/{project}', r'cd ~/build/{project}', Rsync.SYNC_CMD
|
||||
]
|
||||
BUILD_CLEAN = ['rm -rf dist/* build/* src/calibre/plugins/*']
|
||||
BUILD_BUILD = [
|
||||
'python setup.py build',
|
||||
]
|
||||
FORCE_SHUTDOWN = 0 # number of seconds to wait before doing a forced power off (0 means disabled)
|
||||
|
||||
def add_options(self, parser):
|
||||
if not parser.has_option('--dont-shutdown'):
|
||||
parser.add_option(
|
||||
'-s',
|
||||
'--dont-shutdown',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='Dont shutdown the VM after building'
|
||||
)
|
||||
if not parser.has_option('--dont-strip'):
|
||||
parser.add_option(
|
||||
'-x',
|
||||
'--dont-strip',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='Dont strip the generated binaries'
|
||||
)
|
||||
|
||||
def get_build_script(self):
|
||||
rs = ['export RSYNC_PASSWORD=%s' % get_rsync_pw()]
|
||||
ans = '\n'.join(self.BUILD_PREFIX + rs) + '\n\n'
|
||||
ans += ' && \\\n'.join(self.BUILD_RSYNC) + ' && \\\n'
|
||||
ans += ' && \\\n'.join(self.BUILD_CLEAN) + ' && \\\n'
|
||||
ans += ' && \\\n'.join(self.BUILD_BUILD) + ' && \\\n'
|
||||
ans += self.FREEZE_TEMPLATE.format(freeze_command=self.FREEZE_COMMAND) + '\n'
|
||||
ans = ans.format(project=PROJECT, host=BUILD_HOST)
|
||||
return ans
|
||||
|
||||
def run_vm(self):
|
||||
if is_vm_running(self.VM_NAME):
|
||||
return True
|
||||
self.__p = subprocess.Popen(
|
||||
("VBoxManage startvm %s --type gui" % self.VM_NAME).split()
|
||||
)
|
||||
return False
|
||||
|
||||
def start_vm(self, sleep=75):
|
||||
ssh_host = self.VM_NAME
|
||||
already_running = self.run_vm()
|
||||
if not already_running:
|
||||
time.sleep(2)
|
||||
print('Waiting for SSH server to start')
|
||||
while not is_host_reachable(ssh_host, timeout=1):
|
||||
time.sleep(0.1)
|
||||
|
||||
def run_vm_builder(self):
|
||||
ssh_host = self.VM_NAME
|
||||
build_script = self.get_build_script()
|
||||
build_script = build_script.encode('utf-8') if isinstance(
|
||||
build_script, unicode
|
||||
) else build_script
|
||||
print('Running VM builder')
|
||||
p = subprocess.Popen(['ssh', ssh_host, 'bash -s'], stdin=subprocess.PIPE)
|
||||
p.stdin.write(build_script), p.stdin.flush(), p.stdin.close()
|
||||
# Save the build script on the build machine for convenient manual
|
||||
# invocation, if needed
|
||||
p2 = subprocess.Popen(['ssh', ssh_host, 'cat > build-calibre'],
|
||||
stdin=subprocess.PIPE)
|
||||
p2.stdin.write(build_script), p2.stdin.flush(), p2.stdin.close()
|
||||
p2.wait()
|
||||
rc = p.wait()
|
||||
if rc != 0:
|
||||
raise SystemExit('VM builder failed with error code: %s' % rc)
|
||||
self.download_installer()
|
||||
|
||||
def installer(self):
|
||||
return installer_name(self.INSTALLER_EXT, self.IS_64_BIT)
|
||||
|
||||
def run(self, opts):
|
||||
if opts.dont_strip:
|
||||
self.FREEZE_COMMAND += ' --dont-strip'
|
||||
subprocess.call(['chmod', '-R', '+r', 'recipes'])
|
||||
start_time = time.time()
|
||||
self.start_vm()
|
||||
startup_time = time.time() - start_time
|
||||
start_time = time.time()
|
||||
self.run_vm_builder()
|
||||
print('Startup completed in %d seconds' % round(startup_time))
|
||||
secs = time.time() - start_time
|
||||
print('Build completed in %d minutes %d seconds' % (secs // 60, secs % 60))
|
||||
if not opts.dont_shutdown:
|
||||
print('Shutting down', self.VM_NAME)
|
||||
subprocess.call(['ssh', self.VM_NAME] + self.SHUTDOWN_CMD)
|
||||
if self.FORCE_SHUTDOWN:
|
||||
while is_host_reachable(self.VM_NAME):
|
||||
time.sleep(0.1) # wait for SSH server to shutdown
|
||||
time.sleep(self.FORCE_SHUTDOWN)
|
||||
subprocess.check_call(
|
||||
('VBoxManage controlvm %s poweroff' % self.VM_NAME).split()
|
||||
)
|
||||
|
||||
def download_installer(self):
|
||||
installer = self.installer()
|
||||
subprocess.check_call([
|
||||
'scp', self.VM_NAME + ':build/calibre/' + installer, 'dist'
|
||||
])
|
||||
if not os.path.exists(installer):
|
||||
raise SystemExit('Failed to download installer: ' + installer)
|
||||
|
||||
def clean(self):
|
||||
installer = self.installer()
|
||||
if os.path.exists(installer):
|
||||
os.remove(installer)
|
@ -1,33 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
from setup.installer import VMInstaller
|
||||
from setup import Command
|
||||
|
||||
class Linux32(VMInstaller):
|
||||
|
||||
description = 'Build 32bit linux binary installer'
|
||||
|
||||
INSTALLER_EXT = 'txz'
|
||||
VM_NAME = 'linux32-build'
|
||||
FREEZE_COMMAND = 'linux_freeze'
|
||||
FREEZE_TEMPLATE = 'python -OO setup.py {freeze_command}'
|
||||
|
||||
|
||||
class Linux64(Linux32):
|
||||
|
||||
description = 'Build 64bit linux binary installer'
|
||||
VM_NAME = 'linux64-build'
|
||||
IS_64_BIT = True
|
||||
|
||||
class Linux(Command):
|
||||
|
||||
description = 'Build linux binary installers'
|
||||
|
||||
sub_commands = ['linux64', 'linux32']
|
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Change the version of sqlite below (get the current version from https://sqlite.org/download.html)
|
||||
# You might also need to change 2013 to 2014 in the setup.py script
|
||||
|
||||
cd $SW/build/apsw-* && rm -rf build/* && \
|
||||
python setup.py fetch --version=3.8.5 --sqlite --missing-checksum-ok && python setup.py install
|
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
LBZ2=libbz2.so.1.0.6
|
||||
|
||||
cd $SW/build/bzip2* && make -f Makefile-libbz2_so && \
|
||||
rm -f $SW/lib/libbz2* && cp -a $LBZ2 $SW/lib && ln -s $LBZ2 $SW/lib/libbz2.so && ln -s $LBZ2 $SW/lib/libbz2.so.1 && ln -s $LBZ2 $SW/lib/libbz2.so.1.0 && \
|
||||
cp -a bzlib.h $SW/include
|
@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd $SW/build/chmlib* && \
|
||||
./configure --disable-dependency-tracking --prefix=$SW && make && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/dbus-python-* && \
|
||||
./configure --prefix=$SW && make && make install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/dbus-glib-* && ./configure --prefix=$SW --disable-static && make && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/expat-* &&\
|
||||
./configure --prefix=$SW && make && make install
|
@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
export FREETYPE_CFLAGS="-I$SW/include/freetype2"
|
||||
export FREETYPE_LIBS="-L$SW/lib -lfreetype -lz -lbz2"
|
||||
|
||||
cd $SW/build/fontconfig-2.* && \
|
||||
./configure --prefix=$SW --disable-static --disable-docs --with-expat=$SW --with-add-fonts=/usr/X11/lib/X11/fonts --disable-dependency-tracking && make && make install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/freetype* && \
|
||||
./configure --disable-static --prefix=$SW && make && make install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/glib-* && ./configure --prefix=$SW --disable-selinux --disable-fam --disable-static --with-libiconv=gnu && make && make install
|
@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/icu*/source && \
|
||||
./configure --prefix=/usr --sysconfdir=/etc --mandir=/usr/share/man --sbindir=/usr/bin && make && \
|
||||
rm -rf $SW/icu && rm -rf $SW/include/layout $SW/include/unicode && rm -f $SW/lib/libicu* && \
|
||||
make -j1 DESTDIR=$SW/icu install && \
|
||||
cp -ar $SW/icu/usr/include/* $SW/include && cp -a $SW/icu/usr/lib/libicu* $SW/lib/ && \
|
||||
rm -rf $SW/icu
|
||||
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/libgcrypt-* && ./configure --prefix=$SW --disable-static && make && make install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/libgpg-error* && ./configure --prefix=$SW --disable-static && make && make install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/libiconv-* && \
|
||||
./configure --disable-static --disable-dependency-tracking --enable-shared --prefix=$SW && make && make install
|
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export libusbmuxd_CFLAGS=-I$SW/include
|
||||
export libusbmuxd_LIBS=-lusbmuxd
|
||||
export libplist_CFLAGS=-I$SW/include
|
||||
export libplist_LIBS=-lplist
|
||||
export libplistmm_CFLAGS=-I$SW/include
|
||||
export libplistmm_LIBS=-lplist++
|
||||
export openssl_CFLAGS=-I$SW/include
|
||||
export openssl_LIBS="-lcrypto -lssl"
|
||||
|
||||
cd $SW/build/libimobiledevice-* && ./configure --prefix=$SW --disable-dependency-tracking --without-cython --disable-static && make && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd $SW/build/libjpeg-turbo* && \
|
||||
./configure --disable-dependency-tracking --enable-shared --with-jpeg8 --prefix=$SW && make && make install
|
@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export LIBUSB_CFLAGS="-I$SW/include/libusb-1.0"
|
||||
export LIBUSB_LIBS="-L$SW/lib -lusb-1.0"
|
||||
export CFLAGS="$CFLAGS -DHAVE_ICONV"
|
||||
export LDFLAGS="$LDFLAGS -liconv"
|
||||
|
||||
cd $SW/build/libmtp-* && \
|
||||
./configure --disable-mtpz --disable-dependency-tracking --disable-static --prefix=$SW --with-libiconv-prefix=$SW --with-udev=$SW/udev && \
|
||||
make && make install
|
||||
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export CPPFLAGS=$CFLAGS
|
||||
|
||||
cd $SW/build/libpng* && \
|
||||
./configure --prefix=$SW --disable-dependency-tracking --disable-static && make && make install
|
||||
|
@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/libusb-* && \
|
||||
./configure --disable-udev --disable-dependency-tracking --disable-static --prefix=$SW && \
|
||||
make && make install
|
||||
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/libwebp-* && ./configure --prefix=$SW --disable-static && make && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/libxml2-2.* && \
|
||||
./configure --prefix=$SW --enable-shared --disable-static --with-iconv=$SW --with-zlib=$SW --without-python --without-debug --disable-dependency-tracking && make && make install
|
||||
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/libxslt-*
|
||||
./configure --prefix=$SW --enable-shared --disable-static --without-python --without-debug --disable-dependency-tracking --with-libxml-prefix=$SW && make && make install
|
||||
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/lxml-3* && rm -rf build/* && python setup.py install
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export CPPFLAGS=$CFLAGS
|
||||
|
||||
cd $SW/build/mozjpeg && \
|
||||
./configure --prefix=$SW/private/mozjpeg --disable-dependency-tracking --disable-shared --with-jpeg8 --without-turbojpeg && make && make install
|
||||
|
@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd $SW/build/nasm* && \
|
||||
./configure --prefix=$SW && make -j2 && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/ncurses-* && \
|
||||
./configure --prefix=$SW --with-shared --without-debug --without-ada --enable-widec && make && make install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/netifaces-* && python setup.py build && cp build/*/netifaces.so $SW/lib/python*/site-packages/
|
@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
if [[ `uname -m` == "i686" ]]; then
|
||||
openssltarget=linux-elf;
|
||||
optflags=''
|
||||
else
|
||||
openssltarget=linux-x86_64;
|
||||
optflags='enable-ec_nistp_64_gcc_128';
|
||||
fi
|
||||
|
||||
cd $SW/build/openssl-* && \
|
||||
./Configure --prefix=/usr --openssldir=/etc/ssl shared zlib $optflags $openssltarget -Wa,--noexecstack $CFLAGS $LDFLAGS && make && make test && \
|
||||
rm -rf $SW/openssl && rm -rf $SW/include/openssl && rm -f $SW/lib/libcrypto* $SW/lib/libssl* && \
|
||||
make INSTALL_PREFIX=$SW/openssl install_sw && cp -ra $SW/openssl/usr/include/openssl $SW/include/ && cp -a $SW/openssl/usr/lib/lib*.so* $SW/lib && \
|
||||
rm -rf $SW/openssl
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export CPPFLAGS=$CFLAGS
|
||||
|
||||
cd $SW/build/optipng* && \
|
||||
./configure -prefix=$SW -with-system-libs && make && make install
|
||||
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd $SW/build/Pillow* && \
|
||||
echo Disabling zip_safe && \
|
||||
python -c "f = open('setup.py', 'r+b'); raw = f.read(); import re; raw = re.sub(r'zip_safe\s*=\s*True', 'zip_safe=False', raw); f.seek(0); f.truncate(0); f.write(raw)" && \
|
||||
python setup.py install
|
||||
|
@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/libplist-* && \
|
||||
./configure --without-cython --disable-dependency-tracking --prefix=$SW && \
|
||||
make && make install
|
@ -1,25 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export CMAKE_INCLUDE_PATH=$SW/include
|
||||
export CMAKE_LIBRARY_PATH=$SW/lib
|
||||
|
||||
cd $SW/build/podofo* && \
|
||||
rm -rf $SW/include/podofo && \
|
||||
rm -rf podofo-build && mkdir podofo-build && \
|
||||
cd podofo-build && \
|
||||
|
||||
echo "Running cmake..." && \
|
||||
|
||||
cmake -G "Unix Makefiles" -Wno-dev \
|
||||
-DFREETYPE_INCLUDE_DIR=$SW/include/freetype2 \
|
||||
-DFREETYPE_LIBRARIES=-lfreetype \
|
||||
-DCMAKE_BUILD_TYPE=RELEASE \
|
||||
-DPODOFO_BUILD_SHARED:BOOL=TRUE \
|
||||
-DPODOFO_BUILD_STATIC:BOOL=FALSE \
|
||||
-DCMAKE_INSTALL_PREFIX=$SW \
|
||||
.. && \
|
||||
make VERBOSE=0 podofo_shared && \
|
||||
rm -rf $SW/lib/libpodofo* $SW/include/podofo && \
|
||||
mkdir $SW/include/podofo && \
|
||||
cp src/libpodofo* $SW/lib && \
|
||||
cp -r podofo_config.h ../src/* $SW/include/podofo/
|
@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export CXXFLAGS="$CFLAGS"
|
||||
export FONTCONFIG_CFLAGS="-I$SW/include/fontconfig -I$SW/include"
|
||||
export FONTCONFIG_LIBS="-L$SW/lib -lfontconfig"
|
||||
export FREETYPE_CFLAGS="-I$SW/include/freetype2 -I$SW/include"
|
||||
export FREETYPE_LIBS="-L$SW/lib -lfreetype -lz"
|
||||
export FREETYPE_CONFIG="$SW/bin/freetype-config"
|
||||
export LIBJPEG_LIBS="-L$SW/lib -ljpeg"
|
||||
export LIBPNG_LIBS="-L$SW/lib -lpng"
|
||||
export LIBPNG_CFLAGS="-I$SW/include/libpng16"
|
||||
|
||||
cd $SW/build/poppler* && \
|
||||
./configure --prefix $SW --without-x --enable-shared --disable-dependency-tracking --disable-silent-rules --enable-zlib --enable-splash-output --disable-cairo-output --disable-poppler-glib --disable-poppler-qt4 --disable-poppler-qt5 --disable-poppler-cpp --disable-gtk-test --enable-libjpeg --enable-compile-warnings=no && make V=1 && make install
|
||||
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/psutil-* && python setup.py build && cp -r build/lib*/* $SW/lib/python2.7/site-packages/
|
@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/PyQt-gpl-* && \
|
||||
python configure.py --verbose --confirm-license -c -j10 --no-designer-plugin --no-qml-plugin --no-docstrings && \
|
||||
make -j2 && make install
|
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export CFLAGS="$CFLAGS -DHAVE_LOAD_EXTENSION"
|
||||
|
||||
# Needed otherwise _ssl module fails to import because system openssl is too old
|
||||
export LD_LIBRARY_PATH=$SW/lib
|
||||
|
||||
cd $SW/build/Python-* && \
|
||||
./configure --prefix=$SW --enable-ipv6 --enable-unicode=ucs4 --with-signal-module --with-threads --with-pymalloc --with-system-expat --enable-shared && make -j2 && make install
|
||||
|
||||
# Install setuptools as described in windows/notes.
|
||||
# Use setuptools to install the various python packages
|
@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# See windows/notes.rst for instructions on slimming down Qt.
|
||||
|
||||
# We disable loading of bearer plugins because many distros ship with broken bearer plugins that cause hangs.
|
||||
# At least, this was the case in Qt 4.x Dont know if it is still true for Qt 5 but since we dont need bearers anyway, it cant hurt.
|
||||
|
||||
cd $SW/build/qt-* && sed -i -e 's:/bearer":/bearer-disabled-by-kovid":' qtbase/src/network/bearer/qnetworkconfigmanager_p.cpp || die "sed for bearer failed."
|
||||
|
||||
# Change pointing_hand to hand2, see https://bugreports.qt.io/browse/QTBUG-41151
|
||||
|
||||
cd $SW/build/qt-* && sed -i -e 's:pointing_hand":hand2":' qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp || die "sed for pointing_hand failed."
|
||||
|
||||
# libudev is disabled because systemd based distros use libudev.so.1 while non systemd based distros use libudev.so.0 (debian stable currently uses libudev.so.0). And according to the incompetent udev developers, we cannot use mismatching udev client and daemon versions. http://www.marshut.com/yiqmk/can-apps-ship-their-own-copy-of-libudev.html
|
||||
|
||||
rm -rf build && mkdir build && cd build && \
|
||||
../configure -opensource -confirm-license -prefix $SW/qt -release -nomake examples -nomake tests -no-sql-odbc -no-sql-psql -no-qml-debug -qt-xcb -cups -no-c++11 -force-pkg-config -pulseaudio -no-libudev -openssl -gtkstyle -icu $CFLAGS $LDFLAGS && \
|
||||
make -j4 && rm -rf $SW/qt && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/readline* && \
|
||||
./configure --prefix=$SW --disable-static && make && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/sip-* && \
|
||||
python configure.py && make && make install
|
@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export CFLAGS="$CFLAGS"
|
||||
cd $SW/build/sqlite-* &&\
|
||||
./configure --prefix=$SW --disable-dependency-tracking --disable-static && make && make install
|
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Apply the patch to prevent detection of WIFI devices, from http://www.mobileread.com/forums/showthread.php?t=255234
|
||||
|
||||
export libplist_CFLAGS="-I$SW/include"
|
||||
export libplist_LIBS="-L$SW/lib -lplist"
|
||||
export CPPFLAGS="$CFLAGS"
|
||||
export CXXFLAGS="$CFLAGS"
|
||||
|
||||
cd $SW/build/libusbmuxd-* && \
|
||||
./configure --prefix=$SW --disable-dependency-tracking && \
|
||||
make && make install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/xpyb && ./autogen.sh && ./configure --prefix=$SW && make && make install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/zlib-* && \
|
||||
./configure --prefix=$SW && make && make install
|
@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $HOME
|
||||
rm sw-linux*;
|
||||
cp /usr/lib/x86_64-linux-gnu/libffi.so.5 /lib/x86_64-linux-gnu/libdbus-1.so.3 ~/sw/lib/
|
||||
echo "[Paths]\nPrefix = .." > ~/sw/qt/bin/qt.conf && cat ~/sw/qt/bin/qt.conf
|
||||
echo "[Paths]\nPrefix = ../qt" > ~/sw/bin/qt.conf && cat ~/sw/bin/qt.conf
|
||||
tar cf sw-linux.tar --exclude sw/build --exclude sw/sources --exclude sw/man --exclude '*.pyc' --exclude '*.pyo' --exclude 'sw/share/doc' --exclude sw/share/gtk-doc --exclude sw/share/man --exclude sw/share/info sw && xz -9 sw-linux.tar
|
||||
rm ~/sw/lib/libffi.so.5 ~/sw/lib/libdbus-1.so.3 ~/sw/qt/bin/qt.conf ~/sw/bin/qt.conf
|
@ -1,451 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2014, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
'''
|
||||
Setup instructions for linux build-system
|
||||
|
||||
Edit /etc/network/interfaces and add
|
||||
|
||||
iface eth1 inet static
|
||||
address 192.168.xxx.xxx
|
||||
|
||||
Also add eth1 to the auto line (use sudo ifup eth1 to start eth1 without rebooting)
|
||||
|
||||
sudo visudo (all no password actions for user)
|
||||
sudo apt-get install build-essential module-assistant vim zsh vim-scripts rsync \
|
||||
htop nasm unzip libdbus-1-dev cmake libltdl-dev libudev-dev apt-file p7zip \
|
||||
libdbus-glib-1-dev libcups2-dev "^libxcb.*" libx11-xcb-dev libglu1-mesa-dev \
|
||||
libxrender-dev flex bison gperf libasound2-dev libgstreamer0.10-dev \
|
||||
libgstreamer-plugins-base0.10-dev libpulse-dev libgtk2.0-dev libffi-dev xcb-proto python-xcbgen dh-autoreconf
|
||||
apt-file update
|
||||
|
||||
# For recent enough version of debian (>= sid) also install libxkbcommon-dev
|
||||
|
||||
mkdir -p ~/bin ~/sw/sources ~/sw/build
|
||||
|
||||
chsh -s /bin/zsh
|
||||
|
||||
Edit /etc/default/grub and change the GRUB_TIMEOUT to 1, then run
|
||||
sudo update-grub
|
||||
|
||||
Copy over authorized_keys, .vimrc and .zshrc
|
||||
|
||||
Create ~/.zshenv as
|
||||
|
||||
export SW=$HOME/sw
|
||||
export MAKEOPTS="-j2"
|
||||
export CFLAGS=-I$SW/include
|
||||
export LDFLAGS=-L$SW/lib
|
||||
export LD_LIBRARY_PATH=$SW/lib
|
||||
export PKG_CONFIG_PATH=$SW/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||
|
||||
typeset -U path
|
||||
path=($SW/bin "$path[@]")
|
||||
path=($SW/qt/bin "$path[@]")
|
||||
path=(~/bin "$path[@]")
|
||||
|
||||
'''
|
||||
|
||||
import sys, os, shutil, platform, subprocess, stat, py_compile, glob, textwrap, tarfile, time
|
||||
from functools import partial
|
||||
|
||||
from setup import Command, modules, basenames, functions, __version__, __appname__
|
||||
from setup.build_environment import QT_DLLS, QT_PLUGINS, qt, PYQT_MODULES, sw as SW
|
||||
from setup.parallel_build import create_job, parallel_build
|
||||
|
||||
j = os.path.join
|
||||
is64bit = platform.architecture()[0] == '64bit'
|
||||
py_ver = '.'.join(map(str, sys.version_info[:2]))
|
||||
arch = 'x86_64' if is64bit else 'i686'
|
||||
|
||||
|
||||
def binary_includes():
|
||||
return [
|
||||
j(SW, 'bin', x) for x in ('pdftohtml', 'pdfinfo', 'pdftoppm', 'optipng')] + [
|
||||
|
||||
j(SW, 'private', 'mozjpeg', 'bin', x) for x in ('jpegtran', 'cjpeg')] + [
|
||||
|
||||
j(SW, 'lib', 'lib' + x) for x in (
|
||||
'usb-1.0.so.0', 'mtp.so.9', 'expat.so.1', 'sqlite3.so.0',
|
||||
'podofo.so.0.9.3', 'z.so.1', 'bz2.so.1.0', 'poppler.so.56',
|
||||
'iconv.so.2', 'xml2.so.2', 'xslt.so.1', 'jpeg.so.8', 'png16.so.16', 'webp.so.5',
|
||||
'exslt.so.0', 'imobiledevice.so.5', 'usbmuxd.so.4', 'plist.so.3',
|
||||
'ssl.so.1.0.0', 'crypto.so.1.0.0', 'readline.so.6', 'chm.so.0', 'icudata.so.53',
|
||||
'icui18n.so.53', 'icuuc.so.53', 'icuio.so.53', 'python%s.so.1.0' % py_ver,
|
||||
'gcrypt.so.20', 'gpg-error.so.0', 'gobject-2.0.so.0', 'glib-2.0.so.0',
|
||||
'gthread-2.0.so.0', 'gmodule-2.0.so.0', 'gio-2.0.so.0', 'dbus-glib-1.so.2',
|
||||
)] + [
|
||||
|
||||
glob.glob('/lib/*/lib' + x)[-1] for x in (
|
||||
'dbus-1.so.3', 'pcre.so.3'
|
||||
)] + [
|
||||
|
||||
glob.glob('/usr/lib/*/lib' + x)[-1] for x in (
|
||||
'gstreamer-0.10.so.0', 'gstbase-0.10.so.0', 'gstpbutils-0.10.so.0',
|
||||
'gstapp-0.10.so.0', 'gstinterfaces-0.10.so.0', 'gstvideo-0.10.so.0', 'orc-0.4.so.0',
|
||||
'ffi.so.5',
|
||||
# 'stdc++.so.6',
|
||||
# We dont include libstdc++.so as the OpenGL dlls on the target
|
||||
# computer fail to load in the QPA xcb plugin if they were compiled
|
||||
# with a newer version of gcc than the one on the build computer.
|
||||
# libstdc++, like glibc is forward compatible and I dont think any
|
||||
# distros do not have libstdc++.so.6, so it should be safe to leave it out.
|
||||
# https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html (The current
|
||||
# debian stable libstdc++ is libstdc++.so.6.0.17)
|
||||
)] + [
|
||||
j(qt['libs'], 'lib%s.so.5' % x) for x in QT_DLLS]
|
||||
|
||||
|
||||
def ignore_in_lib(base, items, ignored_dirs=None):
|
||||
ans = []
|
||||
if ignored_dirs is None:
|
||||
ignored_dirs = {'.svn', '.bzr', '.git', 'test', 'tests', 'testing'}
|
||||
for name in items:
|
||||
path = os.path.join(base, name)
|
||||
if os.path.isdir(path):
|
||||
if name in ignored_dirs or not os.path.exists(j(path, '__init__.py')):
|
||||
if name != 'plugins':
|
||||
ans.append(name)
|
||||
else:
|
||||
if name.rpartition('.')[-1] not in ('so', 'py'):
|
||||
ans.append(name)
|
||||
return ans
|
||||
|
||||
def import_site_packages(srcdir, dest):
|
||||
if not os.path.exists(dest):
|
||||
os.mkdir(dest)
|
||||
for x in os.listdir(srcdir):
|
||||
ext = x.rpartition('.')[-1]
|
||||
f = j(srcdir, x)
|
||||
if ext in ('py', 'so'):
|
||||
shutil.copy2(f, dest)
|
||||
elif ext == 'pth' and x != 'setuptools.pth':
|
||||
for line in open(f, 'rb').read().splitlines():
|
||||
src = os.path.abspath(j(srcdir, line))
|
||||
if os.path.exists(src) and os.path.isdir(src):
|
||||
import_site_packages(src, dest)
|
||||
elif os.path.exists(j(f, '__init__.py')):
|
||||
shutil.copytree(f, j(dest, x), ignore=ignore_in_lib)
|
||||
|
||||
def is_elf(path):
|
||||
with open(path, 'rb') as f:
|
||||
return f.read(4) == b'\x7fELF'
|
||||
|
||||
STRIPCMD = ['strip']
|
||||
def strip_files(files, argv_max=(256 * 1024)):
|
||||
""" Strip a list of files """
|
||||
while files:
|
||||
cmd = list(STRIPCMD)
|
||||
pathlen = sum(len(s) + 1 for s in cmd)
|
||||
while pathlen < argv_max and files:
|
||||
f = files.pop()
|
||||
cmd.append(f)
|
||||
pathlen += len(f) + 1
|
||||
if len(cmd) > len(STRIPCMD):
|
||||
all_files = cmd[len(STRIPCMD):]
|
||||
unwritable_files = tuple(filter(None, (None if os.access(x, os.W_OK) else (x, os.stat(x).st_mode) for x in all_files)))
|
||||
[os.chmod(x, stat.S_IWRITE | old_mode) for x, old_mode in unwritable_files]
|
||||
subprocess.check_call(cmd)
|
||||
[os.chmod(x, old_mode) for x, old_mode in unwritable_files]
|
||||
|
||||
class LinuxFreeze(Command):
|
||||
|
||||
def add_options(self, parser):
|
||||
if not parser.has_option('--dont-strip'):
|
||||
parser.add_option('-x', '--dont-strip', default=False,
|
||||
action='store_true', help='Dont strip the generated binaries')
|
||||
|
||||
def run(self, opts):
|
||||
self.drop_privileges()
|
||||
self.opts = opts
|
||||
self.src_root = self.d(self.SRC)
|
||||
self.base = self.j(self.src_root, 'build', 'linfrozen')
|
||||
self.lib_dir = self.j(self.base, 'lib')
|
||||
self.bin_dir = self.j(self.base, 'bin')
|
||||
|
||||
self.initbase()
|
||||
self.copy_libs()
|
||||
self.copy_python()
|
||||
self.build_launchers()
|
||||
if not self.opts.dont_strip:
|
||||
self.strip_files()
|
||||
self.create_tarfile()
|
||||
|
||||
def initbase(self):
|
||||
if os.path.exists(self.base):
|
||||
shutil.rmtree(self.base)
|
||||
os.makedirs(self.base)
|
||||
|
||||
def copy_libs(self):
|
||||
self.info('Copying libs...')
|
||||
os.mkdir(self.lib_dir)
|
||||
os.mkdir(self.bin_dir)
|
||||
|
||||
for x in binary_includes():
|
||||
dest = self.bin_dir if '/bin/' in x else self.lib_dir
|
||||
shutil.copy2(x, dest)
|
||||
|
||||
base = qt['plugins']
|
||||
dest = self.j(self.lib_dir, 'qt_plugins')
|
||||
os.mkdir(dest)
|
||||
for x in QT_PLUGINS:
|
||||
shutil.copytree(self.j(base, x), self.j(dest, x))
|
||||
|
||||
def copy_python(self):
|
||||
self.info('Copying python...')
|
||||
|
||||
srcdir = self.j(SW, 'lib/python'+py_ver)
|
||||
self.py_dir = self.j(self.lib_dir, self.b(srcdir))
|
||||
if not os.path.exists(self.py_dir):
|
||||
os.mkdir(self.py_dir)
|
||||
|
||||
for x in os.listdir(srcdir):
|
||||
y = self.j(srcdir, x)
|
||||
ext = os.path.splitext(x)[1]
|
||||
if os.path.isdir(y) and x not in ('test', 'hotshot', 'distutils',
|
||||
'site-packages', 'idlelib', 'lib2to3', 'dist-packages'):
|
||||
shutil.copytree(y, self.j(self.py_dir, x),
|
||||
ignore=ignore_in_lib)
|
||||
if os.path.isfile(y) and ext in ('.py', '.so'):
|
||||
shutil.copy2(y, self.py_dir)
|
||||
|
||||
srcdir = self.j(srcdir, 'site-packages')
|
||||
dest = self.j(self.py_dir, 'site-packages')
|
||||
import_site_packages(srcdir, dest)
|
||||
|
||||
filter_pyqt = {x+'.so' for x in PYQT_MODULES}
|
||||
pyqt = self.j(dest, 'PyQt5')
|
||||
for x in os.listdir(pyqt):
|
||||
if x.endswith('.so') and x not in filter_pyqt:
|
||||
os.remove(self.j(pyqt, x))
|
||||
|
||||
for x in os.listdir(self.SRC):
|
||||
c = self.j(self.SRC, x)
|
||||
if os.path.exists(self.j(c, '__init__.py')):
|
||||
shutil.copytree(c, self.j(dest, x), ignore=partial(ignore_in_lib, ignored_dirs={}))
|
||||
elif os.path.isfile(c):
|
||||
shutil.copy2(c, self.j(dest, x))
|
||||
|
||||
shutil.copytree(self.j(self.src_root, 'resources'), self.j(self.base,
|
||||
'resources'))
|
||||
|
||||
self.create_site_py()
|
||||
|
||||
for x in os.walk(self.py_dir):
|
||||
for f in x[-1]:
|
||||
if f.endswith('.py'):
|
||||
y = self.j(x[0], f)
|
||||
rel = os.path.relpath(y, self.py_dir)
|
||||
try:
|
||||
py_compile.compile(y, dfile=rel, doraise=True)
|
||||
os.remove(y)
|
||||
z = y+'c'
|
||||
if os.path.exists(z):
|
||||
os.remove(z)
|
||||
except:
|
||||
if '/uic/port_v3/' not in y:
|
||||
self.warn('Failed to byte-compile', y)
|
||||
|
||||
def run_builder(self, cmd, verbose=True):
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
if verbose:
|
||||
self.info(*cmd)
|
||||
x = p.stdout.read() + p.stderr.read()
|
||||
if x.strip():
|
||||
self.info(x.strip())
|
||||
|
||||
if p.wait() != 0:
|
||||
self.info('Failed to run builder')
|
||||
sys.exit(1)
|
||||
|
||||
def create_tarfile(self):
|
||||
self.info('Creating archive...')
|
||||
base = self.j(self.d(self.SRC), 'dist')
|
||||
if not os.path.exists(base):
|
||||
os.mkdir(base)
|
||||
dist = os.path.join(base, '%s-%s-%s.tar'%(__appname__, __version__, arch))
|
||||
with tarfile.open(dist, mode='w', format=tarfile.PAX_FORMAT) as tf:
|
||||
cwd = os.getcwd()
|
||||
os.chdir(self.base)
|
||||
try:
|
||||
for x in os.listdir('.'):
|
||||
tf.add(x)
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
self.info('Compressing archive...')
|
||||
ans = dist.rpartition('.')[0] + '.txz'
|
||||
if False:
|
||||
os.rename(dist, ans)
|
||||
else:
|
||||
start_time = time.time()
|
||||
subprocess.check_call(['xz', '--threads=0', '-f', '-9', dist])
|
||||
secs = time.time() - start_time
|
||||
self.info('Compressed in %d minutes %d seconds' % (secs // 60, secs % 60))
|
||||
os.rename(dist + '.xz', ans)
|
||||
self.info('Archive %s created: %.2f MB'%(
|
||||
os.path.basename(ans), os.stat(ans).st_size/(1024.**2)))
|
||||
|
||||
def build_launchers(self):
|
||||
self.obj_dir = self.j(self.src_root, 'build', 'launcher')
|
||||
if not os.path.exists(self.obj_dir):
|
||||
os.makedirs(self.obj_dir)
|
||||
base = self.j(self.src_root, 'setup', 'installer', 'linux')
|
||||
sources = [self.j(base, x) for x in ['util.c']]
|
||||
headers = [self.j(base, x) for x in ['util.h']]
|
||||
objects = [self.j(self.obj_dir, self.b(x)+'.o') for x in sources]
|
||||
cflags = '-fno-strict-aliasing -W -Wall -c -O2 -pipe -DPYTHON_VER="python%s"'%py_ver
|
||||
cflags = cflags.split() + ['-I%s/include/python%s' % (SW, py_ver)]
|
||||
for src, obj in zip(sources, objects):
|
||||
if not self.newer(obj, headers+[src, __file__]):
|
||||
continue
|
||||
cmd = ['gcc'] + cflags + ['-fPIC', '-o', obj, src]
|
||||
self.run_builder(cmd)
|
||||
|
||||
dll = self.j(self.lib_dir, 'libcalibre-launcher.so')
|
||||
if self.newer(dll, objects):
|
||||
cmd = ['gcc', '-O2', '-Wl,--rpath=$ORIGIN/../lib', '-fPIC', '-o', dll, '-shared'] + objects + \
|
||||
['-L%s/lib'%SW, '-lpython'+py_ver]
|
||||
self.info('Linking libcalibre-launcher.so')
|
||||
self.run_builder(cmd)
|
||||
|
||||
src = self.j(base, 'main.c')
|
||||
|
||||
modules['console'].append('calibre.linux')
|
||||
basenames['console'].append('calibre_postinstall')
|
||||
functions['console'].append('main')
|
||||
c_launcher = '/tmp/calibre-c-launcher'
|
||||
lsrc = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'launcher.c')
|
||||
cmd = ['gcc', '-O2', '-o', c_launcher, lsrc, ]
|
||||
self.info('Compiling launcher')
|
||||
self.run_builder(cmd, verbose=False)
|
||||
|
||||
jobs = []
|
||||
self.info('Processing launchers')
|
||||
for typ in ('console', 'gui', ):
|
||||
for mod, bname, func in zip(modules[typ], basenames[typ],
|
||||
functions[typ]):
|
||||
xflags = list(cflags)
|
||||
xflags.remove('-c')
|
||||
xflags += ['-DGUI_APP='+('1' if typ == 'gui' else '0')]
|
||||
xflags += ['-DMODULE="%s"'%mod, '-DBASENAME="%s"'%bname,
|
||||
'-DFUNCTION="%s"'%func]
|
||||
|
||||
exe = self.j(self.bin_dir, bname)
|
||||
if self.newer(exe, [src, __file__]+headers):
|
||||
cmd = ['gcc'] + xflags + [src, '-o', exe, '-L' + self.lib_dir, '-lcalibre-launcher']
|
||||
jobs.append(create_job(cmd))
|
||||
sh = self.j(self.base, bname)
|
||||
shutil.copy2(c_launcher, sh)
|
||||
os.chmod(sh,
|
||||
stat.S_IREAD|stat.S_IEXEC|stat.S_IWRITE|stat.S_IRGRP|stat.S_IXGRP|stat.S_IROTH|stat.S_IXOTH)
|
||||
if jobs:
|
||||
if not parallel_build(jobs, self.info, verbose=False):
|
||||
raise SystemExit(1)
|
||||
|
||||
def strip_files(self):
|
||||
from calibre import walk
|
||||
files = {self.j(self.bin_dir, x) for x in os.listdir(self.bin_dir)} | {
|
||||
x for x in {
|
||||
self.j(self.d(self.bin_dir), x) for x in os.listdir(self.bin_dir)} if os.path.exists(x)}
|
||||
for x in walk(self.lib_dir):
|
||||
x = os.path.realpath(x)
|
||||
if x not in files and is_elf(x):
|
||||
files.add(x)
|
||||
self.info('Stripping %d files...' % len(files))
|
||||
before = sum(os.path.getsize(x) for x in files)
|
||||
strip_files(files)
|
||||
after = sum(os.path.getsize(x) for x in files)
|
||||
self.info('Stripped %.1f MB' % ((before - after)/(1024*1024.)))
|
||||
|
||||
def create_site_py(self): # {{{
|
||||
with open(self.j(self.py_dir, 'site.py'), 'wb') as f:
|
||||
f.write(textwrap.dedent('''\
|
||||
import sys
|
||||
import encodings # noqa
|
||||
import __builtin__
|
||||
import locale
|
||||
import os
|
||||
import codecs
|
||||
|
||||
def set_default_encoding():
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
except:
|
||||
print ('WARNING: Failed to set default libc locale, using en_US.UTF-8')
|
||||
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
|
||||
try:
|
||||
enc = locale.getdefaultlocale()[1]
|
||||
except Exception:
|
||||
enc = None
|
||||
if not enc:
|
||||
enc = locale.nl_langinfo(locale.CODESET)
|
||||
if not enc or enc.lower() == 'ascii':
|
||||
enc = 'UTF-8'
|
||||
try:
|
||||
enc = codecs.lookup(enc).name
|
||||
except LookupError:
|
||||
enc = 'UTF-8'
|
||||
sys.setdefaultencoding(enc)
|
||||
del sys.setdefaultencoding
|
||||
|
||||
class _Helper(object):
|
||||
"""Define the builtin 'help'.
|
||||
This is a wrapper around pydoc.help (with a twist).
|
||||
|
||||
"""
|
||||
|
||||
def __repr__(self):
|
||||
return "Type help() for interactive help, " \
|
||||
"or help(object) for help about object."
|
||||
def __call__(self, *args, **kwds):
|
||||
import pydoc
|
||||
return pydoc.help(*args, **kwds)
|
||||
|
||||
def set_helper():
|
||||
__builtin__.help = _Helper()
|
||||
|
||||
def setup_openssl_environment():
|
||||
# Workaround for Linux distros that have still failed to get their heads
|
||||
# out of their asses and implement a common location for SSL certificates.
|
||||
# It's not that hard people, there exists a wonderful tool called the symlink
|
||||
# See http://www.mobileread.com/forums/showthread.php?t=256095
|
||||
if b'SSL_CERT_FILE' not in os.environ and b'SSL_CERT_DIR' not in os.environ:
|
||||
if os.access('/etc/pki/tls/certs/ca-bundle.crt', os.R_OK):
|
||||
os.environ['SSL_CERT_FILE'] = '/etc/pki/tls/certs/ca-bundle.crt'
|
||||
elif os.path.isdir('/etc/ssl/certs'):
|
||||
os.environ['SSL_CERT_DIR'] = '/etc/ssl/certs'
|
||||
|
||||
def main():
|
||||
try:
|
||||
sys.argv[0] = sys.calibre_basename
|
||||
dfv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
|
||||
if dfv and os.path.exists(dfv):
|
||||
sys.path.insert(0, os.path.abspath(dfv))
|
||||
set_default_encoding()
|
||||
set_helper()
|
||||
setup_openssl_environment()
|
||||
mod = __import__(sys.calibre_module, fromlist=[1])
|
||||
func = getattr(mod, sys.calibre_function)
|
||||
return func()
|
||||
except SystemExit as err:
|
||||
if err.code is None:
|
||||
return 0
|
||||
if isinstance(err.code, int):
|
||||
return err.code
|
||||
print (err.code)
|
||||
return 1
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return 1
|
||||
'''))
|
||||
# }}}
|
||||
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* launcher.c
|
||||
* Copyright (C) 2014 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PATHLEN 1023
|
||||
|
||||
#define SET(x, y) if (setenv(x, y, 1) != 0) { fprintf(stderr, "Failed to set environment variable with error: %s\n", strerror(errno)); return 1; }
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
static char buf[PATHLEN+1] = {0}, lib[PATHLEN+1] = {0}, base[PATHLEN+1] = {0}, exe[PATHLEN+1] = {0}, *ldp = NULL;
|
||||
|
||||
if (readlink("/proc/self/exe", buf, PATHLEN) == -1) {
|
||||
fprintf(stderr, "Failed to read path of executable with error: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
strncpy(lib, buf, PATHLEN);
|
||||
strncpy(base, dirname(lib), PATHLEN);
|
||||
snprintf(exe, PATHLEN, "%s/bin/%s", base, basename(buf));
|
||||
memset(lib, 0, PATHLEN);
|
||||
snprintf(lib, PATHLEN, "%s/lib", base);
|
||||
|
||||
/* qt-at-spi causes crashes and performance issues in various distros, so disable it */
|
||||
SET("QT_ACCESSIBILITY", "0")
|
||||
memset(buf, 0, PATHLEN);
|
||||
ldp = getenv("QT_PLUGIN_PATH");
|
||||
if (ldp == NULL) snprintf(buf, PATHLEN, "%s/qt_plugins", lib);
|
||||
else snprintf(buf, PATHLEN, "%s/qt_plugins:%s", lib, ldp);
|
||||
SET("QT_PLUGIN_PATH", buf);
|
||||
|
||||
memset(buf, 0, PATHLEN);
|
||||
ldp = getenv("LD_LIBRARY_PATH");
|
||||
if (ldp == NULL) strncpy(buf, lib, PATHLEN);
|
||||
else snprintf(buf, PATHLEN, "%s:%s", lib, ldp);
|
||||
SET("LD_LIBRARY_PATH", buf)
|
||||
|
||||
argv[0] = exe;
|
||||
if (execv(exe, argv) == -1) {
|
||||
fprintf(stderr, "Failed to execute binary: %s with error: %s\n", exe, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ret = 0;
|
||||
set_gui_app(GUI_APP);
|
||||
ret = execute_python_entrypoint(argc, argv, BASENAME, MODULE, FUNCTION, NULL, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1,263 +0,0 @@
|
||||
#include "util.h"
|
||||
#include <Python.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
static bool GUI_APP = False;
|
||||
|
||||
static char exe_path[PATH_MAX];
|
||||
static char base_dir[PATH_MAX];
|
||||
static char bin_dir[PATH_MAX];
|
||||
static char lib_dir[PATH_MAX];
|
||||
static char extensions_dir[PATH_MAX];
|
||||
static char resources_dir[PATH_MAX];
|
||||
|
||||
void set_gui_app(bool yes) { GUI_APP = yes; }
|
||||
|
||||
int report_error(const char *msg, int code) {
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
return code;
|
||||
}
|
||||
|
||||
int report_libc_error(const char *msg) {
|
||||
char buf[2000];
|
||||
int err = errno;
|
||||
|
||||
snprintf(buf, 2000, "%s::%s", msg, strerror(err));
|
||||
return report_error(buf, err);
|
||||
}
|
||||
|
||||
int pyobject_to_int(PyObject *res) {
|
||||
int ret = 0; PyObject *tmp;
|
||||
if (res != NULL) {
|
||||
tmp = PyNumber_Int(res);
|
||||
if (tmp == NULL) ret = (PyObject_IsTrue(res)) ? 1 : 0;
|
||||
else ret = (int)PyInt_AS_LONG(tmp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int handle_sysexit(PyObject *e) {
|
||||
PyObject *code;
|
||||
|
||||
code = PyObject_GetAttrString(e, "code");
|
||||
if (!code) return 0;
|
||||
return pyobject_to_int(code);
|
||||
}
|
||||
|
||||
int report_python_error(const char *preamble, int code) {
|
||||
PyObject *exc, *val, *tb, *str;
|
||||
int ret, issysexit = 0; char *i, *buf;
|
||||
|
||||
if (!PyErr_Occurred()) return code;
|
||||
issysexit = PyErr_ExceptionMatches(PyExc_SystemExit);
|
||||
|
||||
PyErr_Fetch(&exc, &val, &tb);
|
||||
|
||||
if (exc != NULL) {
|
||||
PyErr_NormalizeException(&exc, &val, &tb);
|
||||
|
||||
if (issysexit) {
|
||||
return (val) ? handle_sysexit(val) : 0;
|
||||
}
|
||||
if (val != NULL) {
|
||||
str = PyObject_Unicode(val);
|
||||
if (str == NULL) {
|
||||
PyErr_Clear();
|
||||
str = PyObject_Str(val);
|
||||
}
|
||||
i = PyString_AsString(str);
|
||||
if (i == NULL) OOM;
|
||||
buf = (char*)calloc(strlen(i)+strlen(preamble)+5, sizeof(char));
|
||||
if (buf == NULL) OOM;
|
||||
sprintf(buf, "%s::%s", preamble, i);
|
||||
ret = report_error(buf, code);
|
||||
if (buf) free(buf);
|
||||
if (tb != NULL) {
|
||||
PyErr_Restore(exc, val, tb);
|
||||
PyErr_Print();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return report_error(preamble, code);
|
||||
}
|
||||
|
||||
static void get_paths()
|
||||
{
|
||||
char linkname[256]; /* /proc/<pid>/exe */
|
||||
char *p;
|
||||
pid_t pid;
|
||||
int ret;
|
||||
|
||||
pid = getpid();
|
||||
|
||||
if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid) < 0)
|
||||
{
|
||||
/* This should only happen on large word systems. I'm not sure
|
||||
what the proper response is here.
|
||||
Since it really is an assert-like condition, aborting the
|
||||
program seems to be in order. */
|
||||
exit(report_error("PID too large", EXIT_FAILURE));
|
||||
}
|
||||
|
||||
|
||||
ret = readlink(linkname, exe_path, PATH_MAX);
|
||||
|
||||
if (ret == -1) {
|
||||
exit(report_error("Failed to read exe path.", EXIT_FAILURE));
|
||||
}
|
||||
|
||||
if (ret >= PATH_MAX) {
|
||||
exit(report_error("exe path buffer too small.", EXIT_FAILURE));
|
||||
}
|
||||
|
||||
exe_path[ret] = 0;
|
||||
|
||||
p = rindex(exe_path, '/');
|
||||
|
||||
if (p == NULL) {
|
||||
exit(report_error("No path separators in executable path", EXIT_FAILURE));
|
||||
}
|
||||
strncat(base_dir, exe_path, p - exe_path);
|
||||
p = rindex(base_dir, '/');
|
||||
if (p == NULL) {
|
||||
exit(report_error("Only one path separator in executable path", EXIT_FAILURE));
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
snprintf(bin_dir, PATH_MAX, "%s/bin", base_dir);
|
||||
snprintf(lib_dir, PATH_MAX, "%s/lib", base_dir);
|
||||
snprintf(resources_dir, PATH_MAX, "%s/resources", base_dir);
|
||||
snprintf(extensions_dir, PATH_MAX, "%s/%s/site-packages/calibre/plugins", lib_dir, PYTHON_VER);
|
||||
}
|
||||
|
||||
|
||||
void setup_stream(const char *name, const char *errors) {
|
||||
PyObject *stream;
|
||||
char buf[100];
|
||||
|
||||
snprintf(buf, 20, "%s", name);
|
||||
stream = PySys_GetObject(buf);
|
||||
|
||||
snprintf(buf, 20, "%s", "utf-8");
|
||||
snprintf(buf+21, 30, "%s", errors);
|
||||
|
||||
if (!PyFile_SetEncodingAndErrors(stream, buf, buf+21))
|
||||
exit(report_python_error("Failed to set stream encoding", 1));
|
||||
|
||||
}
|
||||
|
||||
void setup_streams() {
|
||||
if (!GUI_APP) { // Remove buffering
|
||||
setvbuf(stdin, NULL, _IONBF, 2);
|
||||
setvbuf(stdout, NULL, _IONBF, 2);
|
||||
setvbuf(stderr, NULL, _IONBF, 2);
|
||||
}
|
||||
|
||||
/*setup_stream("stdin", "strict");
|
||||
setup_stream("stdout", "strict");
|
||||
setup_stream("stderr", "strict");*/
|
||||
}
|
||||
|
||||
void initialize_interpreter(int argc, char **argv, char *outr, char *errr,
|
||||
const char *basename, const char *module, const char *function) {
|
||||
char *path, *encoding, *p;
|
||||
|
||||
get_paths();
|
||||
|
||||
path = (char*)calloc(3*PATH_MAX, sizeof(char));
|
||||
if (!path) OOM;
|
||||
|
||||
snprintf(path, 3*PATH_MAX,
|
||||
"%s/%s:%s/%s/plat-linux2:%s/%s/lib-dynload:%s/%s/site-packages",
|
||||
lib_dir, PYTHON_VER, lib_dir, PYTHON_VER, lib_dir, PYTHON_VER,
|
||||
lib_dir, PYTHON_VER);
|
||||
|
||||
Py_OptimizeFlag = 2;
|
||||
Py_NoSiteFlag = 1;
|
||||
Py_DontWriteBytecodeFlag = 1;
|
||||
Py_IgnoreEnvironmentFlag = 1;
|
||||
Py_NoUserSiteDirectory = 1;
|
||||
Py_VerboseFlag = 0;
|
||||
Py_DebugFlag = 0;
|
||||
Py_HashRandomizationFlag = 1;
|
||||
|
||||
Py_SetProgramName(exe_path);
|
||||
Py_SetPythonHome(base_dir);
|
||||
|
||||
//printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath());
|
||||
Py_Initialize();
|
||||
if (!Py_FileSystemDefaultEncoding) {
|
||||
encoding = getenv("PYTHONIOENCODING");
|
||||
if (encoding != NULL) {
|
||||
Py_FileSystemDefaultEncoding = strndup(encoding, 20);
|
||||
p = index(Py_FileSystemDefaultEncoding, ':');
|
||||
if (p != NULL) *p = 0;
|
||||
} else
|
||||
Py_FileSystemDefaultEncoding = strndup("UTF-8", 10);
|
||||
}
|
||||
|
||||
|
||||
setup_streams();
|
||||
|
||||
PySys_SetArgv(argc, argv);
|
||||
//printf("Path after Py_Initialize(): %s\r\n\n", Py_GetPath());
|
||||
PySys_SetPath(path);
|
||||
//printf("Path set by me: %s\r\n\n", path);
|
||||
PySys_SetObject("gui_app", PyBool_FromLong((long)GUI_APP));
|
||||
PySys_SetObject("calibre_basename", PyBytes_FromString(basename));
|
||||
PySys_SetObject("calibre_module", PyBytes_FromString(module));
|
||||
PySys_SetObject("calibre_function", PyBytes_FromString(function));
|
||||
PySys_SetObject("extensions_location", PyBytes_FromString(extensions_dir));
|
||||
PySys_SetObject("resources_location", PyBytes_FromString(resources_dir));
|
||||
PySys_SetObject("executables_location", PyBytes_FromString(base_dir));
|
||||
PySys_SetObject("frozen_path", PyBytes_FromString(base_dir));
|
||||
PySys_SetObject("frozen", Py_True);
|
||||
Py_INCREF(Py_True);
|
||||
|
||||
|
||||
if (GUI_APP && outr && errr) {
|
||||
// PySys_SetObject("stdout_redirect", PyUnicode_FromWideChar(outr, wcslen(outr)));
|
||||
// PySys_SetObject("stderr_redirect", PyUnicode_FromWideChar(errr, wcslen(outr)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int execute_python_entrypoint(int argc, char **argv, const char *basename, const char *module, const char *function,
|
||||
char *outr, char *errr) {
|
||||
PyObject *site, *pmain, *res;
|
||||
int ret = 0;
|
||||
|
||||
initialize_interpreter(argc, argv, outr, errr, basename, module, function);
|
||||
|
||||
site = PyImport_ImportModule("site");
|
||||
|
||||
if (site == NULL)
|
||||
ret = report_python_error("Failed to import site module", 1);
|
||||
else {
|
||||
Py_XINCREF(site);
|
||||
|
||||
pmain = PyObject_GetAttrString(site, "main");
|
||||
if (pmain == NULL || !PyCallable_Check(pmain))
|
||||
ret = report_python_error("site module has no main function", 1);
|
||||
else {
|
||||
Py_XINCREF(pmain);
|
||||
res = PyObject_CallObject(pmain, NULL);
|
||||
|
||||
if (res == NULL)
|
||||
ret = report_python_error("Python function terminated unexpectedly", 1);
|
||||
|
||||
ret = pyobject_to_int(res);
|
||||
}
|
||||
}
|
||||
PyErr_Clear();
|
||||
Py_Finalize();
|
||||
|
||||
//printf("11111 Returning: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define UNICODE
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#define OOM exit(report_error("Out of memory", EXIT_FAILURE))
|
||||
#define True 1
|
||||
#define False 0
|
||||
typedef int bool;
|
||||
|
||||
void set_gui_app(bool yes);
|
||||
|
||||
int execute_python_entrypoint(int argc, char **argv, const char *basename,
|
||||
const char *module, const char *function,
|
||||
char *outr, char *errr);
|
@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
from setup.installer import VMInstaller
|
||||
|
||||
class OSX(VMInstaller):
|
||||
|
||||
description = 'Build OS X binary installer'
|
||||
|
||||
INSTALLER_EXT = 'dmg'
|
||||
VM_NAME = 'osx-build'
|
||||
FREEZE_TEMPLATE = 'python -OO setup.py {freeze_command}'
|
||||
FREEZE_COMMAND = 'osx32_freeze'
|
||||
FORCE_SHUTDOWN = 10 # number of seconds to wait before doing a forced power off
|
@ -1,10 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
#include "util.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
// These variables must be filled in before compiling
|
||||
static const char *ENV_VARS[] = { /*ENV_VARS*/ NULL };
|
||||
static const char *ENV_VAR_VALS[] = { /*ENV_VAR_VALS*/ NULL};
|
||||
static char PROGRAM[] = "**PROGRAM**";
|
||||
static const char MODULE[] = "**MODULE**";
|
||||
static const char FUNCTION[] = "**FUNCTION**";
|
||||
static const char PYVER[] = "**PYVER**";
|
||||
|
||||
|
||||
int
|
||||
main(int argc, const char **argv, const char **envp) {
|
||||
return run(ENV_VARS, ENV_VAR_VALS, PROGRAM, MODULE, FUNCTION, PYVER, **IS_GUI**, argc, argv, envp);
|
||||
}
|
||||
|
@ -1,726 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import with_statement
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import sys, os, shutil, plistlib, subprocess, glob, zipfile, tempfile, \
|
||||
py_compile, stat, operator, time
|
||||
from functools import partial
|
||||
from contextlib import contextmanager
|
||||
from itertools import repeat
|
||||
|
||||
abspath, join, basename = os.path.abspath, os.path.join, os.path.basename
|
||||
|
||||
from setup import (
|
||||
__version__ as VERSION, __appname__ as APPNAME, basenames, modules as
|
||||
main_modules, Command, SRC, functions as main_functions)
|
||||
from setup.build_environment import sw as SW, QT_FRAMEWORKS, QT_PLUGINS, PYQT_MODULES
|
||||
from setup.installer.osx.app.sign import current_dir, sign_app
|
||||
|
||||
LICENSE = open('LICENSE', 'rb').read()
|
||||
ENV = dict(
|
||||
FONTCONFIG_PATH='@executable_path/../Resources/fonts',
|
||||
FONTCONFIG_FILE='@executable_path/../Resources/fonts/fonts.conf',
|
||||
QT_PLUGIN_PATH='@executable_path/../MacOS/qt-plugins',
|
||||
PYTHONIOENCODING='UTF-8',
|
||||
SSL_CERT_FILE='@executable_path/../Resources/resources/mozilla-ca-certs.pem',
|
||||
)
|
||||
|
||||
|
||||
info = warn = None
|
||||
|
||||
@contextmanager
|
||||
def timeit():
|
||||
times = [0, 0]
|
||||
st = time.time()
|
||||
yield times
|
||||
dt = time.time() - st
|
||||
times[0], times[1] = dt // 60, dt % 60
|
||||
|
||||
class OSX32_Freeze(Command):
|
||||
|
||||
description = 'Freeze OSX calibre installation'
|
||||
|
||||
def add_options(self, parser):
|
||||
parser.add_option('--test-launchers', default=False,
|
||||
action='store_true',
|
||||
help='Only build launchers')
|
||||
if not parser.has_option('--dont-strip'):
|
||||
parser.add_option('-x', '--dont-strip', default=False,
|
||||
action='store_true', help='Dont strip the generated binaries')
|
||||
|
||||
def run(self, opts):
|
||||
global info, warn
|
||||
info, warn = self.info, self.warn
|
||||
main(opts.test_launchers, opts.dont_strip)
|
||||
|
||||
def compile_launcher_lib(contents_dir, gcc, base):
|
||||
info('\tCompiling calibre_launcher.dylib')
|
||||
fd = join(contents_dir, 'Frameworks')
|
||||
dest = join(fd, 'calibre-launcher.dylib')
|
||||
src = join(base, 'util.c')
|
||||
cmd = [gcc] + '-Wall -dynamiclib -std=gnu99'.split() + [src] + \
|
||||
['-I'+base] + \
|
||||
['-I%s/python/Python.framework/Versions/Current/Headers' % SW] + \
|
||||
'-current_version 1.0 -compatibility_version 1.0'.split() + \
|
||||
'-fvisibility=hidden -o'.split() + [dest] + \
|
||||
['-install_name',
|
||||
'@executable_path/../Frameworks/'+os.path.basename(dest)] + \
|
||||
[('-F%s/python' % SW), '-framework', 'Python', '-framework', 'CoreFoundation', '-headerpad_max_install_names']
|
||||
# info('\t'+' '.join(cmd))
|
||||
sys.stdout.flush()
|
||||
subprocess.check_call(cmd)
|
||||
return dest
|
||||
|
||||
|
||||
def compile_launchers(contents_dir, xprograms, pyver):
|
||||
gcc = os.environ.get('CC', 'gcc')
|
||||
base = os.path.dirname(__file__)
|
||||
lib = compile_launcher_lib(contents_dir, gcc, base)
|
||||
src = open(join(base, 'launcher.c'), 'rb').read()
|
||||
env, env_vals = [], []
|
||||
for key, val in ENV.items():
|
||||
env.append('"%s"'% key)
|
||||
env_vals.append('"%s"'% val)
|
||||
env = ', '.join(env)+', '
|
||||
env_vals = ', '.join(env_vals)+', '
|
||||
src = src.replace('/*ENV_VARS*/', env)
|
||||
src = src.replace('/*ENV_VAR_VALS*/', env_vals)
|
||||
programs = [lib]
|
||||
for program, x in xprograms.iteritems():
|
||||
module, func, ptype = x
|
||||
info('\tCompiling', program)
|
||||
out = join(contents_dir, 'MacOS', program)
|
||||
programs.append(out)
|
||||
psrc = src.replace('**PROGRAM**', program)
|
||||
psrc = psrc.replace('**MODULE**', module)
|
||||
psrc = psrc.replace('**FUNCTION**', func)
|
||||
psrc = psrc.replace('**PYVER**', pyver)
|
||||
psrc = psrc.replace('**IS_GUI**', ('1' if ptype == 'gui' else '0'))
|
||||
fsrc = '/tmp/%s.c'%program
|
||||
with open(fsrc, 'wb') as f:
|
||||
f.write(psrc)
|
||||
cmd = [gcc, '-Wall', '-I'+base, fsrc, lib, '-o', out,
|
||||
'-headerpad_max_install_names']
|
||||
# info('\t'+' '.join(cmd))
|
||||
sys.stdout.flush()
|
||||
subprocess.check_call(cmd)
|
||||
return programs
|
||||
|
||||
|
||||
def flipwritable(fn, mode=None):
|
||||
"""
|
||||
Flip the writability of a file and return the old mode. Returns None
|
||||
if the file is already writable.
|
||||
"""
|
||||
if os.access(fn, os.W_OK):
|
||||
return None
|
||||
old_mode = os.stat(fn).st_mode
|
||||
os.chmod(fn, stat.S_IWRITE | old_mode)
|
||||
return old_mode
|
||||
|
||||
|
||||
STRIPCMD = ['/usr/bin/strip', '-x', '-S', '-']
|
||||
def strip_files(files, argv_max=(256 * 1024)):
|
||||
"""
|
||||
Strip a list of files
|
||||
"""
|
||||
tostrip = [(fn, flipwritable(fn)) for fn in files if os.path.exists(fn)]
|
||||
while tostrip:
|
||||
cmd = list(STRIPCMD)
|
||||
flips = []
|
||||
pathlen = reduce(operator.add, [len(s) + 1 for s in cmd])
|
||||
while pathlen < argv_max:
|
||||
if not tostrip:
|
||||
break
|
||||
added, flip = tostrip.pop()
|
||||
pathlen += len(added) + 1
|
||||
cmd.append(added)
|
||||
flips.append((added, flip))
|
||||
else:
|
||||
cmd.pop()
|
||||
tostrip.append(flips.pop())
|
||||
os.spawnv(os.P_WAIT, cmd[0], cmd)
|
||||
for args in flips:
|
||||
flipwritable(*args)
|
||||
|
||||
def flush(func):
|
||||
def ff(*args, **kwargs):
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
ret = func(*args, **kwargs)
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
return ret
|
||||
return ff
|
||||
|
||||
class Py2App(object):
|
||||
|
||||
FID = '@executable_path/../Frameworks'
|
||||
|
||||
def __init__(self, build_dir, test_launchers=False, dont_strip=False):
|
||||
self.build_dir = build_dir
|
||||
self.dont_strip = dont_strip
|
||||
self.contents_dir = join(self.build_dir, 'Contents')
|
||||
self.resources_dir = join(self.contents_dir, 'Resources')
|
||||
self.frameworks_dir = join(self.contents_dir, 'Frameworks')
|
||||
self.version_info = '.'.join(map(str, sys.version_info[:2]))
|
||||
self.site_packages = join(self.resources_dir, 'Python', 'site-packages')
|
||||
self.to_strip = []
|
||||
self.warnings = []
|
||||
|
||||
self.run(test_launchers)
|
||||
|
||||
def warn(self, *args):
|
||||
warn(*args)
|
||||
|
||||
def run(self, test_launchers):
|
||||
ret = 0
|
||||
if not test_launchers:
|
||||
if os.path.exists(self.build_dir):
|
||||
shutil.rmtree(self.build_dir)
|
||||
os.makedirs(self.build_dir)
|
||||
self.create_skeleton()
|
||||
self.create_plist()
|
||||
|
||||
self.add_python_framework()
|
||||
self.add_site_packages()
|
||||
self.add_stdlib()
|
||||
self.add_qt_frameworks()
|
||||
self.add_calibre_plugins()
|
||||
self.add_podofo()
|
||||
self.add_poppler()
|
||||
self.add_imaging_libs()
|
||||
self.add_fontconfig()
|
||||
self.add_misc_libraries()
|
||||
|
||||
self.add_resources()
|
||||
self.compile_py_modules()
|
||||
|
||||
self.copy_site()
|
||||
self.create_exe()
|
||||
if not test_launchers and not self.dont_strip:
|
||||
self.strip_files()
|
||||
if not test_launchers:
|
||||
self.create_console_app()
|
||||
self.create_gui_apps()
|
||||
|
||||
ret = self.makedmg(self.build_dir, APPNAME+'-'+VERSION)
|
||||
|
||||
return ret
|
||||
|
||||
@flush
|
||||
def add_resources(self):
|
||||
shutil.copytree('resources', os.path.join(self.resources_dir,
|
||||
'resources'))
|
||||
|
||||
@flush
|
||||
def strip_files(self):
|
||||
info('\nStripping files...')
|
||||
strip_files(self.to_strip)
|
||||
|
||||
@flush
|
||||
def create_exe(self):
|
||||
info('\nCreating launchers')
|
||||
programs = {}
|
||||
progs = []
|
||||
for x in ('console', 'gui'):
|
||||
progs += list(zip(basenames[x], main_modules[x], main_functions[x], repeat(x)))
|
||||
for program, module, func, ptype in progs:
|
||||
programs[program] = (module, func, ptype)
|
||||
programs = compile_launchers(self.contents_dir, programs,
|
||||
self.version_info)
|
||||
for out in programs:
|
||||
self.fix_dependencies_in_lib(out)
|
||||
|
||||
@flush
|
||||
def set_id(self, path_to_lib, new_id):
|
||||
old_mode = flipwritable(path_to_lib)
|
||||
subprocess.check_call(['install_name_tool', '-id', new_id, path_to_lib])
|
||||
if old_mode is not None:
|
||||
flipwritable(path_to_lib, old_mode)
|
||||
|
||||
@flush
|
||||
def get_dependencies(self, path_to_lib):
|
||||
install_name = subprocess.check_output(['otool', '-D', path_to_lib]).splitlines()[-1].strip()
|
||||
raw = subprocess.check_output(['otool', '-L', path_to_lib])
|
||||
for line in raw.splitlines():
|
||||
if 'compatibility' not in line or line.strip().endswith(':'):
|
||||
continue
|
||||
idx = line.find('(')
|
||||
path = line[:idx].strip()
|
||||
yield path, path == install_name
|
||||
|
||||
@flush
|
||||
def get_local_dependencies(self, path_to_lib):
|
||||
for x, is_id in self.get_dependencies(path_to_lib):
|
||||
if x.startswith('@rpath/Qt'):
|
||||
yield x, x[len('@rpath/'):], is_id
|
||||
else:
|
||||
for y in (SW+'/lib/', SW+'/python/Python.framework/', SW+'/private/ssl/lib/'):
|
||||
if x.startswith(y):
|
||||
if y == SW+'/python/Python.framework/':
|
||||
y = SW+'/python/'
|
||||
yield x, x[len(y):], is_id
|
||||
break
|
||||
|
||||
@flush
|
||||
def change_dep(self, old_dep, new_dep, is_id, path_to_lib):
|
||||
cmd = ['-id', new_dep] if is_id else ['-change', old_dep, new_dep]
|
||||
subprocess.check_call(['install_name_tool'] + cmd + [path_to_lib])
|
||||
|
||||
@flush
|
||||
def fix_dependencies_in_lib(self, path_to_lib):
|
||||
self.to_strip.append(path_to_lib)
|
||||
old_mode = flipwritable(path_to_lib)
|
||||
for dep, bname, is_id in self.get_local_dependencies(path_to_lib):
|
||||
ndep = self.FID+'/'+bname
|
||||
self.change_dep(dep, ndep, is_id, path_to_lib)
|
||||
ldeps = list(self.get_local_dependencies(path_to_lib))
|
||||
if ldeps:
|
||||
info('\nFailed to fix dependencies in', path_to_lib)
|
||||
info('Remaining local dependencies:', ldeps)
|
||||
raise SystemExit(1)
|
||||
if old_mode is not None:
|
||||
flipwritable(path_to_lib, old_mode)
|
||||
|
||||
@flush
|
||||
def add_python_framework(self):
|
||||
info('\nAdding Python framework')
|
||||
src = join(SW + '/python', 'Python.framework')
|
||||
x = join(self.frameworks_dir, 'Python.framework')
|
||||
curr = os.path.realpath(join(src, 'Versions', 'Current'))
|
||||
currd = join(x, 'Versions', basename(curr))
|
||||
rd = join(currd, 'Resources')
|
||||
os.makedirs(rd)
|
||||
shutil.copy2(join(curr, 'Resources', 'Info.plist'), rd)
|
||||
shutil.copy2(join(curr, 'Python'), currd)
|
||||
self.set_id(join(currd, 'Python'),
|
||||
self.FID+'/Python.framework/Versions/%s/Python'%basename(curr))
|
||||
# The following is needed for codesign in OS X >= 10.9.5
|
||||
with current_dir(x):
|
||||
os.symlink(basename(curr), 'Versions/Current')
|
||||
for y in ('Python', 'Resources'):
|
||||
os.symlink('Versions/Current/%s'%y, y)
|
||||
|
||||
@flush
|
||||
def add_qt_frameworks(self):
|
||||
info('\nAdding Qt Frameworks')
|
||||
for f in QT_FRAMEWORKS:
|
||||
self.add_qt_framework(f)
|
||||
pdir = join(SW, 'qt', 'plugins')
|
||||
ddir = join(self.contents_dir, 'MacOS', 'qt-plugins')
|
||||
os.mkdir(ddir)
|
||||
for x in QT_PLUGINS:
|
||||
shutil.copytree(join(pdir, x), join(ddir, x))
|
||||
for l in glob.glob(join(ddir, '*/*.dylib')):
|
||||
self.fix_dependencies_in_lib(l)
|
||||
x = os.path.relpath(l, ddir)
|
||||
self.set_id(l, '@executable_path/'+x)
|
||||
|
||||
def add_qt_framework(self, f):
|
||||
libname = f
|
||||
f = f+'.framework'
|
||||
src = join(SW, 'qt', 'lib', f)
|
||||
ignore = shutil.ignore_patterns('Headers', '*.h', 'Headers/*')
|
||||
dest = join(self.frameworks_dir, f)
|
||||
shutil.copytree(src, dest, symlinks=True,
|
||||
ignore=ignore)
|
||||
lib = os.path.realpath(join(dest, libname))
|
||||
rpath = os.path.relpath(lib, self.frameworks_dir)
|
||||
self.set_id(lib, self.FID+'/'+rpath)
|
||||
self.fix_dependencies_in_lib(lib)
|
||||
# The following is needed for codesign in OS X >= 10.9.5
|
||||
# The presence of the .prl file in the root of the framework causes
|
||||
# codesign to fail.
|
||||
with current_dir(dest):
|
||||
for x in os.listdir('.'):
|
||||
if x != 'Versions' and not os.path.islink(x):
|
||||
os.remove(x)
|
||||
|
||||
@flush
|
||||
def create_skeleton(self):
|
||||
c = join(self.build_dir, 'Contents')
|
||||
for x in ('Frameworks', 'MacOS', 'Resources'):
|
||||
os.makedirs(join(c, x))
|
||||
for x in glob.glob(join('icons', 'icns', '*.iconset')):
|
||||
subprocess.check_call([
|
||||
'iconutil', '-c', 'icns', x, '-o', join(
|
||||
self.resources_dir, basename(x).partition('.')[0] + '.icns')])
|
||||
|
||||
@flush
|
||||
def add_calibre_plugins(self):
|
||||
dest = join(self.frameworks_dir, 'plugins')
|
||||
os.mkdir(dest)
|
||||
for f in glob.glob('src/calibre/plugins/*.so'):
|
||||
shutil.copy2(f, dest)
|
||||
self.fix_dependencies_in_lib(join(dest, basename(f)))
|
||||
|
||||
@flush
|
||||
def create_plist(self):
|
||||
from calibre.ebooks import BOOK_EXTENSIONS
|
||||
env = dict(**ENV)
|
||||
env['CALIBRE_LAUNCHED_FROM_BUNDLE']='1'
|
||||
docs = [{'CFBundleTypeName':'E-book',
|
||||
'CFBundleTypeExtensions':list(BOOK_EXTENSIONS),
|
||||
'CFBundleTypeIconFile':'book.icns',
|
||||
'CFBundleTypeRole':'Viewer',
|
||||
}]
|
||||
|
||||
pl = dict(
|
||||
CFBundleDevelopmentRegion='English',
|
||||
CFBundleDisplayName=APPNAME,
|
||||
CFBundleName=APPNAME,
|
||||
CFBundleIdentifier='net.kovidgoyal.calibre',
|
||||
CFBundleVersion=VERSION,
|
||||
CFBundleShortVersionString=VERSION,
|
||||
CFBundlePackageType='APPL',
|
||||
CFBundleSignature='????',
|
||||
CFBundleExecutable='calibre',
|
||||
CFBundleDocumentTypes=docs,
|
||||
LSMinimumSystemVersion='10.7.2',
|
||||
LSRequiresNativeExecution=True,
|
||||
NSAppleScriptEnabled=False,
|
||||
NSHumanReadableCopyright=time.strftime('Copyright %Y, Kovid Goyal'),
|
||||
CFBundleGetInfoString=('calibre, an E-book management '
|
||||
'application. Visit https://calibre-ebook.com for details.'),
|
||||
CFBundleIconFile='calibre.icns',
|
||||
NSHighResolutionCapable=True,
|
||||
LSApplicationCategoryType='public.app-category.productivity',
|
||||
LSEnvironment=env
|
||||
)
|
||||
plistlib.writePlist(pl, join(self.contents_dir, 'Info.plist'))
|
||||
|
||||
@flush
|
||||
def install_dylib(self, path, set_id=True):
|
||||
shutil.copy2(path, self.frameworks_dir)
|
||||
if set_id:
|
||||
self.set_id(join(self.frameworks_dir, basename(path)),
|
||||
self.FID+'/'+basename(path))
|
||||
self.fix_dependencies_in_lib(join(self.frameworks_dir, basename(path)))
|
||||
|
||||
@flush
|
||||
def add_podofo(self):
|
||||
info('\nAdding PoDoFo')
|
||||
pdf = join(SW, 'lib', 'libpodofo.0.9.3.dylib')
|
||||
self.install_dylib(pdf)
|
||||
|
||||
@flush
|
||||
def add_poppler(self):
|
||||
info('\nAdding poppler')
|
||||
for x in ('libpoppler.56.dylib',):
|
||||
self.install_dylib(os.path.join(SW, 'lib', x))
|
||||
for x in ('pdftohtml', 'pdftoppm', 'pdfinfo'):
|
||||
self.install_dylib(os.path.join(SW, 'bin', x), False)
|
||||
|
||||
@flush
|
||||
def add_imaging_libs(self):
|
||||
info('\nAdding libjpeg, libpng, libwebp, optipng and mozjpeg')
|
||||
for x in ('jpeg.8', 'png16.16', 'webp.5'):
|
||||
self.install_dylib(os.path.join(SW, 'lib', 'lib%s.dylib' % x))
|
||||
self.install_dylib(os.path.join(SW, 'bin', 'optipng'), False)
|
||||
for x in ('jpegtran', 'cjpeg'):
|
||||
self.install_dylib(os.path.join(SW, 'private', 'mozjpeg', 'bin', x), False)
|
||||
|
||||
@flush
|
||||
def add_fontconfig(self):
|
||||
info('\nAdding fontconfig')
|
||||
for x in ('fontconfig.1', 'freetype.6', 'expat.1',
|
||||
'plist.3', 'usbmuxd.4', 'imobiledevice.5'):
|
||||
src = os.path.join(SW, 'lib', 'lib'+x+'.dylib')
|
||||
self.install_dylib(src)
|
||||
dst = os.path.join(self.resources_dir, 'fonts')
|
||||
if os.path.exists(dst):
|
||||
shutil.rmtree(dst)
|
||||
src = os.path.join(SW, 'etc', 'fonts')
|
||||
shutil.copytree(src, dst, symlinks=False)
|
||||
fc = os.path.join(dst, 'fonts.conf')
|
||||
raw = open(fc, 'rb').read()
|
||||
raw = raw.replace('<dir>/usr/share/fonts</dir>', '''\
|
||||
<dir>/Library/Fonts</dir>
|
||||
<dir>/System/Library/Fonts</dir>
|
||||
<dir>/usr/X11R6/lib/X11/fonts</dir>
|
||||
<dir>/usr/share/fonts</dir>
|
||||
<dir>/var/root/Library/Fonts</dir>
|
||||
<dir>/usr/share/fonts</dir>
|
||||
''')
|
||||
open(fc, 'wb').write(raw)
|
||||
|
||||
@flush
|
||||
def add_misc_libraries(self):
|
||||
# Reminder to self to add iconv.dylib in the new freeze code
|
||||
for x in (
|
||||
'usb-1.0.0', 'mtp.9', 'ltdl.7', 'chm.0', 'sqlite3.0',
|
||||
'icudata.53', 'icui18n.53', 'icuio.53', 'icuuc.53',
|
||||
'crypto.1.0.0', 'ssl.1.0.0', # 'iconv.2'
|
||||
):
|
||||
info('\nAdding', x)
|
||||
x = 'lib%s.dylib'%x
|
||||
src = join(SW, 'private', 'ssl', 'lib', x) if ('ssl' in x or 'crypto' in x) else join(SW, 'lib', x)
|
||||
shutil.copy2(src, self.frameworks_dir)
|
||||
dest = join(self.frameworks_dir, x)
|
||||
self.set_id(dest, self.FID+'/'+x)
|
||||
self.fix_dependencies_in_lib(dest)
|
||||
|
||||
@flush
|
||||
def add_site_packages(self):
|
||||
info('\nAdding site-packages')
|
||||
os.makedirs(self.site_packages)
|
||||
paths = reversed(map(abspath, [x for x in sys.path if x.startswith('/')]))
|
||||
upaths = []
|
||||
for x in paths:
|
||||
if x not in upaths and (x.endswith('.egg') or
|
||||
x.endswith('/site-packages')):
|
||||
upaths.append(x)
|
||||
upaths.append(os.path.expanduser('~/build/calibre/src'))
|
||||
for x in upaths:
|
||||
info('\t', x)
|
||||
tdir = None
|
||||
try:
|
||||
if not os.path.isdir(x):
|
||||
try:
|
||||
zf = zipfile.ZipFile(x)
|
||||
except:
|
||||
self.warn(x, 'is neither a directory nor a zipfile')
|
||||
continue
|
||||
tdir = tempfile.mkdtemp()
|
||||
zf.extractall(tdir)
|
||||
x = tdir
|
||||
self.add_modules_from_dir(x)
|
||||
self.add_packages_from_dir(x)
|
||||
finally:
|
||||
if tdir is not None:
|
||||
shutil.rmtree(tdir)
|
||||
shutil.rmtree(os.path.join(self.site_packages, 'calibre', 'plugins'))
|
||||
sp = join(self.resources_dir, 'Python', 'site-packages')
|
||||
for x in os.listdir(join(sp, 'PyQt5')):
|
||||
if x.endswith('.so') and x.rpartition('.')[0] not in PYQT_MODULES:
|
||||
os.remove(join(sp, 'PyQt5', x))
|
||||
os.remove(join(sp, 'PyQt5', 'uic/port_v3/proxy_base.py'))
|
||||
self.remove_bytecode(sp)
|
||||
|
||||
@flush
|
||||
def add_modules_from_dir(self, src):
|
||||
for x in glob.glob(join(src, '*.py'))+glob.glob(join(src, '*.so')):
|
||||
shutil.copy2(x, self.site_packages)
|
||||
if x.endswith('.so'):
|
||||
self.fix_dependencies_in_lib(x)
|
||||
|
||||
@flush
|
||||
def add_packages_from_dir(self, src):
|
||||
for x in os.listdir(src):
|
||||
x = join(src, x)
|
||||
if os.path.isdir(x) and os.path.exists(join(x, '__init__.py')):
|
||||
if self.filter_package(basename(x)):
|
||||
continue
|
||||
self.add_package_dir(x)
|
||||
|
||||
@flush
|
||||
def add_package_dir(self, x, dest=None):
|
||||
def ignore(root, files):
|
||||
ans = []
|
||||
for y in files:
|
||||
ext = os.path.splitext(y)[1]
|
||||
if ext not in ('', '.py', '.so') or \
|
||||
(not ext and not os.path.isdir(join(root, y))):
|
||||
ans.append(y)
|
||||
|
||||
return ans
|
||||
if dest is None:
|
||||
dest = self.site_packages
|
||||
dest = join(dest, basename(x))
|
||||
shutil.copytree(x, dest, symlinks=True, ignore=ignore)
|
||||
self.postprocess_package(x, dest)
|
||||
for x in os.walk(dest):
|
||||
for f in x[-1]:
|
||||
if f.endswith('.so'):
|
||||
f = join(x[0], f)
|
||||
self.fix_dependencies_in_lib(f)
|
||||
|
||||
@flush
|
||||
def filter_package(self, name):
|
||||
return name in ('Cython', 'modulegraph', 'macholib', 'py2app',
|
||||
'bdist_mpkg', 'altgraph')
|
||||
|
||||
@flush
|
||||
def postprocess_package(self, src_path, dest_path):
|
||||
pass
|
||||
|
||||
@flush
|
||||
def add_stdlib(self):
|
||||
info('\nAdding python stdlib')
|
||||
src = SW + '/python/Python.framework/Versions/Current/lib/python'
|
||||
src += self.version_info
|
||||
dest = join(self.resources_dir, 'Python', 'lib', 'python')
|
||||
dest += self.version_info
|
||||
os.makedirs(dest)
|
||||
for x in os.listdir(src):
|
||||
if x in ('site-packages', 'config', 'test', 'lib2to3', 'lib-tk',
|
||||
'lib-old', 'idlelib', 'plat-mac', 'plat-darwin', 'site.py'):
|
||||
continue
|
||||
x = join(src, x)
|
||||
if os.path.isdir(x):
|
||||
self.add_package_dir(x, dest)
|
||||
elif os.path.splitext(x)[1] in ('.so', '.py'):
|
||||
shutil.copy2(x, dest)
|
||||
dest2 = join(dest, basename(x))
|
||||
if dest2.endswith('.so'):
|
||||
self.fix_dependencies_in_lib(dest2)
|
||||
self.remove_bytecode(join(self.resources_dir, 'Python', 'lib'))
|
||||
confdir = join(self.resources_dir, 'Python',
|
||||
'lib/python%s/config'%self.version_info)
|
||||
os.makedirs(confdir)
|
||||
shutil.copy2(join(src, 'config/Makefile'), confdir)
|
||||
incdir = join(self.resources_dir, 'Python',
|
||||
'include/python'+self.version_info)
|
||||
os.makedirs(incdir)
|
||||
shutil.copy2(join(src.replace('/lib/', '/include/'), 'pyconfig.h'),
|
||||
incdir)
|
||||
|
||||
@flush
|
||||
def remove_bytecode(self, dest):
|
||||
for x in os.walk(dest):
|
||||
root = x[0]
|
||||
for f in x[-1]:
|
||||
if os.path.splitext(f) in ('.pyc', '.pyo'):
|
||||
os.remove(join(root, f))
|
||||
|
||||
@flush
|
||||
def compile_py_modules(self):
|
||||
info('\nCompiling Python modules')
|
||||
base = join(self.resources_dir, 'Python')
|
||||
for x in os.walk(base):
|
||||
root = x[0]
|
||||
for f in x[-1]:
|
||||
if f.endswith('.py'):
|
||||
y = join(root, f)
|
||||
rel = os.path.relpath(y, base)
|
||||
try:
|
||||
py_compile.compile(y, dfile=rel, doraise=True)
|
||||
os.remove(y)
|
||||
except:
|
||||
self.warn('WARNING: Failed to byte-compile', y)
|
||||
|
||||
def create_app_clone(self, name, specialise_plist, remove_doc_types=True):
|
||||
info('\nCreating ' + name)
|
||||
cc_dir = os.path.join(self.contents_dir, name, 'Contents')
|
||||
exe_dir = join(cc_dir, 'MacOS')
|
||||
os.makedirs(exe_dir)
|
||||
for x in os.listdir(self.contents_dir):
|
||||
if x.endswith('.app'):
|
||||
continue
|
||||
if x == 'Info.plist':
|
||||
plist = plistlib.readPlist(join(self.contents_dir, x))
|
||||
specialise_plist(plist)
|
||||
if remove_doc_types:
|
||||
plist.pop('CFBundleDocumentTypes')
|
||||
exe = plist['CFBundleExecutable']
|
||||
# We cannot symlink the bundle executable as if we do,
|
||||
# codesigning fails
|
||||
nexe = plist['CFBundleExecutable'] = exe + '-placeholder-for-codesigning'
|
||||
shutil.copy2(join(self.contents_dir, 'MacOS', exe), join(exe_dir, nexe))
|
||||
exe = join(exe_dir, plist['CFBundleExecutable'])
|
||||
plistlib.writePlist(plist, join(cc_dir, x))
|
||||
elif x == 'MacOS':
|
||||
for item in os.listdir(join(self.contents_dir, 'MacOS')):
|
||||
os.symlink('../../../MacOS/'+item, join(exe_dir, item))
|
||||
else:
|
||||
os.symlink(join('../..', x), join(cc_dir, x))
|
||||
|
||||
@flush
|
||||
def create_console_app(self):
|
||||
def specialise_plist(plist):
|
||||
plist['LSBackgroundOnly'] = '1'
|
||||
plist['CFBundleIdentifier'] = 'com.calibre-ebook.console'
|
||||
plist['CFBundleExecutable'] = 'calibre-parallel'
|
||||
self.create_app_clone('console.app', specialise_plist)
|
||||
# Comes from the terminal-notifier project:
|
||||
# https://github.com/alloy/terminal-notifier
|
||||
dest = join(self.contents_dir, 'calibre-notifier.app')
|
||||
shutil.copytree(join(SW, 'build/notifier.app'), dest)
|
||||
shutil.copy2(join(self.resources_dir, 'calibre.icns'), join(dest, 'Contents', 'Resources', 'library.icns'))
|
||||
|
||||
@flush
|
||||
def create_gui_apps(self):
|
||||
from calibre.customize.ui import all_input_formats
|
||||
def specialise_plist(launcher, remove_types, plist):
|
||||
plist['CFBundleDisplayName'] = plist['CFBundleName'] = {
|
||||
'ebook-viewer':'E-book Viewer', 'ebook-edit':'Edit Book', 'calibre-debug': 'calibre (debug)',
|
||||
}[launcher]
|
||||
plist['CFBundleExecutable'] = launcher
|
||||
if launcher != 'calibre-debug':
|
||||
plist['CFBundleIconFile'] = launcher + '.icns'
|
||||
plist['CFBundleIdentifier'] = 'com.calibre-ebook.' + launcher
|
||||
if not remove_types:
|
||||
input_formats = sorted(all_input_formats())
|
||||
e = plist['CFBundleDocumentTypes'][0]
|
||||
exts = 'epub azw3'.split() if launcher == 'ebook-edit' else input_formats
|
||||
e['CFBundleTypeExtensions'] = exts
|
||||
for launcher in ('ebook-viewer', 'ebook-edit', 'calibre-debug'):
|
||||
remove_types = launcher == 'calibre-debug'
|
||||
self.create_app_clone(launcher + '.app', partial(specialise_plist, launcher, remove_types), remove_doc_types=remove_types)
|
||||
|
||||
@flush
|
||||
def copy_site(self):
|
||||
base = os.path.dirname(__file__)
|
||||
shutil.copy2(join(base, 'site.py'), join(self.resources_dir, 'Python',
|
||||
'lib', 'python'+self.version_info))
|
||||
|
||||
@flush
|
||||
def makedmg(self, d, volname,
|
||||
destdir='dist',
|
||||
internet_enable=True,
|
||||
format='UDBZ'):
|
||||
''' Copy a directory d into a dmg named volname '''
|
||||
info('\nSigning...')
|
||||
sys.stdout.flush()
|
||||
if not os.path.exists(destdir):
|
||||
os.makedirs(destdir)
|
||||
dmg = os.path.join(destdir, volname+'.dmg')
|
||||
if os.path.exists(dmg):
|
||||
os.unlink(dmg)
|
||||
tdir = tempfile.mkdtemp()
|
||||
appdir = os.path.join(tdir, os.path.basename(d))
|
||||
shutil.copytree(d, appdir, symlinks=True)
|
||||
with timeit() as times:
|
||||
sign_app(appdir)
|
||||
info('Signing completed in %d minutes %d seconds' % tuple(times))
|
||||
os.symlink('/Applications', os.path.join(tdir, 'Applications'))
|
||||
size_in_mb = int(subprocess.check_output(['du', '-s', '-k', tdir]).decode('utf-8').split()[0]) / 1024.
|
||||
cmd = ['/usr/bin/hdiutil', 'create', '-srcfolder', tdir, '-volname', volname, '-format', format]
|
||||
if 190 < size_in_mb < 250:
|
||||
# We need -size 255m because of a bug in hdiutil. When the size of
|
||||
# srcfolder is close to 200MB hdiutil fails with
|
||||
# diskimages-helper: resize request is above maximum size allowed.
|
||||
cmd += ['-size', '255m']
|
||||
info('\nCreating dmg...')
|
||||
with timeit() as times:
|
||||
subprocess.check_call(cmd + [dmg])
|
||||
if internet_enable:
|
||||
subprocess.check_call(['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg])
|
||||
info('dmg created in %d minutes and %d seconds' % tuple(times))
|
||||
shutil.rmtree(tdir)
|
||||
size = os.stat(dmg).st_size/(1024*1024.)
|
||||
info('\nInstaller size: %.2fMB\n'%size)
|
||||
return dmg
|
||||
|
||||
def test_exe():
|
||||
build_dir = abspath(join('build', APPNAME+'.app'))
|
||||
py2app = Py2App(build_dir)
|
||||
py2app.create_exe()
|
||||
return 0
|
||||
|
||||
|
||||
def main(test=False, dont_strip=False):
|
||||
if 'test_exe' in sys.argv:
|
||||
return test_exe()
|
||||
build_dir = abspath(join(os.path.dirname(SRC), 'build', APPNAME+'.app'))
|
||||
Py2App(build_dir, test_launchers=test, dont_strip=dont_strip)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -1,85 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=utf-8
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import subprocess, os, sys, plistlib
|
||||
from contextlib import contextmanager
|
||||
from glob import glob
|
||||
|
||||
@contextmanager
|
||||
def current_dir(path):
|
||||
cwd = os.getcwd()
|
||||
os.chdir(path)
|
||||
yield path
|
||||
os.chdir(cwd)
|
||||
|
||||
def codesign(items):
|
||||
if isinstance(items, basestring):
|
||||
items = [items]
|
||||
# If you get errors while codesigning that look like "A timestamp was
|
||||
# expected but not found" it means that codesign failed to contact Apple's time
|
||||
# servers, probably due to network congestion, so add --timestamp=none to
|
||||
# this command line. That means the signature will fail once your code
|
||||
# signing key expires and key revocation wont work, but...
|
||||
subprocess.check_call(['codesign', '-s', 'Kovid Goyal'] + list(items))
|
||||
|
||||
def files_in(folder):
|
||||
for record in os.walk(folder):
|
||||
for f in record[-1]:
|
||||
yield os.path.join(record[0], f)
|
||||
|
||||
def expand_dirs(items):
|
||||
items = set(items)
|
||||
dirs = set(x for x in items if os.path.isdir(x))
|
||||
items.difference_update(dirs)
|
||||
for x in dirs:
|
||||
items.update(set(files_in(x)))
|
||||
return items
|
||||
|
||||
def get_executable(info_path):
|
||||
return plistlib.readPlist(info_path)['CFBundleExecutable']
|
||||
|
||||
def sign_app(appdir):
|
||||
appdir = os.path.abspath(appdir)
|
||||
key = open(os.path.expanduser('~/key')).read().strip()
|
||||
subprocess.check_call(['security', 'unlock-keychain', '-p', key])
|
||||
with current_dir(os.path.join(appdir, 'Contents')):
|
||||
executables = {get_executable('Info.plist')}
|
||||
|
||||
# Sign the sub application bundles
|
||||
sub_apps = glob('*.app')
|
||||
for sa in sub_apps:
|
||||
exe = get_executable(sa + '/Contents/Info.plist')
|
||||
if exe in executables:
|
||||
raise ValueError('Multiple app bundles share the same executable: %s' % exe)
|
||||
executables.add(exe)
|
||||
codesign(sub_apps)
|
||||
|
||||
# Sign everything in MacOS except the main executables of the various
|
||||
# app bundles which will be signed automatically by codesign when
|
||||
# signing the app bundles
|
||||
with current_dir('MacOS'):
|
||||
items = set(os.listdir('.')) - executables
|
||||
codesign(expand_dirs(items))
|
||||
|
||||
# Sign everything in Frameworks
|
||||
with current_dir('Frameworks'):
|
||||
fw = set(glob('*.framework'))
|
||||
codesign(fw)
|
||||
items = set(os.listdir('.')) - fw
|
||||
codesign(expand_dirs(items))
|
||||
|
||||
# Now sign the main app
|
||||
codesign(appdir)
|
||||
# Verify the signature
|
||||
subprocess.check_call(['codesign', '--deep', '--verify', '-v', appdir])
|
||||
subprocess.check_call('spctl --verbose=4 --assess --type execute'.split() + [appdir])
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sign_app(sys.argv[-1])
|
@ -1,154 +0,0 @@
|
||||
"""
|
||||
Append module search paths for third-party packages to sys.path.
|
||||
|
||||
This is stripped down and customized for use in py2app applications
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
def makepath(*paths):
|
||||
dir = os.path.abspath(os.path.join(*paths))
|
||||
return dir, os.path.normcase(dir)
|
||||
|
||||
def abs__file__():
|
||||
"""Set all module __file__ attribute to an absolute path"""
|
||||
for m in sys.modules.values():
|
||||
if hasattr(m, '__loader__'):
|
||||
continue # don't mess with a PEP 302-supplied __file__
|
||||
try:
|
||||
m.__file__ = os.path.abspath(m.__file__)
|
||||
except AttributeError:
|
||||
continue
|
||||
|
||||
# This ensures that the initial path provided by the interpreter contains
|
||||
# only absolute pathnames, even if we're running from the build directory.
|
||||
L = []
|
||||
_dirs_in_sys_path = {}
|
||||
dir = dircase = None # sys.path may be empty at this point
|
||||
for dir in sys.path:
|
||||
# Filter out duplicate paths (on case-insensitive file systems also
|
||||
# if they only differ in case); turn relative paths into absolute
|
||||
# paths.
|
||||
dir, dircase = makepath(dir)
|
||||
if dircase not in _dirs_in_sys_path:
|
||||
L.append(dir)
|
||||
_dirs_in_sys_path[dircase] = 1
|
||||
sys.path[:] = L
|
||||
del dir, dircase, L
|
||||
_dirs_in_sys_path = None
|
||||
|
||||
def _init_pathinfo():
|
||||
global _dirs_in_sys_path
|
||||
_dirs_in_sys_path = d = {}
|
||||
for dir in sys.path:
|
||||
if dir and not os.path.isdir(dir):
|
||||
continue
|
||||
dir, dircase = makepath(dir)
|
||||
d[dircase] = 1
|
||||
|
||||
def addsitedir(sitedir):
|
||||
global _dirs_in_sys_path
|
||||
if _dirs_in_sys_path is None:
|
||||
_init_pathinfo()
|
||||
reset = 1
|
||||
else:
|
||||
reset = 0
|
||||
sitedir, sitedircase = makepath(sitedir)
|
||||
if sitedircase not in _dirs_in_sys_path:
|
||||
sys.path.append(sitedir) # Add path component
|
||||
try:
|
||||
names = os.listdir(sitedir)
|
||||
except os.error:
|
||||
return
|
||||
names.sort()
|
||||
for name in names:
|
||||
if name[-4:] == os.extsep + "pth":
|
||||
addpackage(sitedir, name)
|
||||
if reset:
|
||||
_dirs_in_sys_path = None
|
||||
|
||||
def addpackage(sitedir, name):
|
||||
global _dirs_in_sys_path
|
||||
if _dirs_in_sys_path is None:
|
||||
_init_pathinfo()
|
||||
reset = 1
|
||||
else:
|
||||
reset = 0
|
||||
fullname = os.path.join(sitedir, name)
|
||||
try:
|
||||
f = open(fullname)
|
||||
except IOError:
|
||||
return
|
||||
while True:
|
||||
dir = f.readline()
|
||||
if not dir:
|
||||
break
|
||||
if dir[0] == '#':
|
||||
continue
|
||||
if dir.startswith("import"):
|
||||
exec dir
|
||||
continue
|
||||
if dir[-1] == '\n':
|
||||
dir = dir[:-1]
|
||||
dir, dircase = makepath(sitedir, dir)
|
||||
if dircase not in _dirs_in_sys_path and os.path.exists(dir):
|
||||
sys.path.append(dir)
|
||||
_dirs_in_sys_path[dircase] = 1
|
||||
if reset:
|
||||
_dirs_in_sys_path = None
|
||||
|
||||
|
||||
# Remove sys.setdefaultencoding() so that users cannot change the
|
||||
# encoding after initialization. The test for presence is needed when
|
||||
# this module is run as a script, because this code is executed twice.
|
||||
#
|
||||
if hasattr(sys, "setdefaultencoding"):
|
||||
sys.setdefaultencoding('utf-8')
|
||||
del sys.setdefaultencoding
|
||||
|
||||
def run_entry_point():
|
||||
bname, mod, func = sys.calibre_basename, sys.calibre_module, sys.calibre_function
|
||||
sys.argv[0] = bname
|
||||
pmod = __import__(mod, fromlist=[1], level=0)
|
||||
return getattr(pmod, func)()
|
||||
|
||||
def add_calibre_vars(base):
|
||||
sys.frameworks_dir = os.path.join(os.path.dirname(base), 'Frameworks')
|
||||
sys.resources_location = os.path.abspath(os.path.join(base, 'resources'))
|
||||
sys.extensions_location = os.path.join(sys.frameworks_dir, 'plugins')
|
||||
sys.binaries_path = os.path.join(os.path.dirname(base), 'MacOS')
|
||||
sys.console_binaries_path = os.path.join(os.path.dirname(base),
|
||||
'console.app', 'Contents', 'MacOS')
|
||||
|
||||
dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
|
||||
if dv and os.path.exists(dv):
|
||||
sys.path.insert(0, os.path.abspath(dv))
|
||||
|
||||
def nuke_stdout():
|
||||
# Redirect stdout, stdin and stderr to /dev/null
|
||||
from calibre.constants import plugins
|
||||
plugins['speedup'][0].detach(os.devnull)
|
||||
|
||||
def main():
|
||||
global __file__
|
||||
|
||||
# Needed on OS X <= 10.8, which passes -psn_... as a command line arg when
|
||||
# starting via launch services
|
||||
for arg in tuple(sys.argv[1:]):
|
||||
if arg.startswith('-psn_'):
|
||||
sys.argv.remove(arg)
|
||||
|
||||
base = sys.resourcepath
|
||||
sys.frozen = 'macosx_app'
|
||||
sys.new_app_bundle = True
|
||||
abs__file__()
|
||||
|
||||
add_calibre_vars(base)
|
||||
addsitedir(sys.site_packages)
|
||||
|
||||
if sys.calibre_is_gui_app and not (
|
||||
sys.stdout.isatty() or sys.stderr.isatty() or sys.stdin.isatty()):
|
||||
nuke_stdout()
|
||||
|
||||
return run_entry_point()
|
@ -1,225 +0,0 @@
|
||||
#include "util.h"
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <Python.h>
|
||||
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
|
||||
static const char *ERR_OOM = "Out of memory";
|
||||
|
||||
static int
|
||||
report_error(const char *msg) {
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
fflush(stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
report_code(const char *preamble, const char* msg, int code) {
|
||||
fprintf(stderr, "%s: %s\n", preamble, msg);
|
||||
fflush(stderr);
|
||||
return code;
|
||||
}
|
||||
|
||||
#define EXE "@executable_path/.."
|
||||
|
||||
static void
|
||||
set_env_vars(const char **ENV_VARS, const char **ENV_VAR_VALS, const char* exe_path) {
|
||||
int i = 0;
|
||||
char buf[3*PATH_MAX];
|
||||
const char *env_var, *val;
|
||||
|
||||
while(1) {
|
||||
env_var = ENV_VARS[i];
|
||||
if (env_var == NULL) break;
|
||||
val = ENV_VAR_VALS[i++];
|
||||
if (strstr(val, EXE) == val && strlen(val) >= strlen(EXE)+1) {
|
||||
strncpy(buf, exe_path, 3*PATH_MAX-150);
|
||||
strncpy(buf+strlen(exe_path), val+strlen(EXE), 150);
|
||||
setenv(env_var, buf, 1);
|
||||
} else
|
||||
setenv(env_var, val, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void initialize_interpreter(const char **ENV_VARS, const char **ENV_VAR_VALS,
|
||||
char *PROGRAM, const char *MODULE, const char *FUNCTION, const char *PYVER, int IS_GUI,
|
||||
const char* exe_path, const char *rpath, int argc, const char **argv) {
|
||||
PyObject *pargv, *v;
|
||||
int i;
|
||||
Py_OptimizeFlag = 2;
|
||||
Py_NoSiteFlag = 1;
|
||||
Py_DontWriteBytecodeFlag = 1;
|
||||
Py_IgnoreEnvironmentFlag = 1;
|
||||
Py_NoUserSiteDirectory = 1;
|
||||
Py_HashRandomizationFlag = 1;
|
||||
|
||||
//Py_VerboseFlag = 1;
|
||||
//Py_DebugFlag = 1;
|
||||
|
||||
Py_SetProgramName(PROGRAM);
|
||||
|
||||
char pyhome[1000];
|
||||
snprintf(pyhome, 1000, "%s/Python", rpath);
|
||||
Py_SetPythonHome(pyhome);
|
||||
|
||||
set_env_vars(ENV_VARS, ENV_VAR_VALS, exe_path);
|
||||
|
||||
//printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath());
|
||||
Py_Initialize();
|
||||
|
||||
char *dummy_argv[1] = {""};
|
||||
PySys_SetArgv(1, dummy_argv);
|
||||
//printf("Path after Py_Initialize(): %s\r\n\n", Py_GetPath());
|
||||
char path[3000];
|
||||
snprintf(path, 3000, "%s/lib/python%s:%s/lib/python%s/lib-dynload:%s/site-packages", pyhome, PYVER, pyhome, PYVER, pyhome);
|
||||
|
||||
PySys_SetPath(path);
|
||||
//printf("Path set by me: %s\r\n\n", path);
|
||||
|
||||
PySys_SetObject("calibre_basename", PyBytes_FromString(PROGRAM));
|
||||
PySys_SetObject("calibre_module", PyBytes_FromString(MODULE));
|
||||
PySys_SetObject("calibre_function", PyBytes_FromString(FUNCTION));
|
||||
PySys_SetObject("calibre_is_gui_app", ((IS_GUI) ? Py_True : Py_False));
|
||||
PySys_SetObject("resourcepath", PyBytes_FromString(rpath));
|
||||
snprintf(path, 3000, "%s/site-packages", pyhome);
|
||||
PySys_SetObject("site_packages", PyBytes_FromString(pyhome));
|
||||
|
||||
|
||||
pargv = PyList_New(argc);
|
||||
if (pargv == NULL) exit(report_error(ERR_OOM));
|
||||
for (i = 0; i < argc; i++) {
|
||||
v = PyBytes_FromString(argv[i]);
|
||||
if (v == NULL) exit(report_error(ERR_OOM));
|
||||
PyList_SetItem(pargv, i, v);
|
||||
}
|
||||
PySys_SetObject("argv", pargv);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int pyobject_to_int(PyObject *res) {
|
||||
int ret; PyObject *tmp;
|
||||
tmp = PyNumber_Int(res);
|
||||
if (tmp == NULL) ret = (PyObject_IsTrue(res)) ? 1 : 0;
|
||||
else ret = (int)PyInt_AS_LONG(tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int handle_sysexit(PyObject *e) {
|
||||
PyObject *code;
|
||||
|
||||
code = PyObject_GetAttrString(e, "code");
|
||||
if (!code) return 0;
|
||||
return pyobject_to_int(code);
|
||||
}
|
||||
|
||||
int calibre_show_python_error(const char *preamble, int code) {
|
||||
PyObject *exc, *val, *tb, *str;
|
||||
int ret, issysexit = 0; char *i;
|
||||
|
||||
if (!PyErr_Occurred()) return code;
|
||||
issysexit = PyErr_ExceptionMatches(PyExc_SystemExit);
|
||||
|
||||
PyErr_Fetch(&exc, &val, &tb);
|
||||
|
||||
if (exc != NULL) {
|
||||
PyErr_NormalizeException(&exc, &val, &tb);
|
||||
|
||||
if (issysexit) {
|
||||
return (val) ? handle_sysexit(val) : 0;
|
||||
}
|
||||
if (val != NULL) {
|
||||
str = PyObject_Unicode(val);
|
||||
if (str == NULL) {
|
||||
PyErr_Clear();
|
||||
str = PyObject_Str(val);
|
||||
}
|
||||
i = PyString_AsString(str);
|
||||
ret = report_code(preamble, (i==NULL)?ERR_OOM:i, code);
|
||||
if (tb != NULL) {
|
||||
PyErr_Restore(exc, val, tb);
|
||||
PyErr_Print();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return report_code(preamble, "", code);
|
||||
}
|
||||
|
||||
EXPORT
|
||||
int
|
||||
run(const char **ENV_VARS, const char **ENV_VAR_VALS, char *PROGRAM,
|
||||
const char *MODULE, const char *FUNCTION, const char *PYVER,
|
||||
int IS_GUI, int argc, const char **argv, const char **envp) {
|
||||
char *pathPtr = NULL, *t = NULL;
|
||||
char buf[3*PATH_MAX];
|
||||
int ret = 0, i;
|
||||
PyObject *site, *mainf, *res;
|
||||
uint32_t buf_size = PATH_MAX+1;
|
||||
char *ebuf = calloc(buf_size, sizeof(char));
|
||||
|
||||
ret = _NSGetExecutablePath(ebuf, &buf_size);
|
||||
if (ret == -1) {
|
||||
free(ebuf);
|
||||
ebuf = calloc(buf_size, sizeof(char));
|
||||
if (_NSGetExecutablePath(ebuf, &buf_size) != 0)
|
||||
return report_error("Failed to find real path of executable.");
|
||||
}
|
||||
pathPtr = realpath(ebuf, buf);
|
||||
if (pathPtr == NULL) {
|
||||
return report_error(strerror(errno));
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
t = rindex(pathPtr, '/');
|
||||
if (t == NULL) return report_error("Failed to determine bundle path.");
|
||||
*t = '\0';
|
||||
}
|
||||
if (strstr(pathPtr, "/calibre.app/Contents/") != NULL) {
|
||||
// We are one of the duplicate executables created to workaround codesign's limitations
|
||||
for (i = 0; i < 2; i++) {
|
||||
t = rindex(pathPtr, '/');
|
||||
if (t == NULL) return report_error("Failed to resolve bundle path in dummy executable");
|
||||
*t = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
char rpath[PATH_MAX+1], exe_path[PATH_MAX+1];
|
||||
snprintf(exe_path, PATH_MAX+1, "%s/Contents", pathPtr);
|
||||
snprintf(rpath, PATH_MAX+1, "%s/Resources", exe_path);
|
||||
initialize_interpreter(ENV_VARS, ENV_VAR_VALS, PROGRAM, MODULE, FUNCTION, PYVER, IS_GUI,
|
||||
exe_path, rpath, argc, argv);
|
||||
|
||||
site = PyImport_ImportModule("site");
|
||||
|
||||
if (site == NULL)
|
||||
ret = calibre_show_python_error("Failed to import site module", -1);
|
||||
else {
|
||||
Py_XINCREF(site);
|
||||
|
||||
mainf = PyObject_GetAttrString(site, "main");
|
||||
if (mainf == NULL || !PyCallable_Check(mainf))
|
||||
ret = calibre_show_python_error("site module has no main function", -1);
|
||||
else {
|
||||
Py_XINCREF(mainf);
|
||||
res = PyObject_CallObject(mainf, NULL);
|
||||
|
||||
if (res == NULL)
|
||||
ret = calibre_show_python_error("Python function terminated unexpectedly", -1);
|
||||
else {
|
||||
}
|
||||
}
|
||||
}
|
||||
PyErr_Clear();
|
||||
Py_Finalize();
|
||||
|
||||
//printf("11111 Returning: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
int run(const char **ENV_VARS, const char **ENV_VAR_VALS, char *PROGRAM,
|
||||
const char *MODULE, const char *FUNCTION, const char *PYVER, int IS_GUI,
|
||||
int argc, const char **argv, const char **envp);
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
easy_install --always-unzip -U appscript
|
@ -1,7 +0,0 @@
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
# Change the https URLs to http in setup.py
|
||||
|
||||
cd $SW/build/apsw-* && rm -rf build/* && \
|
||||
python setup.py fetch --version=3.8.6 --sqlite --missing-checksum-ok && python setup.py install
|
@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd $SW/build/chmlib* && \
|
||||
#cp /usr/share/libtool/config.* . && \
|
||||
./configure --disable-dependency-tracking --disable-pread --disable-io64 --prefix=$SW && make && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/expat-* &&\
|
||||
./configure --prefix=$SW && make && make install
|
@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
export FREETYPE_CFLAGS="-I$SW/include/freetype2"
|
||||
export FREETYPE_LIBS="-L$SW/lib -lfreetype -lz -lbz2"
|
||||
|
||||
cd $SW/build/fontconfig-2.* && \
|
||||
./configure --prefix=$SW --disable-static --disable-docs --with-expat=$SW --with-add-fonts=/usr/X11/lib/X11/fonts --disable-dependency-tracking && make && make install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/freetype* && \
|
||||
./configure --disable-static --prefix=$SW && make && make install
|
@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export CFLAGS="$CFLAGS -DU_CHARSET_IS_UTF8=1"
|
||||
export CPPFLAGS="$CFLAGS"
|
||||
export CXXFLAGS="$CFLAGS"
|
||||
|
||||
cd $SW/build/icu*/source && \
|
||||
./runConfigureICU MacOSX --disable-samples --prefix=$SW && make && make install && python ~/build/calibre/setup/installer/osx/fix_icu.py
|
||||
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/libiconv-* && \
|
||||
./configure --enable-static --disable-dependency-tracking --disable-shared --prefix=$SW && make && make install
|
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export libusbmuxd_CFLAGS=-I$SW/include
|
||||
export libusbmuxd_LIBS=-lusbmuxd
|
||||
export libplist_CFLAGS=-I$SW/include
|
||||
export libplist_LIBS=-lplist
|
||||
export libplistmm_CFLAGS=-I$SW/include
|
||||
export libplistmm_LIBS=-lplist++
|
||||
export openssl_CFLAGS=-I/usr/include
|
||||
export openssl_LIBS="-lcrypto -lssl"
|
||||
|
||||
cd $SW/build/libimobiledevice-* && ./configure --prefix=$SW --disable-dependency-tracking --without-cython --disable-static && make && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd $SW/build/libjpeg-turbo* && \
|
||||
./configure --disable-dependency-tracking --enable-shared --with-jpeg8 --without-turbojpeg --prefix=$SW --host x86_64-apple-darwin NASM=$SW/bin/nasm && make -j2 && make install
|
@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/libtool*/libltdl && \
|
||||
./configure --prefix=$SW --disable-dependency-tracking --enable-ltdl-install && \
|
||||
make && make install
|
@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export LIBUSB_CFLAGS="-I$SW/include/libusb-1.0"
|
||||
export LIBUSB_LIBS="-L$SW/lib -lusb-1.0"
|
||||
export CFLAGS="$CFLAGS -DHAVE_ICONV"
|
||||
export LDFLAGS="$LDFLAGS -liconv"
|
||||
|
||||
cd $SW/build/libmtp-* && \
|
||||
./configure --disable-dependency-tracking --disable-static --prefix=$SW --with-libiconv-prefix=$SW && \
|
||||
make && make install
|
||||
|
@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
export CPPFLAGS=$CFLAGS
|
||||
|
||||
cd $SW/build/libpng* && \
|
||||
./configure --prefix=$SW --disable-dependency-tracking && make && make install
|
||||
|
@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/libusb-* && \
|
||||
./configure --disable-dependency-tracking --disable-static --prefix=$SW && \
|
||||
make && make install
|
||||
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/libwebp-* && ./configure --prefix=$SW --disable-static && make && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/libxml2-2.* && \
|
||||
./configure --prefix=$SW/private/libxml2 --disable-shared --enable-static --with-iconv=$SW --with-zlib=$SW --without-python --without-debug --disable-dependency-tracking && make && make install
|
||||
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/libxslt-*
|
||||
./configure --prefix=$SW/private/libxml2 --disable-shared --without-python --without-debug --disable-dependency-tracking --with-libxml-prefix=$SW/private/libxml2 && make && make install
|
||||
|
@ -1,21 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# lxml must be built with statically linked libxml2 and libxslt as python on
|
||||
# OS X loads the system version of these libraries, which can cause incompatibility
|
||||
# First run python setup.py install and abort it when it reaches the compiling phase
|
||||
|
||||
CC=gcc
|
||||
BTEMP=build/temp.macosx-10.7-x86_64-2.7
|
||||
BLIB=build/lib.macosx-10.7-x86_64-2.7
|
||||
PYH=$SW/python/Python.framework/Versions/Current/Headers
|
||||
LXML=src/lxml/includes
|
||||
LIBXML=$SW/private/libxml2
|
||||
|
||||
cd $SW/build/lxml-3* && rm -rf build/* && \
|
||||
echo Builiding extension modules... && \
|
||||
mkdir -p $BTEMP/src/lxml/ $BLIB/lxml/ && \
|
||||
$CC $CFLAGS -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I$LIBXML/include/libxml2 -I$LIBXML/include/libxslt -I/usr/include -I$PYH -I$LXML -c src/lxml/lxml.etree.c -o $BTEMP/src/lxml/lxml.etree.o -w -flat_namespace && \
|
||||
$CC $CFLAGS -bundle -undefined dynamic_lookup $BTEMP/src/lxml/lxml.etree.o $LIBXML/lib/libxml2.a $LIBXML/lib/libxslt.a $LIBXML/lib/libexslt.a $SW/lib/libz.a $SW/lib/libiconv.a -lm -o $BLIB/lxml/etree.so && \
|
||||
$CC $CFLAGS -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I$LIBXML/include/libxml2 -I$LIBXML/include/libxslt -I/usr/include -I$PYH -I$LXML -c src/lxml/lxml.objectify.c -o $BTEMP/src/lxml/lxml.objectify.o -w -flat_namespace && \
|
||||
$CC $CFLAGS -bundle -undefined dynamic_lookup $BTEMP/src/lxml/lxml.objectify.o $LIBXML/lib/libxml2.a $LIBXML/lib/libxslt.a $LIBXML/lib/libexslt.a $SW/lib/libz.a $SW/lib/libiconv.a -lm -o $BLIB/lxml/objectify.so && \
|
||||
python setup.py install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/macfsevents* && \
|
||||
python setup.py install
|
@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export CPPFLAGS=$CFLAGS
|
||||
|
||||
cd $SW/build/mozjpeg && \
|
||||
./configure --prefix=$SW/private/mozjpeg --disable-dependency-tracking --disable-shared --with-jpeg8 --without-turbojpeg && make && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd $SW/build/nasm* && \
|
||||
./configure --prefix=$SW && make -j2 && make install
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/netifaces-* && python setup.py build && cp build/*/netifaces.so $SW/python/Python.framework/Versions/Current/lib/python*/site-packages/
|
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
SSLDIR=$SW/private/ssl
|
||||
|
||||
cd $SW/build/openssl-* && \
|
||||
rm -rf $SSLDIR && \
|
||||
./Configure darwin64-x86_64-cc shared enable-ec_nistp_64_gcc_128 no-ssl2 --openssldir=$SSLDIR && make && make install
|
@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export CPPFLAGS=$CFLAGS
|
||||
|
||||
cd $SW/build/optipng* && \
|
||||
./configure -prefix=$SW -with-system-libs && make && make install
|
@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
export CFLAGS="$CFLAGS -mmacosx-version-min=10.7"
|
||||
export LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names -mmacosx-version-min=10.7"
|
||||
|
||||
cd $SW/build/Pillow* && \
|
||||
echo Disabling zip_safe && \
|
||||
python -c "f = open('setup.py', 'r+b'); raw = f.read(); import re; raw = re.sub(r'zip_safe\s*=\s*True', 'zip_safe=False', raw); f.seek(0); f.truncate(0); f.write(raw)" && \
|
||||
python setup.py install
|
||||
|
@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export libxml2_CFLAGS="-I/usr/include/libxml2"
|
||||
export libxml2_LIBS="-L/usr/lib -lxml2"
|
||||
|
||||
cd $SW/build/libplist-* && \
|
||||
./configure --without-cython --disable-dependency-tracking --prefix=$SW && \
|
||||
make && make install
|
@ -1,29 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export CMAKE_INCLUDE_PATH=$SW/include
|
||||
export CMAKE_LIBRARY_PATH=$SW/lib
|
||||
|
||||
cd $SW/build/podofo* && \
|
||||
rm -rf podofo-build && mkdir podofo-build && \
|
||||
cd podofo-build && \
|
||||
|
||||
echo "Running cmake..." && \
|
||||
|
||||
# We set c++98 and libstdc++ as PoDoFo does not use C++11 and without that it
|
||||
# will be compiled with C++11 and linked against libc++, which means the PoDoFo
|
||||
# calibre extension would also have to be compiled and liked that way.
|
||||
cmake -G "Unix Makefiles" -Wno-dev \
|
||||
-DFREETYPE_INCLUDE_DIR=$SW/include/freetype2 \
|
||||
-DFREETYPE_LIBRARIES=-lfreetype \
|
||||
-DCMAKE_BUILD_TYPE=RELEASE \
|
||||
-DPODOFO_BUILD_SHARED:BOOL=TRUE \
|
||||
-DPODOFO_BUILD_STATIC:BOOL=FALSE \
|
||||
-DCMAKE_CXX_FLAGS="${CFLAGS} -std=c++98 -stdlib=libstdc++" \
|
||||
-DCMAKE_INSTALL_PREFIX=$SW \
|
||||
.. && \
|
||||
make VERBOSE=0 podofo_shared && \
|
||||
rm -rf $SW/lib/libpodofo*.dylib $SW/include/podofo && \
|
||||
mkdir $SW/include/podofo && \
|
||||
cp src/libpodofo.*.dylib $SW/lib && \
|
||||
cp -r podofo_config.h ../src/* $SW/include/podofo/ && \
|
||||
cd $SW/lib/ && install_name_tool -id $SW/lib/libpodofo* $SW/lib/libpodofo.* && ln -s libpodofo*.dylib libpodofo.dylib
|
@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export CXXFLAGS="$CFLAGS"
|
||||
export FONTCONFIG_CFLAGS="-I$SW/include/fontconfig -I$SW/include"
|
||||
export FONTCONFIG_LIBS="-L$SW/lib -lfontconfig"
|
||||
export FREETYPE_CFLAGS="-I$SW/include/freetype2 -I$SW/include"
|
||||
export FREETYPE_LIBS="-L$SW/lib -lfreetype -lz"
|
||||
export FREETYPE_CONFIG="$SW/bin/freetype-config"
|
||||
export LIBJPEG_LIBS="-L$SW/lib -ljpeg"
|
||||
export LIBPNG_LIBS="-L$SW/lib -lpng"
|
||||
export LIBPNG_CFLAGS="-I$SW/include/libpng12"
|
||||
|
||||
cd $SW/build/poppler* && \
|
||||
./configure --prefix $SW --without-x --enable-shared --disable-dependency-tracking --disable-silent-rules --enable-zlib --enable-splash-output --disable-cairo-output --disable-poppler-glib --disable-poppler-qt4 --disable-poppler-cpp --disable-gtk-test --enable-libjpeg --enable-compile-warnings=no && make V=1 && make install
|
||||
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/psutil-* && python setup.py build && cp -r build/lib*/* $SW/python/Python.framework/Versions/Current/lib/python*/site-packages/
|
@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/PyQt-gpl-* && \
|
||||
python configure.py --verbose --confirm-license -c -j10 --no-designer-plugin --no-qml-plugin --no-docstrings && \
|
||||
make -j2 && make install
|
@ -1,16 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Edit setup.py
|
||||
|
||||
# Disable Tk by adding return 0 to the start of detect_tkinter_darwin
|
||||
|
||||
OPENSSL=$SW/private/ssl
|
||||
export CFLAGS="-I$OPENSSL/include $CFLAGS -DHAVE_LOAD_EXTENSION"
|
||||
export LDFLAGS="-L$OPENSSL/lib $LDFLAGS"
|
||||
|
||||
cd $SW/build/Python-* && \
|
||||
./configure --prefix=$SW --enable-framework=$SW/python --enable-ipv6 --enable-unicode=ucs2 --with-signal-module --with-threads --with-pymalloc --with-system-expat && make -j2 && make install
|
||||
|
||||
# Now create a symlink from ~/sw/bin/python to the newly installed python binary so that it becomes the default python
|
||||
# Install setuptools as described in windows/notes. Create symlink for ~/sw/bin/easy_install
|
||||
# Use setuptools to install the various python packages
|
@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# See windows/notes.rst for instructions on slimming down Qt.
|
||||
# For versions of Qt < 5.6 you need to apply this patch:
|
||||
# https://codereview.qt-project.org/#/c/125923/
|
||||
|
||||
cd $SW/build/qt-* && \
|
||||
rm -rf build && mkdir build && cd build && \
|
||||
../configure -opensource -confirm-license -prefix $SW/qt -release -nomake examples -nomake tests -no-sql-odbc -no-sql-psql -no-qml-debug -I $SW/include -L $SW/lib && \
|
||||
make -j2 && rm -rf $SW/qt && make install
|
||||
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd $SW/build/sip-* && \
|
||||
python configure.py && make && make install
|
@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export CFLAGS="$CFLAGS -O2 -DSQLITE_ENABLE_LOCKING_STYLE"
|
||||
cd $SW/build/sqlite-* &&\
|
||||
./configure --prefix=$SW --disable-dependency-tracking --disable-static && make && make install
|
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Edit makefile.unix setting the vars as shown
|
||||
|
||||
CXX=g++
|
||||
CXXFLAGS=-O2 -arch x86_64 -dynamic
|
||||
DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_SILENT -DSILENT
|
||||
STRIP=strip
|
||||
DESTDIR=$SW
|
||||
WHAT=RARDLL
|
||||
|
||||
cd $SW/unrar && make -fmakefile.unic lib && cp libunrar.so $SW/lib/libunrar.dylib
|
@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Apply the patch to prevent detection of WiFi devices from http://www.mobileread.com/forums/showthread.php?t=255234
|
||||
|
||||
export libplist_CFLAGS="-I$SW/include"
|
||||
export libplist_LIBS="-L$SW/lib -lplist"
|
||||
export CPPFLAGS="$CFLAGS"
|
||||
export CXXFLAGS="$CFLAGS"
|
||||
|
||||
cd $SW/build/libusbmuxd-* && \
|
||||
./configure --prefix=$SW --disable-dependency-tracking && \
|
||||
make && make install
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $SW/build/zlib-* && \
|
||||
./configure --prefix=$SW && make && \
|
||||
libtool -static -o libz.a *.o && make install
|
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $HOME
|
||||
rm sw-osx*;
|
||||
echo "[Paths]\nPrefix = .." > ~/sw/qt/bin/qt.conf && cat ~/sw/qt/bin/qt.conf
|
||||
echo "[Paths]\nPrefix = ../qt" > ~/sw/bin/qt.conf && cat ~/sw/bin/qt.conf
|
||||
tar cf sw-osx.tar --exclude sw/build --exclude sw/sources --exclude sw/man --exclude '*.pyc' --exclude '*.pyo' --exclude 'sw/share/doc' --exclude sw/share/gtk-doc --exclude sw/share/man --exclude sw/share/info sw && bzip2 --best sw-osx.tar
|
||||
rm ~/sw/qt/bin/qt.conf ~/sw/bin/qt.conf
|
@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=utf-8
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
# The ICU build system does not put correct install names in the dylibs it
|
||||
# generates. This script will fix that.
|
||||
|
||||
import os, glob, subprocess, re
|
||||
|
||||
SW = os.environ['SW']
|
||||
cc = subprocess.check_call
|
||||
|
||||
icu_libs = {os.path.abspath(os.path.realpath(x)) for x in glob.glob(os.path.join(SW, 'lib', 'libicu*.dylib'))}
|
||||
|
||||
def get_install_name(lib):
|
||||
return subprocess.check_output(['otool', '-D', lib]).decode('utf-8').splitlines()[-1]
|
||||
|
||||
def get_dependencies(lib):
|
||||
return [x.strip().partition(' ')[0] for x in
|
||||
subprocess.check_output(['otool', '-L', lib]).decode('utf-8').splitlines()[2:]]
|
||||
|
||||
for lib in icu_libs:
|
||||
install_name = os.path.basename(lib)
|
||||
print ('Fixing install names in', install_name)
|
||||
m = re.match(r'libicu[a-z0-9]+\.\d+', install_name)
|
||||
install_name = m.group() + '.dylib' # We only want the major version in the install name
|
||||
new_install_name = os.path.join(os.path.dirname(lib), install_name)
|
||||
cc(['install_name_tool', '-id', new_install_name, lib])
|
||||
for dep in get_dependencies(lib):
|
||||
name = os.path.basename(dep)
|
||||
if name.startswith('libicu'):
|
||||
ndep = os.path.join(SW, 'lib', name)
|
||||
if ndep != dep:
|
||||
cc(['install_name_tool', '-change', dep, ndep, lib])
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,382 +0,0 @@
|
||||
// XUnzip.h Version 1.3
|
||||
//
|
||||
// Authors: Mark Adler et al. (see below)
|
||||
//
|
||||
// Modified by: Lucian Wischik
|
||||
// lu@wischik.com
|
||||
//
|
||||
// Version 1.0 - Turned C files into just a single CPP file
|
||||
// - Made them compile cleanly as C++ files
|
||||
// - Gave them simpler APIs
|
||||
// - Added the ability to zip/unzip directly in memory without
|
||||
// any intermediate files
|
||||
//
|
||||
// Modified by: Hans Dietrich
|
||||
// hdietrich@gmail.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Lucian Wischik's comments:
|
||||
// --------------------------
|
||||
// THIS FILE is almost entirely based upon code by info-zip.
|
||||
// It has been modified by Lucian Wischik.
|
||||
// The original code may be found at http://www.info-zip.org
|
||||
// The original copyright text follows.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Original authors' comments:
|
||||
// ---------------------------
|
||||
// This is version 2002-Feb-16 of the Info-ZIP copyright and license. The
|
||||
// definitive version of this document should be available at
|
||||
// ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely.
|
||||
//
|
||||
// Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
|
||||
//
|
||||
// For the purposes of this copyright and license, "Info-ZIP" is defined as
|
||||
// the following set of individuals:
|
||||
//
|
||||
// Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
|
||||
// Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase,
|
||||
// Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
|
||||
// David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
|
||||
// Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
|
||||
// Kai Uwe Rommel, Steve Salisbury, Dave Smith, Christian Spieler,
|
||||
// Antoine Verheijen, Paul von Behren, Rich Wales, Mike White
|
||||
//
|
||||
// This software is provided "as is", without warranty of any kind, express
|
||||
// or implied. In no event shall Info-ZIP or its contributors be held liable
|
||||
// for any direct, indirect, incidental, special or consequential damages
|
||||
// arising out of the use of or inability to use this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// definition, disclaimer, and this list of conditions.
|
||||
//
|
||||
// 2. Redistributions in binary form (compiled executables) must reproduce
|
||||
// the above copyright notice, definition, disclaimer, and this list of
|
||||
// conditions in documentation and/or other materials provided with the
|
||||
// distribution. The sole exception to this condition is redistribution
|
||||
// of a standard UnZipSFX binary as part of a self-extracting archive;
|
||||
// that is permitted without inclusion of this license, as long as the
|
||||
// normal UnZipSFX banner has not been removed from the binary or disabled.
|
||||
//
|
||||
// 3. Altered versions--including, but not limited to, ports to new
|
||||
// operating systems, existing ports with new graphical interfaces, and
|
||||
// dynamic, shared, or static library versions--must be plainly marked
|
||||
// as such and must not be misrepresented as being the original source.
|
||||
// Such altered versions also must not be misrepresented as being
|
||||
// Info-ZIP releases--including, but not limited to, labeling of the
|
||||
// altered versions with the names "Info-ZIP" (or any variation thereof,
|
||||
// including, but not limited to, different capitalizations),
|
||||
// "Pocket UnZip", "WiZ" or "MacZip" without the explicit permission of
|
||||
// Info-ZIP. Such altered versions are further prohibited from
|
||||
// misrepresentative use of the Zip-Bugs or Info-ZIP e-mail addresses or
|
||||
// of the Info-ZIP URL(s).
|
||||
//
|
||||
// 4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip", "UnZip",
|
||||
// "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and "MacZip" for its
|
||||
// own source and binary releases.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef XUNZIP_H
|
||||
#define XUNZIP_H
|
||||
|
||||
|
||||
#ifndef XZIP_H
|
||||
DECLARE_HANDLE(HZIP); // An HZIP identifies a zip file that has been opened
|
||||
#endif
|
||||
|
||||
typedef DWORD ZRESULT;
|
||||
// return codes from any of the zip functions. Listed later.
|
||||
|
||||
#define ZIP_HANDLE 1
|
||||
#define ZIP_FILENAME 2
|
||||
#define ZIP_MEMORY 3
|
||||
|
||||
typedef struct
|
||||
{ int index; // index of this file within the zip
|
||||
char name[MAX_PATH]; // filename within the zip
|
||||
DWORD attr; // attributes, as in GetFileAttributes.
|
||||
FILETIME atime,ctime,mtime;// access, create, modify filetimes
|
||||
long comp_size; // sizes of item, compressed and uncompressed. These
|
||||
long unc_size; // may be -1 if not yet known (e.g. being streamed in)
|
||||
} ZIPENTRY;
|
||||
|
||||
typedef struct
|
||||
{ int index; // index of this file within the zip
|
||||
TCHAR name[MAX_PATH]; // filename within the zip
|
||||
DWORD attr; // attributes, as in GetFileAttributes.
|
||||
FILETIME atime,ctime,mtime;// access, create, modify filetimes
|
||||
long comp_size; // sizes of item, compressed and uncompressed. These
|
||||
long unc_size; // may be -1 if not yet known (e.g. being streamed in)
|
||||
} ZIPENTRYW;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// OpenZip()
|
||||
//
|
||||
// Purpose: Open an existing zip archive file
|
||||
//
|
||||
// Parameters: z - archive file name if flags is ZIP_FILENAME; for other
|
||||
// uses see below
|
||||
// len - for memory (ZIP_MEMORY) should be the buffer size;
|
||||
// for other uses, should be 0
|
||||
// flags - indicates usage, see below; for files, this will be
|
||||
// ZIP_FILENAME
|
||||
//
|
||||
// Returns: HZIP - non-zero if zip archive opened ok, otherwise 0
|
||||
//
|
||||
HZIP OpenZip(void *z, unsigned int len, DWORD flags);
|
||||
// OpenZip - opens a zip file and returns a handle with which you can
|
||||
// subsequently examine its contents. You can open a zip file from:
|
||||
// from a pipe: OpenZip(hpipe_read,0, ZIP_HANDLE);
|
||||
// from a file (by handle): OpenZip(hfile,0, ZIP_HANDLE);
|
||||
// from a file (by name): OpenZip("c:\\test.zip",0, ZIP_FILENAME);
|
||||
// from a memory block: OpenZip(bufstart, buflen, ZIP_MEMORY);
|
||||
// If the file is opened through a pipe, then items may only be
|
||||
// accessed in increasing order, and an item may only be unzipped once,
|
||||
// although GetZipItem can be called immediately before and after unzipping
|
||||
// it. If it's opened i n any other way, then full random access is possible.
|
||||
// Note: pipe input is not yet implemented.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// GetZipItem()
|
||||
//
|
||||
// Purpose: Get information about an item in an open zip archive
|
||||
//
|
||||
// Parameters: hz - handle of open zip archive
|
||||
// index - index number (0 based) of item in zip
|
||||
// ze - pointer to a ZIPENTRY (if ANSI) or ZIPENTRYW struct
|
||||
// (if Unicode)
|
||||
//
|
||||
// Returns: ZRESULT - ZR_OK if success, otherwise some other value
|
||||
//
|
||||
|
||||
#ifdef _UNICODE
|
||||
#define GetZipItem GetZipItemW
|
||||
#else
|
||||
#define GetZipItem GetZipItemA
|
||||
#endif
|
||||
|
||||
ZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze);
|
||||
ZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *ze);
|
||||
// GetZipItem - call this to get information about an item in the zip.
|
||||
// If index is -1 and the file wasn't opened through a pipe,
|
||||
// then it returns information about the whole zipfile
|
||||
// (and in particular ze.index returns the number of index items).
|
||||
// Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY)
|
||||
// See below for notes on what happens when you unzip such an item.
|
||||
// Note: if you are opening the zip through a pipe, then random access
|
||||
// is not possible and GetZipItem(-1) fails and you can't discover the number
|
||||
// of items except by calling GetZipItem on each one of them in turn,
|
||||
// starting at 0, until eventually the call fails. Also, in the event that
|
||||
// you are opening through a pipe and the zip was itself created into a pipe,
|
||||
// then then comp_size and sometimes unc_size as well may not be known until
|
||||
// after the item has been unzipped.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// FindZipItem()
|
||||
//
|
||||
// Purpose: Find item by name and return information about it
|
||||
//
|
||||
// Parameters: hz - handle of open zip archive
|
||||
// name - name of file to look for inside zip archive
|
||||
// ic - TRUE = case insensitive
|
||||
// index - pointer to index number returned, or -1
|
||||
// ze - pointer to a ZIPENTRY (if ANSI) or ZIPENTRYW struct
|
||||
// (if Unicode)
|
||||
//
|
||||
// Returns: ZRESULT - ZR_OK if success, otherwise some other value
|
||||
//
|
||||
|
||||
#ifdef _UNICODE
|
||||
#define FindZipItem FindZipItemW
|
||||
#else
|
||||
#define FindZipItem FindZipItemA
|
||||
#endif
|
||||
|
||||
ZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze);
|
||||
ZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRYW *ze);
|
||||
// FindZipItem - finds an item by name. ic means 'insensitive to case'.
|
||||
// It returns the index of the item, and returns information about it.
|
||||
// If nothing was found, then index is set to -1 and the function returns
|
||||
// an error code.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// UnzipItem()
|
||||
//
|
||||
// Purpose: Find item by index and unzip it
|
||||
//
|
||||
// Parameters: hz - handle of open zip archive
|
||||
// index - index number of file to unzip
|
||||
// dst - target file name of unzipped file
|
||||
// len - for memory (ZIP_MEMORY. length of buffer;
|
||||
// otherwise 0
|
||||
// flags - indicates usage, see below; for files, this will be
|
||||
// ZIP_FILENAME
|
||||
//
|
||||
// Returns: ZRESULT - ZR_OK if success, otherwise some other value
|
||||
//
|
||||
|
||||
ZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len, DWORD flags);
|
||||
// UnzipItem - given an index to an item, unzips it. You can unzip to:
|
||||
// to a pipe: UnzipItem(hz,i, hpipe_write,0,ZIP_HANDLE);
|
||||
// to a file (by handle): UnzipItem(hz,i, hfile,0,ZIP_HANDLE);
|
||||
// to a file (by name): UnzipItem(hz,i, ze.name,0,ZIP_FILENAME);
|
||||
// to a memory block: UnzipItem(hz,i, buf,buflen,ZIP_MEMORY);
|
||||
// In the final case, if the buffer isn't large enough to hold it all,
|
||||
// then the return code indicates that more is yet to come. If it was
|
||||
// large enough, and you want to know precisely how big, GetZipItem.
|
||||
// Note: zip files are normally stored with relative pathnames. If you
|
||||
// unzip with ZIP_FILENAME a relative pathname then the item gets created
|
||||
// relative to the current directory - it first ensures that all necessary
|
||||
// subdirectories have been created. Also, the item may itself be a directory.
|
||||
// If you unzip a directory with ZIP_FILENAME, then the directory gets created.
|
||||
// If you unzip it to a handle or a memory block, then nothing gets created
|
||||
// and it emits 0 bytes.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CloseZip()
|
||||
//
|
||||
// Purpose: Close an open zip archive
|
||||
//
|
||||
// Parameters: hz - handle to an open zip archive
|
||||
//
|
||||
// Returns: ZRESULT - ZR_OK if success, otherwise some other value
|
||||
//
|
||||
ZRESULT CloseZip(HZIP hz);
|
||||
// CloseZip - the zip handle must be closed with this function.
|
||||
|
||||
unsigned int FormatZipMessage(ZRESULT code, char *buf,unsigned int len);
|
||||
// FormatZipMessage - given an error code, formats it as a string.
|
||||
// It returns the length of the error message. If buf/len points
|
||||
// to a real buffer, then it also writes as much as possible into there.
|
||||
|
||||
|
||||
// These are the result codes:
|
||||
#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned,
|
||||
#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage.
|
||||
// The following come from general system stuff (e.g. files not openable)
|
||||
#define ZR_GENMASK 0x0000FF00
|
||||
#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle
|
||||
#define ZR_NOFILE 0x00000200 // couldn't create/open the file
|
||||
#define ZR_NOALLOC 0x00000300 // failed to allocate some resource
|
||||
#define ZR_WRITE 0x00000400 // a general error writing to the file
|
||||
#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip
|
||||
#define ZR_MORE 0x00000600 // there's still more data to be unzipped
|
||||
#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile
|
||||
#define ZR_READ 0x00000800 // a general error reading the file
|
||||
// The following come from mistakes on the part of the caller
|
||||
#define ZR_CALLERMASK 0x00FF0000
|
||||
#define ZR_ARGS 0x00010000 // general mistake with the arguments
|
||||
#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't
|
||||
#define ZR_MEMSIZE 0x00030000 // the memory size is too small
|
||||
#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function
|
||||
#define ZR_ENDED 0x00050000 // the zip creation has already been closed
|
||||
#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken
|
||||
#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped
|
||||
#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip
|
||||
// The following come from bugs within the zip library itself
|
||||
#define ZR_BUGMASK 0xFF000000
|
||||
#define ZR_NOTINITED 0x01000000 // initialisation didn't work
|
||||
#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file
|
||||
#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed
|
||||
#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// e.g.
|
||||
//
|
||||
// SetCurrentDirectory("c:\\docs\\stuff");
|
||||
// HZIP hz = OpenZip("c:\\stuff.zip",0,ZIP_FILENAME);
|
||||
// ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index;
|
||||
// for (int i=0; i<numitems; i++)
|
||||
// { GetZipItem(hz,i,&ze);
|
||||
// UnzipItem(hz,i,ze.name,0,ZIP_FILENAME);
|
||||
// }
|
||||
// CloseZip(hz);
|
||||
//
|
||||
//
|
||||
// HRSRC hrsrc = FindResource(hInstance,MAKEINTRESOURCE(1),RT_RCDATA);
|
||||
// HANDLE hglob = LoadResource(hInstance,hrsrc);
|
||||
// void *zipbuf=LockResource(hglob);
|
||||
// unsigned int ziplen=SizeofResource(hInstance,hrsrc);
|
||||
// HZIP hz = OpenZip(zipbuf, ziplen, ZIP_MEMORY);
|
||||
// - unzip to a membuffer -
|
||||
// ZIPENTRY ze; int i; FindZipItem(hz,"file.dat",&i,&ze);
|
||||
// char *ibuf = new char[ze.unc_size];
|
||||
// UnzipItem(hz,i, ibuf, ze.unc_size,ZIP_MEMORY);
|
||||
// delete[] buf;
|
||||
// - unzip to a fixed membuff -
|
||||
// ZIPENTRY ze; int i; FindZipItem(hz,"file.dat",&i,&ze);
|
||||
// char ibuf[1024]; ZIPRESULT zr=ZR_MORE; unsigned long totsize=0;
|
||||
// while (zr==ZR_MORE)
|
||||
// { zr = UnzipItem(hz,i, ibuf,1024,ZIP_MEMORY);
|
||||
// unsigned long bufsize=1024; if (zr==ZR_OK) bufsize=ze.unc_size-totsize;
|
||||
// totsize+=bufsize;
|
||||
// }
|
||||
// - unzip to a pipe -
|
||||
// HANDLE hthread=CreateWavReaderThread(&hread,&hwrite);
|
||||
// FindZipItem(hz,"sound.wav",&i,&ze);
|
||||
// UnzipItem(hz,i, hwrite,0,ZIP_HANDLE);
|
||||
// CloseHandle(hwrite);
|
||||
// WaitForSingleObject(hthread,INFINITE);
|
||||
// CloseHandle(hread); CloseHandle(hthread);
|
||||
// - finished -
|
||||
// CloseZip(hz);
|
||||
// // note: no need to free resources obtained through Find/Load/LockResource
|
||||
//
|
||||
//
|
||||
// SetCurrentDirectory("c:\\docs\\pipedzipstuff");
|
||||
// HANDLE hread,hwrite; CreatePipe(&hread,&hwrite);
|
||||
// CreateZipWriterThread(hwrite);
|
||||
// HZIP hz = OpenZip(hread,0,ZIP_HANDLE);
|
||||
// for (int i=0; ; i++)
|
||||
// { ZIPENTRY ze; ZRESULT res = GetZipItem(hz,i,&ze);
|
||||
// if (res!=ZE_OK) break; // no more
|
||||
// UnzipItem(hz,i, ze.name,0,ZIP_FILENAME);
|
||||
// }
|
||||
// CloseZip(hz);
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
// Now we indulge in a little skullduggery so that the code works whether
|
||||
// the user has included just zip or both zip and unzip.
|
||||
// Idea: if header files for both zip and unzip are present, then presumably
|
||||
// the cpp files for zip and unzip are both present, so we will call
|
||||
// one or the other of them based on a dynamic choice. If the header file
|
||||
// for only one is present, then we will bind to that particular one.
|
||||
HZIP OpenZipU(void *z,unsigned int len,DWORD flags);
|
||||
ZRESULT CloseZipU(HZIP hz);
|
||||
unsigned int FormatZipMessageU(ZRESULT code, char *buf,unsigned int len);
|
||||
bool IsZipHandleU(HZIP hz);
|
||||
#define OpenZip OpenZipU
|
||||
|
||||
#ifdef XZIP_H
|
||||
#undef CloseZip
|
||||
#define CloseZip(hz) (IsZipHandleU(hz)?CloseZipU(hz):CloseZipZ(hz))
|
||||
#else
|
||||
#define CloseZip CloseZipU
|
||||
#define FormatZipMessage FormatZipMessageU
|
||||
#endif
|
||||
|
||||
|
||||
#endif //XUNZIP_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user