Update To 11.40.268.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   combined_permissions = list(permissions)
151   socket_permissions = desc.get('SOCKET_PERMISSIONS', [])
152   if socket_permissions:
153     combined_permissions.append({'socket': socket_permissions})
154   filesystem_permissions = desc.get('FILESYSTEM_PERMISSIONS', [])
155   if filesystem_permissions:
156     combined_permissions.append({'fileSystem': filesystem_permissions})
157   pretty_permissions = json.dumps(combined_permissions,
158                                   sort_keys=True, indent=4)
159   replace = {
160       'name': desc['TITLE'],
161       'description': '%s Example' % desc['TITLE'],
162       'key': True,
163       'channel': None,
164       'permissions': pretty_permissions,
165       'multi_platform': desc.get('MULTI_PLATFORM', False),
166       'version': build_version.ChromeVersionNoTrunk(),
167       'min_chrome_version': desc.get('MIN_CHROME_VERSION')
168   }
169   RunTemplateFileIfChanged(srcpath, dstpath, replace)
170
171
172 def FindAndCopyFiles(src_files, root, search_dirs, dst_dir):
173   buildbot_common.MakeDir(dst_dir)
174   for src_name in src_files:
175     src_file = FindFile(src_name, root, search_dirs)
176     if not src_file:
177       ErrorExit('Failed to find: ' + src_name)
178     dst_file = os.path.join(dst_dir, src_name)
179     if os.path.exists(dst_file):
180       if os.stat(src_file).st_mtime <= os.stat(dst_file).st_mtime:
181         Trace('Skipping "%s", destination "%s" is newer.' % (
182             src_file, dst_file))
183         continue
184     dst_path = os.path.dirname(dst_file)
185     if not os.path.exists(dst_path):
186       buildbot_common.MakeDir(dst_path)
187     buildbot_common.CopyFile(src_file, dst_file)
188
189
190 def ModifyDescInPlace(desc):
191   """Perform post-load processing on .dsc file data.
192
193   Currently this consists of:
194   - Add -Wall to CXXFLAGS
195   """
196
197   for target in desc['TARGETS']:
198     target.setdefault('CXXFLAGS', [])
199     target['CXXFLAGS'].insert(0, '-Wall')
200
201
202 def ProcessProject(pepperdir, srcroot, dstroot, desc, toolchains, configs=None,
203                    first_toolchain=False):
204   if not configs:
205     configs = ['Debug', 'Release']
206
207   name = desc['NAME']
208   out_dir = os.path.join(dstroot, desc['DEST'], name)
209   buildbot_common.MakeDir(out_dir)
210   srcdirs = desc.get('SEARCH', ['.', SDK_RESOURCE_DIR])
211
212   # Copy sources to example directory
213   sources = GenerateSourceCopyList(desc)
214   FindAndCopyFiles(sources, srcroot, srcdirs, out_dir)
215
216   # Copy public headers to the include directory.
217   for headers_set in desc.get('HEADERS', []):
218     headers = headers_set['FILES']
219     header_out_dir = os.path.join(dstroot, headers_set['DEST'])
220     FindAndCopyFiles(headers, srcroot, srcdirs, header_out_dir)
221
222   make_path = os.path.join(out_dir, 'Makefile')
223
224   outdir = os.path.dirname(os.path.abspath(make_path))
225   if getos.GetPlatform() == 'win':
226     AddMakeBat(pepperdir, outdir)
227
228   # If this project has no TARGETS, then we don't need to generate anything.
229   if 'TARGETS' not in desc:
230     return (name, desc['DEST'])
231
232   if IsNexe(desc):
233     template = os.path.join(SDK_RESOURCE_DIR, 'Makefile.example.template')
234   else:
235     template = os.path.join(SDK_RESOURCE_DIR, 'Makefile.library.template')
236
237   # Ensure the order of |tools| is the same as toolchains; that way if
238   # first_toolchain is set, it will choose based on the order of |toolchains|.
239   tools = [tool for tool in toolchains if tool in desc['TOOLS']]
240   if first_toolchain:
241     tools = [tools[0]]
242
243   ModifyDescInPlace(desc)
244
245   template_dict = {
246     'desc': desc,
247     'rel_sdk': '/'.join(['..'] * (len(desc['DEST'].split('/')) + 1)),
248     'pre': desc.get('PRE', ''),
249     'post': desc.get('POST', ''),
250     'tools': tools,
251     'sel_ldr': desc.get('SEL_LDR'),
252     'targets': desc['TARGETS'],
253     'multi_platform': desc.get('MULTI_PLATFORM', False),
254   }
255   RunTemplateFileIfChanged(template, make_path, template_dict)
256
257   if IsExample(desc):
258     ProcessHTML(srcroot, dstroot, desc, toolchains, configs,
259                 first_toolchain)
260     if not desc.get('NO_PACKAGE_FILES'):
261       GenerateManifest(srcroot, dstroot, desc)
262
263   return (name, desc['DEST'])
264
265
266 def GenerateMasterMakefile(pepperdir, out_path, targets, deps):
267   """Generate a Master Makefile that builds all examples.
268
269   Args:
270     pepperdir: NACL_SDK_ROOT
271     out_path: Root for output such that out_path+NAME = full path
272     targets: List of targets names
273   """
274   in_path = os.path.join(SDK_RESOURCE_DIR, 'Makefile.index.template')
275   out_path = os.path.join(out_path, 'Makefile')
276   rel_path = os.path.relpath(pepperdir, os.path.dirname(out_path))
277   template_dict = {
278     'projects': targets,
279     'deps' : deps,
280     'rel_sdk' : rel_path,
281   }
282   RunTemplateFileIfChanged(in_path, out_path, template_dict)
283   outdir = os.path.dirname(os.path.abspath(out_path))
284   if getos.GetPlatform() == 'win':
285     AddMakeBat(pepperdir, outdir)