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