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