const-gen.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import os
  4. import re
  5. import subprocess
  6. import sys
  7. from collections import defaultdict
  8. from collections import namedtuple
  9. Name = namedtuple('Name', 'name desc')
  10. Device = namedtuple('Device', 'name bus alias desc')
  11. Machines = namedtuple('Machines', 'name items default')
  12. TARGETS = [
  13. Name("alpha", "Alpha"),
  14. Name("arm", "ARM (aarch32)"),
  15. Name("aarch64", "ARM64 (aarch64)"),
  16. Name("avr", "AVR"),
  17. Name("cris", "CRIS"),
  18. Name("hppa", "HPPA"),
  19. Name("i386", "i386 (x86)"),
  20. Name("m68k", "m68k"),
  21. Name("microblaze", "Microblaze"),
  22. Name("microblazeel", "Microblaze (Little Endian)"),
  23. Name("mips", "MIPS"),
  24. Name("mipsel", "MIPS (Little Endian)"),
  25. Name("mips64", "MIPS64"),
  26. Name("mips64el", "MIPS64 (Little Endian)"),
  27. Name("moxie", "Moxie"),
  28. Name("nios2", "NIOS2"),
  29. Name("or1k", "OpenRISC"),
  30. Name("ppc", "PowerPC"),
  31. Name("ppc64", "PowerPC64"),
  32. Name("riscv32", "RISC-V32"),
  33. Name("riscv64", "RISC-V64"),
  34. Name("rx", "RX"),
  35. Name("s390x", "S390x (zSeries)"),
  36. Name("sh4", "SH4"),
  37. Name("sh4eb", "SH4 (Big Endian)"),
  38. Name("sparc", "SPARC"),
  39. Name("sparc64", "SPARC64"),
  40. Name("tricore", "TriCore"),
  41. Name("x86_64", "x86_64"),
  42. Name("xtensa", "Xtensa"),
  43. Name("xtensaeb", "Xtensa (Big Endian)")
  44. ]
  45. DEFAULTS = {
  46. "aarch64": "virt",
  47. "arm": "virt",
  48. "avr": "mega",
  49. "i386": "q35",
  50. "rx": "gdbsim-r5f562n7",
  51. "tricore": "tricore_testboard",
  52. "x86_64": "q35"
  53. }
  54. HEADER = '''//
  55. // Copyright © 2020 osy. All rights reserved.
  56. //
  57. // Licensed under the Apache License, Version 2.0 (the "License");
  58. // you may not use this file except in compliance with the License.
  59. // You may obtain a copy of the License at
  60. //
  61. // http://www.apache.org/licenses/LICENSE-2.0
  62. //
  63. // Unless required by applicable law or agreed to in writing, software
  64. // distributed under the License is distributed on an "AS IS" BASIS,
  65. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  66. // See the License for the specific language governing permissions and
  67. // limitations under the License.
  68. //
  69. // !! THIS FILE IS GENERATED FROM const-gen.py, DO NOT MODIFY MANUALLY !!
  70. #import "UTMConfiguration+Constants.h"
  71. @implementation UTMConfiguration (ConstantsGenerated)
  72. '''
  73. def parseListing(listing):
  74. output = listing.splitlines()[1:]
  75. result = set()
  76. for line in output:
  77. idx = line.find(' ')
  78. if idx < 0:
  79. break
  80. name = line[0:idx]
  81. description = line[idx:].strip()
  82. result.add(Name(name, description))
  83. return result
  84. def parseDeviceListing(listing):
  85. output = listing.splitlines()
  86. group = ''
  87. result = defaultdict(set)
  88. for line in output:
  89. if not line:
  90. continue
  91. if not line.startswith('name '):
  92. group = line.rstrip(':')
  93. continue
  94. search = re.search('^name "(?P<name>[^"]*)"(?:, bus (?P<bus>[^\s]+))?(?:, alias "(?P<alias>[^"]+)")?(?:, desc "(?P<desc>[^"]+)")?$', line)
  95. item = Device(search.group('name'), search.group('bus'), search.group('alias'), search.group('desc'))
  96. result[group].add(item)
  97. return result
  98. def sortItems(items):
  99. return sorted(items, key=lambda item: item.desc if item.desc else item.name)
  100. def getMachines(qemu_path):
  101. output = subprocess.check_output([qemu_path, '-machine', 'help']).decode('utf-8')
  102. return parseListing(output)
  103. def getDefaultMachine(target, machines):
  104. find = None
  105. if target in DEFAULTS:
  106. find = DEFAULTS[target]
  107. for (idx, machine) in enumerate(machines):
  108. if find and find == machine.name:
  109. return idx
  110. elif not find and "default" in machine.desc:
  111. return idx
  112. print(machines)
  113. return -1
  114. def getSoundCards(qemu_path):
  115. output = subprocess.check_output([qemu_path, '-soundhw', 'help']).decode('utf-8')
  116. return parseListing(output)
  117. def getNetworkCards(qemu_path):
  118. output = subprocess.check_output([qemu_path, '-device', 'help']).decode('utf-8')
  119. devices = parseDeviceListing(output)
  120. return devices["Network devices"]
  121. def generateArray(name, array):
  122. output = '+ (NSArray<NSString *>*){} {{\n'.format(name)
  123. output += ' return @[\n'
  124. for item in array:
  125. output += ' @"{}",\n'.format(item)
  126. output += ' ];\n'
  127. output += '}\n\n'
  128. return output
  129. def generateMap(name, keyName, keys, arrays):
  130. output = '+ (NSArray<NSString *>*){}:(NSString *){} {{\n'.format(name, keyName)
  131. output += ' return @{\n'
  132. for key in keys:
  133. output += ' @"{}":\n'.format(key)
  134. output += ' @[\n'
  135. for item in arrays[key]:
  136. output += ' @"{}",\n'.format(item)
  137. output += ' ],\n'
  138. output += ' }}[{}];\n'.format(keyName)
  139. output += '}\n\n'
  140. return output
  141. def generateIndexMap(name, keyName, keys, indexMap):
  142. output = '+ (NSInteger){}:(NSString *){} {{\n'.format(name, keyName)
  143. output += ' return [@{\n'
  144. for key in keys:
  145. output += ' @"{}": @{},\n'.format(key, indexMap[key])
  146. output += ' }}[{}] integerValue];\n'.format(keyName)
  147. output += '}\n\n'
  148. return output
  149. def generate(targets, machines, networkCards, soundCards):
  150. targetKeys = [item.name for item in targets]
  151. output = HEADER
  152. output += generateArray('supportedArchitectures', targetKeys)
  153. output += generateArray('supportedArchitecturesPretty', [item.desc for item in targets])
  154. output += generateMap('supportedTargetsForArchitecture', 'architecture', targetKeys, {machine.name: [item.name for item in machine.items] for machine in machines})
  155. output += generateMap('supportedTargetsForArchitecturePretty', 'architecture', targetKeys, {machine.name: [item.desc for item in machine.items] for machine in machines})
  156. output += generateIndexMap('defaultTargetIndexForArchitecture', 'architecture', targetKeys, {machine.name: machine.default for machine in machines})
  157. output += generateArray('supportedNetworkCards', [item.name for item in networkCards])
  158. output += generateArray('supportedNetworkCardsPretty', [item.desc if item.desc else item.name for item in networkCards])
  159. output += generateArray('supportedSoundCardDevices', [item.name for item in soundCards])
  160. output += generateArray('supportedSoundCardDevicesPretty', [item.desc if item.desc else item.name for item in soundCards])
  161. output += '@end\n'
  162. return output
  163. def main(argv):
  164. base = argv[1]
  165. allMachines = []
  166. soundCards = set()
  167. networkCards = set()
  168. # parse outputs
  169. for target in TARGETS:
  170. path = '{}/{}-softmmu/qemu-system-{}'.format(base, target.name, target.name)
  171. if not os.path.exists(path):
  172. path = '{}/qemu-system-{}'.format(base, target.name)
  173. if not os.path.exists(path):
  174. raise "Invalid path."
  175. machines = sortItems(getMachines(path))
  176. default = getDefaultMachine(target.name, machines)
  177. allMachines.append(Machines(target.name, machines, default))
  178. networkCards = networkCards.union(getNetworkCards(path))
  179. soundCards = soundCards.union(getSoundCards(path))
  180. # generate constants
  181. print(generate(TARGETS, allMachines, sortItems(networkCards), sortItems(soundCards)))
  182. if __name__ == "__main__":
  183. main(sys.argv)