• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2012 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import json
6import os
7import sys
8
9import buildbot_common
10import build_version
11import getos
12from buildbot_common import ErrorExit
13from easy_template import RunTemplateFileIfChanged
14from build_paths import SDK_RESOURCE_DIR
15
16def Trace(msg):
17  if Trace.verbose:
18    sys.stderr.write(str(msg) + '\n')
19Trace.verbose = False
20
21
22def IsExample(desc):
23  dest = desc['DEST']
24  return dest.startswith(('examples', 'tests', 'getting_started'))
25
26
27def GenerateSourceCopyList(desc):
28  sources = []
29  # Some examples use their own Makefile/sources/etc.
30  if 'TARGETS' not in desc:
31    # Only copy the DATA files.
32    return desc.get('DATA', [])
33
34  # Add sources for each target
35  for target in desc['TARGETS']:
36    sources.extend(target['SOURCES'])
37
38  # And HTML and data files
39  sources.extend(desc.get('DATA', []))
40
41  if IsExample(desc):
42    sources.append('common.js')
43    if not desc.get('NO_PACKAGE_FILES'):
44      sources.extend(['icon128.png', 'background.js'])
45
46  return sources
47
48
49def GetSourcesDict(sources):
50  source_map = {}
51  for key in ['.c', '.cc']:
52    source_list = [fname for fname in sources if fname.endswith(key)]
53    if source_list:
54      source_map[key] = source_list
55    else:
56      source_map[key] = []
57  return source_map
58
59
60def GetProjectObjects(source_dict):
61  object_list = []
62  for key in ['.c', '.cc']:
63    for src in source_dict[key]:
64      object_list.append(os.path.splitext(src)[0])
65  return object_list
66
67
68def GetPlatforms(plat_list, plat_filter, first_toolchain):
69  platforms = []
70  for plat in plat_list:
71    if plat in plat_filter:
72      platforms.append(plat)
73
74  if first_toolchain:
75    return [platforms[0]]
76  return platforms
77
78
79def ErrorMsgFunc(text):
80  sys.stderr.write(text + '\n')
81
82
83def AddMakeBat(pepperdir, makepath):
84  """Create a simple batch file to execute Make.
85
86  Creates a simple batch file named make.bat for the Windows platform at the
87  given path, pointing to the Make executable in the SDK."""
88
89  makepath = os.path.abspath(makepath)
90  if not makepath.startswith(pepperdir):
91    ErrorExit('Make.bat not relative to Pepper directory: ' + makepath)
92
93  makeexe = os.path.abspath(os.path.join(pepperdir, 'tools'))
94  relpath = os.path.relpath(makeexe, makepath)
95
96  fp = open(os.path.join(makepath, 'make.bat'), 'wb')
97  outpath = os.path.join(relpath, 'make.exe')
98
99  # Since make.bat is only used by Windows, for Windows path style
100  outpath = outpath.replace(os.path.sep, '\\')
101  fp.write('@%s %%*\n' % outpath)
102  fp.close()
103
104
105def FindFile(name, srcroot, srcdirs):
106  checks = []
107  for srcdir in srcdirs:
108    srcfile = os.path.join(srcroot, srcdir, name)
109    srcfile = os.path.abspath(srcfile)
110    if os.path.exists(srcfile):
111      return srcfile
112    else:
113      checks.append(srcfile)
114
115  ErrorMsgFunc('%s not found in:\n\t%s' % (name, '\n\t'.join(checks)))
116  return None
117
118
119def IsNexe(desc):
120  for target in desc['TARGETS']:
121    if target['TYPE'] == 'main':
122      return True
123  return False
124
125
126def ProcessHTML(srcroot, dstroot, desc, toolchains, configs, first_toolchain):
127  name = desc['NAME']
128  nmf = desc['TARGETS'][0]['NAME']
129  outdir = os.path.join(dstroot, desc['DEST'], name)
130  srcpath = os.path.join(srcroot, 'index.html')
131  dstpath = os.path.join(outdir, 'index.html')
132
133  tools = GetPlatforms(toolchains, desc['TOOLS'], first_toolchain)
134
135  path = "{tc}/{config}"
136  replace = {
137    'title': desc['TITLE'],
138    'attrs':
139        'data-name="%s" data-tools="%s" data-configs="%s" data-path="%s"' % (
140        nmf, ' '.join(tools), ' '.join(configs), path),
141  }
142  RunTemplateFileIfChanged(srcpath, dstpath, replace)
143
144
145def GenerateManifest(srcroot, dstroot, desc):
146  outdir = os.path.join(dstroot, desc['DEST'], desc['NAME'])
147  srcpath = os.path.join(SDK_RESOURCE_DIR, 'manifest.json.template')
148  dstpath = os.path.join(outdir, 'manifest.json')
149  permissions = desc.get('PERMISSIONS', [])
150  socket_permissions = desc.get('SOCKET_PERMISSIONS', [])
151  combined_permissions = list(permissions)
152  if socket_permissions:
153    combined_permissions.append({'socket': socket_permissions})
154  pretty_permissions = json.dumps(combined_permissions,
155                                  sort_keys=True, indent=4)
156  replace = {
157      'name': desc['TITLE'],
158      'description': '%s Example' % desc['TITLE'],
159      'key': True,
160      'channel': None,
161      'permissions': pretty_permissions,
162      'multi_platform': desc.get('MULTI_PLATFORM', False),
163      'version': build_version.ChromeVersionNoTrunk(),
164      'min_chrome_version': desc.get('MIN_CHROME_VERSION')
165  }
166  RunTemplateFileIfChanged(srcpath, dstpath, replace)
167
168
169def FindAndCopyFiles(src_files, root, search_dirs, dst_dir):
170  buildbot_common.MakeDir(dst_dir)
171  for src_name in src_files:
172    src_file = FindFile(src_name, root, search_dirs)
173    if not src_file:
174      ErrorExit('Failed to find: ' + src_name)
175    dst_file = os.path.join(dst_dir, src_name)
176    if os.path.exists(dst_file):
177      if os.stat(src_file).st_mtime <= os.stat(dst_file).st_mtime:
178        Trace('Skipping "%s", destination "%s" is newer.' % (
179            src_file, dst_file))
180        continue
181    dst_path = os.path.dirname(dst_file)
182    if not os.path.exists(dst_path):
183      buildbot_common.MakeDir(dst_path)
184    buildbot_common.CopyFile(src_file, dst_file)
185
186
187def ModifyDescInPlace(desc):
188  """Perform post-load processing on .dsc file data.
189
190  Currently this consists of:
191  - Add -Wall to CXXFLAGS
192  """
193
194  for target in desc['TARGETS']:
195    target.setdefault('CXXFLAGS', [])
196    target['CXXFLAGS'].insert(0, '-Wall')
197
198
199def ProcessProject(pepperdir, srcroot, dstroot, desc, toolchains, configs=None,
200                   first_toolchain=False):
201  if not configs:
202    configs = ['Debug', 'Release']
203
204  name = desc['NAME']
205  out_dir = os.path.join(dstroot, desc['DEST'], name)
206  buildbot_common.MakeDir(out_dir)
207  srcdirs = desc.get('SEARCH', ['.', SDK_RESOURCE_DIR])
208
209  # Copy sources to example directory
210  sources = GenerateSourceCopyList(desc)
211  FindAndCopyFiles(sources, srcroot, srcdirs, out_dir)
212
213  # Copy public headers to the include directory.
214  for headers_set in desc.get('HEADERS', []):
215    headers = headers_set['FILES']
216    header_out_dir = os.path.join(dstroot, headers_set['DEST'])
217    FindAndCopyFiles(headers, srcroot, srcdirs, header_out_dir)
218
219  make_path = os.path.join(out_dir, 'Makefile')
220
221  outdir = os.path.dirname(os.path.abspath(make_path))
222  if getos.GetPlatform() == 'win':
223    AddMakeBat(pepperdir, outdir)
224
225  # If this project has no TARGETS, then we don't need to generate anything.
226  if 'TARGETS' not in desc:
227    return (name, desc['DEST'])
228
229  if IsNexe(desc):
230    template = os.path.join(SDK_RESOURCE_DIR, 'Makefile.example.template')
231  else:
232    template = os.path.join(SDK_RESOURCE_DIR, 'Makefile.library.template')
233
234  # Ensure the order of |tools| is the same as toolchains; that way if
235  # first_toolchain is set, it will choose based on the order of |toolchains|.
236  tools = [tool for tool in toolchains if tool in desc['TOOLS']]
237  if first_toolchain:
238    tools = [tools[0]]
239
240  ModifyDescInPlace(desc)
241
242  template_dict = {
243    'desc': desc,
244    'rel_sdk': '/'.join(['..'] * (len(desc['DEST'].split('/')) + 1)),
245    'pre': desc.get('PRE', ''),
246    'post': desc.get('POST', ''),
247    'tools': tools,
248    'sel_ldr': desc.get('SEL_LDR'),
249    'targets': desc['TARGETS'],
250    'multi_platform': desc.get('MULTI_PLATFORM', False),
251  }
252  RunTemplateFileIfChanged(template, make_path, template_dict)
253
254  if IsExample(desc):
255    ProcessHTML(srcroot, dstroot, desc, toolchains, configs,
256                first_toolchain)
257    if not desc.get('NO_PACKAGE_FILES'):
258      GenerateManifest(srcroot, dstroot, desc)
259
260  return (name, desc['DEST'])
261
262
263def GenerateMasterMakefile(pepperdir, out_path, targets, deps):
264  """Generate a Master Makefile that builds all examples.
265
266  Args:
267    pepperdir: NACL_SDK_ROOT
268    out_path: Root for output such that out_path+NAME = full path
269    targets: List of targets names
270  """
271  in_path = os.path.join(SDK_RESOURCE_DIR, 'Makefile.index.template')
272  out_path = os.path.join(out_path, 'Makefile')
273  rel_path = os.path.relpath(pepperdir, os.path.dirname(out_path))
274  template_dict = {
275    'projects': targets,
276    'deps' : deps,
277    'rel_sdk' : rel_path,
278  }
279  RunTemplateFileIfChanged(in_path, out_path, template_dict)
280  outdir = os.path.dirname(os.path.abspath(out_path))
281  if getos.GetPlatform() == 'win':
282    AddMakeBat(pepperdir, outdir)
283