Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
#
# This file is part of LiteX.
#
# Copyright (c) 2026 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
import argparse
import json
import logging
import os
import tempfile
import unittest
from types import SimpleNamespace
from unittest.mock import Mock, patch
from litex.soc.integration.builder import Builder, builder_argdict, builder_args
from litex.soc.integration.soc import SoCRegion
from litex.build.log import buffer_build_log, start_build_log, stop_build_log
class _FakePlatform:
def __init__(self):
self.name = "unit"
self.sources = []
self.output_dir = None
def get_bitstream_extension(self, mode):
return {
"sram" : ".bit",
"flash" : ".bin",
}[mode]
class _FakeSoC:
def __init__(self, cpu_type=None):
self.platform = _FakePlatform()
self.cpu_type = cpu_type
def get_build_name(self):
return self.platform.name
class _BuildableFakeSoC(_FakeSoC):
def __init__(self):
_FakeSoC.__init__(self, cpu_type="unitcpu")
self.cpu = SimpleNamespace(use_rom=False)
self.finalized = 0
self.build_calls = []
self.exit_calls = []
def finalize(self):
self.finalized += 1
def build(self, build_dir, **kwargs):
self.build_calls.append((build_dir, kwargs))
return "vns"
def do_exit(self, vns):
self.exit_calls.append(vns)
class _NoBiosBuildableFakeSoC(_BuildableFakeSoC):
def __init__(self):
_BuildableFakeSoC.__init__(self)
self.cpu_type = None
class _LoggingBuildableFakeSoC(_BuildableFakeSoC):
def finalize(self):
print("\x1b[1munit stdout from finalize\x1b[0m")
os.write(2, b"\x1b[32munit stderr from finalize\x1b[0m\n")
logging.getLogger("unit").warning("\x1b[36munit logging from finalize\x1b[0m")
_BuildableFakeSoC.finalize(self)
class _InitMemsFakeSoC(_BuildableFakeSoC):
def __init__(self):
_BuildableFakeSoC.__init__(self)
self.init_mems_calls = []
def init_mems(self, **kwargs):
self.init_mems_calls.append(kwargs)
class _RomFakeSoC:
def __init__(self):
self.bus = SimpleNamespace(
data_width = 32,
regions = {"rom": SoCRegion(origin=0x00000000, size=16, mode="rx")},
)
self.cpu = SimpleNamespace(endianness="little")
self.init_rom_calls = []
def init_rom(self, name, contents, auto_size):
self.init_rom_calls.append((name, contents, auto_size))
class _IncludeFakeSoC:
def __init__(self):
self.mem_regions = {
"rom" : SoCRegion(origin=0x00000000, size=0x1000, mode="rx"),
"sram" : SoCRegion(origin=0x10000000, size=0x1000),
"csr" : SoCRegion(origin=0xe0000000, size=0x10000, cached=False),
}
self.constants = {"CONFIG_CLOCK_FREQUENCY": 100000000}
self.csr_regions = {}
self.csr = SimpleNamespace(ordering="big")
self.cpu = SimpleNamespace(
reset_address = 0x00000000,
linker_output_format = "elf32-littleriscv",
)
def _make_builder(output_dir, soc=None, **kwargs):
if soc is None:
soc = _FakeSoC()
return Builder(soc, output_dir=output_dir, **kwargs)
def _make_argdict(*args):
parser = argparse.ArgumentParser()
builder_args(parser)
return builder_argdict(parser.parse_args(list(args)))
class TestBuilderArguments(unittest.TestCase):
def test_no_compile_disables_software_and_gateware(self):
argdict = _make_argdict("--no-compile")
self.assertFalse(argdict["compile_software"])
self.assertFalse(argdict["compile_gateware"])
def test_individual_compile_flags_are_mapped(self):
no_software = _make_argdict("--no-compile-software")
no_gateware = _make_argdict("--no-compile-gateware")
self.assertFalse(no_software["compile_software"])
self.assertTrue(no_software["compile_gateware"])
self.assertTrue(no_gateware["compile_software"])
self.assertFalse(no_gateware["compile_gateware"])
def test_build_log_options_are_mapped(self):
default = _make_argdict()
explicit = _make_argdict("--build-log", "custom.log")
enabled = _make_argdict("--build-log")
disabled = _make_argdict("--no-build-log")
self.assertTrue(default["build_log"])
self.assertEqual(explicit["build_log"], "custom.log")
self.assertTrue(enabled["build_log"])
self.assertFalse(disabled["build_log"])
def test_export_and_bios_options_are_mapped(self):
argdict = _make_argdict(
"--soc-json", "soc.json",
"--soc-csv", "soc.csv",
"--soc-svd", "soc.svd",
"--memory-x", "memory.x",
"--bios-lto",
"--bios-format", "float",
"--bios-console", "lite",
"--libc-mode", "full",
"--no-integrated-rom-auto-size",
"--hierarchical-verilog",
)
self.assertEqual(argdict["csr_json"], "soc.json")
self.assertEqual(argdict["csr_csv"], "soc.csv")
self.assertEqual(argdict["csr_svd"], "soc.svd")
self.assertEqual(argdict["memory_x"], "memory.x")
self.assertTrue(argdict["bios_lto"])
self.assertEqual(argdict["bios_format"], "float")
self.assertEqual(argdict["bios_console"], "lite")
self.assertEqual(argdict["libc_mode"], "full")
self.assertFalse(argdict["integrated_rom_auto_size"])
self.assertTrue(argdict["hierarchical"])
class TestBuilderPaths(unittest.TestCase):
def test_default_directories_and_exports_are_under_output_dir(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = _make_builder(tmp_dir)
self.assertEqual(builder.output_dir, os.path.abspath(tmp_dir))
self.assertEqual(builder.gateware_dir, os.path.join(os.path.abspath(tmp_dir), "gateware"))
self.assertEqual(builder.software_dir, os.path.join(os.path.abspath(tmp_dir), "software"))
self.assertEqual(builder.include_dir, os.path.join(os.path.abspath(tmp_dir), "software", "include"))
self.assertEqual(builder.generated_dir, os.path.join(os.path.abspath(tmp_dir), "software", "include", "generated"))
self.assertEqual(builder.csr_csv, os.path.join(os.path.abspath(tmp_dir), "csr.csv"))
self.assertEqual(builder.csr_json, os.path.join(os.path.abspath(tmp_dir), "csr.json"))
self.assertEqual(builder.get_build_log_filename(), os.path.join(os.path.abspath(tmp_dir), "litex.log"))
def test_build_log_filename_can_be_disabled_or_explicit(self):
with tempfile.TemporaryDirectory() as tmp_dir:
disabled = _make_builder(tmp_dir, build_log=False)
explicit = _make_builder(tmp_dir, build_log="custom.log")
self.assertIsNone(disabled.get_build_log_filename())
self.assertEqual(explicit.get_build_log_filename(), os.path.abspath("custom.log"))
def test_output_filename_helpers(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = _make_builder(tmp_dir)
self.assertEqual(
builder.get_bios_filename(),
os.path.join(builder.software_dir, "bios", "bios.bin"),
)
self.assertEqual(
builder.get_bitstream_filename(),
os.path.join(builder.gateware_dir, "unit.bit"),
)
self.assertEqual(
builder.get_bitstream_filename(mode="flash"),
os.path.join(builder.gateware_dir, "unit.bin"),
)
self.assertEqual(
builder.get_bitstream_filename(ext=".fs"),
os.path.join(builder.gateware_dir, "unit.fs"),
)
with self.assertRaisesRegex(ValueError, "Unsupported bitstream mode"):
builder.get_bitstream_filename(mode="invalid")
class TestBuilderJsonImports(unittest.TestCase):
def test_json_imports_are_namespaced_and_interrupt_constants_are_filtered(self):
with tempfile.TemporaryDirectory() as tmp_dir:
json_file = os.path.join(tmp_dir, "remote.json")
with open(json_file, "w") as f:
json.dump({
"csr_bases": {
"uart": "0xe0001800",
},
"csr_registers": {
"uart_rx": {
"addr" : "0xe0001800",
"size" : 1,
},
},
"constants": {
"config_csr_data_width" : 32,
"uart_interrupt" : 5,
"with_feature" : True,
},
"memories": {
"rom": {
"base" : "0x10000000",
"size" : "0x1000",
"type" : "rx",
},
},
}, f)
builder = _make_builder(tmp_dir)
builder.add_json(json_file, origin=0x1000, name="remote")
constants = builder._get_json_constants()
mems = builder._get_json_mem_regions()
csrs = builder._get_json_csr_regions()
self.assertEqual(constants["REMOTE_WITH_FEATURE"], True)
self.assertNotIn("REMOTE_UART_INTERRUPT", constants)
self.assertEqual(mems["remote_rom"].origin, 0x10001000)
self.assertEqual(mems["remote_rom"].size, 0x1000)
self.assertEqual(csrs["remote_uart"].origin, 0xe0002800)
def test_json_item_collisions_are_reported(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = _make_builder(tmp_dir)
with self.assertRaisesRegex(ValueError, "JSON constant collision on FOO"):
builder._merge_json_items({"FOO": 1}, {"FOO": 2}, "constant")
def test_json_constant_exclusion_can_be_disabled(self):
with tempfile.TemporaryDirectory() as tmp_dir:
json_file = os.path.join(tmp_dir, "remote.json")
with open(json_file, "w") as f:
json.dump({
"csr_bases": {},
"constants": {
"timer0_interrupt": 1,
},
"memories": {},
}, f)
builder = _make_builder(tmp_dir)
builder.add_json(json_file, exclude_constants=[])
self.assertEqual(builder._get_json_constants()["TIMER0_INTERRUPT"], 1)
class TestBuilderGeneratedFiles(unittest.TestCase):
def test_generate_includes_without_bios_writes_runtime_headers_only(self):
with tempfile.TemporaryDirectory() as tmp_dir:
memory_x = os.path.join(tmp_dir, "memory.x")
builder = _make_builder(tmp_dir, soc=_IncludeFakeSoC(), memory_x=memory_x)
with patch("litex.soc.cores.bitbang.collect_i2c_info", return_value=([], [])):
builder._generate_includes(with_bios=False)
generated_dir = builder.generated_dir
self.assertTrue(os.path.exists(os.path.join(generated_dir, "mem.h")))
self.assertTrue(os.path.exists(os.path.join(generated_dir, "soc.h")))
self.assertTrue(os.path.exists(os.path.join(generated_dir, "csr.h")))
self.assertTrue(os.path.exists(os.path.join(generated_dir, "git.h")))
self.assertTrue(os.path.exists(memory_x))
self.assertFalse(os.path.exists(os.path.join(generated_dir, "variables.mak")))
self.assertFalse(os.path.exists(os.path.join(generated_dir, "output_format.ld")))
self.assertFalse(os.path.exists(os.path.join(generated_dir, "regions.ld")))
with open(os.path.join(generated_dir, "mem.h")) as f:
mem_h = f.read()
self.assertIn("#define MEM_REGIONS \"", mem_h)
self.assertIn("#define MEM_REGIONS_DETAILS \"", mem_h)
self.assertIn("Region Origin End Size", mem_h)
self.assertIn("ROM 0x00000000 0x00000fff 0x1000", mem_h)
self.assertIn("CSR 0xe0000000 0xe000ffff 0x10000", mem_h)
def test_generate_includes_with_bios_writes_linker_files(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = _make_builder(tmp_dir, soc=_IncludeFakeSoC(), compile_software=False)
with patch("litex.soc.integration.builder.export.get_cpu_mak", return_value=[
("TRIPLE", "--not-found--"),
("CPU", "unitcpu"),
("CPUFAMILY", "riscv"),
("CPUFLAGS", ""),
("CPUENDIANNESS", "little"),
("CLANG", "0"),
("CPU_DIRECTORY", tmp_dir),
]):
with patch("litex.soc.cores.bitbang.collect_i2c_info", return_value=([], [])):
builder._generate_includes(with_bios=True)
generated_dir = builder.generated_dir
self.assertTrue(os.path.exists(os.path.join(generated_dir, "variables.mak")))
self.assertTrue(os.path.exists(os.path.join(generated_dir, "output_format.ld")))
self.assertTrue(os.path.exists(os.path.join(generated_dir, "regions.ld")))
def test_generate_csr_map_writes_default_csv_and_json_exports(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = _make_builder(tmp_dir, soc=_IncludeFakeSoC())
builder._generate_csr_map()
with open(builder.csr_json) as f:
csr_json = json.load(f)
with open(builder.csr_csv) as f:
csr_csv = f.read()
self.assertEqual(csr_json["constants"]["config_clock_frequency"], 100000000)
self.assertIn("memory_region,csr,0xe0000000,65536", csr_csv)
def test_variables_contents_escapes_makefile_paths_and_validates_console(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = _make_builder(tmp_dir, soc=_IncludeFakeSoC(), compile_software=False)
builder.add_software_package("custom", r"C:\liteX\custom")
with patch("litex.soc.integration.builder.export.get_cpu_mak", return_value=[
("TRIPLE", "--not-found--"),
("CPU", "unitcpu"),
("CPUFAMILY", "riscv"),
("CPUFLAGS", ""),
("CPUENDIANNESS", "little"),
("CLANG", "0"),
("CPU_DIRECTORY", r"C:\cpu"),
]):
variables = builder._get_variables_contents()
builder.bios_console = "invalid"
with self.assertRaisesRegex(ValueError, "Unsupported BIOS console"):
builder._get_variables_contents()
self.assertIn(r"CUSTOM_DIRECTORY=C:\\liteX\\custom", variables)
self.assertIn("BIOS_CONSOLE_FULL=1", variables)
class TestBuilderRomSoftware(unittest.TestCase):
def _make_rom_builder(self, tmp_dir, auto_size):
builder = object.__new__(Builder)
builder.software_dir = tmp_dir
builder.integrated_rom_auto_size = auto_size
builder.soc = _RomFakeSoC()
return builder
def test_initialize_rom_software_keeps_auto_size_contents_unpadded(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = self._make_rom_builder(tmp_dir, auto_size=True)
bios_file = os.path.join(tmp_dir, "bios", "bios.bin")
with patch("litex.soc.integration.builder.soc_core.get_mem_data", return_value=[1, 2]) as get_mem_data:
builder._initialize_rom_software()
get_mem_data.assert_called_once_with(bios_file, data_width=32, endianness="little")
self.assertEqual(builder.soc.init_rom_calls, [("rom", [1, 2], True)])
def test_initialize_rom_software_pads_when_auto_size_is_disabled(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = self._make_rom_builder(tmp_dir, auto_size=False)
bios_file = os.path.join(tmp_dir, "bios", "bios.bin")
with patch("litex.soc.integration.builder.soc_core.get_mem_data", return_value=[1, 2]) as get_mem_data:
builder._initialize_rom_software()
get_mem_data.assert_called_once_with(bios_file, data_width=32, endianness="little")
self.assertEqual(builder.soc.init_rom_calls, [("rom", [1, 2, 0, 0], False)])
def test_initialize_rom_software_does_not_truncate_when_auto_size_is_disabled(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = self._make_rom_builder(tmp_dir, auto_size=False)
with patch("litex.soc.integration.builder.soc_core.get_mem_data", return_value=[1, 2, 3, 4, 5]):
builder._initialize_rom_software()
self.assertEqual(builder.soc.init_rom_calls, [("rom", [1, 2, 3, 4, 5], False)])
def test_generate_rom_software_skips_bios_when_disabled(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = object.__new__(Builder)
builder.software_dir = tmp_dir
builder.compile_software = True
builder.software_packages = [
("libbase", os.path.join(tmp_dir, "libbase_src")),
("bios", os.path.join(tmp_dir, "bios_src")),
]
with patch("litex.soc.integration.builder.os.cpu_count", return_value=2):
with patch("litex.soc.integration.builder.subprocess.check_call") as check_call:
builder._generate_rom_software(compile_bios=False)
check_call.assert_called_once_with([
"make", "-j2",
"-C", os.path.join(tmp_dir, "libbase"),
"-f", os.path.join(tmp_dir, "libbase_src", "Makefile"),
])
def test_generate_rom_software_is_noop_when_software_compile_is_disabled(self):
builder = object.__new__(Builder)
builder.software_dir = "software"
builder.compile_software = False
builder.software_packages = [("libbase", "libbase_src")]
with patch("litex.soc.integration.builder.subprocess.check_call") as check_call:
builder._generate_rom_software()
check_call.assert_not_called()
def test_prepare_rom_software_creates_all_package_directories(self):
with tempfile.TemporaryDirectory() as tmp_dir:
builder = object.__new__(Builder)
builder.software_dir = tmp_dir
builder.software_packages = [
("libbase", "libbase_src"),
("bios", "bios_src"),
]
builder._prepare_rom_software()
self.assertTrue(os.path.isdir(os.path.join(tmp_dir, "libbase")))
self.assertTrue(os.path.isdir(os.path.join(tmp_dir, "bios")))
def test_check_meson_accepts_supported_version(self):
builder = object.__new__(Builder)
with patch("litex.soc.integration.builder.shutil.which", return_value="/usr/bin/meson"):
with patch("litex.soc.integration.builder.subprocess.check_output", return_value=b"0.60.0\n"):
builder._check_meson()
def test_check_meson_rejects_missing_or_old_version(self):
builder = object.__new__(Builder)
with patch("litex.soc.integration.builder.shutil.which", return_value=None):
with self.assertRaisesRegex(OSError, "Unable to find valid Meson"):
builder._check_meson()
with patch("litex.soc.integration.builder.shutil.which", return_value="/usr/bin/meson"):
with patch("litex.soc.integration.builder.subprocess.check_output", return_value=b"0.58.0\n"):
with self.assertRaisesRegex(OSError, "Meson version too old"):
builder._check_meson()
class TestBuilderBuild(unittest.TestCase):
def test_build_adds_bios_package_only_once(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _BuildableFakeSoC()
builder = _make_builder(tmp_dir, soc=soc, compile_software=False, compile_gateware=False)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
builder.build()
builder.build()
bios_packages = [package for package in builder.software_packages if package[0] == "bios"]
self.assertEqual(len(bios_packages), 1)
self.assertEqual(soc.finalized, 2)
self.assertEqual(len(soc.build_calls), 2)
self.assertFalse(soc.build_calls[0][1]["run"])
self.assertEqual(soc.exit_calls, ["vns", "vns"])
def test_build_preserves_user_added_bios_package(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _BuildableFakeSoC()
builder = _make_builder(tmp_dir, soc=soc, compile_software=False, compile_gateware=False)
bios_dir = os.path.join(tmp_dir, "custom_bios")
builder.add_software_package("bios", bios_dir)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
builder.build()
bios_packages = [package for package in builder.software_packages if package[0] == "bios"]
self.assertEqual(bios_packages, [("bios", bios_dir)])
def test_build_copies_marked_platform_sources_to_gateware_dir(self):
with tempfile.TemporaryDirectory() as tmp_dir:
source_dir = os.path.join(tmp_dir, "src")
os.makedirs(source_dir)
copied_source = os.path.join(source_dir, "copied.v")
kept_source = os.path.join(source_dir, "kept.v")
with open(copied_source, "w") as f:
f.write("module copied(); endmodule\n")
with open(kept_source, "w") as f:
f.write("module kept(); endmodule\n")
soc = _BuildableFakeSoC()
soc.platform.sources = [
(copied_source, "verilog", "work", True),
(kept_source, "verilog", "work"),
]
builder = _make_builder(tmp_dir, soc=soc, compile_software=False, compile_gateware=False)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
builder.build()
self.assertTrue(os.path.exists(os.path.join(builder.gateware_dir, "copied.v")))
self.assertEqual(soc.platform.sources, [
("copied.v", "verilog", "work"),
(kept_source, "verilog", "work"),
])
def test_build_preserves_explicit_run_and_hierarchical_kwargs(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _BuildableFakeSoC()
builder = _make_builder(
tmp_dir,
soc=soc,
compile_software=False,
compile_gateware=False,
build_backend="edalize",
hierarchical=True,
)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
builder.build(run=True, hierarchical=False, build_name="top")
_, kwargs = soc.build_calls[0]
self.assertTrue(kwargs["run"])
self.assertFalse(kwargs["hierarchical"])
self.assertEqual(kwargs["build_backend"], "edalize")
self.assertEqual(kwargs["build_name"], "top")
def test_build_without_cpu_does_not_add_bios_or_create_software_dir(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _NoBiosBuildableFakeSoC()
builder = _make_builder(tmp_dir, soc=soc, compile_software=False, compile_gateware=False)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
builder.build()
self.assertFalse(any(package[0] == "bios" for package in builder.software_packages))
self.assertFalse(os.path.exists(builder.software_dir))
builder._generate_includes.assert_called_once_with(with_bios=False)
def test_build_passes_user_kwargs_to_init_mems(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _InitMemsFakeSoC()
builder = _make_builder(tmp_dir, soc=soc, compile_software=False, compile_gateware=False)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
builder.build(load=True, build_name="top")
self.assertEqual(soc.init_mems_calls, [{"load": True, "build_name": "top"}])
def test_build_writes_default_build_log(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _LoggingBuildableFakeSoC()
builder = _make_builder(tmp_dir, soc=soc, compile_software=False, compile_gateware=False)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
builder.build()
log_file = os.path.join(builder.output_dir, "litex.log")
with open(log_file, "r") as f:
log = f.read()
self.assertIn("# LiteX build log", log)
self.assertIn("unit stdout from finalize", log)
self.assertIn("unit stderr from finalize", log)
self.assertIn("unit logging from finalize", log)
self.assertNotIn("\x1b[", log)
def test_build_log_includes_buffered_early_soc_logs(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _BuildableFakeSoC()
builder = _make_builder(tmp_dir, soc=soc, compile_software=False, compile_gateware=False)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
buffer_build_log()
logging.getLogger("unit").warning("\x1b[33mearly soc log\x1b[0m")
builder.build()
with open(os.path.join(builder.output_dir, "litex.log"), "r") as f:
log = f.read()
self.assertIn("early soc log", log)
self.assertNotIn("\x1b[", log)
def test_build_log_strips_direct_logging_handler_colors(self):
root = logging.getLogger()
old_handlers = root.handlers[:]
try:
for handler in old_handlers:
root.removeHandler(handler)
root.addHandler(logging.NullHandler())
with tempfile.TemporaryDirectory() as tmp_dir:
log_file = os.path.join(tmp_dir, "litex.log")
start_build_log(log_file)
try:
logging.getLogger("unit").warning("\x1b[32mdirect logging handler\x1b[0m")
finally:
stop_build_log()
with open(log_file, "r") as f:
log = f.read()
self.assertIn("direct logging handler", log)
self.assertNotIn("\x1b[", log)
finally:
for handler in root.handlers[:]:
root.removeHandler(handler)
for handler in old_handlers:
root.addHandler(handler)
def test_build_log_can_be_disabled(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _LoggingBuildableFakeSoC()
builder = _make_builder(tmp_dir, soc=soc, compile_software=False, compile_gateware=False, build_log=False)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
builder.build()
self.assertFalse(os.path.exists(os.path.join(builder.output_dir, "litex.log")))
def test_active_build_log_is_not_nested_by_builder(self):
with tempfile.TemporaryDirectory() as tmp_dir:
log_file = os.path.join(tmp_dir, "litex.log")
soc = _LoggingBuildableFakeSoC()
builder = _make_builder(tmp_dir, soc=soc, compile_software=False, compile_gateware=False, build_log=log_file)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
start_build_log(log_file)
try:
builder.build()
finally:
stop_build_log()
with open(log_file, "r") as f:
log = f.read()
self.assertEqual(log.count("unit stdout from finalize"), 1)
def test_build_generates_docs_when_requested(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _BuildableFakeSoC()
builder = _make_builder(
tmp_dir,
soc=soc,
compile_software=False,
compile_gateware=False,
generate_doc=True,
)
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
with patch("litex.soc.doc.generate_docs") as generate_docs:
with patch("litex.soc.integration.builder.subprocess.check_call") as check_call:
builder.build()
doc_dir = os.path.join(builder.output_dir, "doc")
generate_docs.assert_called_once_with(soc, doc_dir)
check_call.assert_called_once_with([
"sphinx-build", "-M", "html", doc_dir, os.path.join(doc_dir, "_build")
])
def test_build_removes_software_dir_when_variables_change(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _BuildableFakeSoC()
builder = _make_builder(tmp_dir, soc=soc, compile_gateware=False)
stale_file = os.path.join(builder.software_dir, "stale.txt")
os.makedirs(builder.generated_dir)
with open(os.path.join(builder.generated_dir, "variables.mak"), "w") as f:
f.write("old")
with open(stale_file, "w") as f:
f.write("stale")
builder._get_variables_contents = Mock(return_value="new")
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
builder.build()
self.assertFalse(os.path.exists(stale_file))
self.assertTrue(os.path.isdir(builder.software_dir))
def test_build_keeps_software_dir_when_variables_are_unchanged(self):
with tempfile.TemporaryDirectory() as tmp_dir:
soc = _BuildableFakeSoC()
builder = _make_builder(tmp_dir, soc=soc, compile_gateware=False)
stale_file = os.path.join(builder.software_dir, "stale.txt")
os.makedirs(builder.generated_dir)
with open(os.path.join(builder.generated_dir, "variables.mak"), "w") as f:
f.write("same")
with open(stale_file, "w") as f:
f.write("stale")
builder._get_variables_contents = Mock(return_value="same")
builder._generate_includes = Mock()
builder._generate_csr_map = Mock()
builder.build()
self.assertTrue(os.path.exists(stale_file))
if __name__ == "__main__":
unittest.main()
d66325f4eThis file is pinned to the selected release. Download the original to open it in your design tool.