generate_make.py revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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 os
6import sys
7
8import buildbot_common
9import build_utils
10from buildbot_common import ErrorExit
11from easy_template import RunTemplateFileIfChanged
12from build_paths import SCRIPT_DIR, SDK_EXAMPLE_DIR
13
14def Trace(msg):
15  if Trace.verbose:
16    sys.stderr.write(str(msg) + '\n')
17Trace.verbose = False
18
19
20def IsExample(desc):
21  dest = desc['DEST']
22  return dest.startswith('examples') or dest.startswith('tests')
23
24
25def GenerateSourceCopyList(desc):
26  sources = []
27  # Add sources for each target
28  for target in desc['TARGETS']:
29    sources.extend(target['SOURCES'])
30
31  # And HTML and data files
32  sources.extend(desc.get('DATA', []))
33
34  if IsExample(desc):
35    sources.extend(['common.js', 'icon128.png', 'background.js'])
36
37  return sources
38
39
40def GetSourcesDict(sources):
41  source_map = {}
42  for key in ['.c', '.cc']:
43    source_list = [fname for fname in sources if fname.endswith(key)]
44    if source_list:
45      source_map[key] = source_list
46    else:
47      source_map[key] = []
48  return source_map
49
50
51def GetProjectObjects(source_dict):
52  object_list = []
53  for key in ['.c', '.cc']:
54    for src in source_dict[key]:
55      object_list.append(os.path.splitext(src)[0])
56  return object_list
57
58
59def GetPlatforms(plat_list, plat_filter, first_toolchain):
60  platforms = []
61  for plat in plat_list:
62    if plat in plat_filter:
63      platforms.append(plat)
64
65  if first_toolchain:
66    return [platforms[0]]
67  return platforms
68
69
70def ErrorMsgFunc(text):
71  sys.stderr.write(text + '\n')
72
73
74def AddMakeBat(pepperdir, makepath):
75  """Create a simple batch file to execute Make.
76
77  Creates a simple batch file named make.bat for the Windows platform at the
78  given path, pointing to the Make executable in the SDK."""
79
80  makepath = os.path.abspath(makepath)
81  if not makepath.startswith(pepperdir):
82    ErrorExit('Make.bat not relative to Pepper directory: ' + makepath)
83
84  makeexe = os.path.abspath(os.path.join(pepperdir, 'tools'))
85  relpath = os.path.relpath(makeexe, makepath)
86
87  fp = open(os.path.join(makepath, 'make.bat'), 'wb')
88  outpath = os.path.join(relpath, 'make.exe')
89
90  # Since make.bat is only used by Windows, for Windows path style
91  outpath = outpath.replace(os.path.sep, '\\')
92  fp.write('@%s %%*\n' % outpath)
93  fp.close()
94
95
96def FindFile(name, srcroot, srcdirs):
97  checks = []
98  for srcdir in srcdirs:
99    srcfile = os.path.join(srcroot, srcdir, name)
100    srcfile = os.path.abspath(srcfile)
101    if os.path.exists(srcfile):
102      return srcfile
103    else:
104      checks.append(srcfile)
105
106  ErrorMsgFunc('%s not found in:\n\t%s' % (name, '\n\t'.join(checks)))
107  return None
108
109
110def IsNexe(desc):
111  for target in desc['TARGETS']:
112    if target['TYPE'] == 'main':
113      return True
114  return False
115
116
117def ProcessHTML(srcroot, dstroot, desc, toolchains, configs, first_toolchain):
118  name = desc['NAME']
119  nmf = desc['TARGETS'][0]['NAME']
120  outdir = os.path.join(dstroot, desc['DEST'], name)
121  srcpath = os.path.join(srcroot, 'index.html')
122  dstpath = os.path.join(outdir, 'index.html')
123
124  tools = GetPlatforms(toolchains, desc['TOOLS'], first_toolchain)
125
126  path = "{tc}/{config}"
127  replace = {
128    'title': desc['TITLE'],
129    'attrs':
130        'data-name="%s" data-tools="%s" data-configs="%s" data-path="%s"' % (
131        nmf, ' '.join(tools), ' '.join(configs), path),
132  }
133  RunTemplateFileIfChanged(srcpath, dstpath, replace)
134
135
136def GenerateManifest(srcroot, dstroot, desc):
137  outdir = os.path.join(dstroot, desc['DEST'], desc['NAME'])
138  srcpath = os.path.join(SDK_EXAMPLE_DIR, 'resources', 'manifest.json.template')
139  dstpath = os.path.join(outdir, 'manifest.json')
140  replace = {
141      'name': desc['TITLE'],
142      'description': '%s Example' % desc['TITLE'],
143      'permissions': desc.get('PERMISSIONS', []),
144      'version': build_utils.ChromeVersionNoTrunk()
145  }
146  RunTemplateFileIfChanged(srcpath, dstpath, replace)
147
148
149def FindAndCopyFiles(src_files, root, search_dirs, dst_dir):
150  buildbot_common.MakeDir(dst_dir)
151  for src_name in src_files:
152    src_file = FindFile(src_name, root, search_dirs)
153    if not src_file:
154      ErrorExit('Failed to find: ' + src_name)
155    dst_file = os.path.join(dst_dir, src_name)
156    if os.path.exists(dst_file):
157      if os.stat(src_file).st_mtime <= os.stat(dst_file).st_mtime:
158        Trace('Skipping "%s", destination "%s" is newer.' % (
159            src_file, dst_file))
160        continue
161    buildbot_common.CopyFile(src_file, dst_file)
162
163
164def ProcessProject(srcroot, dstroot, desc, toolchains, configs=None,
165                   first_toolchain=False):
166  if not configs:
167    configs = ['Debug', 'Release']
168
169  name = desc['NAME']
170  out_dir = os.path.join(dstroot, desc['DEST'], name)
171  buildbot_common.MakeDir(out_dir)
172  srcdirs = desc.get('SEARCH', ['.', '..', '../..'])
173  srcdirs.append(os.path.join(SDK_EXAMPLE_DIR, 'resources'))
174
175  # Copy sources to example directory
176  sources = GenerateSourceCopyList(desc)
177  FindAndCopyFiles(sources, srcroot, srcdirs, out_dir)
178
179  # Copy public headers to the include directory.
180  for headers_set in desc.get('HEADERS', []):
181    headers = headers_set['FILES']
182    header_out_dir = os.path.join(dstroot, headers_set['DEST'])
183    FindAndCopyFiles(headers, srcroot, srcdirs, header_out_dir)
184
185  make_path = os.path.join(out_dir, 'Makefile')
186
187  if IsNexe(desc):
188    template = os.path.join(SCRIPT_DIR, 'template.mk')
189  else:
190    template = os.path.join(SCRIPT_DIR, 'library.mk')
191
192  # Ensure the order of |tools| is the same as toolchains; that way if
193  # first_toolchain is set, it will choose based on the order of |toolchains|.
194  tools = [tool for tool in toolchains if tool in desc['TOOLS']]
195  if first_toolchain:
196    tools = [tools[0]]
197  template_dict = {
198    'rel_sdk': '/'.join(['..'] * (len(desc['DEST'].split('/')) + 1)),
199    'pre': desc.get('PRE', ''),
200    'post': desc.get('POST', ''),
201    'tools': tools,
202    'targets': desc['TARGETS'],
203  }
204  RunTemplateFileIfChanged(template, make_path, template_dict)
205
206  outdir = os.path.dirname(os.path.abspath(make_path))
207  pepperdir = os.path.dirname(os.path.dirname(outdir))
208  AddMakeBat(pepperdir, outdir)
209
210  if IsExample(desc):
211    ProcessHTML(srcroot, dstroot, desc, toolchains, configs,
212                first_toolchain)
213    GenerateManifest(srcroot, dstroot, desc)
214
215  return (name, desc['DEST'])
216
217
218def GenerateMasterMakefile(out_path, targets, depth):
219  """Generate a Master Makefile that builds all examples.
220
221  Args:
222    out_path: Root for output such that out_path+NAME = full path
223    targets: List of targets names
224    depth: How deep in from NACL_SDK_ROOT
225  """
226  in_path = os.path.join(SDK_EXAMPLE_DIR, 'Makefile')
227  out_path = os.path.join(out_path, 'Makefile')
228  template_dict = {
229    'projects': targets,
230    'rel_sdk' : '/'.join(['..'] * depth)
231  }
232  RunTemplateFileIfChanged(in_path, out_path, template_dict)
233  outdir = os.path.dirname(os.path.abspath(out_path))
234  pepperdir = os.path.dirname(outdir)
235  AddMakeBat(pepperdir, outdir)
236
237
238