Skip to content
This repository was archived by the owner on Apr 22, 2023. It is now read-only.

Commit 69e3007

Browse files
committed
build: i18n: Autodownload ICU, Intl small-icu by default!
* make `--with-intl=small-icu` the default * Download, verify (md5), unpack ICU's zip if not there * update docs This is to support joyent#7676, Intl by default. There's a "list" of URLs being used, but right now only the first is picked up. The logic works something like this: * if there is no directory `deps/icu`, * if no zip file (currently `icu4c-54_1-src.zip`), * download zip file (icu-project.org -> sf.net) * verify the MD5 sum of the zipfile * if bad, print error and exit * unpack the zipfile into `deps/icu` * if `deps/icu` now exists, use it, else fail with help text Also: * refactor some code into tools/configure.d/nodedownload.py * add `intl-none` option for `vcbuild.bat`
1 parent f6556b6 commit 69e3007

File tree

5 files changed

+122
-11
lines changed

5 files changed

+122
-11
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ ipch/
4646
email.md
4747
deps/v8-*
4848
deps/icu
49+
deps/icu*.zip
50+
deps/icu*.tgz
4951
./node_modules
5052
.svn/
5153

README.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,41 @@ make doc
8383
man doc/node.1
8484
```
8585

86-
### To build `Intl` (ECMA-402) support:
86+
### `Intl` (ECMA-402) support:
8787

88-
*Note:* more docs, including how to reduce disk footprint, are on
88+
The `small-icu` mode is enabled by default. It will build
89+
with English-only data. You can add full data at runtime.
90+
91+
*Note:* more docs are on
8992
[the wiki](https://github.com/joyent/node/wiki/Intl).
9093

94+
#### Build with full ICU support (all locales supported by ICU):
95+
96+
Unix/Macintosh:
97+
98+
```sh
99+
./configure --with-intl=full-icu
100+
```
101+
102+
Windows:
103+
104+
```sh
105+
vcbuild full-icu
106+
```
107+
108+
#### Build with no Intl support `:-(`
109+
110+
```sh
111+
./configure --with-intl=none
112+
```
113+
91114
#### Use existing installed ICU (Unix/Macintosh only):
92115

93116
```sh
94117
pkg-config --modversion icu-i18n && ./configure --with-intl=system-icu
95118
```
96119

97-
#### Build ICU from source:
120+
#### Build with a specific ICU:
98121

99122
First: Unpack latest ICU
100123
[icu4c-**##.#**-src.tgz](http://icu-project.org/download) (or `.zip`)

configure

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@ import re
66
import shlex
77
import subprocess
88
import sys
9+
import urllib
10+
import zipfile
11+
import hashlib
912

1013
CC = os.environ.get('CC', 'cc')
1114

1215
root_dir = os.path.dirname(__file__)
1316
sys.path.insert(0, os.path.join(root_dir, 'tools', 'gyp', 'pylib'))
1417
from gyp.common import GetFlavor
1518

19+
# imports in tools/configure.d
20+
sys.path.insert(0, os.path.join(root_dir, 'tools', 'configure.d'))
21+
import nodedownload
22+
1623
# parse our options
1724
parser = optparse.OptionParser()
1825

@@ -244,7 +251,7 @@ parser.add_option('--with-icu-path',
244251
parser.add_option('--with-intl',
245252
action='store',
246253
dest='with_intl',
247-
help='Intl mode: none, full-icu, small-icu (default is none)')
254+
help='Intl mode: none, full-icu, small-icu (default is small-icu)')
248255

249256
parser.add_option('--with-perfctr',
250257
action='store_true',
@@ -712,6 +719,58 @@ def glob_to_var(dir_base, dir_sub):
712719
return list
713720

714721
def configure_intl(o):
722+
icus = [
723+
{
724+
'url': 'http://download.icu-project.org/files/icu4c/54.1/icu4c-54_1-src.zip',
725+
# from https://ssl.icu-project.org/files/icu4c/54.1/icu4c-src-54_1.md5:
726+
'md5': '6b89d60e2f0e140898ae4d7f72323bca',
727+
},
728+
]
729+
class ConfigOpener(urllib.FancyURLopener):
730+
# append to existing version (UA)
731+
version = '%s (node.js/configure)' % urllib.URLopener.version
732+
def icu_download(path):
733+
# download ICU, if needed
734+
def fmtMb(amt):
735+
return "{:.1f}".format(amt / 1024000.)
736+
def reporthook(count, size, total):
737+
sys.stdout.write(' ICU: %c %sMB total, %sMB downloaded \r' %
738+
(nodedownload.spin(count),
739+
nodedownload.formatSize(total),
740+
nodedownload.formatSize(count*size)))
741+
for icu in icus:
742+
url = icu['url']
743+
md5 = icu['md5']
744+
local = url.split('/')[-1]
745+
targetfile = os.path.join(root_dir, 'deps', local)
746+
if not os.path.isfile(targetfile):
747+
try:
748+
sys.stdout.write(' <%s>\nConnecting...\r' % url)
749+
sys.stdout.flush()
750+
msg = urllib.urlretrieve(url, targetfile, reporthook=reporthook)
751+
print '' # clear the line
752+
except:
753+
print ' ** Error occurred while downloading\n <%s>' % url
754+
raise
755+
else:
756+
print ' Re-using existing %s' % targetfile
757+
if os.path.isfile(targetfile):
758+
digest = hashlib.md5()
759+
count = 0
760+
sys.stdout.write(' Checking file integrity with MD5:\r')
761+
with open(targetfile, 'rb') as f:
762+
chunk = f.read(1024)
763+
while chunk != "":
764+
digest.update(chunk)
765+
chunk = f.read(1024)
766+
gotmd5 = digest.hexdigest()
767+
print ' MD5: %s %s' % (gotmd5, targetfile)
768+
if (md5 == gotmd5):
769+
return targetfile
770+
else:
771+
print ' Expected: %s *MISMATCH*' % md5
772+
print '\n ** Corrupted ZIP? Delete %s to retry download.\n' % targetfile
773+
return None
715774
icu_config = {
716775
'variables': {}
717776
}
@@ -739,6 +798,8 @@ def configure_intl(o):
739798
o['variables']['icu_gyp_path'] = options.with_icu_path
740799
return
741800
# --with-intl=<with_intl>
801+
if with_intl is None:
802+
with_intl = 'small-icu' # The default mode
742803
if with_intl == 'none' or with_intl is None:
743804
o['variables']['v8_enable_i18n_support'] = 0
744805
return # no Intl
@@ -773,16 +834,28 @@ def configure_intl(o):
773834
byteorder = sys.byteorder
774835
o['variables']['icu_gyp_path'] = 'tools/icu/icu-generic.gyp'
775836
# ICU source dir relative to root
776-
icu_full_path = os.path.join(root_dir, 'deps/icu')
837+
icu_parent_path = os.path.join(root_dir, 'deps')
838+
icu_full_path = os.path.join(icu_parent_path, 'icu')
777839
o['variables']['icu_path'] = icu_full_path
778840
if not os.path.isdir(icu_full_path):
779-
print 'Error: ICU path is not a directory: %s' % (icu_full_path)
841+
print '* ECMA-402 (Intl) support didn\'t find ICU in %s..' % (icu_full_path)
842+
# can we download (or find) a zipfile?
843+
localzip = icu_download(icu_full_path)
844+
if localzip:
845+
with zipfile.ZipFile(localzip, 'r') as icuzip:
846+
print ' Extracting ICU source zip: %s' % localzip
847+
icuzip.extractall(icu_parent_path)
848+
if not os.path.isdir(icu_full_path):
849+
print ' Cannot build Intl without ICU in %s.' % (icu_full_path)
850+
print ' (Fix, or disable with "--with-intl=none" )'
780851
sys.exit(1)
852+
else:
853+
print '* Using ICU in %s' % (icu_full_path)
781854
# Now, what version of ICU is it? We just need the "major", such as 54.
782855
# uvernum.h contains it as a #define.
783856
uvernum_h = os.path.join(icu_full_path, 'source/common/unicode/uvernum.h')
784857
if not os.path.isfile(uvernum_h):
785-
print 'Error: could not load %s - is ICU installed?' % uvernum_h
858+
print ' Error: could not load %s - is ICU installed?' % uvernum_h
786859
sys.exit(1)
787860
icu_ver_major = None
788861
matchVerExp = r'^\s*#define\s+U_ICU_VERSION_SHORT\s+"([^"]*)".*'
@@ -792,7 +865,7 @@ def configure_intl(o):
792865
if m:
793866
icu_ver_major = m.group(1)
794867
if not icu_ver_major:
795-
print 'Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h
868+
print ' Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h
796869
sys.exit(1)
797870
icu_endianness = sys.byteorder[0]; # TODO(srl295): EBCDIC should be 'e'
798871
o['variables']['icu_ver_major'] = icu_ver_major
@@ -819,8 +892,8 @@ def configure_intl(o):
819892
# this is the icudt*.dat file which node will be using (platform endianness)
820893
o['variables']['icu_data_file'] = icu_data_file
821894
if not os.path.isfile(icu_data_path):
822-
print 'Error: ICU prebuilt data file %s does not exist.' % icu_data_path
823-
print 'See the README.md.'
895+
print ' Error: ICU prebuilt data file %s does not exist.' % icu_data_path
896+
print ' See the README.md.'
824897
# .. and we're not about to build it from .gyp!
825898
sys.exit(1)
826899
# map from variable name to subdirs

tools/configure.d/nodedownload.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Moved some utilities here from ../../configure
2+
3+
def formatSize(amt):
4+
"""Format a size as a string"""
5+
return "{:.1f}".format(amt / 1024000.)
6+
7+
def spin(c):
8+
"""print out a spinner based on 'c'"""
9+
# spin = "\\|/-"
10+
spin = ".:|'"
11+
return (spin[c % len(spin)])

vcbuild.bat

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ if /i "%1"=="upload" set upload=1&goto arg-ok
6565
if /i "%1"=="jslint" set jslint=1&goto arg-ok
6666
if /i "%1"=="small-icu" set i18n_arg=%1&goto arg-ok
6767
if /i "%1"=="full-icu" set i18n_arg=%1&goto arg-ok
68+
if /i "%1"=="intl-none" set i18n_arg=%1&goto arg-ok
6869

6970
echo Warning: ignoring invalid command line option `%1`.
7071

@@ -85,6 +86,7 @@ if defined noperfctr set noperfctr_arg=--without-perfctr& set noperfctr_msi_arg=
8586

8687
if "%i18n_arg%"=="full-icu" set i18n_arg=--with-intl=full-icu
8788
if "%i18n_arg%"=="small-icu" set i18n_arg=--with-intl=small-icu
89+
if "%i18n_arg%"=="intl-none" set i18n_arg=--with-intl=none
8890

8991
:project-gen
9092
@rem Skip project generation if requested.
@@ -232,7 +234,7 @@ python tools/closure_linter/closure_linter/gjslint.py --unix_mode --strict --noj
232234
goto exit
233235

234236
:help
235-
echo vcbuild.bat [debug/release] [msi] [test-all/test-uv/test-internet/test-pummel/test-simple/test-message] [clean] [noprojgen] [nobuild] [nosign] [x86/x64]
237+
echo vcbuild.bat [debug/release] [msi] [test-all/test-uv/test-internet/test-pummel/test-simple/test-message] [clean] [noprojgen] [small-icu/full-icu/intl-none] [nobuild] [nosign] [x86/x64]
236238
echo Examples:
237239
echo vcbuild.bat : builds release build
238240
echo vcbuild.bat debug : builds debug build

0 commit comments

Comments
 (0)