• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# Copyright 2013 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
6"""A helper script to print paths of NaCl binaries, includes, libs, etc.
7
8It is similar in behavior to pkg-config or sdl-config.
9"""
10
11import optparse
12import os
13import posixpath
14import sys
15
16import getos
17
18
19if sys.version_info < (2, 6, 0):
20  sys.stderr.write("python 2.6 or later is required run this script\n")
21  sys.exit(1)
22
23
24VALID_ARCHES = ('arm', 'x86_32', 'x86_64', 'i686')
25VALID_PNACL_ARCHES = (None, 'pnacl')
26ARCH_NAME = {
27  'arm': 'arm',
28  'x86_32': 'i686',
29  'i686': 'i686',
30  'x86_64': 'x86_64'
31}
32
33ARCH_ALT_NAME = {
34  'arm': 'arm',
35  'x86_32': 'x86_32',
36  'i686': 'x86_32',
37  'x86_64': 'x86_64'
38}
39
40ARCH_BASE_NAME = {
41  'arm': 'arm',
42  'x86_32': 'x86',
43  'i686': 'x86',
44  'x86_64': 'x86'
45}
46
47NACL_TOOLCHAINS = ('newlib', 'glibc', 'pnacl', 'bionic')
48HOST_TOOLCHAINS = ('linux', 'mac', 'win')
49VALID_TOOLCHAINS = list(HOST_TOOLCHAINS) + list(NACL_TOOLCHAINS) + ['host']
50
51# This is not an exhaustive list of tools, just the ones that need to be
52# special-cased.
53
54# e.g. For PNaCL cc => pnacl-clang
55#      For NaCl  cc => pnacl-gcc
56#
57# Most tools will be passed through directly.
58# e.g. For PNaCl foo => pnacl-foo
59#      For NaCl  foo => x86_64-nacl-foo.
60PNACL_TOOLS = {
61  'cc': 'clang',
62  'c++': 'clang++',
63  'gcc': 'clang',
64  'g++': 'clang++',
65  'ld': 'clang++'
66}
67
68NACL_TOOLS = {
69  'cc': 'gcc',
70  'c++': 'g++',
71  'gcc': 'gcc',
72  'g++': 'g++',
73  'ld': 'g++'
74}
75
76
77class Error(Exception):
78  pass
79
80
81def Expect(condition, message):
82  if not condition:
83    raise Error(message)
84
85
86def ExpectToolchain(toolchain, expected_toolchains):
87  Expect(toolchain in expected_toolchains,
88         'Expected toolchain to be one of [%s], not %s.' % (
89             ', '.join(expected_toolchains), toolchain))
90
91
92def ExpectArch(arch, expected_arches):
93  Expect(arch in expected_arches,
94         'Expected arch to be one of [%s], not %s.' % (
95             ', '.join(map(str, expected_arches)), arch))
96
97
98def CheckValidToolchainArch(toolchain, arch, arch_required=False):
99  if toolchain or arch or arch_required:
100    ExpectToolchain(toolchain, VALID_TOOLCHAINS)
101
102  if toolchain in HOST_TOOLCHAINS:
103    Expect(arch is None,
104           'Expected no arch for host toolchain %r. Got %r.' % (
105               toolchain, arch))
106  elif toolchain == 'pnacl':
107    Expect(arch is None or arch == 'pnacl',
108           'Expected no arch for toolchain %r. Got %r.' % (toolchain, arch))
109  elif arch_required:
110    Expect(arch is not None,
111           'Expected arch to be one of [%s] for toolchain %r.\n'
112           'Use the -a or --arch flags to specify one.\n' % (
113               ', '.join(VALID_ARCHES), toolchain))
114
115  if arch:
116    if toolchain == 'pnacl':
117      ExpectArch(arch, VALID_PNACL_ARCHES)
118    else:
119      ExpectArch(arch, VALID_ARCHES)
120
121    if arch == 'arm':
122      Expect(toolchain in ['newlib', 'bionic'],
123             'The arm arch only supports newlib.')
124
125
126def GetArchName(arch):
127  return ARCH_NAME.get(arch)
128
129
130def GetArchAltName(arch):
131  return ARCH_ALT_NAME.get(arch)
132
133
134def GetArchBaseName(arch):
135  return ARCH_BASE_NAME.get(arch)
136
137
138def CanonicalizeToolchain(toolchain):
139  if toolchain == 'host':
140    return getos.GetPlatform()
141  return toolchain
142
143
144def GetPosixSDKPath():
145  sdk_path = getos.GetSDKPath()
146  if getos.GetPlatform() == 'win':
147    return sdk_path.replace('\\', '/')
148  else:
149    return sdk_path
150
151
152def GetToolchainDir(toolchain, arch=None):
153  ExpectToolchain(toolchain, NACL_TOOLCHAINS)
154  root = GetPosixSDKPath()
155  platform = getos.GetPlatform()
156  if toolchain == 'pnacl':
157    subdir = '%s_pnacl' % platform
158  else:
159    assert arch is not None
160    subdir = '%s_%s_%s' % (platform, GetArchBaseName(arch), toolchain)
161
162  return posixpath.join(root, 'toolchain', subdir)
163
164
165def GetToolchainArchDir(toolchain, arch):
166  ExpectToolchain(toolchain, NACL_TOOLCHAINS)
167  assert arch is not None
168  toolchain_dir = GetToolchainDir(toolchain, arch)
169  arch_dir = '%s-nacl' % GetArchName(arch)
170  return posixpath.join(toolchain_dir, arch_dir)
171
172
173def GetToolchainBinDir(toolchain, arch=None):
174  ExpectToolchain(toolchain, NACL_TOOLCHAINS)
175  return posixpath.join(GetToolchainDir(toolchain, arch), 'bin')
176
177
178def GetSDKIncludeDirs(toolchain):
179  root = GetPosixSDKPath()
180  base_include = posixpath.join(root, 'include')
181  return [base_include, posixpath.join(base_include, toolchain)]
182
183
184def GetSDKLibDir():
185  return posixpath.join(GetPosixSDKPath(), 'lib')
186
187
188# Commands
189
190def GetToolPath(toolchain, arch, tool):
191  if tool == 'gdb':
192    # Always use the same gdb; it supports multiple toolchains/architectures.
193    # NOTE: this is always a i686 executable. i686-nacl-gdb is a symlink to
194    # x86_64-nacl-gdb.
195    return posixpath.join(GetToolchainBinDir('newlib', 'x86_64'),
196                        'x86_64-nacl-gdb')
197
198  if toolchain == 'pnacl':
199    CheckValidToolchainArch(toolchain, arch)
200    tool = PNACL_TOOLS.get(tool, tool)
201    full_tool_name = 'pnacl-%s' % tool
202  else:
203    CheckValidToolchainArch(toolchain, arch, arch_required=True)
204    ExpectArch(arch, VALID_ARCHES)
205    tool = NACL_TOOLS.get(tool, tool)
206    full_tool_name = '%s-nacl-%s' % (GetArchName(arch), tool)
207  return posixpath.join(GetToolchainBinDir(toolchain, arch), full_tool_name)
208
209
210def GetCFlags(toolchain):
211  ExpectToolchain(toolchain, VALID_TOOLCHAINS)
212  return ' '.join('-I%s' % dirname for dirname in GetSDKIncludeDirs(toolchain))
213
214
215def GetIncludeDirs(toolchain):
216  ExpectToolchain(toolchain, VALID_TOOLCHAINS)
217  return ' '.join(GetSDKIncludeDirs(toolchain))
218
219
220def GetLDFlags():
221  return '-L%s' % GetSDKLibDir()
222
223
224def main(args):
225  usage = 'Usage: %prog [options] <command>'
226  parser = optparse.OptionParser(usage=usage, description=__doc__)
227  parser.add_option('-t', '--toolchain', help='toolchain name. This can also '
228                    'be specified with the NACL_TOOLCHAIN environment '
229                    'variable.')
230  parser.add_option('-a', '--arch', help='architecture name. This can also be '
231                    'specified with the NACL_ARCH environment variable.')
232
233  group = optparse.OptionGroup(parser, 'Commands')
234  group.add_option('--tool', help='get tool path')
235  group.add_option('--cflags',
236                    help='output all preprocessor and compiler flags',
237                    action='store_true')
238  group.add_option('--libs', '--ldflags', help='output all linker flags',
239                    action='store_true')
240  group.add_option('--include-dirs',
241                   help='output include dirs, separated by spaces',
242                   action='store_true')
243  parser.add_option_group(group)
244
245  options, _ = parser.parse_args(args)
246
247  # Get toolchain/arch from environment, if not specified on commandline
248  options.toolchain = options.toolchain or os.getenv('NACL_TOOLCHAIN')
249  options.arch = options.arch or os.getenv('NACL_ARCH')
250
251  options.toolchain = CanonicalizeToolchain(options.toolchain)
252  CheckValidToolchainArch(options.toolchain, options.arch)
253
254  if options.cflags:
255    print GetCFlags(options.toolchain)
256  elif options.include_dirs:
257    print GetIncludeDirs(options.toolchain)
258  elif options.libs:
259    print GetLDFlags()
260  elif options.tool:
261    print GetToolPath(options.toolchain, options.arch, options.tool)
262  else:
263    parser.error('Expected a command. Run with --help for more information.')
264
265  return 0
266
267
268if __name__ == '__main__':
269  try:
270    sys.exit(main(sys.argv[1:]))
271  except Error as e:
272    sys.stderr.write(str(e) + '\n')
273    sys.exit(1)
274