2 # Copyright (c) 2013 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.
11 import buildbot_common
16 from build_paths import NACL_DIR, SDK_SRC_DIR, OUT_DIR, SDK_RESOURCE_DIR
17 from build_paths import GSTORE
18 from generate_index import LandingPage
20 sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
21 sys.path.append(os.path.join(NACL_DIR, 'build'))
26 MAKE = 'nacl_sdk/make_3.99.90-26-gf80222c/make.exe'
32 VALID_TOOLCHAINS = ['newlib', 'glibc', 'pnacl', 'win', 'linux', 'mac']
34 # Global verbosity setting.
35 # If set to try (normally via a command line arg) then build_projects will
36 # add V=1 to all calls to 'make'
40 def CopyFilesFromTo(filelist, srcdir, dstdir):
41 for filename in filelist:
42 srcpath = os.path.join(srcdir, filename)
43 dstpath = os.path.join(dstdir, filename)
44 buildbot_common.CopyFile(srcpath, dstpath)
47 def UpdateHelpers(pepperdir, clobber=False):
48 tools_dir = os.path.join(pepperdir, 'tools')
49 if not os.path.exists(tools_dir):
50 buildbot_common.ErrorExit('SDK tools dir is missing: %s' % tools_dir)
52 exampledir = os.path.join(pepperdir, 'examples')
54 buildbot_common.RemoveDir(exampledir)
55 buildbot_common.MakeDir(exampledir)
57 # Copy files for individual build and landing page
58 files = ['favicon.ico', 'httpd.cmd', 'index.css', 'index.js',
59 'button_close.png', 'button_close_hover.png']
60 CopyFilesFromTo(files, SDK_RESOURCE_DIR, exampledir)
62 # Copy tools scripts and make includes
63 buildbot_common.CopyDir(os.path.join(SDK_SRC_DIR, 'tools', '*.py'),
65 buildbot_common.CopyDir(os.path.join(SDK_SRC_DIR, 'tools', '*.mk'),
68 # On Windows add a prebuilt make
69 if getos.GetPlatform() == 'win':
70 buildbot_common.BuildStep('Add MAKE')
71 http_download.HttpDownload(GSTORE + MAKE,
72 os.path.join(tools_dir, 'make.exe'))
75 def ValidateToolchains(toolchains):
76 invalid_toolchains = set(toolchains) - set(VALID_TOOLCHAINS)
77 if invalid_toolchains:
78 buildbot_common.ErrorExit('Invalid toolchain(s): %s' % (
79 ', '.join(invalid_toolchains)))
82 def UpdateProjects(pepperdir, project_tree, toolchains,
83 clobber=False, configs=None, first_toolchain=False):
85 configs = ['Debug', 'Release']
86 if not os.path.exists(os.path.join(pepperdir, 'tools')):
87 buildbot_common.ErrorExit('Examples depend on missing tools.')
88 if not os.path.exists(os.path.join(pepperdir, 'toolchain')):
89 buildbot_common.ErrorExit('Examples depend on missing toolchains.')
91 ValidateToolchains(toolchains)
93 # Create the library output directories
94 libdir = os.path.join(pepperdir, 'lib')
95 platform = getos.GetPlatform()
96 for config in configs:
97 for arch in LIB_DICT[platform]:
98 dirpath = os.path.join(libdir, '%s_%s_host' % (platform, arch), config)
100 buildbot_common.RemoveDir(dirpath)
101 buildbot_common.MakeDir(dirpath)
104 for branch, projects in project_tree.iteritems():
105 dirpath = os.path.join(pepperdir, branch)
107 buildbot_common.RemoveDir(dirpath)
108 buildbot_common.MakeDir(dirpath)
109 targets = [desc['NAME'] for desc in projects]
111 # Generate master make for this branch of projects
112 generate_make.GenerateMasterMakefile(pepperdir,
113 os.path.join(pepperdir, branch),
116 if branch.startswith('examples') and not landing_page:
117 landing_page = LandingPage()
119 # Generate individual projects
120 for desc in projects:
121 srcroot = os.path.dirname(desc['FILEPATH'])
122 generate_make.ProcessProject(pepperdir, srcroot, pepperdir, desc,
123 toolchains, configs=configs,
124 first_toolchain=first_toolchain)
126 if branch.startswith('examples'):
127 landing_page.AddDesc(desc)
130 # Generate the landing page text file.
131 index_html = os.path.join(pepperdir, 'examples', 'index.html')
132 index_template = os.path.join(SDK_RESOURCE_DIR, 'index.html.template')
133 with open(index_html, 'w') as fh:
134 out = landing_page.GeneratePage(index_template)
137 # Generate top Make for examples
138 targets = ['api', 'demo', 'getting_started', 'tutorial']
139 targets = [x for x in targets if 'examples/'+x in project_tree]
140 branch_name = 'examples'
141 generate_make.GenerateMasterMakefile(pepperdir,
142 os.path.join(pepperdir, branch_name),
146 def BuildProjectsBranch(pepperdir, branch, deps, clean, config, args=None):
147 make_dir = os.path.join(pepperdir, branch)
148 print "\nMake: " + make_dir
150 if getos.GetPlatform() == 'win':
151 # We need to modify the environment to build host on Windows.
152 make = os.path.join(make_dir, 'make.bat')
157 if os.environ.get('USE_GOMA') == '1':
158 env = dict(os.environ)
159 env['NACL_COMPILER_PREFIX'] = 'gomacc'
160 # Add -m32 to the CFLAGS when building using i686-nacl-gcc
161 # otherwise goma won't recognise it as different to the x86_64
163 env['X86_32_CFLAGS'] = '-m32'
164 env['X86_32_CXXFLAGS'] = '-m32'
167 jobs = str(multiprocessing.cpu_count())
169 make_cmd = [make, '-j', jobs]
171 make_cmd.append('CONFIG='+config)
173 make_cmd.append('IGNORE_DEPS=1')
176 make_cmd.append('V=1')
181 make_cmd.append('TOOLCHAIN=all')
183 buildbot_common.Run(make_cmd, cwd=make_dir, env=env)
185 # Clean to remove temporary files but keep the built
186 buildbot_common.Run(make_cmd + ['clean'], cwd=make_dir, env=env)
189 def BuildProjects(pepperdir, project_tree, deps=True,
190 clean=False, config='Debug'):
192 # Make sure we build libraries (which live in 'src') before
193 # any of the examples.
194 build_first = [p for p in project_tree if p != 'src']
195 build_second = [p for p in project_tree if p == 'src']
197 for branch in build_first + build_second:
198 BuildProjectsBranch(pepperdir, branch, deps, clean, config)
202 parser = optparse.OptionParser()
203 parser.add_option('-c', '--clobber',
204 help='Clobber project directories before copying new files',
205 action='store_true', default=False)
206 parser.add_option('-b', '--build',
207 help='Build the projects.', action='store_true')
208 parser.add_option('--config',
209 help='Choose configuration to build (Debug or Release). Builds both '
211 parser.add_option('-x', '--experimental',
212 help='Build experimental projects', action='store_true')
213 parser.add_option('-t', '--toolchain',
214 help='Build using toolchain. Can be passed more than once.',
215 action='append', default=[])
216 parser.add_option('-d', '--dest',
217 help='Select which build destinations (project types) are valid.',
219 parser.add_option('-p', '--project',
220 help='Select which projects are valid.',
222 parser.add_option('-v', '--verbose', action='store_true')
224 # To setup bash completion for this command first install optcomplete
225 # and then add this line to your .bashrc:
226 # complete -F _optcomplete build_projects.py
229 optcomplete.autocomplete(parser)
233 options, args = parser.parse_args(argv[1:])
235 parser.error('The -p/--project option is deprecated.\n'
236 'Just use positional paramaters instead.')
238 if 'NACL_SDK_ROOT' in os.environ:
239 # We don't want the currently configured NACL_SDK_ROOT to have any effect
241 del os.environ['NACL_SDK_ROOT']
243 pepper_ver = str(int(build_version.ChromeMajorVersion()))
244 pepperdir = os.path.join(OUT_DIR, 'pepper_' + pepper_ver)
246 if not options.toolchain:
247 # Order matters here: the default toolchain for an example's Makefile will
248 # be the first toolchain in this list that is available in the example.
249 # e.g. If an example supports newlib and glibc, then the default will be
251 options.toolchain = ['pnacl', 'newlib', 'glibc', 'host']
253 if 'host' in options.toolchain:
254 options.toolchain.remove('host')
255 options.toolchain.append(getos.GetPlatform())
256 print 'Adding platform: ' + getos.GetPlatform()
258 ValidateToolchains(options.toolchain)
261 if options.toolchain:
262 filters['TOOLS'] = options.toolchain
263 print 'Filter by toolchain: ' + str(options.toolchain)
264 if not options.experimental:
265 filters['EXPERIMENTAL'] = False
267 filters['DEST'] = options.dest
268 print 'Filter by type: ' + str(options.dest)
270 filters['NAME'] = args
271 print 'Filter by name: ' + str(args)
274 project_tree = parse_dsc.LoadProjectTree(SDK_SRC_DIR, include=filters)
275 except parse_dsc.ValidationError as e:
276 buildbot_common.ErrorExit(str(e))
277 parse_dsc.PrintProjectTree(project_tree)
279 UpdateHelpers(pepperdir, clobber=options.clobber)
280 UpdateProjects(pepperdir, project_tree, options.toolchain,
281 clobber=options.clobber)
289 configs = [options.config]
291 configs = ['Debug', 'Release']
292 for config in configs:
293 BuildProjects(pepperdir, project_tree, config=config)
298 if __name__ == '__main__':
299 script_name = os.path.basename(sys.argv[0])
301 sys.exit(main(sys.argv))
302 except parse_dsc.ValidationError as e:
303 buildbot_common.ErrorExit('%s: %s' % (script_name, e))
304 except KeyboardInterrupt:
305 buildbot_common.ErrorExit('%s: interrupted' % script_name)