Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / build_tools / generate_make.py
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
5 import json
6 import os
7 import sys
8
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
15
16 def Trace(msg):
17   if Trace.verbose:
18     sys.stderr.write(str(msg) + '\n')
19 Trace.verbose = False
20
21
22 def IsExample(desc):
23   dest = desc['DEST']
24   return dest.startswith(('examples', 'tests', 'getting_started'))
25
26
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', [])
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
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
58
59
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
66
67
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)
73
74   if first_toolchain:
75     return [platforms[0]]
76   return platforms
77
78
79 def ErrorMsgFunc(text):
80   sys.stderr.write(text + '\n')
81
82
83 def 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
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)
114
115   ErrorMsgFunc('%s not found in:\n\t%s' % (name, '\n\t'.join(checks)))
116   return None
117
118
119 def IsNexe(desc):
120   for target in desc['TARGETS']:
121     if target['TYPE'] == 'main':
122       return True
123   return False
124
125
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')
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
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       'version': build_version.ChromeVersionNoTrunk()
163   }
164   RunTemplateFileIfChanged(srcpath, dstpath, replace)
165
166
167 def FindAndCopyFiles(src_files, root, search_dirs, dst_dir):
168   buildbot_common.MakeDir(dst_dir)
169   for src_name in src_files:
170     src_file = FindFile(src_name, root, search_dirs)
171     if not src_file:
172       ErrorExit('Failed to find: ' + src_name)
173     dst_file = os.path.join(dst_dir, src_name)
174     if os.path.exists(dst_file):
175       if os.stat(src_file).st_mtime <= os.stat(dst_file).st_mtime:
176         Trace('Skipping "%s", destination "%s" is newer.' % (
177             src_file, dst_file))
178         continue
179     dst_path = os.path.dirname(dst_file)
180     if not os.path.exists(dst_path):
181       buildbot_common.MakeDir(dst_path)
182     buildbot_common.CopyFile(src_file, dst_file)
183
184
185 def ModifyDescInPlace(desc):
186   """Perform post-load processing on .dsc file data.
187
188   Currently this consists of:
189   - Add -Wall to CXXFLAGS
190   - Synthesize SEL_LDR_LIBS and SEL_LDR_DEPS by stripping
191     down LIBS and DEPS (removing certain ppapi-only libs).
192   """
193
194   ppapi_only_libs = ['ppapi_simple']
195
196   for target in desc['TARGETS']:
197     target.setdefault('CXXFLAGS', [])
198     target['CXXFLAGS'].insert(0, '-Wall')
199
200     def filter_out(key):
201       value = target.get(key, [])
202       if type(value) == dict:
203         value = dict(value)
204         for key in value.keys():
205           value[key] = [v for v in value[key] if v not in ppapi_only_libs]
206       else:
207         value = [v for v in value if v not in ppapi_only_libs]
208       return value
209
210     target['SEL_LDR_LIBS'] = filter_out('LIBS')
211     target['SEL_LDR_DEPS'] = filter_out('DEPS')
212
213
214 def ProcessProject(pepperdir, srcroot, dstroot, desc, toolchains, configs=None,
215                    first_toolchain=False):
216   if not configs:
217     configs = ['Debug', 'Release']
218
219   name = desc['NAME']
220   out_dir = os.path.join(dstroot, desc['DEST'], name)
221   buildbot_common.MakeDir(out_dir)
222   srcdirs = desc.get('SEARCH', ['.', SDK_RESOURCE_DIR])
223
224   # Copy sources to example directory
225   sources = GenerateSourceCopyList(desc)
226   FindAndCopyFiles(sources, srcroot, srcdirs, out_dir)
227
228   # Copy public headers to the include directory.
229   for headers_set in desc.get('HEADERS', []):
230     headers = headers_set['FILES']
231     header_out_dir = os.path.join(dstroot, headers_set['DEST'])
232     FindAndCopyFiles(headers, srcroot, srcdirs, header_out_dir)
233
234   make_path = os.path.join(out_dir, 'Makefile')
235
236   outdir = os.path.dirname(os.path.abspath(make_path))
237   if getos.GetPlatform() == 'win':
238     AddMakeBat(pepperdir, outdir)
239
240   # If this project has no TARGETS, then we don't need to generate anything.
241   if 'TARGETS' not in desc:
242     return (name, desc['DEST'])
243
244   if IsNexe(desc):
245     template = os.path.join(SDK_RESOURCE_DIR, 'Makefile.example.template')
246   else:
247     template = os.path.join(SDK_RESOURCE_DIR, 'Makefile.library.template')
248
249   # Ensure the order of |tools| is the same as toolchains; that way if
250   # first_toolchain is set, it will choose based on the order of |toolchains|.
251   tools = [tool for tool in toolchains if tool in desc['TOOLS']]
252   if first_toolchain:
253     tools = [tools[0]]
254
255   ModifyDescInPlace(desc)
256
257   template_dict = {
258     'desc': desc,
259     'rel_sdk': '/'.join(['..'] * (len(desc['DEST'].split('/')) + 1)),
260     'pre': desc.get('PRE', ''),
261     'post': desc.get('POST', ''),
262     'tools': tools,
263     'sel_ldr': desc.get('SEL_LDR'),
264     'targets': desc['TARGETS'],
265   }
266   RunTemplateFileIfChanged(template, make_path, template_dict)
267
268   if IsExample(desc):
269     ProcessHTML(srcroot, dstroot, desc, toolchains, configs,
270                 first_toolchain)
271     if not desc.get('NO_PACKAGE_FILES'):
272       GenerateManifest(srcroot, dstroot, desc)
273
274   return (name, desc['DEST'])
275
276
277 def GenerateMasterMakefile(pepperdir, out_path, targets):
278   """Generate a Master Makefile that builds all examples.
279
280   Args:
281     pepperdir: NACL_SDK_ROOT
282     out_path: Root for output such that out_path+NAME = full path
283     targets: List of targets names
284   """
285   in_path = os.path.join(SDK_RESOURCE_DIR, 'Makefile.index.template')
286   out_path = os.path.join(out_path, 'Makefile')
287   rel_path = os.path.relpath(pepperdir, os.path.dirname(out_path))
288   template_dict = {
289     'projects': targets,
290     'rel_sdk' : rel_path,
291   }
292   RunTemplateFileIfChanged(in_path, out_path, template_dict)
293   outdir = os.path.dirname(os.path.abspath(out_path))
294   if getos.GetPlatform() == 'win':
295     AddMakeBat(pepperdir, outdir)