mirror of
https://github.com/shenmintao/aic8800d80.git
synced 2026-11-10 16:49:17 +00:00
fix(legacy-mcu1): declare matched initramfs firmware and return probe errors
Backport the issue #117 loader fix, declaring the 80 firmware/configuration files actually shipped by legacy-mcu1 rather than the main firmware set. Preserve the existing V3 binaries and loader profiles. All three modules build against Linux 6.17 headers; inventory, built-module metadata and extracted probe error/re-enumeration regression checks pass. Hardware boot validation remains pending.
This commit is contained in:
1 parent
a9683a4560
commit
28e84ec90e
7 files changed
+245
-4
No files matched your search
@@ -35,6 +35,15 @@ cannot download dependencies because the database is stale, run
|
|||||||
`sudo pacman -Syu` yourself, reboot if the kernel was updated, and rerun the
|
`sudo pacman -Syu` yourself, reboot if the kernel was updated, and rerun the
|
||||||
installer with headers matching the running kernel.
|
installer with headers matching the running kernel.
|
||||||
|
|
||||||
|
The USB modules declare the complete firmware set shipped in `fw/`, including
|
||||||
|
configuration files and extension patches, so initramfs tools can include those
|
||||||
|
files when they include the modules. Rerun the installer after updating the
|
||||||
|
driver to rebuild DKMS modules and refresh the current kernel's initramfs.
|
||||||
|
If the adapter only works after reloading its modules after boot, check that
|
||||||
|
the initramfs contains its `aic8800*/` firmware directory (issue #117).
|
||||||
|
Custom firmware paths supplied with `aic_fw_path` still need to be included
|
||||||
|
in the initramfs by the administrator.
|
||||||
|
|
||||||
> For more information, please refer to the [README.md](README.md) file.
|
> For more information, please refer to the [README.md](README.md) file.
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -9725,7 +9725,11 @@ MODULE_IMPORT_NS("VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver");
|
|||||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
|
||||||
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
|
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef AICWF_USB_SUPPORT
|
||||||
|
#include "../aicwf_firmware.h"
|
||||||
|
#else
|
||||||
MODULE_FIRMWARE(RWNX_CONFIG_FW_NAME);
|
MODULE_FIRMWARE(RWNX_CONFIG_FW_NAME);
|
||||||
|
#endif
|
||||||
|
|
||||||
MODULE_DESCRIPTION(RW_DRV_DESCRIPTION);
|
MODULE_DESCRIPTION(RW_DRV_DESCRIPTION);
|
||||||
MODULE_VERSION(RWNX_VERS_MOD);
|
MODULE_VERSION(RWNX_VERS_MOD);
|
||||||
|
|||||||
@@ -3972,6 +3972,7 @@ struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AICWF_USB_SUPPORT
|
||||||
#ifndef CONFIG_RWNX_SDM
|
#ifndef CONFIG_RWNX_SDM
|
||||||
MODULE_FIRMWARE(RWNX_AGC_FW_NAME);
|
MODULE_FIRMWARE(RWNX_AGC_FW_NAME);
|
||||||
MODULE_FIRMWARE(RWNX_FCU_FW_NAME);
|
MODULE_FIRMWARE(RWNX_FCU_FW_NAME);
|
||||||
@@ -3981,5 +3982,6 @@ MODULE_FIRMWARE(RWNX_MAC_FW_NAME);
|
|||||||
#ifndef CONFIG_RWNX_TL4
|
#ifndef CONFIG_RWNX_TL4
|
||||||
MODULE_FIRMWARE(RWNX_MAC_FW_NAME2);
|
MODULE_FIRMWARE(RWNX_MAC_FW_NAME2);
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* !AICWF_USB_SUPPORT */
|
||||||
|
|
||||||
|
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
#include "aicwf_txq_prealloc.h"
|
#include "aicwf_txq_prealloc.h"
|
||||||
|
|
||||||
|
|
||||||
#define DRV_CONFIG_FW_NAME "fw.bin"
|
|
||||||
#define DRV_DESCRIPTION "AIC BLUETOOTH"
|
#define DRV_DESCRIPTION "AIC BLUETOOTH"
|
||||||
#define DRV_COPYRIGHT "Copyright(c) 2015-2020 AICSemi"
|
#define DRV_COPYRIGHT "Copyright(c) 2015-2020 AICSemi"
|
||||||
#define DRV_AUTHOR "AICSemi"
|
#define DRV_AUTHOR "AICSemi"
|
||||||
@@ -75,7 +74,7 @@ MODULE_IMPORT_NS("VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver");
|
|||||||
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
|
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MODULE_FIRMWARE(DRV_CONFIG_FW_NAME);
|
#include "../aicwf_firmware.h"
|
||||||
MODULE_DESCRIPTION(DRV_DESCRIPTION);
|
MODULE_DESCRIPTION(DRV_DESCRIPTION);
|
||||||
MODULE_VERSION(DRV_VERS_MOD);
|
MODULE_VERSION(DRV_VERS_MOD);
|
||||||
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
|
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
|
||||||
|
|||||||
@@ -1773,11 +1773,17 @@ static int aicwf_usb_probe(struct usb_interface *intf, const struct usb_device_i
|
|||||||
goto out_free_bus;
|
goto out_free_bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (system_config(usb_dev)) {
|
ret = system_config(usb_dev);
|
||||||
|
if (ret) {
|
||||||
|
if (ret > 0)
|
||||||
|
ret = -EIO;
|
||||||
goto out_free_bus;
|
goto out_free_bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aicfw_download_fw(usb_dev)){
|
ret = aicfw_download_fw(usb_dev);
|
||||||
|
if (ret) {
|
||||||
|
if (ret > 0)
|
||||||
|
ret = -EIO;
|
||||||
goto out_free_bus;
|
goto out_free_bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* Files installed below /lib/firmware by install.sh.
|
||||||
|
*
|
||||||
|
* Both USB modules may be loaded in an initramfs. Declare the complete matched
|
||||||
|
* firmware set, including configuration and extension patches, so initramfs
|
||||||
|
* generators can copy it along with either module. Keep this list in sync with
|
||||||
|
* fw/; tests/firmware/test_firmware.py checks the installed paths.
|
||||||
|
*/
|
||||||
|
#ifndef AICWF_FIRMWARE_H
|
||||||
|
#define AICWF_FIRMWARE_H
|
||||||
|
|
||||||
|
MODULE_FIRMWARE("aic8800/aic_userconfig.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800/fmacfw.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fmacfw_m2d.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fmacfw_no_msg_ep.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fmacfw_no_msg_ep_rf.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fmacfw_rf.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_adid.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_adid_rf.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_adid_u03.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_ble_scan.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_ble_scan_ad_filter_dcdc.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_ble_scan_ad_filter_ldo.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_patch.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_patch_rf.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_patch_table.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_patch_table_u03.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/fw_patch_u03.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800/m2d_ota.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80/aic_userconfig_8800d80.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800D80/calibmode_8800d80.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80/fmacfw_8800d80_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80/fmacfw_8800d80_u02_ipc.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80/fw_adid_8800d80_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80/fw_ble_scan_ad_filter.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80/fw_patch_8800d80_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80/fw_patch_table_8800d80_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80/lmacfw_rf_8800d80_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/aic_powerlimit_8800d80n.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/aic_userconfig_8800d80n.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fmacfw_btusb_8800d80n_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fmacfw_calib_8800d80n_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fmacfw_cinit_8800d80n_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fmacfw_patch_8800d80n_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fmacfw_patch_tbl_8800d80n_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fw_patch_8800d80n_rf_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fw_patch_8800d80n_rf_u02_ext0.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fw_patch_8800d80n_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fw_patch_8800d80n_u02_ext0.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fw_patch_table_8800d80n_rf_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/fw_patch_table_8800d80n_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80N/lmacfw_rf_8800d80n.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/aic_powerlimit_8800d80x2.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/aic_userconfig_8800d80x2.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/aicbt.conf");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/fmacfw_8800d80x2.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/fw_adid_8800d80x2_u03.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/fw_adid_8800d80x2_u05.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/fw_patch_8800d80x2_u03.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/fw_patch_8800d80x2_u05.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/fw_patch_8800d80x2_u05_ext0.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/fw_patch_8800d80x2_u05_ext1.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/fw_patch_table_8800d80x2_u03.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/fw_patch_table_8800d80x2_u05.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800D80X2/lmacfw_rf_8800d80x2.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/aic_powerlimit_8800dc.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/aic_powerlimit_8800dw.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/aic_userconfig_8800dc.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/aic_userconfig_8800dw.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/aic_userconfig_8800dw_u2.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/aic_userconfig_8800dw_w311.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fmacfw_calib_8800dc_h_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fmacfw_calib_8800dc_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fmacfw_patch_8800dc_h_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fmacfw_patch_8800dc_ipc_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fmacfw_patch_8800dc_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fmacfw_patch_tbl_8800dc_h_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fmacfw_patch_tbl_8800dc_ipc_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fmacfw_patch_tbl_8800dc_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fw_adid_8800dc_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fw_adid_8800dc_u02h.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fw_patch_8800dc_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fw_patch_8800dc_u02_ext0.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fw_patch_8800dc_u02h.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fw_patch_table_8800dc_u02.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/fw_patch_table_8800dc_u02h.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DC/lmacfw_rf_8800dc.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DLN/aic_powerlimit_8800dln.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800DLN/aic_userconfig_8800dln.txt");
|
||||||
|
MODULE_FIRMWARE("aic8800DLN/fmacfw_gaintbl_8800dln.bin");
|
||||||
|
MODULE_FIRMWARE("aic8800DLN/fmacfw_initvar_8800dln.bin");
|
||||||
|
|
||||||
|
#endif /* AICWF_FIRMWARE_H */
|
||||||
|
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Check initramfs firmware inventory and extracted probe error handling.
|
||||||
|
|
||||||
|
Run with Python 3 and a C compiler. Pass --modules BUILD_DIR to also check the
|
||||||
|
firmware metadata in built modules using modinfo. No modules are installed.
|
||||||
|
The probe test mocks USB and allocation, not kernel scheduling or hardware.
|
||||||
|
"""
|
||||||
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--modules", type=Path)
|
||||||
|
args, remaining = parser.parse_known_args()
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
|
def function(source, signature):
|
||||||
|
start = source.index(signature)
|
||||||
|
brace = source.index("{", start)
|
||||||
|
end, depth = brace + 1, 1
|
||||||
|
while depth:
|
||||||
|
depth += (source[end] == "{") - (source[end] == "}")
|
||||||
|
end += 1
|
||||||
|
return source[start:end]
|
||||||
|
|
||||||
|
|
||||||
|
class FirmwareTests(unittest.TestCase):
|
||||||
|
def test_declared_files_match_installed_inventory(self):
|
||||||
|
expected = {p.relative_to(ROOT / "fw").as_posix()
|
||||||
|
for p in (ROOT / "fw").rglob("*") if p.is_file()}
|
||||||
|
header = (ROOT / "drivers/aic8800/aicwf_firmware.h").read_text()
|
||||||
|
declared = re.findall(r'MODULE_FIRMWARE\("([^"]+)"\)', header)
|
||||||
|
self.assertEqual(len(declared), len(set(declared)))
|
||||||
|
self.assertEqual(set(declared), expected)
|
||||||
|
|
||||||
|
@unittest.skipUnless(args.modules, "pass --modules to inspect built modules")
|
||||||
|
def test_built_modules_declare_installed_files(self):
|
||||||
|
expected = {p.relative_to(ROOT / "fw").as_posix()
|
||||||
|
for p in (ROOT / "fw").rglob("*") if p.is_file()}
|
||||||
|
for name in ("aic_load_fw", "aic8800_fdrv"):
|
||||||
|
with self.subTest(module=name):
|
||||||
|
module = args.modules / name / (name + ".ko")
|
||||||
|
declared = subprocess.check_output(
|
||||||
|
["modinfo", "-F", "firmware", str(module)], text=True).splitlines()
|
||||||
|
self.assertEqual(set(declared), expected)
|
||||||
|
|
||||||
|
def test_probe_errors_and_intentional_reenumeration(self):
|
||||||
|
source = (ROOT / "drivers/aic8800/aic_load_fw/aicwf_usb.c").read_text()
|
||||||
|
probe = function(source, "static int aicwf_usb_probe(")
|
||||||
|
# The real post-allocation probe and cleanup, with allocations supplied
|
||||||
|
# by the fixture, exercises the actual failure labels and return value.
|
||||||
|
body = probe[probe.index("ret = aicwf_bus_start(bus_if);"):probe.rfind("}")]
|
||||||
|
prelude = r'''
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#define USB_SPEED_HIGH 2
|
||||||
|
#define USB_SPEED_SUPER 3
|
||||||
|
#define PRODUCT_ID_AIC8801 1
|
||||||
|
#define PRODUCT_ID_AIC8800D81 2
|
||||||
|
#define PRODUCT_ID_AIC8800D81X2 3
|
||||||
|
#define PRODUCT_ID_AIC8800D89X2 4
|
||||||
|
#define usb_err(...) ((void)0)
|
||||||
|
#define printk(...) ((void)0)
|
||||||
|
#define kfree(...) ((void)0)
|
||||||
|
struct usb_device { int speed; };
|
||||||
|
struct aic_usb_dev { int chipid; bool app_cmp; void *rx_priv; };
|
||||||
|
static int config_result, download_result, cleanup, downloads, reboots, fw_loaded;
|
||||||
|
static struct aic_usb_dev device;
|
||||||
|
static struct usb_device usb_device;
|
||||||
|
static int aicwf_bus_start(void *bus) { return 0; }
|
||||||
|
static void aic_bt_platform_init(struct aic_usb_dev *dev) {}
|
||||||
|
static void system_reboot(struct aic_usb_dev *dev) { reboots++; }
|
||||||
|
static void rwnx_send_reboot(struct aic_usb_dev *dev) { reboots++; }
|
||||||
|
static int system_config(struct aic_usb_dev *dev) { return config_result; }
|
||||||
|
static int aicfw_download_fw(struct aic_usb_dev *dev) { downloads++; return download_result; }
|
||||||
|
static void aicwf_bus_deinit(void *dev) { cleanup++; }
|
||||||
|
static void aicwf_rx_deinit(void *dev) {}
|
||||||
|
static void aicwf_usb_deinit(void *dev) {}
|
||||||
|
static void usb_set_intfdata(void *intf, void *data) {}
|
||||||
|
static int probe(void) {
|
||||||
|
int ret = 0;
|
||||||
|
struct aic_usb_dev *usb_dev = &device;
|
||||||
|
struct usb_device *usb = &usb_device;
|
||||||
|
void *bus_if = NULL, *dev = NULL, *intf = NULL;
|
||||||
|
'''
|
||||||
|
checks = r'''
|
||||||
|
}
|
||||||
|
static void setup(void) {
|
||||||
|
config_result = download_result = cleanup = downloads = reboots = fw_loaded = 0;
|
||||||
|
device.chipid = 0; device.app_cmp = false; usb_device.speed = USB_SPEED_HIGH;
|
||||||
|
}
|
||||||
|
int main(void) {
|
||||||
|
setup(); assert(probe() == 0 && device.app_cmp && fw_loaded && downloads == 1);
|
||||||
|
setup(); config_result = -EIO;
|
||||||
|
assert(probe() == -EIO && cleanup == 1 && downloads == 0 && !fw_loaded);
|
||||||
|
setup(); config_result = 1;
|
||||||
|
assert(probe() == -EIO && cleanup == 1 && downloads == 0);
|
||||||
|
setup(); download_result = -ENOMEM;
|
||||||
|
assert(probe() == -ENOMEM && cleanup == 1 && !device.app_cmp && !fw_loaded);
|
||||||
|
setup(); download_result = 1; assert(probe() == -EIO && cleanup == 1);
|
||||||
|
setup(); device.chipid = PRODUCT_ID_AIC8800D81;
|
||||||
|
assert(probe() == 0 && reboots == 1 && cleanup == 1 && downloads == 0);
|
||||||
|
setup(); usb_device.speed = 1;
|
||||||
|
assert(probe() == 0 && reboots == 1 && cleanup == 1 && downloads == 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
with tempfile.TemporaryDirectory(prefix="aic-firmware-test-") as temp:
|
||||||
|
c_file = Path(temp) / "probe.c"
|
||||||
|
binary = Path(temp) / "probe"
|
||||||
|
c_file.write_text(prelude + body + checks)
|
||||||
|
subprocess.run([os.environ.get("CC", "cc"), "-std=gnu11", "-o",
|
||||||
|
str(binary), str(c_file)], check=True)
|
||||||
|
subprocess.run([str(binary)], check=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main(argv=[__file__] + remaining)
|
||||||
|
|
||||||
Reference in new issue
Block a user