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.
5import StringIO
6import sys
7import os
8import optparse
9
10SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
11sys.path.append(os.path.join(os.path.dirname(SCRIPT_DIR), 'tools'))
12
13import getos
14
15valid_tools = ['newlib', 'glibc', getos.GetPlatform()]
16
17
18def Error(msg):
19  print(msg)
20  sys.exit(1)
21
22
23PREAMBLE = """\
24{
25  'includes': ['%s/build_tools/nacl.gypi'],
26"""
27
28NEXE_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
59NLIB_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
92HOST_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
108HOST_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
130NMF_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
150TOOLCHAIN_CONFIG = """\
151        '%(toolchain)s-release' : {
152          'cflags' : ['-O2'],
153        },
154        '%(toolchain)s-debug' : {
155          'cflags' : ['-g', '-O0'],
156        },
157"""
158
159NEXE_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
174WIN32_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
211def 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
226def ConfigName(toolchain):
227  if toolchain == getos.GetPlatform():
228    return 'host'
229  else:
230    return toolchain
231
232
233def 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
361def 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
377if __name__ == '__main__':
378  main(sys.argv[1:])
379