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.
13 import buildbot_common
18 from build_paths
import SDK_SRC_DIR
, OUT_DIR
, SDK_RESOURCE_DIR
19 from build_paths
import GSTORE
20 from generate_index
import LandingPage
22 sys
.path
.append(os
.path
.join(SDK_SRC_DIR
, 'tools'))
26 MAKE
= 'nacl_sdk/make_3.99.90-26-gf80222c/make.exe'
43 # Global verbosity setting.
44 # If set to True (normally via a command line arg) then build_projects will
45 # add V=1 to all calls to 'make'
51 sys
.stderr
.write(str(msg
) + '\n')
54 def CopyFilesFromTo(filelist
, srcdir
, dstdir
):
55 for filename
in filelist
:
56 srcpath
= os
.path
.join(srcdir
, filename
)
57 dstpath
= os
.path
.join(dstdir
, filename
)
58 buildbot_common
.CopyFile(srcpath
, dstpath
)
61 def UpdateHelpers(pepperdir
, clobber
=False):
62 tools_dir
= os
.path
.join(pepperdir
, 'tools')
63 if not os
.path
.exists(tools_dir
):
64 buildbot_common
.ErrorExit('SDK tools dir is missing: %s' % tools_dir
)
66 exampledir
= os
.path
.join(pepperdir
, 'examples')
68 buildbot_common
.RemoveDir(exampledir
)
69 buildbot_common
.MakeDir(exampledir
)
71 # Copy files for individual build and landing page
72 files
= ['favicon.ico', 'httpd.cmd', 'index.css', 'index.js',
73 'button_close.png', 'button_close_hover.png']
74 CopyFilesFromTo(files
, SDK_RESOURCE_DIR
, exampledir
)
76 # Copy tools scripts and make includes
77 buildbot_common
.CopyDir(os
.path
.join(SDK_SRC_DIR
, 'tools', '*.py'),
79 buildbot_common
.CopyDir(os
.path
.join(SDK_SRC_DIR
, 'tools', '*.mk'),
82 # Copy tools/lib scripts
83 tools_lib_dir
= os
.path
.join(pepperdir
, 'tools', 'lib')
84 buildbot_common
.MakeDir(tools_lib_dir
)
85 buildbot_common
.CopyDir(os
.path
.join(SDK_SRC_DIR
, 'tools', 'lib', '*.py'),
88 # On Windows add a prebuilt make
89 if getos
.GetPlatform() == 'win':
90 buildbot_common
.BuildStep('Add MAKE')
91 make_url
= posixpath
.join(GSTORE
, MAKE
)
92 make_exe
= os
.path
.join(tools_dir
, 'make.exe')
93 with
open(make_exe
, 'wb') as f
:
94 f
.write(urllib2
.urlopen(make_url
).read())
97 def ValidateToolchains(toolchains
):
98 invalid_toolchains
= set(toolchains
) - set(VALID_TOOLCHAINS
)
99 if invalid_toolchains
:
100 buildbot_common
.ErrorExit('Invalid toolchain(s): %s' % (
101 ', '.join(invalid_toolchains
)))
104 def GetDeps(projects
):
107 # Build list of all project names
108 localtargets
= [proj
['NAME'] for proj
in projects
]
111 for proj
in projects
:
113 # generate a list of dependencies
114 for targ
in proj
.get('TARGETS', []):
115 deplist
.extend(targ
.get('DEPS', []) + targ
.get('LIBS', []))
117 # and add dependencies to targets built in this subtree
118 localdeps
= [dep
for dep
in deplist
if dep
in localtargets
]
120 out
[proj
['NAME']] = localdeps
125 def UpdateProjects(pepperdir
, project_tree
, toolchains
,
126 clobber
=False, configs
=None, first_toolchain
=False):
128 configs
= ['Debug', 'Release']
129 if not os
.path
.exists(os
.path
.join(pepperdir
, 'tools')):
130 buildbot_common
.ErrorExit('Examples depend on missing tools.')
131 if not os
.path
.exists(os
.path
.join(pepperdir
, 'toolchain')):
132 buildbot_common
.ErrorExit('Examples depend on missing toolchains.')
134 ValidateToolchains(toolchains
)
136 # Create the library output directories
137 libdir
= os
.path
.join(pepperdir
, 'lib')
138 platform
= getos
.GetPlatform()
139 for config
in configs
:
140 for arch
in LIB_DICT
[platform
]:
141 dirpath
= os
.path
.join(libdir
, '%s_%s_host' % (platform
, arch
), config
)
143 buildbot_common
.RemoveDir(dirpath
)
144 buildbot_common
.MakeDir(dirpath
)
147 for branch
, projects
in project_tree
.iteritems():
148 dirpath
= os
.path
.join(pepperdir
, branch
)
150 buildbot_common
.RemoveDir(dirpath
)
151 buildbot_common
.MakeDir(dirpath
)
152 targets
= [desc
['NAME'] for desc
in projects
]
153 deps
= GetDeps(projects
)
155 # Generate master make for this branch of projects
156 generate_make
.GenerateMasterMakefile(pepperdir
,
157 os
.path
.join(pepperdir
, branch
),
160 if branch
.startswith('examples') and not landing_page
:
161 landing_page
= LandingPage()
163 # Generate individual projects
164 for desc
in projects
:
165 srcroot
= os
.path
.dirname(desc
['FILEPATH'])
166 generate_make
.ProcessProject(pepperdir
, srcroot
, pepperdir
, desc
,
167 toolchains
, configs
=configs
,
168 first_toolchain
=first_toolchain
)
170 if branch
.startswith('examples'):
171 landing_page
.AddDesc(desc
)
174 # Generate the landing page text file.
175 index_html
= os
.path
.join(pepperdir
, 'examples', 'index.html')
176 index_template
= os
.path
.join(SDK_RESOURCE_DIR
, 'index.html.template')
177 with
open(index_html
, 'w') as fh
:
178 out
= landing_page
.GeneratePage(index_template
)
181 # Generate top Make for examples
182 targets
= ['api', 'demo', 'getting_started', 'tutorial']
183 targets
= [x
for x
in targets
if 'examples/'+x
in project_tree
]
184 branch_name
= 'examples'
185 generate_make
.GenerateMasterMakefile(pepperdir
,
186 os
.path
.join(pepperdir
, branch_name
),
190 def BuildProjectsBranch(pepperdir
, branch
, deps
, clean
, config
, args
=None):
191 make_dir
= os
.path
.join(pepperdir
, branch
)
192 print "\nMake: " + make_dir
194 if getos
.GetPlatform() == 'win':
195 # We need to modify the environment to build host on Windows.
196 make
= os
.path
.join(make_dir
, 'make.bat')
201 if os
.environ
.get('USE_GOMA') == '1':
202 env
= dict(os
.environ
)
203 env
['NACL_COMPILER_PREFIX'] = 'gomacc'
204 # Add -m32 to the CFLAGS when building using i686-nacl-gcc
205 # otherwise goma won't recognise it as different to the x86_64
207 env
['X86_32_CFLAGS'] = '-m32'
208 env
['X86_32_CXXFLAGS'] = '-m32'
211 jobs
= str(multiprocessing
.cpu_count())
213 make_cmd
= [make
, '-j', jobs
]
215 make_cmd
.append('CONFIG='+config
)
216 # We always ENABLE_BIONIC in case we need it. If neither --bionic nor
217 # -t bionic have been provided on the command line, then VALID_TOOLCHAINS
218 # will not contain a bionic target.
219 make_cmd
.append('ENABLE_BIONIC=1')
221 make_cmd
.append('IGNORE_DEPS=1')
224 make_cmd
.append('V=1')
229 make_cmd
.append('TOOLCHAIN=all')
231 buildbot_common
.Run(make_cmd
, cwd
=make_dir
, env
=env
)
233 # Clean to remove temporary files but keep the built
234 buildbot_common
.Run(make_cmd
+ ['clean'], cwd
=make_dir
, env
=env
)
237 def BuildProjects(pepperdir
, project_tree
, deps
=True,
238 clean
=False, config
='Debug'):
239 # Make sure we build libraries (which live in 'src') before
240 # any of the examples.
241 build_first
= [p
for p
in project_tree
if p
!= 'src']
242 build_second
= [p
for p
in project_tree
if p
== 'src']
244 for branch
in build_first
+ build_second
:
245 BuildProjectsBranch(pepperdir
, branch
, deps
, clean
, config
)
249 parser
= argparse
.ArgumentParser(description
=__doc__
)
250 parser
.add_argument('-c', '--clobber',
251 help='Clobber project directories before copying new files',
252 action
='store_true', default
=False)
253 parser
.add_argument('-b', '--build',
254 help='Build the projects. Otherwise the projects are only copied.',
256 parser
.add_argument('--config',
257 help='Choose configuration to build (Debug or Release). Builds both '
259 parser
.add_argument('--bionic',
260 help='Enable bionic projects', action
='store_true')
261 parser
.add_argument('-x', '--experimental',
262 help='Build experimental projects', action
='store_true')
263 parser
.add_argument('-t', '--toolchain',
264 help='Build using toolchain. Can be passed more than once.',
265 action
='append', default
=[])
266 parser
.add_argument('-d', '--dest',
267 help='Select which build destinations (project types) are valid.',
269 parser
.add_argument('projects', nargs
='*',
270 help='Select which projects to build.')
271 parser
.add_argument('-v', '--verbose', action
='store_true')
273 # To setup bash completion for this command first install optcomplete
274 # and then add this line to your .bashrc:
275 # complete -F _optcomplete build_projects.py
278 optcomplete
.autocomplete(parser
)
282 options
= parser
.parse_args(args
)
288 buildbot_common
.verbose
= verbose
290 if 'NACL_SDK_ROOT' in os
.environ
:
291 # We don't want the currently configured NACL_SDK_ROOT to have any effect
293 del os
.environ
['NACL_SDK_ROOT']
295 pepper_ver
= str(int(build_version
.ChromeMajorVersion()))
296 pepperdir
= os
.path
.join(OUT_DIR
, 'pepper_' + pepper_ver
)
298 if not options
.toolchain
:
299 # Order matters here: the default toolchain for an example's Makefile will
300 # be the first toolchain in this list that is available in the example.
301 # e.g. If an example supports newlib and glibc, then the default will be
303 options
.toolchain
= ['pnacl', 'newlib', 'glibc', 'host', 'clang-newlib']
304 if options
.experimental
or options
.bionic
:
305 options
.toolchain
.append('bionic')
307 if 'host' in options
.toolchain
:
308 options
.toolchain
.remove('host')
309 options
.toolchain
.append(getos
.GetPlatform())
310 Trace('Adding platform: ' + getos
.GetPlatform())
312 ValidateToolchains(options
.toolchain
)
315 if options
.toolchain
:
316 filters
['TOOLS'] = options
.toolchain
317 Trace('Filter by toolchain: ' + str(options
.toolchain
))
318 if not options
.experimental
:
319 filters
['EXPERIMENTAL'] = False
321 filters
['DEST'] = options
.dest
322 Trace('Filter by type: ' + str(options
.dest
))
324 filters
['NAME'] = options
.projects
325 Trace('Filter by name: ' + str(options
.projects
))
328 project_tree
= parse_dsc
.LoadProjectTree(SDK_SRC_DIR
, include
=filters
)
329 except parse_dsc
.ValidationError
as e
:
330 buildbot_common
.ErrorExit(str(e
))
333 parse_dsc
.PrintProjectTree(project_tree
)
335 UpdateHelpers(pepperdir
, clobber
=options
.clobber
)
336 UpdateProjects(pepperdir
, project_tree
, options
.toolchain
,
337 clobber
=options
.clobber
)
341 configs
= [options
.config
]
343 configs
= ['Debug', 'Release']
344 for config
in configs
:
345 BuildProjects(pepperdir
, project_tree
, config
=config
, deps
=False)
350 if __name__
== '__main__':
351 script_name
= os
.path
.basename(sys
.argv
[0])
353 sys
.exit(main(sys
.argv
[1:]))
354 except parse_dsc
.ValidationError
as e
:
355 buildbot_common
.ErrorExit('%s: %s' % (script_name
, e
))
356 except KeyboardInterrupt:
357 buildbot_common
.ErrorExit('%s: interrupted' % script_name
)