173 lines
5.8 KiB
Python
173 lines
5.8 KiB
Python
|
#!/usr/bin/env python
|
||
|
#
|
||
|
# Any copyright is dedicated to the Public Domain.
|
||
|
# http://creativecommons.org/publicdomain/zero/1.0/
|
||
|
#
|
||
|
# Generate SOURCES in sources.mozbuild files from ICU's Makefile.in
|
||
|
# files, and also build a standalone copy of ICU using its build
|
||
|
# system to generate a new copy of the in-tree ICU data file.
|
||
|
#
|
||
|
# This script expects to be run from `update-icu.sh` after the in-tree
|
||
|
# copy of ICU has been updated.
|
||
|
|
||
|
from __future__ import print_function
|
||
|
|
||
|
import glob
|
||
|
import os
|
||
|
import shutil
|
||
|
import subprocess
|
||
|
import sys
|
||
|
import tempfile
|
||
|
|
||
|
from mozpack import path as mozpath
|
||
|
|
||
|
|
||
|
def find_source_file(dir, filename):
|
||
|
base = os.path.splitext(filename)[0]
|
||
|
for ext in ('.cpp', '.c'):
|
||
|
f = mozpath.join(dir, base + ext)
|
||
|
if os.path.isfile(f):
|
||
|
return f
|
||
|
raise Exception("Couldn't find source file for: %s" % filename)
|
||
|
|
||
|
|
||
|
def get_sources_from_makefile(makefile):
|
||
|
import pymake.parser
|
||
|
from pymake.parserdata import SetVariable
|
||
|
srcdir = os.path.dirname(makefile)
|
||
|
for statement in pymake.parser.parsefile(makefile):
|
||
|
if (isinstance(statement, SetVariable) and
|
||
|
statement.vnameexp.is_static_string and
|
||
|
statement.vnameexp.s == 'OBJECTS'):
|
||
|
return sorted((find_source_file(srcdir, s)
|
||
|
for s in statement.value.split()),
|
||
|
key=lambda x: x.lower())
|
||
|
|
||
|
|
||
|
def list_headers(path):
|
||
|
result = []
|
||
|
for name in os.listdir(path):
|
||
|
f = mozpath.join(path, name)
|
||
|
if os.path.isfile(f):
|
||
|
result.append(f)
|
||
|
return sorted(result, key=lambda x: x.lower())
|
||
|
|
||
|
|
||
|
def write_sources(mozbuild, sources, headers):
|
||
|
with open(mozbuild, 'wb') as f:
|
||
|
f.write('# THIS FILE IS GENERATED BY /intl/icu_sources_data.py ' +
|
||
|
'DO NOT EDIT\n' +
|
||
|
'SOURCES += [\n')
|
||
|
f.write(''.join(" '/%s',\n" % s for s in sources))
|
||
|
f.write(']\n\n')
|
||
|
f.write('EXPORTS.unicode += [\n')
|
||
|
f.write(''.join(" '/%s',\n" % s for s in headers))
|
||
|
f.write(']\n')
|
||
|
|
||
|
|
||
|
def update_sources(topsrcdir):
|
||
|
print('Updating ICU sources lists...')
|
||
|
sys.path.append(mozpath.join(topsrcdir, 'build/pymake'))
|
||
|
for d in ['common', 'i18n']:
|
||
|
base_path = mozpath.join(topsrcdir, 'intl/icu/source/%s' % d)
|
||
|
makefile = mozpath.join(base_path, 'Makefile.in')
|
||
|
mozbuild = mozpath.join(topsrcdir,
|
||
|
'config/external/icu/%s/sources.mozbuild' % d)
|
||
|
sources = [mozpath.relpath(s, topsrcdir)
|
||
|
for s in get_sources_from_makefile(makefile)]
|
||
|
headers = [mozpath.normsep(os.path.relpath(s, topsrcdir))
|
||
|
for s in list_headers(mozpath.join(base_path, 'unicode'))]
|
||
|
write_sources(mozbuild, sources, headers)
|
||
|
|
||
|
|
||
|
def try_run(name, command, cwd=None, **kwargs):
|
||
|
try:
|
||
|
with tempfile.NamedTemporaryFile(prefix=name, delete=False) as f:
|
||
|
subprocess.check_call(command, cwd=cwd, stdout=f,
|
||
|
stderr=subprocess.STDOUT, **kwargs)
|
||
|
except subprocess.CalledProcessError:
|
||
|
print('''Error running "{}" in directory {}
|
||
|
See output in {}'''.format(' '.join(command), cwd, f.name),
|
||
|
file=sys.stderr)
|
||
|
return False
|
||
|
else:
|
||
|
os.unlink(f.name)
|
||
|
return True
|
||
|
|
||
|
|
||
|
def get_data_file(data_dir):
|
||
|
files = glob.glob(mozpath.join(data_dir, 'icudt*.dat'))
|
||
|
return files[0] if files else None
|
||
|
|
||
|
|
||
|
def update_data_file(topsrcdir):
|
||
|
objdir = tempfile.mkdtemp(prefix='icu-obj-')
|
||
|
configure = mozpath.join(topsrcdir, 'intl/icu/source/configure')
|
||
|
env = dict(os.environ)
|
||
|
# bug 1262101 - these should be shared with the moz.build files
|
||
|
env.update({
|
||
|
'CPPFLAGS': ('-DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 ' +
|
||
|
'-DUCONFIG_NO_LEGACY_CONVERSION ' +
|
||
|
'-DUCONFIG_NO_TRANSLITERATION ' +
|
||
|
'-DUCONFIG_NO_REGULAR_EXPRESSIONS ' +
|
||
|
'-DUCONFIG_NO_BREAK_ITERATION ' +
|
||
|
'-DU_CHARSET_IS_UTF8')
|
||
|
})
|
||
|
print('Running ICU configure...')
|
||
|
if not try_run(
|
||
|
'icu-configure',
|
||
|
['sh', configure,
|
||
|
'--with-data-packaging=archive',
|
||
|
'--enable-static',
|
||
|
'--disable-shared',
|
||
|
'--disable-extras',
|
||
|
'--disable-icuio',
|
||
|
'--disable-layout',
|
||
|
'--disable-tests',
|
||
|
'--disable-samples',
|
||
|
'--disable-strict'],
|
||
|
cwd=objdir,
|
||
|
env=env):
|
||
|
return False
|
||
|
print('Running ICU make...')
|
||
|
if not try_run('icu-make', ['make'], cwd=objdir):
|
||
|
return False
|
||
|
print('Copying ICU data file...')
|
||
|
tree_data_path = mozpath.join(topsrcdir,
|
||
|
'config/external/icu/data/')
|
||
|
old_data_file = get_data_file(tree_data_path)
|
||
|
if not old_data_file:
|
||
|
print('Error: no ICU data file in %s' % tree_data_path,
|
||
|
file=sys.stderr)
|
||
|
return False
|
||
|
new_data_file = get_data_file(mozpath.join(objdir, 'data/out'))
|
||
|
if not new_data_file:
|
||
|
print('Error: no ICU data in ICU objdir', file=sys.stderr)
|
||
|
return False
|
||
|
if os.path.basename(old_data_file) != os.path.basename(new_data_file):
|
||
|
# Data file name has the major version number embedded.
|
||
|
os.unlink(old_data_file)
|
||
|
shutil.copy(new_data_file, tree_data_path)
|
||
|
try:
|
||
|
shutil.rmtree(objdir)
|
||
|
except:
|
||
|
print('Warning: failed to remove %s' % objdir, file=sys.stderr)
|
||
|
return True
|
||
|
|
||
|
|
||
|
def main():
|
||
|
if len(sys.argv) != 2:
|
||
|
print('Usage: icu_sources_data.py <mozilla topsrcdir>',
|
||
|
file=sys.stderr)
|
||
|
sys.exit(1)
|
||
|
|
||
|
topsrcdir = mozpath.abspath(sys.argv[1])
|
||
|
update_sources(topsrcdir)
|
||
|
if not update_data_file(topsrcdir):
|
||
|
print('Error updating ICU data file', file=sys.stderr)
|
||
|
sys.exit(1)
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|