Home | History | Annotate | Download | only in build_tools
      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