From e2fbba666a84fa67597801b8524b3111e2f379b0 Mon Sep 17 00:00:00 2001 From: Luo Xu Date: Tue, 28 Jul 2026 13:43:33 +0800 Subject: [PATCH] fix(bt): fix BLE log compression build on Windows The BLE log compression feature (CONFIG_BT_LOG_CRITICAL_ONLY -> BLE_COMPRESSED_LOG_ENABLE) failed to build on Windows while working correctly on Linux, due to two shell/platform-specific issues in the compression script. 1. Module/source argument quoting. CMakeLists.txt passes the semicolon-separated module and source lists wrapped in single quotes ("'${MODULES}'") to protect ';' from POSIX shells, which strip them. cmd.exe does not treat single quotes as quoting characters, so on Windows the quotes reached the script literally and args.module.split(';') produced "'BLE_MESH" / "BLE_HOST'" instead of the clean names. These never matched the YAML module keys, every module was skipped ("Skipping module ... - config not found"), the compressed sources were never generated, and the build failed. Strip surrounding quote characters before splitting; this is a no-op on Linux/macOS where the shell already removed them. 2. CRLF line endings. With core.autocrlf=true the IDF sources are checked out as CRLF on Windows. The generated *_log_index.h macros use backslash-newline line-continuation; a backslash followed by '\r\n' is not a valid continuation in C, producing floods of syntax errors when the header is compiled. Write generated headers with newline='' to force LF, and normalize source content to LF right after reading so '\r' embedded inside multi-line argument expressions is also handled. Byte offsets stay consistent because both tree-sitter parsing and tag replacement operate on the normalized content. Verified by full clean builds of examples/bluetooth/esp_ble_mesh/ vendor_models/vendor_client (esp32c6, bluedroid + mesh) from both cmd.exe and PowerShell; both produce an identical vendor_client.bin. (cherry picked from commit aa9b565a6d99735f572baa842b1adaeee6737d54) Co-authored-by: luoxu --- .../scripts/ble_log_compress.py | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/components/bt/common/ble_log/extension/log_compression/scripts/ble_log_compress.py b/components/bt/common/ble_log/extension/log_compression/scripts/ble_log_compress.py index 37ec60814a9..0bdffdfc72d 100644 --- a/components/bt/common/ble_log/extension/log_compression/scripts/ble_log_compress.py +++ b/components/bt/common/ble_log/extension/log_compression/scripts/ble_log_compress.py @@ -572,6 +572,16 @@ class LogCompressor: with open(file_path, 'rb') as f: content = f.read() + # Normalize CRLF/CR to LF. On Windows the IDF sources are checked out + # with CRLF line endings (core.autocrlf=true). Without normalization the + # '\r' survives into generated log macros as '\' + '\r' + '\n' inside + # multi-line argument expressions, breaking the backslash + # line-continuation and producing syntax errors when the header is + # compiled. Normalizing once, right after the read, keeps every + # downstream step (tree-sitter parse, byte-offset tag replacement, + # generated macros) on consistent LF offsets. + content = content.replace(b'\r\n', b'\n').replace(b'\r', b'\n') + # NimBLE host macros are emitted to nimble_log_index.h (module BLE_HOST when NimBLE is enabled). # Ensure each compressed NimBLE source includes that header. if ( @@ -774,7 +784,13 @@ class LogCompressor: header_content += f'#endif // __{module.upper()}_INTERNAL_LOG_INDEX_H\n' - with open(header_path, 'w') as f: + # newline='' disables newline translation so the generated header is + # written with LF on every platform. On Windows the default text-mode + # write turns '\n' into '\r\n', which breaks the macro line-continuations + # below: a backslash must be followed immediately by '\n', but with CRLF + # it is followed by '\r' and the continuation (and hence the macro) is + # split, producing a flood of syntax errors when the header is compiled. + with open(header_path, 'w', newline='', encoding='utf-8') as f: f.write(header_content) else: append_content = '' @@ -800,7 +816,7 @@ class LogCompressor: else: raise RuntimeError('#endif not found') lines.insert(idx, append_content) - with open(header_path, 'w', encoding='utf-8') as f: + with open(header_path, 'w', encoding='utf-8', newline='') as f: f.writelines(lines) LOGGER.info(f'Generated log index header: {header_path}') @@ -874,7 +890,15 @@ class LogCompressor: ) # Load configuration - modules = args.module.split(';') + # Strip surrounding quote chars before splitting. CMakeLists.txt wraps the + # semicolon-separated list in single quotes ("'${MODULES}'") to protect the + # ';' from POSIX shells, which strip them. cmd.exe on Windows does NOT treat + # single quotes as quoting characters, so args.module arrives literally as + # 'BLE_MESH;BLE_HOST' and the bare split(';') would yield "'BLE_MESH" / + # "BLE_HOST'" — which never match the YAML keys and every module gets + # skipped. Stripping is a no-op on Linux/macOS where the shell already + # removed the quotes. + modules = args.module.strip("'\"").split(';') config_path = self.build_dir / 'ble_log/module_info.yml' self.load_config(str(config_path), modules) @@ -889,7 +913,9 @@ class LogCompressor: self.db_manager = db_manager # Prepare source files - src_list = args.srcs.split(';') + # Same quote-stripping rationale as args.module above (cmd.exe passes the + # CMakeLists single quotes through literally on Windows). + src_list = args.srcs.strip("'\"").split(';') self.prepare_source_files(src_list) # Collect files to process