qemu: update QEMU to v9.1.0-utm

This commit is contained in:
osy
2024-10-01 15:21:01 -07:00
parent 09dd6008ef
commit 241ab254e6
18 changed files with 1058 additions and 8351 deletions
-1
View File
@@ -412,7 +412,6 @@ extension QEMUArchitecture {
case .cris: return false
case .m68k: return false
case .microblaze, .microblazeel: return false
case .nios2: return false
case .rx: return false
case .sparc, .sparc64: return false
case .tricore: return false
File diff suppressed because it is too large Load Diff
@@ -111,9 +111,7 @@ import Virtualization // for getting network interfaces
cpuArguments
machineArguments
architectureArguments
if !sound.isEmpty {
soundArguments
}
soundArguments
if isUsbUsed {
usbArguments
}
@@ -524,9 +522,8 @@ import Virtualization // for getting network interfaces
if isRemoteSpice {
return false
}
// force CoreAudio backend for mac99 which only supports 44100 Hz
// pcspk doesn't work with SPICE audio
if sound.contains(where: { $0.hardware.rawValue == "screamer" || $0.hardware.rawValue == "pcspk" }) {
if sound.contains(where: { $0.hardware.rawValue == "pcspk" }) {
return true
}
if soundBackend == .qemuSoundBackendCoreAudio {
@@ -537,6 +534,19 @@ import Virtualization // for getting network interfaces
}
@QEMUArgumentBuilder private var soundArguments: [QEMUArgument] {
if sound.isEmpty {
f("-audio")
f("none")
} else if sound.contains(where: { $0.hardware.rawValue == "screamer" }) {
#if os(iOS) || os(visionOS)
f("-audio")
f("none")
#else
// force CoreAudio backend for mac99 which only supports 44100 Hz
f("-audio")
f("coreaudio")
#endif
}
if useCoreAudioBackend {
f("-audiodev")
"coreaudio"
-6
View File
@@ -405,7 +405,6 @@
CE0DF19E25A83C1700A51894 /* qemu-mips64-softmmu.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D63F422653C7400FC7E63 /* qemu-mips64-softmmu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE0DF19F25A83C1700A51894 /* qemu-mips64el-softmmu.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D640822653C7500FC7E63 /* qemu-mips64el-softmmu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE0DF1A025A83C1700A51894 /* qemu-mipsel-softmmu.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D640622653C7500FC7E63 /* qemu-mipsel-softmmu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE0DF1A225A83C1700A51894 /* qemu-nios2-softmmu.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D63DF22653C7400FC7E63 /* qemu-nios2-softmmu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE0DF1A325A83C1700A51894 /* qemu-or1k-softmmu.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D640B22653C7500FC7E63 /* qemu-or1k-softmmu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE0DF1A425A83C1700A51894 /* qemu-ppc-softmmu.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D63E722653C7400FC7E63 /* qemu-ppc-softmmu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE0DF1A525A83C1700A51894 /* qemu-ppc64-softmmu.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D640C22653C7500FC7E63 /* qemu-ppc64-softmmu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
@@ -576,7 +575,6 @@
CE2D93AA24AD46670059923A /* spice-client-glib-2.0.8.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D63FE22653C7500FC7E63 /* spice-client-glib-2.0.8.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE2D93AB24AD46670059923A /* opus.0.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D640322653C7500FC7E63 /* opus.0.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE2D93AD24AD46670059923A /* gstsdp-1.0.0.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D641622653C7500FC7E63 /* gstsdp-1.0.0.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE2D93AE24AD46670059923A /* qemu-nios2-softmmu.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D63DF22653C7400FC7E63 /* qemu-nios2-softmmu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE2D93B024AD46670059923A /* gstaudio-1.0.0.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D63EF22653C7400FC7E63 /* gstaudio-1.0.0.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE2D93B124AD46670059923A /* gstcheck-1.0.0.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D641422653C7500FC7E63 /* gstcheck-1.0.0.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE2D93B224AD46670059923A /* qemu-xtensa-softmmu.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE2D63ED22653C7400FC7E63 /* qemu-xtensa-softmmu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
@@ -1343,7 +1341,6 @@
CE0DF19E25A83C1700A51894 /* qemu-mips64-softmmu.framework in Embed Libraries */,
CE0DF19F25A83C1700A51894 /* qemu-mips64el-softmmu.framework in Embed Libraries */,
CE0DF1A025A83C1700A51894 /* qemu-mipsel-softmmu.framework in Embed Libraries */,
CE0DF1A225A83C1700A51894 /* qemu-nios2-softmmu.framework in Embed Libraries */,
CE0DF1A325A83C1700A51894 /* qemu-or1k-softmmu.framework in Embed Libraries */,
CE0DF1A425A83C1700A51894 /* qemu-ppc-softmmu.framework in Embed Libraries */,
CE0DF1A525A83C1700A51894 /* qemu-ppc64-softmmu.framework in Embed Libraries */,
@@ -1437,7 +1434,6 @@
CE2D93AB24AD46670059923A /* opus.0.framework in Embed Libraries */,
CE2D93AD24AD46670059923A /* gstsdp-1.0.0.framework in Embed Libraries */,
CE064C6A2A563F6E003C833D /* swtpm.0.framework in Embed Libraries */,
CE2D93AE24AD46670059923A /* qemu-nios2-softmmu.framework in Embed Libraries */,
CE02C8AB294EE4EB006DFE48 /* qemu-loongarch64-softmmu.framework in Embed Libraries */,
CE2D93B024AD46670059923A /* gstaudio-1.0.0.framework in Embed Libraries */,
CE2D93B124AD46670059923A /* gstcheck-1.0.0.framework in Embed Libraries */,
@@ -1818,7 +1814,6 @@
CE2D63DC22653C7300FC7E63 /* gthread-2.0.0.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "gthread-2.0.0.framework"; path = "$(SYSROOT_DIR)/Frameworks/gthread-2.0.0.framework"; sourceTree = "<group>"; };
CE2D63DD22653C7400FC7E63 /* gstrtp-1.0.0.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "gstrtp-1.0.0.framework"; path = "$(SYSROOT_DIR)/Frameworks/gstrtp-1.0.0.framework"; sourceTree = "<group>"; };
CE2D63DE22653C7400FC7E63 /* gstriff-1.0.0.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "gstriff-1.0.0.framework"; path = "$(SYSROOT_DIR)/Frameworks/gstriff-1.0.0.framework"; sourceTree = "<group>"; };
CE2D63DF22653C7400FC7E63 /* qemu-nios2-softmmu.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "qemu-nios2-softmmu.framework"; path = "$(SYSROOT_DIR)/Frameworks/qemu-nios2-softmmu.framework"; sourceTree = "<group>"; };
CE2D63E022653C7400FC7E63 /* gstreamer-1.0.0.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "gstreamer-1.0.0.framework"; path = "$(SYSROOT_DIR)/Frameworks/gstreamer-1.0.0.framework"; sourceTree = "<group>"; };
CE2D63E122653C7400FC7E63 /* qemu-sh4eb-softmmu.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "qemu-sh4eb-softmmu.framework"; path = "$(SYSROOT_DIR)/Frameworks/qemu-sh4eb-softmmu.framework"; sourceTree = "<group>"; };
CE2D63E222653C7400FC7E63 /* json-glib-1.0.0.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "json-glib-1.0.0.framework"; path = "$(SYSROOT_DIR)/Frameworks/json-glib-1.0.0.framework"; sourceTree = "<group>"; };
@@ -2600,7 +2595,6 @@
CE2D63F422653C7400FC7E63 /* qemu-mips64-softmmu.framework */,
CE2D640822653C7500FC7E63 /* qemu-mips64el-softmmu.framework */,
CE2D640622653C7500FC7E63 /* qemu-mipsel-softmmu.framework */,
CE2D63DF22653C7400FC7E63 /* qemu-nios2-softmmu.framework */,
CE2D640B22653C7500FC7E63 /* qemu-or1k-softmmu.framework */,
CE2D63E722653C7400FC7E63 /* qemu-ppc-softmmu.framework */,
CE2D640C22653C7500FC7E63 /* qemu-ppc64-softmmu.framework */,
Binary file not shown.
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
From ed481d745d3e725f0694d6032e8aa895d49ae3ec Mon Sep 17 00:00:00 2001
From: Joelle van Dyne <[email protected]>
Date: Thu, 22 Aug 2024 16:42:50 -0500
Subject: [PATCH] block: support locking on change medium
New optional argument for 'blockdev-change-medium' QAPI command to allow
the caller to specify if they wish to enable file locking.
---
block/monitor/block-hmp-cmds.c | 2 +-
block/qapi-sysemu.c | 22 ++++++++++++++++++++++
qapi/block.json | 23 ++++++++++++++++++++++-
ui/cocoa.m | 1 +
4 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index bdf2eb50b6..ff64020a80 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -1007,5 +1007,5 @@ void hmp_change_medium(Monitor *mon, const char *device, const char *target,
}
qmp_blockdev_change_medium(device, NULL, target, arg, true, force,
- !!read_only, read_only_mode, errp);
+ !!read_only, read_only_mode, false, 0, errp);
}
diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c
index e4282631d2..8064bdfb3a 100644
--- a/block/qapi-sysemu.c
+++ b/block/qapi-sysemu.c
@@ -311,6 +311,8 @@ void qmp_blockdev_change_medium(const char *device,
bool has_force, bool force,
bool has_read_only,
BlockdevChangeReadOnlyMode read_only,
+ bool has_file_locking_mode,
+ BlockdevChangeFileLockingMode file_locking_mode,
Error **errp)
{
BlockBackend *blk;
@@ -362,6 +364,26 @@ void qmp_blockdev_change_medium(const char *device,
qdict_put_str(options, "driver", format);
}
+ if (!has_file_locking_mode) {
+ file_locking_mode = BLOCKDEV_CHANGE_FILE_LOCKING_MODE_AUTO;
+ }
+
+ switch (file_locking_mode) {
+ case BLOCKDEV_CHANGE_FILE_LOCKING_MODE_AUTO:
+ break;
+
+ case BLOCKDEV_CHANGE_FILE_LOCKING_MODE_OFF:
+ qdict_put_str(options, "file.locking", "off");
+ break;
+
+ case BLOCKDEV_CHANGE_FILE_LOCKING_MODE_ON:
+ qdict_put_str(options, "file.locking", "on");
+ break;
+
+ default:
+ abort();
+ }
+
medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
if (!medium_bs) {
diff --git a/qapi/block.json b/qapi/block.json
index e66666f5c6..35e8e2e191 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -309,6 +309,23 @@
{ 'enum': 'BlockdevChangeReadOnlyMode',
'data': ['retain', 'read-only', 'read-write'] }
+##
+# @BlockdevChangeFileLockingMode:
+#
+# Specifies the new locking mode of a file image passed to the
+# @blockdev-change-medium command.
+#
+# @auto: Use locking if API is available
+#
+# @off: Disable file image locking
+#
+# @on: Enable file image locking
+#
+# Since: 9.2
+##
+{ 'enum': 'BlockdevChangeFileLockingMode',
+ 'data': ['auto', 'off', 'on'] }
+
##
# @blockdev-change-medium:
#
@@ -330,6 +347,9 @@
# @read-only-mode: change the read-only mode of the device; defaults
# to 'retain'
#
+# @file-locking-mode: change the locking mode of the file image; defaults
+# to 'auto' (since: 9.2)
+#
# @force: if false (the default), an eject request through
# blockdev-open-tray will be sent to the guest if it has locked
# the tray (and the tray will not be opened immediately); if true,
@@ -378,7 +398,8 @@
'filename': 'str',
'*format': 'str',
'*force': 'bool',
- '*read-only-mode': 'BlockdevChangeReadOnlyMode' } }
+ '*read-only-mode': 'BlockdevChangeReadOnlyMode',
+ '*file-locking-mode': 'BlockdevChangeFileLockingMode' } }
##
# @DEVICE_TRAY_MOVED:
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 4c2dd33532..6e73c6e13e 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -1611,6 +1611,7 @@ - (void)changeDeviceMedia:(id)sender
"raw",
true, false,
false, 0,
+ false, 0,
&err);
});
handleAnyDeviceErrors(err);
--
2.41.0
+3 -1
View File
@@ -23,7 +23,7 @@ SPICE_SERVER_SRC="https://www.spice-space.org/download/releases/spice-server/spi
USB_SRC="https://github.com/libusb/libusb/releases/download/v1.0.25/libusb-1.0.25.tar.bz2"
USBREDIR_SRC="https://www.spice-space.org/download/usbredir/usbredir-0.13.0.tar.xz"
SLIRP_SRC="https://gitlab.freedesktop.org/slirp/libslirp/-/archive/v4.7.0/libslirp-v4.7.0.tar.gz"
QEMU_SRC="https://github.com/utmapp/qemu/releases/download/v7.2.0-utm/qemu-7.2.0-utm.tar.bz2"
QEMU_SRC="https://github.com/utmapp/qemu/releases/download/v9.1.0-utm/qemu-9.1.0-utm.tar.xz"
# Source files for spice-client
JSON_GLIB_SRC="https://download.gnome.org/sources/json-glib/1.6/json-glib-1.6.6.tar.xz"
@@ -34,6 +34,8 @@ XML2_SRC="http://xmlsoft.org/sources/libxml2-2.9.12.tar.gz"
SOUP_SRC="https://download.gnome.org/sources/libsoup/2.74/libsoup-2.74.2.tar.xz"
PHODAV_SRC="https://download.gnome.org/sources/phodav/2.5/phodav-2.5.tar.xz"
SPICE_CLIENT_SRC="https://www.spice-space.org/download/gtk/spice-gtk-0.40.tar.xz"
LIBUCONTEXT_REPO="https://github.com/utmapp/libucontext.git"
LIBUCONTEXT_COMMIT="9b1d8f01a6e99166f9808c79966abe10786de8b6"
# Source files for GPU acceleration
WEBKIT_REPO="https://github.com/utmapp/WebKit.git"
+7 -1
View File
@@ -66,9 +66,11 @@ check_env () {
command -v python3 >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'python3' on your host machine.${NC}"; exit 1; }
python_module_test six >/dev/null 2>&1 || { echo >&2 "${RED}'six' not found in your Python 3 installation.${NC}"; exit 1; }
python_module_test pyparsing >/dev/null 2>&1 || { echo >&2 "${RED}'pyparsing' not found in your Python 3 installation.${NC}"; exit 1; }
python_module_test distutils >/dev/null 2>&1 || { echo >&2 "${RED}'distutils' not found in your Python 3 installation.${NC}"; exit 1; }
command -v meson >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'meson' on your host machine.${NC}"; exit 1; }
command -v msgfmt >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'gettext' on your host machine.\n\t'msgfmt' needs to be in your \$PATH as well.${NC}"; exit 1; }
command -v glib-mkenums >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'glib-utils' on your host machine.\n\t'glib-mkenums' needs to be in your \$PATH as well.${NC}"; exit 1; }
command -v glib-compile-resources >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'glib-utils' on your host machine.\n\t'glib-compile-resources' needs to be in your \$PATH as well.${NC}"; exit 1; }
command -v gpg-error-config >/dev/null 2>&1 || { echo >&2 "${RED}You must install 'libgpg-error' on your host machine.\n\t'gpg-error-config' needs to be in your \$PATH as well.${NC}"; exit 1; }
command -v xcrun >/dev/null 2>&1 || { echo >&2 "${RED}'xcrun' is not found. Make sure you are running on OSX."; exit 1; }
command -v otool >/dev/null 2>&1 || { echo >&2 "${RED}'otool' is not found. Make sure you are running on OSX."; exit 1; }
@@ -164,6 +166,7 @@ download_all () {
clone $EPOXY_REPO $EPOXY_COMMIT
clone $VIRGLRENDERER_REPO $VIRGLRENDERER_COMMIT
clone $HYPERVISOR_REPO $HYPERVISOR_COMMIT
clone $LIBUCONTEXT_REPO $LIBUCONTEXT_COMMIT
}
copy_private_headers() {
@@ -217,6 +220,8 @@ generate_meson_cross() {
echo "ranlib = [$(meson_quote $RANLIB)]" >> $cross
echo "strip = [$(meson_quote $STRIP), '-x']" >> $cross
echo "python = ['$(which python3)']" >> $cross
echo "glib-mkenums = ['$(which glib-mkenums)']" >> $cross
echo "glib-compile-resources = ['$(which glib-compile-resources)']" >> $cross
echo "[host_machine]" >> $cross
case $PLATFORM in
ios* | visionos* )
@@ -491,7 +496,7 @@ build_qemu_dependencies () {
}
build_spice_client () {
meson_build "$QEMU_DIR/subprojects/libucontext" -Ddefault_library=static -Dfreestanding=true
meson_build $LIBUCONTEXT_REPO -Ddefault_library=static -Dfreestanding=true
meson_build $JSON_GLIB_SRC -Dintrospection=disabled
build $XML2_SRC --enable-shared=no --without-python
meson_build $SOUP_SRC --default-library static -Dsysprof=disabled -Dtls_check=false -Dintrospection=disabled
@@ -788,6 +793,7 @@ echo "${GREEN}Deleting old sysroot!${NC}"
rm -rf "$PREFIX/"*
rm -f "$BUILD_DIR/BUILD_SUCCESS"
rm -f "$BUILD_DIR/meson.cross"
mkdir -p "$PREFIX/Frameworks"
copy_private_headers
build_pkg_config
build_qemu_dependencies
+11 -13
View File
@@ -28,7 +28,6 @@ TARGETS = [
Name("mipsel", "MIPS (Little Endian)"),
Name("mips64", "MIPS64"),
Name("mips64el", "MIPS64 (Little Endian)"),
Name("nios2", "NIOS2"),
Name("or1k", "OpenRISC"),
Name("ppc", "PowerPC"),
Name("ppc64", "PowerPC64"),
@@ -119,12 +118,16 @@ import Foundation
def parseListing(listing):
output = listing.splitlines()[1:]
result = set()
names = set()
for line in output:
idx = line.find(' ')
if idx < 0:
break
name = line[0:idx]
description = line[idx:].strip()
if name in names:
continue # duplicate
names.add(name)
result.add(Name(name, '{} ({})'.format(description, name)))
return result
@@ -138,7 +141,7 @@ def parseDeviceListing(defaults, listing):
if not line.startswith('name '):
group = line.rstrip(':')
continue
search = re.search('^name "(?P<name>[^"]*)"(?:, bus (?P<bus>[^\s]+))?(?:, alias "(?P<alias>[^"]+)")?(?:, desc "(?P<desc>[^"]+)")?$', line)
search = re.search('^name "(?P<name>[^"]*)"(?:, bus (?P<bus>[^\\s]+))?(?:, alias "(?P<alias>[^"]+)")?(?:, desc "(?P<desc>[^"]+)")?$', line)
name = search.group('name')
desc = search.group('desc')
if not desc:
@@ -149,18 +152,15 @@ def parseDeviceListing(defaults, listing):
result[group].add(item)
return result
def parseCpu(listing):
def parseMips(line):
search = re.search('^(?P<arch>\S+)\s+\'(?P<name>.+)\'.*', line)
return Name(search.group('name'), search.group('name'))
def parseCpu(target, listing):
def parseSingle(line):
name = line.strip()
return Name(name, name)
def parseSparc(line):
search = re.search('^(?P<arch>\S+)\s+(?P<name>.+)\s+IU\s+(?P<iu>\S+)\s+FPU\s+(?P<fpu>\S+)\s+MMU\s+(?P<mmu>\S+)\s+NWINS\s+(?P<nwins>\d+).*$', line)
search = re.search('^\\s+(?P<name>.+)\\s+\\(IU\\s+(?P<iu>\\S+)\\s+FPU\\s+(?P<fpu>\\S+)\\s+MMU\\s+(?P<mmu>\\S+)\\s+NWINS\\s+(?P<nwins>\\d+)\\).*$', line)
return Name(search.group('name'), search.group('name'))
def parseStandard(line):
search = re.search('^(?P<arch>\S+)\s+(?P<name>\S+)\s+(?P<desc>.*)?$', line)
search = re.search('^\\s+(?P<name>\\S+)\\s+(?P<desc>.*)?$', line)
name = search.group('name')
desc = search.group('desc').strip()
desc = ' '.join(desc.split())
@@ -199,13 +199,11 @@ def parseCpu(listing):
break
if len(line.strip().split(' ')) == 1:
cpu = parseSingle(line)
elif line.startswith('Sparc'):
cpu = parseSparc(line)
elif line.startswith('MIPS'):
cpu = parseMips(line)
elif parseSparcFlags(line) != None:
flags += parseSparcFlags(line)
continue
elif target.name.startswith('sparc'):
cpu = parseSparc(line)
else:
cpu = parseStandard(line)
if cpu.name != 'default':
@@ -243,7 +241,7 @@ def getDevices(target, qemu_path):
def getCpus(target, qemu_path):
output = subprocess.check_output([qemu_path, '-cpu', 'help']).decode('utf-8')
return parseCpu(output)
return parseCpu(target, output)
def sanitizeName(name):
sanitized = re.sub('[^0-9a-zA-Z]+', '_', name)