Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / build_tools / build_sdk.py
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Entry point for both build and try bots.
7
8 This script is invoked from XXX, usually without arguments
9 to package an SDK. It automatically determines whether
10 this SDK is for mac, win, linux.
11
12 The script inspects the following environment variables:
13
14 BUILDBOT_BUILDERNAME to determine whether the script is run locally
15 and whether it should upload an SDK to file storage (GSTORE)
16 """
17
18 # pylint: disable=W0621
19
20 # std python includes
21 import datetime
22 import glob
23 import optparse
24 import os
25 import re
26 import sys
27
28 if sys.version_info < (2, 6, 0):
29   sys.stderr.write("python 2.6 or later is required run this script\n")
30   sys.exit(1)
31
32 # local includes
33 import buildbot_common
34 import build_projects
35 import build_updater
36 import build_version
37 import generate_make
38 import generate_notice
39 import manifest_util
40 import parse_dsc
41 import verify_filelist
42
43 from build_paths import SCRIPT_DIR, SDK_SRC_DIR, SRC_DIR, NACL_DIR, OUT_DIR
44 from build_paths import NACLPORTS_DIR, GSTORE, GONACL_APPENGINE_SRC_DIR
45
46 # Add SDK make tools scripts to the python path.
47 sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
48 sys.path.append(os.path.join(NACL_DIR, 'build'))
49
50 import getos
51 import oshelpers
52
53 CYGTAR = os.path.join(NACL_DIR, 'build', 'cygtar.py')
54
55 NACLPORTS_URL = 'https://naclports.googlecode.com/svn/trunk/src'
56 NACLPORTS_REV = 954
57
58 GYPBUILD_DIR = 'gypbuild'
59
60 options = None
61
62
63 def GetGlibcToolchain():
64   tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
65   tcname = 'toolchain_%s_x86.tar.bz2' % getos.GetPlatform()
66   return os.path.join(tcdir, tcname)
67
68
69 def GetNewlibToolchain():
70   tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
71   tcname = 'naclsdk_%s_x86.tgz' % getos.GetPlatform()
72   return os.path.join(tcdir, tcname)
73
74
75 def GetBionicToolchain():
76   tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
77   tcname = 'naclsdk_%s_arm_bionic.tgz' % getos.GetPlatform()
78   return os.path.join(tcdir, tcname)
79
80
81 def GetPNaClToolchain():
82   tcdir = os.path.join(NACL_DIR, 'toolchain', '.tars')
83   tcname = 'naclsdk_pnacl_%s_x86.tgz' % getos.GetPlatform()
84   return os.path.join(tcdir, tcname)
85
86
87 def GetToolchainNaClInclude(tcname, tcpath, arch):
88   if arch == 'x86':
89     if tcname == 'pnacl':
90       return os.path.join(tcpath, 'sdk', 'include')
91     return os.path.join(tcpath, 'x86_64-nacl', 'include')
92   elif arch == 'arm':
93     return os.path.join(tcpath, 'arm-nacl', 'include')
94   else:
95     buildbot_common.ErrorExit('Unknown architecture: %s' % arch)
96
97
98 def GetGypGenDir(xarch):
99   if xarch == 'arm':
100     build_dir = GYPBUILD_DIR + '-arm'
101   else:
102     build_dir = GYPBUILD_DIR
103   return os.path.join(OUT_DIR, build_dir, 'Release', 'gen')
104
105
106 def GetGypBuiltLib(tcname, xarch=None):
107   if tcname == 'pnacl':
108     tcname = 'pnacl_newlib'
109   if not xarch:
110     xarch = ''
111   return os.path.join(GetGypGenDir(xarch), 'tc_' + tcname, 'lib' + xarch)
112
113
114 def GetToolchainNaClLib(tcname, tcpath, xarch):
115   if tcname == 'pnacl':
116     return os.path.join(tcpath, 'sdk', 'lib')
117   elif xarch == '32':
118     return os.path.join(tcpath, 'x86_64-nacl', 'lib32')
119   elif xarch == '64':
120     return os.path.join(tcpath, 'x86_64-nacl', 'lib')
121   elif xarch == 'arm':
122     return os.path.join(tcpath, 'arm-nacl', 'lib')
123
124
125 def GetToolchainDirName(tcname, xarch):
126   if tcname == 'pnacl':
127     return '%s_%s' % (getos.GetPlatform(), tcname)
128   elif xarch == 'arm':
129     return '%s_arm_%s' % (getos.GetPlatform(), tcname)
130   else:
131     return '%s_x86_%s' % (getos.GetPlatform(), tcname)
132
133
134 def GetGypToolchainLib(tcname, xarch):
135   tcpath = os.path.join(GetGypGenDir(xarch), 'sdk', 'toolchain',
136                         GetToolchainDirName(tcname, xarch))
137   return GetToolchainNaClLib(tcname, tcpath, xarch)
138
139
140 def GetOutputToolchainLib(pepperdir, tcname, xarch):
141   tcpath = os.path.join(pepperdir, 'toolchain',
142                         GetToolchainDirName(tcname, xarch))
143   return GetToolchainNaClLib(tcname, tcpath, xarch)
144
145
146 def GetPNaClNativeLib(tcpath, arch):
147   if arch not in ['arm', 'x86-32', 'x86-64']:
148     buildbot_common.ErrorExit('Unknown architecture %s.' % arch)
149   return os.path.join(tcpath, 'lib-' + arch)
150
151
152 def BuildStepDownloadToolchains(toolchains):
153   buildbot_common.BuildStep('Running download_toolchains.py')
154   download_script = os.path.join('build', 'download_toolchains.py')
155   args = [sys.executable, download_script, '--no-arm-trusted',
156           '--arm-untrusted', '--keep']
157   if 'bionic' in toolchains:
158     args.append('--allow-bionic')
159   buildbot_common.Run(args, cwd=NACL_DIR)
160
161
162 def BuildStepCleanPepperDirs(pepperdir, pepperdir_old):
163   buildbot_common.BuildStep('Clean Pepper Dirs')
164   buildbot_common.RemoveDir(pepperdir_old)
165   buildbot_common.RemoveDir(pepperdir)
166   buildbot_common.MakeDir(pepperdir)
167
168
169 def BuildStepMakePepperDirs(pepperdir, subdirs):
170   for subdir in subdirs:
171     buildbot_common.MakeDir(os.path.join(pepperdir, subdir))
172
173 TEXT_FILES = [
174   'AUTHORS',
175   'COPYING',
176   'LICENSE',
177   'README.Makefiles',
178   'getting_started/README',
179 ]
180
181 def BuildStepCopyTextFiles(pepperdir, pepper_ver, chrome_revision,
182                            nacl_revision):
183   buildbot_common.BuildStep('Add Text Files')
184   InstallFiles(SDK_SRC_DIR, pepperdir, TEXT_FILES)
185
186   # Replace a few placeholders in README
187   readme_text = open(os.path.join(SDK_SRC_DIR, 'README')).read()
188   readme_text = readme_text.replace('${VERSION}', pepper_ver)
189   readme_text = readme_text.replace('${CHROME_REVISION}', chrome_revision)
190   readme_text = readme_text.replace('${NACL_REVISION}', nacl_revision)
191
192   # Year/Month/Day Hour:Minute:Second
193   time_format = '%Y/%m/%d %H:%M:%S'
194   readme_text = readme_text.replace('${DATE}',
195       datetime.datetime.now().strftime(time_format))
196
197   open(os.path.join(pepperdir, 'README'), 'w').write(readme_text)
198
199
200 def PrunePNaClToolchain(root):
201   dirs_to_prune = [
202     'lib-bc-x86-64',
203     'usr-bc-x86-64'
204     # TODO(sbc): remove this once its really not needed.
205     # Currently we seem to rely on it at least for <bits/stat.h>
206     #'sysroot',
207   ]
208   for dirname in dirs_to_prune:
209     buildbot_common.RemoveDir(os.path.join(root, dirname))
210
211
212 def BuildStepUntarToolchains(pepperdir, toolchains):
213   buildbot_common.BuildStep('Untar Toolchains')
214   platform = getos.GetPlatform()
215   tmpdir = os.path.join(OUT_DIR, 'tc_temp')
216   buildbot_common.RemoveDir(tmpdir)
217   buildbot_common.MakeDir(tmpdir)
218
219   if 'newlib' in toolchains:
220     # Untar the newlib toolchains
221     tarfile = GetNewlibToolchain()
222     buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
223                         cwd=NACL_DIR)
224
225     # Then rename/move it to the pepper toolchain directory
226     srcdir = os.path.join(tmpdir, 'sdk', 'nacl-sdk')
227     tcname = platform + '_x86_newlib'
228     newlibdir = os.path.join(pepperdir, 'toolchain', tcname)
229     buildbot_common.Move(srcdir, newlibdir)
230
231   if 'bionic' in toolchains:
232     # Untar the bionic toolchains
233     tarfile = GetBionicToolchain()
234     tcname = platform + '_arm_bionic'
235     buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
236                         cwd=NACL_DIR)
237     srcdir = os.path.join(tmpdir, tcname)
238     bionicdir = os.path.join(pepperdir, 'toolchain', tcname)
239     buildbot_common.Move(srcdir, bionicdir)
240
241   if 'arm' in toolchains:
242     # Copy the existing arm toolchain from native_client tree
243     tcname = platform + '_arm_newlib'
244     arm_toolchain = os.path.join(NACL_DIR, 'toolchain', tcname)
245     arm_toolchain_sdk = os.path.join(pepperdir, 'toolchain',
246                                      os.path.basename(arm_toolchain))
247     buildbot_common.CopyDir(arm_toolchain, arm_toolchain_sdk)
248
249   if 'glibc' in toolchains:
250     # Untar the glibc toolchains
251     tarfile = GetGlibcToolchain()
252     tcname = platform + '_x86_glibc'
253     buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
254                         cwd=NACL_DIR)
255
256     # Then rename/move it to the pepper toolchain directory
257     srcdir = os.path.join(tmpdir, 'toolchain', platform + '_x86')
258     glibcdir = os.path.join(pepperdir, 'toolchain', tcname)
259     buildbot_common.Move(srcdir, glibcdir)
260
261   # Untar the pnacl toolchains
262   if 'pnacl' in toolchains:
263     tmpdir = os.path.join(tmpdir, 'pnacl')
264     buildbot_common.RemoveDir(tmpdir)
265     buildbot_common.MakeDir(tmpdir)
266     tarfile = GetPNaClToolchain()
267     tcname = platform + '_pnacl'
268     buildbot_common.Run([sys.executable, CYGTAR, '-C', tmpdir, '-xf', tarfile],
269                         cwd=NACL_DIR)
270
271     # Then rename/move it to the pepper toolchain directory
272     pnacldir = os.path.join(pepperdir, 'toolchain', tcname)
273     buildbot_common.Move(tmpdir, pnacldir)
274     PrunePNaClToolchain(pnacldir)
275
276   buildbot_common.RemoveDir(tmpdir)
277
278   if options.gyp and platform != 'win':
279     # If the gyp options is specified we install a toolchain
280     # wrapper so that gyp can switch toolchains via a commandline
281     # option.
282     bindir = os.path.join(pepperdir, 'toolchain', tcname, 'bin')
283     wrapper = os.path.join(SDK_SRC_DIR, 'tools', 'compiler-wrapper.py')
284     buildbot_common.MakeDir(bindir)
285     buildbot_common.CopyFile(wrapper, bindir)
286
287     # Module 'os' has no 'symlink' member (on Windows).
288     # pylint: disable=E1101
289
290     os.symlink('compiler-wrapper.py', os.path.join(bindir, 'i686-nacl-g++'))
291     os.symlink('compiler-wrapper.py', os.path.join(bindir, 'i686-nacl-gcc'))
292     os.symlink('compiler-wrapper.py', os.path.join(bindir, 'i686-nacl-ar'))
293
294
295 # List of toolchain headers to install.
296 # Source is relative to top of Chromium tree, destination is relative
297 # to the toolchain header directory.
298 NACL_HEADER_MAP = {
299   'newlib': [
300       ('native_client/src/include/nacl/nacl_exception.h', 'nacl/'),
301       ('native_client/src/include/nacl/nacl_minidump.h', 'nacl/'),
302       ('native_client/src/untrusted/irt/irt.h', ''),
303       ('native_client/src/untrusted/irt/irt_dev.h', ''),
304       ('native_client/src/untrusted/nacl/nacl_dyncode.h', 'nacl/'),
305       ('native_client/src/untrusted/nacl/nacl_startup.h', 'nacl/'),
306       ('native_client/src/untrusted/nacl/nacl_thread.h', 'nacl/'),
307       ('native_client/src/untrusted/pthread/pthread.h', ''),
308       ('native_client/src/untrusted/pthread/semaphore.h', ''),
309       ('native_client/src/untrusted/valgrind/dynamic_annotations.h', 'nacl/'),
310       ('ppapi/nacl_irt/irt_ppapi.h', ''),
311   ],
312   'glibc': [
313       ('native_client/src/include/nacl/nacl_exception.h', 'nacl/'),
314       ('native_client/src/include/nacl/nacl_minidump.h', 'nacl/'),
315       ('native_client/src/untrusted/irt/irt.h', ''),
316       ('native_client/src/untrusted/irt/irt_dev.h', ''),
317       ('native_client/src/untrusted/nacl/nacl_dyncode.h', 'nacl/'),
318       ('native_client/src/untrusted/nacl/nacl_startup.h', 'nacl/'),
319       ('native_client/src/untrusted/nacl/nacl_thread.h', 'nacl/'),
320       ('native_client/src/untrusted/valgrind/dynamic_annotations.h', 'nacl/'),
321       ('ppapi/nacl_irt/irt_ppapi.h', ''),
322   ],
323   'host': []
324 }
325
326 def InstallFiles(src_root, dest_root, file_list):
327   """Copy a set of files from src_root to dest_root according
328   to the given mapping.  This allows files to be copied from
329   to a location in the destination tree that is different to the
330   location in the source tree.
331
332   If the destination mapping ends with a '/' then the destination
333   basename is inherited from the the source file.
334
335   Wildcards can be used in the source list but it is not recommended
336   as this can end up adding things to the SDK unintentionally.
337   """
338   for file_spec in file_list:
339     # The list of files to install can be a simple list of
340     # strings or a list of pairs, where each pair corresponds
341     # to a mapping from source to destination names.
342     if type(file_spec) == str:
343       src_file = dest_file = file_spec
344     else:
345       src_file, dest_file = file_spec
346
347     src_file = os.path.join(src_root, src_file)
348
349     # Expand sources files using glob.
350     sources = glob.glob(src_file)
351     if not sources:
352       sources = [src_file]
353
354     if len(sources) > 1 and not dest_file.endswith('/'):
355       buildbot_common.ErrorExit("Target file must end in '/' when "
356                                 "using globbing to install multiple files")
357
358     for source in sources:
359       if dest_file.endswith('/'):
360         dest = os.path.join(dest_file, os.path.basename(source))
361       else:
362         dest = dest_file
363       dest = os.path.join(dest_root, dest)
364       if not os.path.isdir(os.path.dirname(dest)):
365         buildbot_common.MakeDir(os.path.dirname(dest))
366       buildbot_common.CopyFile(source, dest)
367
368
369 def InstallNaClHeaders(tc_dst_inc, tc_name):
370   """Copies NaCl headers to expected locations in the toolchain."""
371   if tc_name == 'arm':
372     # arm toolchain header should be the same as the x86 newlib
373     # ones
374     tc_name = 'newlib'
375
376   InstallFiles(SRC_DIR, tc_dst_inc, NACL_HEADER_MAP[tc_name])
377
378
379 def MakeNinjaRelPath(path):
380   return os.path.join(os.path.relpath(OUT_DIR, SRC_DIR), path)
381
382
383 TOOLCHAIN_LIBS = {
384   'newlib' : [
385     'crti.o',
386     'crtn.o',
387     'libminidump_generator.a',
388     'libnacl.a',
389     'libnacl_dyncode.a',
390     'libnacl_exception.a',
391     'libnacl_list_mappings.a',
392     'libnosys.a',
393     'libppapi.a',
394     'libppapi_stub.a',
395     'libpthread.a',
396   ],
397   'glibc': [
398     'libminidump_generator.a',
399     'libminidump_generator.so',
400     'libnacl.a',
401     'libnacl_dyncode.a',
402     'libnacl_dyncode.so',
403     'libnacl_exception.a',
404     'libnacl_exception.so',
405     'libnacl_list_mappings.a',
406     'libnacl_list_mappings.so',
407     'libppapi.a',
408     'libppapi.so',
409     'libppapi_stub.a',
410   ],
411   'pnacl': [
412     'libminidump_generator.a',
413     'libnacl.a',
414     'libnacl_dyncode.a',
415     'libnacl_exception.a',
416     'libnacl_list_mappings.a',
417     'libnosys.a',
418     'libppapi.a',
419     'libppapi_stub.a',
420     'libpthread.a',
421   ]
422 }
423
424
425 def GypNinjaInstall(pepperdir, toolchains):
426   build_dir = GYPBUILD_DIR
427   ninja_out_dir = os.path.join(OUT_DIR, build_dir, 'Release')
428   tools_files = [
429     ['sel_ldr', 'sel_ldr_x86_32'],
430     ['ncval_new', 'ncval'],
431     ['irt_core_newlib_x32.nexe', 'irt_core_x86_32.nexe'],
432     ['irt_core_newlib_x64.nexe', 'irt_core_x86_64.nexe'],
433   ]
434
435   platform = getos.GetPlatform()
436
437   # TODO(binji): dump_syms doesn't currently build on Windows. See
438   # http://crbug.com/245456
439   if platform != 'win':
440     tools_files += [
441       ['dump_syms', 'dump_syms'],
442       ['minidump_dump', 'minidump_dump'],
443       ['minidump_stackwalk', 'minidump_stackwalk']
444     ]
445
446   tools_files.append(['sel_ldr64', 'sel_ldr_x86_64'])
447
448   if platform == 'linux':
449     tools_files.append(['nacl_helper_bootstrap',
450                         'nacl_helper_bootstrap_x86_32'])
451     tools_files.append(['nacl_helper_bootstrap64',
452                         'nacl_helper_bootstrap_x86_64'])
453
454   buildbot_common.MakeDir(os.path.join(pepperdir, 'tools'))
455
456   # Add .exe extensions to all windows tools
457   for pair in tools_files:
458     if platform == 'win' and not pair[0].endswith('.nexe'):
459       pair[0] += '.exe'
460       pair[1] += '.exe'
461
462   InstallFiles(ninja_out_dir, os.path.join(pepperdir, 'tools'), tools_files)
463
464   for tc in set(toolchains) & set(['newlib', 'glibc', 'pnacl']):
465     if tc == 'pnacl':
466       xarches = (None,)
467     else:
468       xarches = ('arm', '32', '64')
469
470     for xarch in xarches:
471       if tc == 'glibc' and xarch == 'arm':
472         continue
473
474       src_dir = GetGypBuiltLib(tc, xarch)
475       dst_dir = GetOutputToolchainLib(pepperdir, tc, xarch)
476       InstallFiles(src_dir, dst_dir, TOOLCHAIN_LIBS[tc])
477
478       if tc != 'pnacl':
479         src_dir = GetGypToolchainLib(tc, xarch)
480         InstallFiles(src_dir, dst_dir, ['crt1.o'])
481
482
483 def GypNinjaBuild_NaCl(rel_out_dir):
484   gyp_py = os.path.join(NACL_DIR, 'build', 'gyp_nacl')
485   nacl_core_sdk_gyp = os.path.join(NACL_DIR, 'build', 'nacl_core_sdk.gyp')
486   all_gyp = os.path.join(NACL_DIR, 'build', 'all.gyp')
487
488   out_dir = MakeNinjaRelPath(rel_out_dir)
489   out_dir_arm = MakeNinjaRelPath(rel_out_dir + '-arm')
490   GypNinjaBuild('ia32', gyp_py, nacl_core_sdk_gyp, 'nacl_core_sdk', out_dir)
491   GypNinjaBuild('arm', gyp_py, nacl_core_sdk_gyp, 'nacl_core_sdk', out_dir_arm)
492   GypNinjaBuild('ia32', gyp_py, all_gyp, 'ncval_new', out_dir)
493
494   platform = getos.GetPlatform()
495   if platform == 'win':
496     NinjaBuild('sel_ldr64', out_dir)
497   else:
498     out_dir_64 = MakeNinjaRelPath(rel_out_dir + '-64')
499     GypNinjaBuild('x64', gyp_py, nacl_core_sdk_gyp, 'sel_ldr', out_dir_64)
500
501     # We only need sel_ldr from the 64-bit out directory.
502     # sel_ldr needs to be renamed, so we'll call it sel_ldr64.
503     files_to_copy = [('sel_ldr', 'sel_ldr64')]
504     if platform == 'linux':
505       files_to_copy.append(('nacl_helper_bootstrap', 'nacl_helper_bootstrap64'))
506
507     for src, dst in files_to_copy:
508       buildbot_common.CopyFile(
509           os.path.join(SRC_DIR, out_dir_64, 'Release', src),
510           os.path.join(SRC_DIR, out_dir, 'Release', dst))
511
512
513 def GypNinjaBuild_Breakpad(rel_out_dir):
514   # TODO(binji): dump_syms doesn't currently build on Windows. See
515   # http://crbug.com/245456
516   if getos.GetPlatform() == 'win':
517     return
518
519   gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium')
520   out_dir = MakeNinjaRelPath(rel_out_dir)
521   gyp_file = os.path.join(SRC_DIR, 'breakpad', 'breakpad.gyp')
522   build_list = ['dump_syms', 'minidump_dump', 'minidump_stackwalk']
523   GypNinjaBuild('ia32', gyp_py, gyp_file, build_list, out_dir)
524
525
526 def GypNinjaBuild_PPAPI(arch, rel_out_dir):
527   gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium')
528   out_dir = MakeNinjaRelPath(rel_out_dir)
529   gyp_file = os.path.join(SRC_DIR, 'ppapi', 'native_client',
530                           'native_client.gyp')
531   GypNinjaBuild(arch, gyp_py, gyp_file, 'ppapi_lib', out_dir)
532
533
534 def GypNinjaBuild_Pnacl(rel_out_dir, target_arch):
535   # TODO(binji): This will build the pnacl_irt_shim twice; once as part of the
536   # Chromium build, and once here. When we move more of the SDK build process
537   # to gyp, we can remove this.
538   gyp_py = os.path.join(SRC_DIR, 'build', 'gyp_chromium')
539
540   out_dir = MakeNinjaRelPath(rel_out_dir)
541   gyp_file = os.path.join(SRC_DIR, 'ppapi', 'native_client', 'src',
542                           'untrusted', 'pnacl_irt_shim', 'pnacl_irt_shim.gyp')
543   targets = ['pnacl_irt_shim']
544   GypNinjaBuild(target_arch, gyp_py, gyp_file, targets, out_dir, False)
545
546
547 def GypNinjaBuild(arch, gyp_py_script, gyp_file, targets,
548                   out_dir, force_arm_gcc=True):
549   gyp_env = dict(os.environ)
550   gyp_env['GYP_GENERATORS'] = 'ninja'
551   gyp_defines = []
552   if options.mac_sdk:
553     gyp_defines.append('mac_sdk=%s' % options.mac_sdk)
554   if arch:
555     gyp_defines.append('target_arch=%s' % arch)
556     if arch == 'arm':
557       if getos.GetPlatform() == 'linux':
558         if os.path.exists("/usr/bin/arm-linux-gnueabihf-gcc"):
559           # TODO(sbc): make this conditional once all our linux
560           # have the ARM cross compiler installed.
561           gyp_env['CC'] = 'arm-linux-gnueabihf-gcc'
562           gyp_env['CXX'] = 'arm-linux-gnueabihf-g++'
563           gyp_env['AR'] = 'arm-linux-gnueabihf-ar'
564           gyp_env['AS'] = 'arm-linux-gnueabihf-as'
565           gyp_env['CC_host'] = 'cc'
566           gyp_env['CXX_host'] = 'c++'
567       gyp_defines += ['armv7=1', 'arm_thumb=0', 'arm_neon=1',
568           'arm_float_abi=hard']
569       if force_arm_gcc:
570         gyp_defines.append('nacl_enable_arm_gcc=1')
571   if getos.GetPlatform() == 'mac':
572     gyp_defines.append('clang=1')
573
574   gyp_env['GYP_DEFINES'] = ' '.join(gyp_defines)
575   for key in ['GYP_GENERATORS', 'GYP_DEFINES', 'CC']:
576     value = gyp_env.get(key)
577     if value is not None:
578       print '%s="%s"' % (key, value)
579   gyp_generator_flags = ['-G', 'output_dir=%s' % (out_dir,)]
580   gyp_depth = '--depth=.'
581   buildbot_common.Run(
582       [sys.executable, gyp_py_script, gyp_file, gyp_depth] + \
583           gyp_generator_flags,
584       cwd=SRC_DIR,
585       env=gyp_env)
586   NinjaBuild(targets, out_dir)
587
588
589 def NinjaBuild(targets, out_dir):
590   if type(targets) is not list:
591     targets = [targets]
592   out_config_dir = os.path.join(out_dir, 'Release')
593   buildbot_common.Run(['ninja', '-C', out_config_dir] + targets, cwd=SRC_DIR)
594
595
596 def BuildStepBuildToolchains(pepperdir, toolchains):
597   buildbot_common.BuildStep('SDK Items')
598
599   GypNinjaBuild_NaCl(GYPBUILD_DIR)
600   GypNinjaBuild_Breakpad(GYPBUILD_DIR)
601
602   platform = getos.GetPlatform()
603   newlibdir = os.path.join(pepperdir, 'toolchain', platform + '_x86_newlib')
604   glibcdir = os.path.join(pepperdir, 'toolchain', platform + '_x86_glibc')
605   armdir = os.path.join(pepperdir, 'toolchain', platform + '_arm_newlib')
606   pnacldir = os.path.join(pepperdir, 'toolchain', platform + '_pnacl')
607
608   if set(toolchains) & set(['glibc', 'newlib']):
609     GypNinjaBuild_PPAPI('ia32', GYPBUILD_DIR)
610
611   if 'arm' in toolchains:
612     GypNinjaBuild_PPAPI('arm', GYPBUILD_DIR + '-arm')
613
614   GypNinjaInstall(pepperdir, toolchains)
615
616   if 'newlib' in toolchains:
617     InstallNaClHeaders(GetToolchainNaClInclude('newlib', newlibdir, 'x86'),
618                        'newlib')
619
620   if 'glibc' in toolchains:
621     InstallNaClHeaders(GetToolchainNaClInclude('glibc', glibcdir, 'x86'),
622                        'glibc')
623
624   if 'arm' in toolchains:
625     InstallNaClHeaders(GetToolchainNaClInclude('newlib', armdir, 'arm'),
626                        'arm')
627
628   if 'pnacl' in toolchains:
629     # NOTE: For ia32, gyp builds both x86-32 and x86-64 by default.
630     for arch in ('ia32', 'arm'):
631       # Fill in the latest native pnacl shim library from the chrome build.
632       build_dir = GYPBUILD_DIR + '-pnacl-' + arch
633       GypNinjaBuild_Pnacl(build_dir, arch)
634       if arch == 'ia32':
635         nacl_arches = ['x86-32', 'x86-64']
636       elif arch == 'arm':
637         nacl_arches = ['arm']
638       else:
639         buildbot_common.ErrorExit('Unknown architecture: %s' % arch)
640       for nacl_arch in nacl_arches:
641         release_build_dir = os.path.join(OUT_DIR, build_dir, 'Release',
642                                          'gen', 'tc_pnacl_translate',
643                                          'lib-' + nacl_arch)
644
645         buildbot_common.CopyFile(
646             os.path.join(release_build_dir, 'libpnacl_irt_shim.a'),
647             GetPNaClNativeLib(pnacldir, nacl_arch))
648
649     InstallNaClHeaders(GetToolchainNaClInclude('pnacl', pnacldir, 'x86'),
650                        'newlib')
651
652
653 def MakeDirectoryOrClobber(pepperdir, dirname, clobber):
654   dirpath = os.path.join(pepperdir, dirname)
655   if clobber:
656     buildbot_common.RemoveDir(dirpath)
657   buildbot_common.MakeDir(dirpath)
658
659   return dirpath
660
661
662 def BuildStepUpdateHelpers(pepperdir, clobber):
663   buildbot_common.BuildStep('Update project helpers')
664   build_projects.UpdateHelpers(pepperdir, clobber=clobber)
665
666
667 def BuildStepUpdateUserProjects(pepperdir, toolchains,
668                                 build_experimental, clobber):
669   buildbot_common.BuildStep('Update examples and libraries')
670
671   filters = {}
672   if not build_experimental:
673     filters['EXPERIMENTAL'] = False
674   if toolchains:
675     toolchains = toolchains[:]
676
677     # arm isn't a valid toolchain for build_projects
678     if 'arm' in toolchains:
679       toolchains.remove('arm')
680
681     if 'host' in toolchains:
682       toolchains.remove('host')
683       toolchains.append(getos.GetPlatform())
684
685     filters['TOOLS'] = toolchains
686
687   # Update examples and libraries
688   filters['DEST'] = [
689     'getting_started',
690     'examples/api',
691     'examples/demo',
692     'examples/tutorial',
693     'src'
694   ]
695
696   tree = parse_dsc.LoadProjectTree(SDK_SRC_DIR, include=filters)
697   build_projects.UpdateProjects(pepperdir, tree, clobber=clobber,
698                                 toolchains=toolchains)
699
700
701 def BuildStepMakeAll(pepperdir, directory, step_name,
702                      deps=True, clean=False, config='Debug', args=None):
703   buildbot_common.BuildStep(step_name)
704   build_projects.BuildProjectsBranch(pepperdir, directory, clean,
705                                      deps, config, args)
706
707
708 def BuildStepBuildLibraries(pepperdir, directory):
709   BuildStepMakeAll(pepperdir, directory, 'Build Libraries Debug',
710       clean=True, config='Debug')
711   BuildStepMakeAll(pepperdir, directory, 'Build Libraries Release',
712       clean=True, config='Release')
713
714   # Cleanup .pyc file generated while building libraries.  Without
715   # this we would end up shipping the pyc in the SDK tarball.
716   buildbot_common.RemoveFile(os.path.join(pepperdir, 'tools', '*.pyc'))
717
718
719 def GenerateNotice(fileroot, output_filename='NOTICE', extra_files=None):
720   # Look for LICENSE files
721   license_filenames_re = re.compile('LICENSE|COPYING|COPYRIGHT')
722
723   license_files = []
724   for root, _, files in os.walk(fileroot):
725     for filename in files:
726       if license_filenames_re.match(filename):
727         path = os.path.join(root, filename)
728         license_files.append(path)
729
730   if extra_files:
731     license_files += [os.path.join(fileroot, f) for f in extra_files]
732   print '\n'.join(license_files)
733
734   if not os.path.isabs(output_filename):
735     output_filename = os.path.join(fileroot, output_filename)
736   generate_notice.Generate(output_filename, fileroot, license_files)
737
738
739 def BuildStepVerifyFilelist(pepperdir):
740   buildbot_common.BuildStep('Verify SDK Files')
741   file_list_path = os.path.join(SCRIPT_DIR, 'sdk_files.list')
742   try:
743     verify_filelist.Verify(file_list_path, pepperdir)
744     print 'OK'
745   except verify_filelist.ParseException, e:
746     buildbot_common.ErrorExit('Parsing sdk_files.list failed:\n\n%s' % e)
747   except verify_filelist.VerifyException, e:
748     file_list_rel = os.path.relpath(file_list_path)
749     verify_filelist_py = os.path.splitext(verify_filelist.__file__)[0] + '.py'
750     verify_filelist_py = os.path.relpath(verify_filelist_py)
751     pepperdir_rel = os.path.relpath(pepperdir)
752
753     msg = """\
754 SDK verification failed:
755
756 %s
757 Add/remove files from %s to fix.
758
759 Run:
760     ./%s %s %s
761 to test.""" % (e, file_list_rel, verify_filelist_py, file_list_rel,
762                pepperdir_rel)
763     buildbot_common.ErrorExit(msg)
764
765
766 def BuildStepTarBundle(pepper_ver, tarfile):
767   buildbot_common.BuildStep('Tar Pepper Bundle')
768   buildbot_common.MakeDir(os.path.dirname(tarfile))
769   buildbot_common.Run([sys.executable, CYGTAR, '-C', OUT_DIR, '-cjf', tarfile,
770        'pepper_' + pepper_ver], cwd=NACL_DIR)
771
772
773 def GetManifestBundle(pepper_ver, chrome_revision, nacl_revision, tarfile,
774                       archive_url):
775   with open(tarfile, 'rb') as tarfile_stream:
776     archive_sha1, archive_size = manifest_util.DownloadAndComputeHash(
777         tarfile_stream)
778
779   archive = manifest_util.Archive(manifest_util.GetHostOS())
780   archive.url = archive_url
781   archive.size = archive_size
782   archive.checksum = archive_sha1
783
784   bundle = manifest_util.Bundle('pepper_' + pepper_ver)
785   bundle.revision = int(chrome_revision)
786   bundle.repath = 'pepper_' + pepper_ver
787   bundle.version = int(pepper_ver)
788   bundle.description = (
789       'Chrome %s bundle. Chrome revision: %s. NaCl revision: %s' % (
790             pepper_ver, chrome_revision, nacl_revision))
791   bundle.stability = 'dev'
792   bundle.recommended = 'no'
793   bundle.archives = [archive]
794   return bundle
795
796
797 def BuildStepArchiveBundle(name, pepper_ver, chrome_revision, nacl_revision,
798                            tarfile):
799   buildbot_common.BuildStep('Archive %s' % name)
800   bucket_path = 'nativeclient-mirror/nacl/nacl_sdk/%s' % (
801       build_version.ChromeVersion(),)
802   tarname = os.path.basename(tarfile)
803   tarfile_dir = os.path.dirname(tarfile)
804   buildbot_common.Archive(tarname, bucket_path, tarfile_dir)
805
806   # generate "manifest snippet" for this archive.
807   archive_url = GSTORE + 'nacl_sdk/%s/%s' % (
808       build_version.ChromeVersion(), tarname)
809   bundle = GetManifestBundle(pepper_ver, chrome_revision, nacl_revision,
810                              tarfile, archive_url)
811
812   manifest_snippet_file = os.path.join(OUT_DIR, tarname + '.json')
813   with open(manifest_snippet_file, 'wb') as manifest_snippet_stream:
814     manifest_snippet_stream.write(bundle.GetDataAsString())
815
816   buildbot_common.Archive(tarname + '.json', bucket_path, OUT_DIR,
817                           step_link=False)
818
819
820 def BuildStepArchiveSDKTools():
821   # Only push up sdk_tools.tgz and nacl_sdk.zip on the linux buildbot.
822   builder_name = os.getenv('BUILDBOT_BUILDERNAME', '')
823   if builder_name == 'linux-sdk-multi':
824     buildbot_common.BuildStep('Build SDK Tools')
825     build_updater.BuildUpdater(OUT_DIR)
826
827     buildbot_common.BuildStep('Archive SDK Tools')
828     bucket_path = 'nativeclient-mirror/nacl/nacl_sdk/%s' % (
829         build_version.ChromeVersion(),)
830     buildbot_common.Archive('sdk_tools.tgz', bucket_path, OUT_DIR,
831                             step_link=False)
832     buildbot_common.Archive('nacl_sdk.zip', bucket_path, OUT_DIR,
833                             step_link=False)
834
835
836 def BuildStepSyncNaClPorts():
837   """Pull the pinned revision of naclports from SVN."""
838   buildbot_common.BuildStep('Sync naclports')
839   if not os.path.exists(NACLPORTS_DIR):
840     # checkout new copy of naclports
841     cmd = ['svn', 'checkout', '-q', '-r', str(NACLPORTS_REV), NACLPORTS_URL,
842            'naclports']
843     buildbot_common.Run(cmd, cwd=os.path.dirname(NACLPORTS_DIR))
844   else:
845     # sync existing copy to pinned revision.
846     cmd = ['svn', 'update', '-r', str(NACLPORTS_REV)]
847     buildbot_common.Run(cmd, cwd=NACLPORTS_DIR)
848
849
850 def BuildStepBuildNaClPorts(pepper_ver, pepperdir):
851   """Build selected naclports in all configurations."""
852   # TODO(sbc): currently naclports doesn't know anything about
853   # Debug builds so the Debug subfolders are all empty.
854
855   env = dict(os.environ)
856   env['NACL_SDK_ROOT'] = pepperdir
857   env['PEPPER_DIR'] = os.path.basename(pepperdir)  # pepper_NN
858   env['NACLPORTS_NO_ANNOTATE'] = "1"
859   env['NACLPORTS_NO_UPLOAD'] = "1"
860
861   build_script = 'build_tools/bots/linux/naclports-linux-sdk-bundle.sh'
862   buildbot_common.BuildStep('Build naclports')
863   buildbot_common.Run([build_script], env=env, cwd=NACLPORTS_DIR)
864
865   bundle_dir = os.path.join(NACLPORTS_DIR, 'out', 'sdk_bundle')
866   out_dir = os.path.join(bundle_dir, 'pepper_%s' % pepper_ver)
867
868   # Some naclports do not include a standalone LICENSE/COPYING file
869   # so we explicitly list those here for inclusion.
870   extra_licenses = ('tinyxml/readme.txt',
871                     'jpeg-8d/README',
872                     'zlib-1.2.3/README')
873   src_root = os.path.join(NACLPORTS_DIR, 'out', 'repository-i686')
874   output_license = os.path.join(out_dir, 'ports', 'LICENSE')
875   GenerateNotice(src_root , output_license, extra_licenses)
876   readme = os.path.join(out_dir, 'ports', 'README')
877   oshelpers.Copy(['-v', os.path.join(SDK_SRC_DIR, 'README.naclports'), readme])
878
879
880 def BuildStepTarNaClPorts(pepper_ver, tarfile):
881   """Create tar archive containing headers and libs from naclports build."""
882   buildbot_common.BuildStep('Tar naclports Bundle')
883   buildbot_common.MakeDir(os.path.dirname(tarfile))
884   pepper_dir = 'pepper_%s' % pepper_ver
885   archive_dirs = [os.path.join(pepper_dir, 'ports')]
886
887   ports_out = os.path.join(NACLPORTS_DIR, 'out', 'sdk_bundle')
888   cmd = [sys.executable, CYGTAR, '-C', ports_out, '-cjf', tarfile]
889   cmd += archive_dirs
890   buildbot_common.Run(cmd, cwd=NACL_DIR)
891
892
893 def BuildStepBuildAppEngine(pepperdir, chrome_revision):
894   """Build the projects found in src/gonacl_appengine/src"""
895   buildbot_common.BuildStep('Build GoNaCl AppEngine Projects')
896   cmd = ['make', 'upload', 'REVISION=%s' % chrome_revision]
897   env = dict(os.environ)
898   env['NACL_SDK_ROOT'] = pepperdir
899   env['NACLPORTS_NO_ANNOTATE'] = "1"
900   buildbot_common.Run(cmd, env=env, cwd=GONACL_APPENGINE_SRC_DIR)
901
902
903 def main(args):
904   parser = optparse.OptionParser()
905   parser.add_option('--bionic', help='Add bionic build.',
906       action='store_true')
907   parser.add_option('--tar', help='Force the tar step.',
908       action='store_true')
909   parser.add_option('--archive', help='Force the archive step.',
910       action='store_true')
911   parser.add_option('--gyp',
912       help='Use gyp to build examples/libraries/Makefiles.',
913       action='store_true')
914   parser.add_option('--release', help='PPAPI release version.',
915       dest='release', default=None)
916   parser.add_option('--build-ports',
917       help='Build naclport bundle.', action='store_true')
918   parser.add_option('--build-app-engine',
919       help='Build AppEngine demos.', action='store_true')
920   parser.add_option('--experimental',
921       help='build experimental examples and libraries', action='store_true',
922       dest='build_experimental')
923   parser.add_option('--skip-toolchain', help='Skip toolchain untar',
924       action='store_true')
925   parser.add_option('--mac-sdk',
926       help='Set the mac-sdk (e.g. 10.6) to use when building with ninja.')
927
928   # To setup bash completion for this command first install optcomplete
929   # and then add this line to your .bashrc:
930   #  complete -F _optcomplete build_sdk.py
931   try:
932     import optcomplete
933     optcomplete.autocomplete(parser)
934   except ImportError:
935     pass
936
937   global options
938   options, args = parser.parse_args(args[1:])
939   if args:
940     parser.error("Unexpected arguments: %s" % str(args))
941
942   generate_make.use_gyp = options.gyp
943   if buildbot_common.IsSDKBuilder():
944     options.archive = True
945     options.build_ports = True
946     options.build_app_engine = True
947     options.tar = True
948
949   toolchains = ['newlib', 'glibc', 'arm', 'pnacl', 'host']
950   if options.bionic:
951     toolchains.append('bionic')
952
953   print 'Building: ' + ' '.join(toolchains)
954
955   if options.archive and not options.tar:
956     parser.error('Incompatible arguments with archive.')
957
958   chrome_version = int(build_version.ChromeMajorVersion())
959   chrome_revision = build_version.ChromeRevision()
960   nacl_revision = build_version.NaClRevision()
961   pepper_ver = str(chrome_version)
962   pepper_old = str(chrome_version - 1)
963   pepperdir = os.path.join(OUT_DIR, 'pepper_' + pepper_ver)
964   pepperdir_old = os.path.join(OUT_DIR, 'pepper_' + pepper_old)
965   tarname = 'naclsdk_' + getos.GetPlatform() + '.tar.bz2'
966   tarfile = os.path.join(OUT_DIR, tarname)
967
968   if options.release:
969     pepper_ver = options.release
970   print 'Building PEPPER %s at %s' % (pepper_ver, chrome_revision)
971
972   if 'NACL_SDK_ROOT' in os.environ:
973     # We don't want the currently configured NACL_SDK_ROOT to have any effect
974     # of the build.
975     del os.environ['NACL_SDK_ROOT']
976
977   if not options.skip_toolchain:
978     BuildStepCleanPepperDirs(pepperdir, pepperdir_old)
979     BuildStepMakePepperDirs(pepperdir, ['include', 'toolchain', 'tools'])
980     BuildStepDownloadToolchains(toolchains)
981     BuildStepUntarToolchains(pepperdir, toolchains)
982
983   BuildStepBuildToolchains(pepperdir, toolchains)
984
985   BuildStepUpdateHelpers(pepperdir, True)
986   BuildStepUpdateUserProjects(pepperdir, toolchains,
987                               options.build_experimental, True)
988
989   BuildStepCopyTextFiles(pepperdir, pepper_ver, chrome_revision, nacl_revision)
990
991   # Ship with libraries prebuilt, so run that first.
992   BuildStepBuildLibraries(pepperdir, 'src')
993   GenerateNotice(pepperdir)
994
995   # Verify the SDK contains what we expect.
996   BuildStepVerifyFilelist(pepperdir)
997
998   if options.tar:
999     BuildStepTarBundle(pepper_ver, tarfile)
1000
1001   if options.build_ports and getos.GetPlatform() == 'linux':
1002     ports_tarfile = os.path.join(OUT_DIR, 'naclports.tar.bz2')
1003     BuildStepSyncNaClPorts()
1004     BuildStepBuildNaClPorts(pepper_ver, pepperdir)
1005     if options.tar:
1006       BuildStepTarNaClPorts(pepper_ver, ports_tarfile)
1007
1008   if options.build_app_engine and getos.GetPlatform() == 'linux':
1009     BuildStepBuildAppEngine(pepperdir, chrome_revision)
1010
1011   # Archive on non-trybots.
1012   if options.archive:
1013     BuildStepArchiveBundle('build', pepper_ver, chrome_revision, nacl_revision,
1014                            tarfile)
1015     if options.build_ports and getos.GetPlatform() == 'linux':
1016       BuildStepArchiveBundle('naclports', pepper_ver, chrome_revision,
1017                              nacl_revision, ports_tarfile)
1018     BuildStepArchiveSDKTools()
1019
1020   return 0
1021
1022
1023 if __name__ == '__main__':
1024   try:
1025     sys.exit(main(sys.argv))
1026   except KeyboardInterrupt:
1027     buildbot_common.ErrorExit('build_sdk: interrupted')