Home | History | Annotate | Download | only in build_tools
      1 #!/usr/bin/env python
      2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 import StringIO
      6 import sys
      7 import os
      8 import optparse
      9 
     10 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
     11 sys.path.append(os.path.join(os.path.dirname(SCRIPT_DIR), 'tools'))
     12 
     13 import getos
     14 
     15 valid_tools = ['newlib', 'glibc', getos.GetPlatform()]
     16 
     17 
     18 def Error(msg):
     19   print(msg)
     20   sys.exit(1)
     21 
     22 
     23 PREAMBLE = """\
     24 {
     25   'includes': ['%s/build_tools/nacl.gypi'],
     26 """
     27 
     28 NEXE_TARGET = """\
     29     {
     30       'target_name': '%(NAME)s_x86_32%(EXT)s',
     31       'product_name': '%(NAME)s_x86_32%(EXT)s',
     32       'type': '%(GYP_TYPE)s',
     33       'sources': %(SOURCES)s,
     34       'libraries': %(LIBS)s,
     35       'include_dirs': %(INCLUDES)s,
     36       'cflags': ['-m32', '-pedantic'] + %(CFLAGS)s,
     37       'make_valid_configurations': ['newlib-debug', 'newlib-release',
     38                                     'glibc-debug', 'glibc-release'],
     39       'ldflags': ['-m32', '-L../../lib/x86_32/<(CONFIGURATION_NAME)'],
     40       'toolset': 'target',
     41       %(CONFIGS)s
     42     },
     43     {
     44       'target_name': '%(NAME)s_x86_64%(EXT)s',
     45       'product_name': '%(NAME)s_x86_64%(EXT)s',
     46       'type': '%(GYP_TYPE)s',
     47       'sources': %(SOURCES)s,
     48       'libraries': %(LIBS)s,
     49       'include_dirs': %(INCLUDES)s,
     50       'make_valid_configurations': ['newlib-debug', 'newlib-release',
     51                                     'glibc-debug', 'glibc-release'],
     52       'cflags': ['-m64', '-pedantic'] + %(CFLAGS)s,
     53       'ldflags': ['-m64', '-L../../lib/x86_64/<(CONFIGURATION_NAME)'],
     54       'toolset': 'target',
     55       %(CONFIGS)s
     56     },
     57 """
     58 
     59 NLIB_TARGET = """\
     60     {
     61       'target_name': '%(NAME)s_x86_32%(EXT)s',
     62       'product_name': 'lib%(NAME)s%(EXT)s',
     63       'product_dir': '../../lib/x86_32/<(CONFIGURATION_NAME)',
     64       'type': '%(GYP_TYPE)s',
     65       'sources': %(SOURCES)s,
     66       'libraries': %(LIBS)s,
     67       'include_dirs': %(INCLUDES)s,
     68       'cflags': ['-m32', '-pedantic'] + %(CFLAGS)s,
     69       'make_valid_configurations': ['newlib-debug', 'newlib-release',
     70                                     'glibc-debug', 'glibc-release'],
     71       'ldflags': ['-m32'],
     72       'toolset': 'target',
     73       %(CONFIGS)s
     74     },
     75     {
     76       'target_name': '%(NAME)s_x86_64%(EXT)s',
     77       'product_name': 'lib%(NAME)s%(EXT)s',
     78       'product_dir': '../../lib/x86_64/<(CONFIGURATION_NAME)',
     79       'type': '%(GYP_TYPE)s',
     80       'sources': %(SOURCES)s,
     81       'libraries': %(LIBS)s,
     82       'include_dirs': %(INCLUDES)s,
     83       'make_valid_configurations': ['newlib-debug', 'newlib-release',
     84                                     'glibc-debug', 'glibc-release'],
     85       'cflags': ['-m64', '-pedantic'] + %(CFLAGS)s,
     86       'ldflags': ['-m64'],
     87       'toolset': 'target',
     88       %(CONFIGS)s
     89     },
     90 """
     91 
     92 HOST_LIB_TARGET = """\
     93     {
     94       'target_name': '%(NAME)s%(EXT)s',
     95       'type': '%(GYP_TYPE)s',
     96       'toolset': 'host',
     97       'sources': %(SOURCES)s,
     98       'cflags': %(CFLAGS)s,
     99       'cflags_c': ['-std=gnu99'],
    100       'include_dirs': %(INCLUDES)s,
    101       'make_valid_configurations': ['host-debug', 'host-release'],
    102       'product_dir': '../../lib/%(ARCH)s/<(CONFIGURATION_NAME)',
    103       'product_name': '%(NAME)s%(EXT)s',
    104       %(CONFIGS)s
    105     },
    106 """
    107 
    108 HOST_EXE_TARGET = """\
    109     {
    110       'target_name': '%(NAME)s%(EXT)s',
    111       'type': '%(GYP_TYPE)s',
    112       'toolset': 'host',
    113       'sources': %(SOURCES)s,
    114       'cflags': %(CFLAGS)s,
    115       'cflags_c': ['-std=gnu99'],
    116       'ldflags': ['-L../../lib/%(ARCH)s/<(CONFIGURATION_NAME)'],
    117       'libraries': %(LIBS)s,
    118       'include_dirs': %(INCLUDES)s,
    119       'make_valid_configurations': ['host-debug', 'host-release'],
    120       'msvs_settings': {
    121         'VCLinkerTool': {
    122           'AdditionalLibraryDirectories':
    123             ['../../lib/%(ARCH)s/<(CONFIGURATION_NAME)'],
    124          }
    125        },
    126        %(CONFIGS)s
    127     },
    128 """
    129 
    130 NMF_TARGET = """\
    131     {
    132       'target_name': '%(NAME)s_%(TOOLCHAIN)s.nmf',
    133       'product_name': '%(NAME)s.nmf',
    134       'product_dir': '<(PRODUCT_DIR)/%(TOOLCHAIN)s',
    135       'type': 'none',
    136       'make_valid_configurations': ['%(TOOLCHAIN)s-debug', '%(TOOLCHAIN)s-release'],
    137       'actions': [
    138         {
    139           'action_name': 'nmf',
    140           'inputs': ['<(PRODUCT_DIR)/%(NAME)s_x86_32.nexe',
    141                      '<(PRODUCT_DIR)/%(NAME)s_x86_64.nexe'] + %(SODEPS)s,
    142           'outputs': ['<(PRODUCT_DIR)/%(NAME)s.nmf'],
    143           'action': ['../../tools/create_nmf.py', '-t', '%(TOOLCHAIN)s', '-s',
    144                      '<(PRODUCT_DIR)'] + %(NMFACTION)s,
    145         },
    146       ]
    147     },
    148 """
    149 
    150 TOOLCHAIN_CONFIG = """\
    151         '%(toolchain)s-release' : {
    152           'cflags' : ['-O2'],
    153         },
    154         '%(toolchain)s-debug' : {
    155           'cflags' : ['-g', '-O0'],
    156         },
    157 """
    158 
    159 NEXE_CONFIG = """\
    160           '%(toolchain)s-release' : {
    161             'cflags' : ['--%(toolchain)s', '-O2',
    162                         '-idirafter', '../../include'],
    163             'ldflags' : ['--%(toolchain)s'],
    164             'arflags' : ['--%(toolchain)s'],
    165           },
    166           '%(toolchain)s-debug' : {
    167             'cflags' : ['--%(toolchain)s', '-g', '-O0',
    168                         '-idirafter', '../../include'],
    169             'ldflags' : ['--%(toolchain)s'],
    170             'arflags' : ['--%(toolchain)s'],
    171           },
    172 """
    173 
    174 WIN32_CONFIGS = """\
    175   'target_defaults': {
    176     'default_configuration': 'Debug_PPAPI',
    177     'configurations': {
    178       'Debug_PPAPI': {
    179         'msvs_configuration_platform': 'PPAPI',
    180         'msbuild_configuration_attributes': {
    181           'ConfigurationType': 'DynamicLibrary'
    182         },
    183         'include_dirs': ['../../include/win'],
    184         'defines': ['_WINDOWS', '_DEBUG', 'WIN32'],
    185       },
    186       'Release_PPAPI': {
    187         'msvs_configuration_platform': 'PPAPI',
    188         'msbuild_configuration_attributes': {
    189           'ConfigurationType': 'DynamicLibrary'
    190         },
    191         'include_dirs': ['../../include/win'],
    192         'defines': ['_WINDOWS', 'NDEBUG', 'WIN32'],
    193       },
    194       'Debug_NaCl': {
    195         'msvs_configuration_platform': 'NaCl',
    196         'msbuild_configuration_attributes': {
    197           'ConfigurationType': 'Application'
    198         },
    199       },
    200       'Release_NaCl': {
    201         'msvs_configuration_platform': 'NaCl',
    202         'msbuild_configuration_attributes': {
    203           'ConfigurationType': 'Application'
    204         },
    205       },
    206     },
    207   },
    208 """
    209 
    210 
    211 def WriteNaClTargets(output, target, tools):
    212   configs = "'configurations' : {\n"
    213   for tc in tools:
    214     if tc not in valid_tools:
    215       continue
    216     if tc in ['newlib', 'glibc']:
    217       configs += NEXE_CONFIG % {'toolchain': tc}
    218   configs += "      }"
    219   target['CONFIGS'] = configs
    220   if target['TYPE'] == 'lib':
    221     output.write(NLIB_TARGET % target)
    222   else:
    223     output.write(NEXE_TARGET % target)
    224 
    225 
    226 def ConfigName(toolchain):
    227   if toolchain == getos.GetPlatform():
    228     return 'host'
    229   else:
    230     return toolchain
    231 
    232 
    233 def ProcessDSC(filename, outfile=None):
    234   if not os.path.exists(filename):
    235     Error("file not found: %s" % filename)
    236 
    237   desc = open(filename).read()
    238   desc = eval(desc, {}, {})
    239   if not desc.get('TARGETS'):
    240     Error("no TARGETS found in dsc")
    241 
    242   if not outfile:
    243     outfile = desc['NAME'] + '.gyp'
    244     outfile = os.path.join(os.path.dirname(filename), outfile)
    245 
    246   output = StringIO.StringIO()
    247 
    248   srcdir = os.path.dirname(SCRIPT_DIR)
    249   output.write(PREAMBLE % srcdir.replace("\\", '/'))
    250 
    251   win32 = sys.platform in ('win32', 'cygwin')
    252   if win32:
    253     output.write(WIN32_CONFIGS)
    254   else:
    255     for tc in desc['TOOLS']:
    256       if tc in valid_tools:
    257         default = '%s-debug' % ConfigName(tc)
    258         break
    259 
    260     output.write("""\
    261   'target_defaults': {
    262     'default_configuration': '%s',
    263     'configurations' : {\n""" % default)
    264 
    265     for tc in desc['TOOLS']:
    266       if tc not in valid_tools:
    267         continue
    268       output.write(TOOLCHAIN_CONFIG % {'toolchain': ConfigName(tc)})
    269 
    270     output.write("    }\n  },\n")
    271 
    272   output.write("\n  'targets': [\n")
    273 
    274   # make a list of all the so target names so that the nmf rules
    275   # can depend on them all
    276   sofiles = []
    277   soremap = []
    278   for target in desc['TARGETS']:
    279     if target['TYPE'] == 'so':
    280       name = target['NAME']
    281       sofiles.append('<(PRODUCT_DIR)/%s_x86_64.so' % name)
    282       sofiles.append('<(PRODUCT_DIR)/%s_x86_32.so' % name)
    283       soremap += ['-n', '%s_x86_64.so,%s.so' % (name, name)]
    284       soremap += ['-n', '%s_x86_32.so,%s.so' % (name, name)]
    285 
    286 
    287   # iterate through dsc targets generating gyp targets
    288   for target in desc['TARGETS']:
    289     target.setdefault('INCLUDES', [])
    290     target['INCLUDES'] = [x.replace("$(NACL_SDK_ROOT)", "../..")
    291                           for x in target['INCLUDES']]
    292 
    293     libs = target.get('LIBS', [])
    294     if win32:
    295       libs = [l for l in libs if l not in ('ppapi', 'ppapi_cpp')]
    296       target['LIBS'] = ['-l' + l + '.lib' for l in libs]
    297     else:
    298       target['LIBS'] = ['-l' + l for l in libs]
    299     if target['TYPE'] == 'so':
    300       if win32:
    301         target['EXT'] = ''
    302       else:
    303         target['EXT'] = '.so'
    304       target['GYP_TYPE'] = 'shared_library'
    305     elif target['TYPE'] == 'lib':
    306       if win32:
    307         target['EXT'] = ''
    308       else:
    309         target['EXT'] = '.a'
    310       target['GYP_TYPE'] = 'static_library'
    311     elif target['TYPE'] == 'main':
    312       target['EXT'] = '.nexe'
    313       target['GYP_TYPE'] = 'executable'
    314     else:
    315       Error("unknown type: %s" % target['TYPE'])
    316 
    317     target['CFLAGS'] = target.get('CXXFLAGS', [])
    318 
    319     if not win32 and ('newlib' in desc['TOOLS'] or 'glibc' in desc['TOOLS']):
    320       WriteNaClTargets(output, target, desc['TOOLS'])
    321       if target['TYPE'] == 'main':
    322         target['SODEPS'] = sofiles
    323         target['NMFACTION'] = ['-o', '<@(_outputs)', '-L<(NMF_PATH1)',
    324                                '-L<(NMF_PATH2)', '-D', '<(OBJDUMP)',
    325                                '<@(_inputs)']
    326         target['NMFACTION'] += soremap
    327         if 'newlib' in desc['TOOLS']:
    328           target['TOOLCHAIN'] = 'newlib'
    329           output.write(NMF_TARGET % target)
    330         if 'glibc' in desc['TOOLS']:
    331           target['TOOLCHAIN'] = 'glibc'
    332           output.write(NMF_TARGET % target)
    333 
    334     if win32 or getos.GetPlatform() in desc['TOOLS']:
    335       target['ARCH'] = 'x86_32'
    336       target['INCLUDES'].append('../../include')
    337       if win32:
    338         target['HOST'] = 'win'
    339         target['CONFIGS'] = ''
    340         target['CFLAGS'] = []
    341       else:
    342         target['CONFIGS'] = ''
    343         target['HOST'] = 'linux'
    344         target['CFLAGS'].append('-fPIC')
    345       if target['TYPE'] == 'main':
    346         target['GYP_TYPE'] = 'shared_library'
    347         if win32:
    348           target['EXT'] = ''
    349         else:
    350           target['EXT'] = '.so'
    351         output.write(HOST_EXE_TARGET % target)
    352       else:
    353         output.write(HOST_LIB_TARGET % target)
    354 
    355   output.write('  ],\n}\n')
    356 
    357   print('Writing: ' + outfile)
    358   open(outfile, 'w').write(output.getvalue())
    359 
    360 
    361 def main(args):
    362   parser = optparse.OptionParser()
    363   parser.add_option('-o', help='Set output filename.', dest='output')
    364   options, args = parser.parse_args(args)
    365   if not args:
    366     Error('No .dsc file specified.')
    367 
    368   if options.output:
    369     outdir = os.path.dirname(options.output)
    370     if not os.path.exists(outdir):
    371       os.makedirs(outdir)
    372 
    373   assert len(args) == 1
    374   ProcessDSC(args[0], options.output)
    375 
    376 
    377 if __name__ == '__main__':
    378   main(sys.argv[1:])
    379