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