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'
42 # Global verbosity setting.
43 # If set to True (normally via a command line arg) then build_projects will
44 # add V=1 to all calls to 'make'
50 sys
.stderr
.write(str(msg
) + '\n')
53 def CopyFilesFromTo(filelist
, srcdir
, dstdir
):
54 for filename
in filelist
:
55 srcpath
= os
.path
.join(srcdir
, filename
)
56 dstpath
= os
.path
.join(dstdir
, filename
)
57 buildbot_common
.CopyFile(srcpath
, dstpath
)
60 def UpdateHelpers(pepperdir
, clobber
=False):
61 tools_dir
= os
.path
.join(pepperdir
, 'tools')
62 if not os
.path
.exists(tools_dir
):
63 buildbot_common
.ErrorExit('SDK tools dir is missing: %s' % tools_dir
)
65 exampledir
= os
.path
.join(pepperdir
, 'examples')
67 buildbot_common
.RemoveDir(exampledir
)
68 buildbot_common
.MakeDir(exampledir
)
70 # Copy files for individual build and landing page
71 files
= ['favicon.ico', 'httpd.cmd', 'index.css', 'index.js',
72 'button_close.png', 'button_close_hover.png']
73 CopyFilesFromTo(files
, SDK_RESOURCE_DIR
, exampledir
)
75 # Copy tools scripts and make includes
76 buildbot_common
.CopyDir(os
.path
.join(SDK_SRC_DIR
, 'tools', '*.py'),
78 buildbot_common
.CopyDir(os
.path
.join(SDK_SRC_DIR
, 'tools', '*.mk'),
81 # Copy tools/lib scripts
82 tools_lib_dir
= os
.path
.join(pepperdir
, 'tools', 'lib')
83 buildbot_common
.MakeDir(tools_lib_dir
)
84 buildbot_common
.CopyDir(os
.path
.join(SDK_SRC_DIR
, 'tools', 'lib', '*.py'),
87 # On Windows add a prebuilt make
88 if getos
.GetPlatform() == 'win':
89 buildbot_common
.BuildStep('Add MAKE')
90 make_url
= posixpath
.join(GSTORE
, MAKE
)
91 make_exe
= os
.path
.join(tools_dir
, 'make.exe')
92 with
open(make_exe
, 'wb') as f
:
93 f
.write(urllib2
.urlopen(make_url
).read())
96 def ValidateToolchains(toolchains
):
97 invalid_toolchains
= set(toolchains
) - set(VALID_TOOLCHAINS
)
98 if invalid_toolchains
:
99 buildbot_common
.ErrorExit('Invalid toolchain(s): %s' % (
100 ', '.join(invalid_toolchains
)))
102 def GetDeps(projects
):
105 # Build list of all project names
106 localtargets
= [proj
['NAME'] for proj
in projects
]
109 for proj
in projects
:
111 # generate a list of dependencies
112 for targ
in proj
.get('TARGETS', []):
113 deplist
.extend(targ
.get('DEPS', []) + targ
.get('LIBS', []))
115 # and add dependencies to targets built in this subtree
116 localdeps
= [dep
for dep
in deplist
if dep
in localtargets
]
118 out
[proj
['NAME']] = localdeps
123 def UpdateProjects(pepperdir
, project_tree
, toolchains
,
124 clobber
=False, configs
=None, first_toolchain
=False):
126 configs
= ['Debug', 'Release']
127 if not os
.path
.exists(os
.path
.join(pepperdir
, 'tools')):
128 buildbot_common
.ErrorExit('Examples depend on missing tools.')
129 if not os
.path
.exists(os
.path
.join(pepperdir
, 'toolchain')):
130 buildbot_common
.ErrorExit('Examples depend on missing toolchains.')
132 ValidateToolchains(toolchains
)
134 # Create the library output directories
135 libdir
= os
.path
.join(pepperdir
, 'lib')
136 platform
= getos
.GetPlatform()
137 for config
in configs
:
138 for arch
in LIB_DICT
[platform
]:
139 dirpath
= os
.path
.join(libdir
, '%s_%s_host' % (platform
, arch
), config
)
141 buildbot_common
.RemoveDir(dirpath
)
142 buildbot_common
.MakeDir(dirpath
)
145 for branch
, projects
in project_tree
.iteritems():
146 dirpath
= os
.path
.join(pepperdir
, branch
)
148 buildbot_common
.RemoveDir(dirpath
)
149 buildbot_common
.MakeDir(dirpath
)
150 targets
= [desc
['NAME'] for desc
in projects
]
151 deps
= GetDeps(projects
)
153 # Generate master make for this branch of projects
154 generate_make
.GenerateMasterMakefile(pepperdir
,
155 os
.path
.join(pepperdir
, branch
),
158 if branch
.startswith('examples') and not landing_page
:
159 landing_page
= LandingPage()
161 # Generate individual projects
162 for desc
in projects
:
163 srcroot
= os
.path
.dirname(desc
['FILEPATH'])
164 generate_make
.ProcessProject(pepperdir
, srcroot
, pepperdir
, desc
,
165 toolchains
, configs
=configs
,
166 first_toolchain
=first_toolchain
)
168 if branch
.startswith('examples'):
169 landing_page
.AddDesc(desc
)
172 # Generate the landing page text file.
173 index_html
= os
.path
.join(pepperdir
, 'examples', 'index.html')
174 index_template
= os
.path
.join(SDK_RESOURCE_DIR
, 'index.html.template')
175 with
open(index_html
, 'w') as fh
:
176 out
= landing_page
.GeneratePage(index_template
)
179 # Generate top Make for examples
180 targets
= ['api', 'demo', 'getting_started', 'tutorial']
181 targets
= [x
for x
in targets
if 'examples/'+x
in project_tree
]
182 branch_name
= 'examples'
183 generate_make
.GenerateMasterMakefile(pepperdir
,
184 os
.path
.join(pepperdir
, branch_name
),
188 def BuildProjectsBranch(pepperdir
, branch
, deps
, clean
, config
, args
=None):
189 make_dir
= os
.path
.join(pepperdir
, branch
)
190 print "\nMake: " + make_dir
192 if getos
.GetPlatform() == 'win':
193 # We need to modify the environment to build host on Windows.
194 make
= os
.path
.join(make_dir
, 'make.bat')
199 if os
.environ
.get('USE_GOMA') == '1':
200 env
= dict(os
.environ
)
201 env
['NACL_COMPILER_PREFIX'] = 'gomacc'
202 # Add -m32 to the CFLAGS when building using i686-nacl-gcc
203 # otherwise goma won't recognise it as different to the x86_64
205 env
['X86_32_CFLAGS'] = '-m32'
206 env
['X86_32_CXXFLAGS'] = '-m32'
209 jobs
= str(multiprocessing
.cpu_count())
211 make_cmd
= [make
, '-j', jobs
]
213 make_cmd
.append('CONFIG='+config
)
214 # We always ENABLE_BIONIC in case we need it. If neither --bionic nor
215 # -t bionic have been provided on the command line, then VALID_TOOLCHAINS
216 # will not contain a bionic target.
217 make_cmd
.append('ENABLE_BIONIC=1')
219 make_cmd
.append('IGNORE_DEPS=1')
222 make_cmd
.append('V=1')
227 make_cmd
.append('TOOLCHAIN=all')
229 buildbot_common
.Run(make_cmd
, cwd
=make_dir
, env
=env
)
231 # Clean to remove temporary files but keep the built
232 buildbot_common
.Run(make_cmd
+ ['clean'], cwd
=make_dir
, env
=env
)
235 def BuildProjects(pepperdir
, project_tree
, deps
=True,
236 clean
=False, config
='Debug'):
237 # Make sure we build libraries (which live in 'src') before
238 # any of the examples.
239 build_first
= [p
for p
in project_tree
if p
!= 'src']
240 build_second
= [p
for p
in project_tree
if p
== 'src']
242 for branch
in build_first
+ build_second
:
243 BuildProjectsBranch(pepperdir
, branch
, deps
, clean
, config
)
247 parser
= optparse
.OptionParser()
248 parser
.add_option('-c', '--clobber',
249 help='Clobber project directories before copying new files',
250 action
='store_true', default
=False)
251 parser
.add_option('-b', '--build',
252 help='Build the projects. Otherwise the projects are only copied.',
254 parser
.add_option('--config',
255 help='Choose configuration to build (Debug or Release). Builds both '
257 parser
.add_option('--bionic',
258 help='Enable bionic projects', action
='store_true')
259 parser
.add_option('-x', '--experimental',
260 help='Build experimental projects', action
='store_true')
261 parser
.add_option('-t', '--toolchain',
262 help='Build using toolchain. Can be passed more than once.',
263 action
='append', default
=[])
264 parser
.add_option('-d', '--dest',
265 help='Select which build destinations (project types) are valid.',
267 parser
.add_option('-v', '--verbose', action
='store_true')
269 # To setup bash completion for this command first install optcomplete
270 # and then add this line to your .bashrc:
271 # complete -F _optcomplete build_projects.py
274 optcomplete
.autocomplete(parser
)
278 options
, args
= parser
.parse_args(argv
[1:])
284 buildbot_common
.verbose
= verbose
286 if 'NACL_SDK_ROOT' in os
.environ
:
287 # We don't want the currently configured NACL_SDK_ROOT to have any effect
289 del os
.environ
['NACL_SDK_ROOT']
291 pepper_ver
= str(int(build_version
.ChromeMajorVersion()))
292 pepperdir
= os
.path
.join(OUT_DIR
, 'pepper_' + pepper_ver
)
294 if not options
.toolchain
:
295 # Order matters here: the default toolchain for an example's Makefile will
296 # be the first toolchain in this list that is available in the example.
297 # e.g. If an example supports newlib and glibc, then the default will be
299 options
.toolchain
= ['pnacl', 'newlib', 'glibc', 'host']
300 if options
.experimental
or options
.bionic
:
301 options
.toolchain
.append('bionic')
303 if 'host' in options
.toolchain
:
304 options
.toolchain
.remove('host')
305 options
.toolchain
.append(getos
.GetPlatform())
306 Trace('Adding platform: ' + getos
.GetPlatform())
308 ValidateToolchains(options
.toolchain
)
311 if options
.toolchain
:
312 filters
['TOOLS'] = options
.toolchain
313 Trace('Filter by toolchain: ' + str(options
.toolchain
))
314 if not options
.experimental
:
315 filters
['EXPERIMENTAL'] = False
317 filters
['DEST'] = options
.dest
318 Trace('Filter by type: ' + str(options
.dest
))
320 filters
['NAME'] = args
321 Trace('Filter by name: ' + str(args
))
324 project_tree
= parse_dsc
.LoadProjectTree(SDK_SRC_DIR
, include
=filters
)
325 except parse_dsc
.ValidationError
as e
:
326 buildbot_common
.ErrorExit(str(e
))
329 parse_dsc
.PrintProjectTree(project_tree
)
331 UpdateHelpers(pepperdir
, clobber
=options
.clobber
)
332 UpdateProjects(pepperdir
, project_tree
, options
.toolchain
,
333 clobber
=options
.clobber
)
337 configs
= [options
.config
]
339 configs
= ['Debug', 'Release']
340 for config
in configs
:
341 BuildProjects(pepperdir
, project_tree
, config
=config
, deps
=False)
346 if __name__
== '__main__':
347 script_name
= os
.path
.basename(sys
.argv
[0])
349 sys
.exit(main(sys
.argv
))
350 except parse_dsc
.ValidationError
as e
:
351 buildbot_common
.ErrorExit('%s: %s' % (script_name
, e
))
352 except KeyboardInterrupt:
353 buildbot_common
.ErrorExit('%s: interrupted' % script_name
)