Mojo C++ bindings: better log message for serialization warnings.
[chromium-blink-merge.git] / native_client_sdk / src / build_tools / generate_make.py
blobfebbd51fc7ff45b17b834faac8abd4e63b5f5035
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.
5 import json
6 import os
7 import sys
9 import buildbot_common
10 import build_version
11 import getos
12 from buildbot_common import ErrorExit
13 from easy_template import RunTemplateFileIfChanged
14 from build_paths import SDK_RESOURCE_DIR
16 def Trace(msg):
17 if Trace.verbose:
18 sys.stderr.write(str(msg) + '\n')
19 Trace.verbose = False
22 def IsExample(desc):
23 dest = desc['DEST']
24 return dest.startswith(('examples', 'tests', 'getting_started'))
27 def 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', [])
34 # Add sources for each target
35 for target in desc['TARGETS']:
36 sources.extend(target['SOURCES'])
38 # And HTML and data files
39 sources.extend(desc.get('DATA', []))
41 if IsExample(desc):
42 sources.append('common.js')
43 if not desc.get('NO_PACKAGE_FILES'):
44 sources.extend(['icon128.png', 'background.js'])
46 return sources
49 def 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
60 def 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
68 def 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)
74 if first_toolchain:
75 return [platforms[0]]
76 return platforms
79 def ErrorMsgFunc(text):
80 sys.stderr.write(text + '\n')
83 def AddMakeBat(pepperdir, makepath):
84 """Create a simple batch file to execute Make.
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."""
89 makepath = os.path.abspath(makepath)
90 if not makepath.startswith(pepperdir):
91 ErrorExit('Make.bat not relative to Pepper directory: ' + makepath)
93 makeexe = os.path.abspath(os.path.join(pepperdir, 'tools'))
94 relpath = os.path.relpath(makeexe, makepath)
96 fp = open(os.path.join(makepath, 'make.bat'), 'wb')
97 outpath = os.path.join(relpath, 'make.exe')
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()
105 def 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)
115 ErrorMsgFunc('%s not found in:\n\t%s' % (name, '\n\t'.join(checks)))
116 return None
119 def IsNexe(desc):
120 for target in desc['TARGETS']:
121 if target['TYPE'] == 'main':
122 return True
123 return False
126 def 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')
133 tools = GetPlatforms(toolchains, desc['TOOLS'], first_toolchain)
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),
142 RunTemplateFileIfChanged(srcpath, dstpath, replace)
145 def 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')
166 RunTemplateFileIfChanged(srcpath, dstpath, replace)
169 def 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)
187 def ModifyDescInPlace(desc):
188 """Perform post-load processing on .dsc file data.
190 Currently this consists of:
191 - Add -Wall to CXXFLAGS
192 - Synthesize SEL_LDR_LIBS and SEL_LDR_DEPS by stripping
193 down LIBS and DEPS (removing certain ppapi-only libs).
196 ppapi_only_libs = ['ppapi_simple']
198 for target in desc['TARGETS']:
199 target.setdefault('CXXFLAGS', [])
200 target['CXXFLAGS'].insert(0, '-Wall')
202 def filter_out(key):
203 value = target.get(key, [])
204 if type(value) == dict:
205 value = dict(value)
206 for key in value.keys():
207 value[key] = [v for v in value[key] if v not in ppapi_only_libs]
208 else:
209 value = [v for v in value if v not in ppapi_only_libs]
210 return value
212 target['SEL_LDR_LIBS'] = filter_out('LIBS')
213 target['SEL_LDR_DEPS'] = filter_out('DEPS')
216 def ProcessProject(pepperdir, srcroot, dstroot, desc, toolchains, configs=None,
217 first_toolchain=False):
218 if not configs:
219 configs = ['Debug', 'Release']
221 name = desc['NAME']
222 out_dir = os.path.join(dstroot, desc['DEST'], name)
223 buildbot_common.MakeDir(out_dir)
224 srcdirs = desc.get('SEARCH', ['.', SDK_RESOURCE_DIR])
226 # Copy sources to example directory
227 sources = GenerateSourceCopyList(desc)
228 FindAndCopyFiles(sources, srcroot, srcdirs, out_dir)
230 # Copy public headers to the include directory.
231 for headers_set in desc.get('HEADERS', []):
232 headers = headers_set['FILES']
233 header_out_dir = os.path.join(dstroot, headers_set['DEST'])
234 FindAndCopyFiles(headers, srcroot, srcdirs, header_out_dir)
236 make_path = os.path.join(out_dir, 'Makefile')
238 outdir = os.path.dirname(os.path.abspath(make_path))
239 if getos.GetPlatform() == 'win':
240 AddMakeBat(pepperdir, outdir)
242 # If this project has no TARGETS, then we don't need to generate anything.
243 if 'TARGETS' not in desc:
244 return (name, desc['DEST'])
246 if IsNexe(desc):
247 template = os.path.join(SDK_RESOURCE_DIR, 'Makefile.example.template')
248 else:
249 template = os.path.join(SDK_RESOURCE_DIR, 'Makefile.library.template')
251 # Ensure the order of |tools| is the same as toolchains; that way if
252 # first_toolchain is set, it will choose based on the order of |toolchains|.
253 tools = [tool for tool in toolchains if tool in desc['TOOLS']]
254 if first_toolchain:
255 tools = [tools[0]]
257 ModifyDescInPlace(desc)
259 template_dict = {
260 'desc': desc,
261 'rel_sdk': '/'.join(['..'] * (len(desc['DEST'].split('/')) + 1)),
262 'pre': desc.get('PRE', ''),
263 'post': desc.get('POST', ''),
264 'tools': tools,
265 'sel_ldr': desc.get('SEL_LDR'),
266 'targets': desc['TARGETS'],
267 'multi_platform': desc.get('MULTI_PLATFORM', False),
269 RunTemplateFileIfChanged(template, make_path, template_dict)
271 if IsExample(desc):
272 ProcessHTML(srcroot, dstroot, desc, toolchains, configs,
273 first_toolchain)
274 if not desc.get('NO_PACKAGE_FILES'):
275 GenerateManifest(srcroot, dstroot, desc)
277 return (name, desc['DEST'])
280 def GenerateMasterMakefile(pepperdir, out_path, targets, deps):
281 """Generate a Master Makefile that builds all examples.
283 Args:
284 pepperdir: NACL_SDK_ROOT
285 out_path: Root for output such that out_path+NAME = full path
286 targets: List of targets names
288 in_path = os.path.join(SDK_RESOURCE_DIR, 'Makefile.index.template')
289 out_path = os.path.join(out_path, 'Makefile')
290 rel_path = os.path.relpath(pepperdir, os.path.dirname(out_path))
291 template_dict = {
292 'projects': targets,
293 'deps' : deps,
294 'rel_sdk' : rel_path,
296 RunTemplateFileIfChanged(in_path, out_path, template_dict)
297 outdir = os.path.dirname(os.path.abspath(out_path))
298 if getos.GetPlatform() == 'win':
299 AddMakeBat(pepperdir, outdir)