diff --git a/README.md b/README.md index 44a8e64..287a841 100644 --- a/README.md +++ b/README.md @@ -303,5 +303,5 @@ await myMod.buildAndGenerateRTL(); ---------------- -Copyright (C) 2024-2025 Intel Corporation +Copyright (C) 2024-2026 Intel Corporation SPDX-License-Identifier: BSD-3-Clause diff --git a/lib/src/bridge_module.dart b/lib/src/bridge_module.dart index b1fe7e9..9be561b 100644 --- a/lib/src/bridge_module.dart +++ b/lib/src/bridge_module.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2024-2025 Intel Corporation +// Copyright (C) 2024-2026 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // bridge_module.dart @@ -943,9 +943,13 @@ class BridgeModule extends Module with SystemVerilog { } /// Calls [build] and generates SystemVerilog and a filelist into the - /// [outputPath], with optional logging sent to the [logger]. - Future buildAndGenerateRTL( - {Logger? logger, String outputPath = 'output'}) async { + /// [outputPath]. + Future buildAndGenerateRTL({ + @Deprecated('Leave null to use the default logger') Logger? logger, + String outputPath = 'output', + }) async { + logger ??= RohdBridgeLogger.logger; + var synthResults = {}; // Build @@ -956,14 +960,12 @@ class BridgeModule extends Module with SystemVerilog { final defNames = synthResults.map((result) => result.module.definitionName); logger - ?..info('Build Complete...\n') + ..info('Build Complete...\n') ..info('Found ${synthResults.length} hierarchical instances in ' 'design $name') ..info('Synth Results: ${defNames.join(', ')}'); } on Exception catch (e, stackTrace) { - logger != null - ? logger.error('Build failed $e, $stackTrace') - : throw RohdBridgeException('Build failed $e, $stackTrace'); + logger.error('Build failed $e, $stackTrace'); } // Write out RTL @@ -971,7 +973,7 @@ class BridgeModule extends Module with SystemVerilog { Directory(outputGenerationPath).createSync(recursive: true); final filelistContents = StringBuffer(); - logger?.sectionSeparator('Generating RTL'); + logger.sectionSeparator('Generating RTL'); final fileIoFutures = >[]; for (final synthResult in synthResults) { final fileName = '${synthResult.module.definitionName}.sv'; @@ -981,14 +983,14 @@ class BridgeModule extends Module with SystemVerilog { fileIoFutures.add(File(filePath) .writeAsString(synthResult.toSynthFileContents().join('\n'))); - logger?.finer('Generated file ${Directory(filePath).absolute.path}'); + logger.finer('Generated file ${Directory(filePath).absolute.path}'); } await Future.wait(fileIoFutures); File('$outputPath/filelist.f') .writeAsStringSync(filelistContents.toString()); - logger?.fine('done!'); + logger.fine('done!'); } /// Adds an interface to this module with comprehensive configuration options. diff --git a/lib/src/rohd_bridge_logger.dart b/lib/src/rohd_bridge_logger.dart index 9950ddd..531ff0d 100644 --- a/lib/src/rohd_bridge_logger.dart +++ b/lib/src/rohd_bridge_logger.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2024-2025 Intel Corporation +// Copyright (C) 2024-2026 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // rohd_bridge_logger.dart @@ -31,7 +31,7 @@ extension LoggerError on Logger { } } -/// Loggger for ROHD Bridge tool +/// Logger for ROHD Bridge tool abstract class RohdBridgeLogger { /// If set to `true`, then errors will be printed without causing an immediate /// exception halting execution. @@ -39,18 +39,22 @@ abstract class RohdBridgeLogger { /// If set to`true`, some additional log will be printed /// which will be helpful for debug + @Deprecated( + 'Use other levels and flags in `configureLogger` to control verbosity') static bool enableDebugMesage = false; /// The file sink to write to. - static IOSink? fileSink; + @Deprecated('API is moved to be private. Use separate logging if needed.') + static IOSink? get fileSink => _fileSink; + static IOSink? _fileSink; static late Level _printLevel; /// logger for rohd_bridge static final Logger logger = Logger('ROHD Bridge'); - /// Sets up logging to dump to [filePath] and print to console based on - /// [printLevel] and [rootLevel]. + /// Sets up logging to dump to [filePath] (if provided) and print to console + /// based on [printLevel] and [rootLevel]. /// /// The [rootLevel] will set the level of the [Logger.root] to the given /// level. @@ -62,17 +66,26 @@ abstract class RohdBridgeLogger { /// If [continueOnError] is set to `false`, then an exception will be thrown /// immediately upon encountering an error. static void configureLogger( - String filePath, { + String? filePath, { Level printLevel = Level.ALL, Level rootLevel = Level.ALL, bool continueOnError = false, + @Deprecated('Use other levels and flags to control verbosity') bool enableDebugMesage = false, }) { RohdBridgeLogger.continueOnError = continueOnError; Logger.root.level = rootLevel; _printLevel = printLevel; - fileSink = File(filePath).openWrite(); + if (filePath != null) { + final file = File(filePath); + final directory = file.parent; + if (!directory.existsSync()) { + directory.createSync(recursive: true); + } + + _fileSink = file.openWrite(); + } Logger.root.onRecord.listen((record) { final message = '${record.time}: ${record.level.name}: ' @@ -83,7 +96,7 @@ abstract class RohdBridgeLogger { } static void _handleMessage(String message, [Level? level]) { - fileSink!.write(message); + _fileSink?.write(message); if (level != null && level >= _printLevel) { // We actually want to print for logging purposes based on print level. // ignore: avoid_print @@ -95,13 +108,13 @@ abstract class RohdBridgeLogger { static Future terminate() async { Logger.root.clearListeners(); await flush(); - await fileSink!.close(); - fileSink = null; + await _fileSink?.close(); + _fileSink = null; } /// Flush the file sink. static Future flush() async { - await fileSink!.flush(); + await _fileSink?.flush(); } /// Log a section separator diff --git a/test/logger_test.dart b/test/logger_test.dart new file mode 100644 index 0000000..9333108 --- /dev/null +++ b/test/logger_test.dart @@ -0,0 +1,44 @@ +// Copyright (C) 2026 Intel Corporation +// SPDX-License-Identifier: BSD-3-Clause +// +// logger_test.dart +// Unit tests for MI (multiple instances). +// +// 2026 January 2 +// Author: Max Korbel + +import 'dart:io'; + +import 'package:logging/logging.dart'; +import 'package:rohd_bridge/rohd_bridge.dart'; +import 'package:test/test.dart'; + +void main() { + test('unconfigured logger works', () async { + // just make sure no exceptions are thrown + + final top = BridgeModule('top'); + + const outPath = 'tmp_test/unconfigured_logger_test'; + await top.buildAndGenerateRTL(outputPath: outPath); + + Directory(outPath).deleteSync(recursive: true); + }); + + test('configured logger works', () async { + const logPath = 'tmp_test/cfg_logger/cfg_logger.log'; + RohdBridgeLogger.configureLogger(logPath, printLevel: Level.OFF); + + final top = BridgeModule('top'); + + const outPath = 'tmp_test/cfg_logger/'; + await top.buildAndGenerateRTL(outputPath: outPath); + + await RohdBridgeLogger.terminate(); + + expect(File(logPath).existsSync(), isTrue); + expect(File(logPath).readAsStringSync().contains('done!'), isTrue); + + Directory(outPath).deleteSync(recursive: true); + }); +}