generate_make.py revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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 'version': build_version.ChromeVersionNoTrunk() 163 } 164 RunTemplateFileIfChanged(srcpath, dstpath, replace) 165 166 167def 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 185def ProcessProject(pepperdir, srcroot, dstroot, desc, toolchains, configs=None, 186 first_toolchain=False): 187 if not configs: 188 configs = ['Debug', 'Release'] 189 190 name = desc['NAME'] 191 out_dir = os.path.join(dstroot, desc['DEST'], name) 192 buildbot_common.MakeDir(out_dir) 193 srcdirs = desc.get('SEARCH', ['.', SDK_RESOURCE_DIR]) 194 195 # Copy sources to example directory 196 sources = GenerateSourceCopyList(desc) 197 FindAndCopyFiles(sources, srcroot, srcdirs, out_dir) 198 199 # Copy public headers to the include directory. 200 for headers_set in desc.get('HEADERS', []): 201 headers = headers_set['FILES'] 202 header_out_dir = os.path.join(dstroot, headers_set['DEST']) 203 FindAndCopyFiles(headers, srcroot, srcdirs, header_out_dir) 204 205 make_path = os.path.join(out_dir, 'Makefile') 206 207 outdir = os.path.dirname(os.path.abspath(make_path)) 208 if getos.GetPlatform() == 'win': 209 AddMakeBat(pepperdir, outdir) 210 211 # If this project has no TARGETS, then we don't need to generate anything. 212 if 'TARGETS' not in desc: 213 return (name, desc['DEST']) 214 215 if IsNexe(desc): 216 template = os.path.join(SDK_RESOURCE_DIR, 'Makefile.example.template') 217 else: 218 template = os.path.join(SDK_RESOURCE_DIR, 'Makefile.library.template') 219 220 # Ensure the order of |tools| is the same as toolchains; that way if 221 # first_toolchain is set, it will choose based on the order of |toolchains|. 222 tools = [tool for tool in toolchains if tool in desc['TOOLS']] 223 if first_toolchain: 224 tools = [tools[0]] 225 for target in desc['TARGETS']: 226 target.setdefault('CXXFLAGS', []) 227 target['CXXFLAGS'].insert(0, '-Wall') 228 229 template_dict = { 230 'desc': desc, 231 'rel_sdk': '/'.join(['..'] * (len(desc['DEST'].split('/')) + 1)), 232 'pre': desc.get('PRE', ''), 233 'post': desc.get('POST', ''), 234 'tools': tools, 235 'targets': desc['TARGETS'], 236 } 237 RunTemplateFileIfChanged(template, make_path, template_dict) 238 239 if IsExample(desc): 240 ProcessHTML(srcroot, dstroot, desc, toolchains, configs, 241 first_toolchain) 242 if not desc.get('NO_PACKAGE_FILES'): 243 GenerateManifest(srcroot, dstroot, desc) 244 245 return (name, desc['DEST']) 246 247 248def GenerateMasterMakefile(pepperdir, out_path, targets): 249 """Generate a Master Makefile that builds all examples. 250 251 Args: 252 pepperdir: NACL_SDK_ROOT 253 out_path: Root for output such that out_path+NAME = full path 254 targets: List of targets names 255 """ 256 in_path = os.path.join(SDK_RESOURCE_DIR, 'Makefile.index.template') 257 out_path = os.path.join(out_path, 'Makefile') 258 rel_path = os.path.relpath(pepperdir, os.path.dirname(out_path)) 259 template_dict = { 260 'projects': targets, 261 'rel_sdk' : rel_path, 262 } 263 RunTemplateFileIfChanged(in_path, out_path, template_dict) 264 outdir = os.path.dirname(os.path.abspath(out_path)) 265 if getos.GetPlatform() == 'win': 266 AddMakeBat(pepperdir, outdir) 267