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