|
105 | 105 | env.Exit(1)
|
106 | 106 |
|
107 | 107 |
|
| 108 | +def get_framework_version(): |
| 109 | + def _extract_from_cmake_version_file(): |
| 110 | + version_cmake_file = str(Path(FRAMEWORK_DIR) / "tools" / "cmake" / "version.cmake") |
| 111 | + if not os.path.isfile(version_cmake_file): |
| 112 | + return |
| 113 | + |
| 114 | + with open(version_cmake_file, encoding="utf8") as fp: |
| 115 | + pattern = r"set\(IDF_VERSION_(MAJOR|MINOR|PATCH) (\d+)\)" |
| 116 | + matches = re.findall(pattern, fp.read()) |
| 117 | + if len(matches) != 3: |
| 118 | + return |
| 119 | + # If found all three parts of the version |
| 120 | + return ".".join([match[1] for match in matches]) |
| 121 | + |
| 122 | + pkg = platform.get_package("framework-espidf") |
| 123 | + version = get_original_version(str(pkg.metadata.version.truncate())) |
| 124 | + if not version: |
| 125 | + # Fallback value extracted directly from the cmake version file |
| 126 | + version = _extract_from_cmake_version_file() |
| 127 | + if not version: |
| 128 | + version = "0.0.0" |
| 129 | + |
| 130 | + # Normalize to semver (handles "6.0.0-rc1", VCS metadata, etc.) |
| 131 | + try: |
| 132 | + coerced = semantic_version.Version.coerce(version, partial=True) |
| 133 | + major = coerced.major or 0 |
| 134 | + minor = coerced.minor or 0 |
| 135 | + patch = coerced.patch or 0 |
| 136 | + return f"{major}.{minor}.{patch}" |
| 137 | + except (ValueError, TypeError): |
| 138 | + m = re.match(r"(\d+)\.(\d+)\.(\d+)", str(version)) |
| 139 | + return ".".join(m.groups()) if m else "0.0.0" |
| 140 | + |
| 141 | + |
| 142 | +# Configure ESP-IDF version environment variables |
| 143 | +framework_version = get_framework_version() |
| 144 | +_mv = framework_version.split(".") |
| 145 | +major_version = f"{_mv[0]}.{_mv[1] if len(_mv) > 1 else '0'}" |
| 146 | +os.environ["ESP_IDF_VERSION"] = major_version |
| 147 | + |
| 148 | + |
108 | 149 | def create_silent_action(action_func):
|
109 | 150 | """Create a silent SCons action that suppresses output"""
|
110 | 151 | silent_action = env.Action(action_func)
|
@@ -946,8 +987,8 @@ def generate_project_ld_script(sdk_config, ignore_targets=None):
|
946 | 987 |
|
947 | 988 | initial_ld_script = str(Path(FRAMEWORK_DIR) / "components" / "esp_system" / "ld" / idf_variant / "sections.ld.in")
|
948 | 989 |
|
949 |
| - framework_version = [int(v) for v in get_framework_version().split(".")] |
950 |
| - if framework_version[:2] > [5, 2]: |
| 990 | + framework_version_list = [int(v) for v in get_framework_version().split(".")] |
| 991 | + if framework_version_list[:2] > [5, 2]: |
951 | 992 | initial_ld_script = preprocess_linker_file(
|
952 | 993 | initial_ld_script,
|
953 | 994 | str(Path(BUILD_DIR) / "esp-idf" / "esp_system" / "ld" / "sections.ld.in"),
|
@@ -1188,6 +1229,9 @@ def build_bootloader(sdk_config):
|
1188 | 1229 | "-DPROJECT_SOURCE_DIR=" + PROJECT_DIR,
|
1189 | 1230 | "-DLEGACY_INCLUDE_COMMON_HEADERS=",
|
1190 | 1231 | "-DEXTRA_COMPONENT_DIRS=" + str(Path(FRAMEWORK_DIR) / "components" / "bootloader"),
|
| 1232 | + f"-DESP_IDF_VERSION={major_version}", |
| 1233 | + f"-DESP_IDF_VERSION_MAJOR={framework_version.split('.')[0]}", |
| 1234 | + f"-DESP_IDF_VERSION_MINOR={framework_version.split('.')[1]}", |
1191 | 1235 | ],
|
1192 | 1236 | )
|
1193 | 1237 |
|
@@ -1228,7 +1272,84 @@ def build_bootloader(sdk_config):
|
1228 | 1272 | )
|
1229 | 1273 |
|
1230 | 1274 | bootloader_env.MergeFlags(link_args)
|
1231 |
| - bootloader_env.Append(LINKFLAGS=extra_flags) |
| 1275 | + |
| 1276 | + # Handle ESP-IDF 6.0 linker script preprocessing for .ld.in files |
| 1277 | + # In bootloader context, only .ld.in templates exist and need preprocessing |
| 1278 | + processed_extra_flags = [] |
| 1279 | + |
| 1280 | + # Bootloader preprocessing configuration |
| 1281 | + bootloader_config_dir = str(Path(BUILD_DIR) / "bootloader" / "config") |
| 1282 | + bootloader_extra_includes = [ |
| 1283 | + str(Path(FRAMEWORK_DIR) / "components" / "bootloader" / "subproject" / "main" / "ld" / idf_variant) |
| 1284 | + ] |
| 1285 | + |
| 1286 | + i = 0 |
| 1287 | + while i < len(extra_flags): |
| 1288 | + if extra_flags[i] == "-T" and i + 1 < len(extra_flags): |
| 1289 | + linker_script = extra_flags[i + 1] |
| 1290 | + |
| 1291 | + # Process .ld.in templates directly |
| 1292 | + if linker_script.endswith(".ld.in"): |
| 1293 | + script_name = os.path.basename(linker_script).replace(".ld.in", ".ld") |
| 1294 | + target_script = str(Path(BUILD_DIR) / "bootloader" / script_name) |
| 1295 | + |
| 1296 | + preprocessed_script = preprocess_linker_file( |
| 1297 | + linker_script, |
| 1298 | + target_script, |
| 1299 | + config_dir=bootloader_config_dir, |
| 1300 | + extra_include_dirs=bootloader_extra_includes |
| 1301 | + ) |
| 1302 | + |
| 1303 | + bootloader_env.Depends("$BUILD_DIR/bootloader.elf", preprocessed_script) |
| 1304 | + processed_extra_flags.extend(["-T", target_script]) |
| 1305 | + # Handle .ld files - prioritize using original scripts when available |
| 1306 | + elif linker_script.endswith(".ld"): |
| 1307 | + script_basename = os.path.basename(linker_script) |
| 1308 | + |
| 1309 | + # Check if the original .ld file exists in framework and use it directly |
| 1310 | + original_script_path = str(Path(FRAMEWORK_DIR) / "components" / "bootloader" / "subproject" / "main" / "ld" / idf_variant / script_basename) |
| 1311 | + |
| 1312 | + if os.path.isfile(original_script_path): |
| 1313 | + # Use the original script directly - no preprocessing needed |
| 1314 | + processed_extra_flags.extend(["-T", original_script_path]) |
| 1315 | + else: |
| 1316 | + # Only generate from template if no original .ld file exists |
| 1317 | + script_name_in = script_basename.replace(".ld", ".ld.in") |
| 1318 | + bootloader_script_in_path = str(Path(FRAMEWORK_DIR) / "components" / "bootloader" / "subproject" / "main" / "ld" / idf_variant / script_name_in) |
| 1319 | + |
| 1320 | + # ESP32-P4 specific: Check for bootloader.rev3.ld.in |
| 1321 | + if idf_variant == "esp32p4" and script_basename == "bootloader.ld": |
| 1322 | + sdk_config = get_sdk_configuration() |
| 1323 | + if sdk_config.get("ESP32P4_REV_MIN_300", False): |
| 1324 | + bootloader_rev3_path = str(Path(FRAMEWORK_DIR) / "components" / "bootloader" / "subproject" / "main" / "ld" / idf_variant / "bootloader.rev3.ld.in") |
| 1325 | + if os.path.isfile(bootloader_rev3_path): |
| 1326 | + bootloader_script_in_path = bootloader_rev3_path |
| 1327 | + |
| 1328 | + # Preprocess the .ld.in template to generate the .ld file |
| 1329 | + if os.path.isfile(bootloader_script_in_path): |
| 1330 | + target_script = str(Path(BUILD_DIR) / "bootloader" / script_basename) |
| 1331 | + |
| 1332 | + preprocessed_script = preprocess_linker_file( |
| 1333 | + bootloader_script_in_path, |
| 1334 | + target_script, |
| 1335 | + config_dir=bootloader_config_dir, |
| 1336 | + extra_include_dirs=bootloader_extra_includes |
| 1337 | + ) |
| 1338 | + |
| 1339 | + bootloader_env.Depends("$BUILD_DIR/bootloader.elf", preprocessed_script) |
| 1340 | + processed_extra_flags.extend(["-T", target_script]) |
| 1341 | + else: |
| 1342 | + # Pass through if neither original nor template found (e.g., ROM scripts) |
| 1343 | + processed_extra_flags.extend(["-T", linker_script]) |
| 1344 | + else: |
| 1345 | + # Pass through any other linker flags unchanged |
| 1346 | + processed_extra_flags.extend(["-T", linker_script]) |
| 1347 | + i += 2 |
| 1348 | + else: |
| 1349 | + processed_extra_flags.append(extra_flags[i]) |
| 1350 | + i += 1 |
| 1351 | + |
| 1352 | + bootloader_env.Append(LINKFLAGS=processed_extra_flags) |
1232 | 1353 | bootloader_libs = find_lib_deps(components_map, elf_config, link_args)
|
1233 | 1354 |
|
1234 | 1355 | bootloader_env.Prepend(__RPATH="-Wl,--start-group ")
|
@@ -1324,31 +1445,6 @@ def find_default_component(target_configs):
|
1324 | 1445 | env.Exit(1)
|
1325 | 1446 |
|
1326 | 1447 |
|
1327 |
| -def get_framework_version(): |
1328 |
| - def _extract_from_cmake_version_file(): |
1329 |
| - version_cmake_file = str(Path(FRAMEWORK_DIR) / "tools" / "cmake" / "version.cmake") |
1330 |
| - if not os.path.isfile(version_cmake_file): |
1331 |
| - return |
1332 |
| - |
1333 |
| - with open(version_cmake_file, encoding="utf8") as fp: |
1334 |
| - pattern = r"set\(IDF_VERSION_(MAJOR|MINOR|PATCH) (\d+)\)" |
1335 |
| - matches = re.findall(pattern, fp.read()) |
1336 |
| - if len(matches) != 3: |
1337 |
| - return |
1338 |
| - # If found all three parts of the version |
1339 |
| - return ".".join([match[1] for match in matches]) |
1340 |
| - |
1341 |
| - pkg = platform.get_package("framework-espidf") |
1342 |
| - version = get_original_version(str(pkg.metadata.version.truncate())) |
1343 |
| - if not version: |
1344 |
| - # Fallback value extracted directly from the cmake version file |
1345 |
| - version = _extract_from_cmake_version_file() |
1346 |
| - if not version: |
1347 |
| - version = "0.0.0" |
1348 |
| - |
1349 |
| - return version |
1350 |
| - |
1351 |
| - |
1352 | 1448 | def create_version_file():
|
1353 | 1449 | version_file = str(Path(FRAMEWORK_DIR) / "version.txt")
|
1354 | 1450 | if not os.path.isfile(version_file):
|
@@ -1433,26 +1529,73 @@ def get_app_partition_offset(pt_table, pt_offset):
|
1433 | 1529 | return factory_app_params.get("offset", "0x10000")
|
1434 | 1530 |
|
1435 | 1531 |
|
1436 |
| -def preprocess_linker_file(src_ld_script, target_ld_script): |
1437 |
| - return env.Command( |
1438 |
| - target_ld_script, |
1439 |
| - src_ld_script, |
1440 |
| - env.VerboseAction( |
1441 |
| - " ".join( |
1442 |
| - [ |
| 1532 | +def preprocess_linker_file(src_ld_script, target_ld_script, config_dir=None, extra_include_dirs=None): |
| 1533 | + """ |
| 1534 | + Preprocess a linker script file (.ld.in) to generate the final .ld file. |
| 1535 | + Supports both IDF 5.x (linker_script_generator.cmake) and IDF 6.x (linker_script_preprocessor.cmake). |
| 1536 | + |
| 1537 | + Args: |
| 1538 | + src_ld_script: Source .ld.in file path |
| 1539 | + target_ld_script: Target .ld file path |
| 1540 | + config_dir: Configuration directory (defaults to BUILD_DIR/config for main app) |
| 1541 | + extra_include_dirs: Additional include directories (list) |
| 1542 | + """ |
| 1543 | + if config_dir is None: |
| 1544 | + config_dir = str(Path(BUILD_DIR) / "config") |
| 1545 | + |
| 1546 | + # Convert all paths to forward slashes for CMake compatibility on Windows |
| 1547 | + config_dir = fs.to_unix_path(config_dir) |
| 1548 | + src_ld_script = fs.to_unix_path(src_ld_script) |
| 1549 | + target_ld_script = fs.to_unix_path(target_ld_script) |
| 1550 | + |
| 1551 | + # Check IDF version to determine which CMake script to use |
| 1552 | + framework_version_list = [int(v) for v in get_framework_version().split(".")] |
| 1553 | + |
| 1554 | + # IDF 6.0+ uses linker_script_preprocessor.cmake with CFLAGS approach |
| 1555 | + if framework_version_list[0] >= 6: |
| 1556 | + include_dirs = [f'"{config_dir}"'] |
| 1557 | + include_dirs.append(f'"{fs.to_unix_path(str(Path(FRAMEWORK_DIR) / "components" / "esp_system" / "ld"))}"') |
| 1558 | + |
| 1559 | + if extra_include_dirs: |
| 1560 | + include_dirs.extend(f'"{fs.to_unix_path(dir_path)}"' for dir_path in extra_include_dirs) |
| 1561 | + |
| 1562 | + cflags_value = "-I" + " -I".join(include_dirs) |
| 1563 | + |
| 1564 | + return env.Command( |
| 1565 | + target_ld_script, |
| 1566 | + src_ld_script, |
| 1567 | + env.VerboseAction( |
| 1568 | + " ".join([ |
| 1569 | + f'"{CMAKE_DIR}"', |
| 1570 | + f'-DCC="{fs.to_unix_path(str(Path(TOOLCHAIN_DIR) / "bin" / "$CC"))}"', |
| 1571 | + f'-DSOURCE="{src_ld_script}"', |
| 1572 | + f'-DTARGET="{target_ld_script}"', |
| 1573 | + f'-DCFLAGS="{cflags_value}"', |
| 1574 | + "-P", |
| 1575 | + f'"{fs.to_unix_path(str(Path(FRAMEWORK_DIR) / "tools" / "cmake" / "linker_script_preprocessor.cmake"))}"', |
| 1576 | + ]), |
| 1577 | + "Generating LD script $TARGET", |
| 1578 | + ), |
| 1579 | + ) |
| 1580 | + else: |
| 1581 | + # IDF 5.x: Use legacy linker_script_generator.cmake method |
| 1582 | + return env.Command( |
| 1583 | + target_ld_script, |
| 1584 | + src_ld_script, |
| 1585 | + env.VerboseAction( |
| 1586 | + " ".join([ |
1443 | 1587 | f'"{CMAKE_DIR}"',
|
1444 | 1588 | f'-DCC="{str(Path(TOOLCHAIN_DIR) / "bin" / "$CC")}"',
|
1445 | 1589 | "-DSOURCE=$SOURCE",
|
1446 | 1590 | "-DTARGET=$TARGET",
|
1447 |
| - f'-DCONFIG_DIR="{str(Path(BUILD_DIR) / "config")}"', |
| 1591 | + f'-DCONFIG_DIR="{config_dir}"', |
1448 | 1592 | f'-DLD_DIR="{str(Path(FRAMEWORK_DIR) / "components" / "esp_system" / "ld")}"',
|
1449 | 1593 | "-P",
|
1450 | 1594 | f'"{str(Path("$BUILD_DIR") / "esp-idf" / "esp_system" / "ld" / "linker_script_generator.cmake")}"',
|
1451 |
| - ] |
| 1595 | + ]), |
| 1596 | + "Generating LD script $TARGET", |
1452 | 1597 | ),
|
1453 |
| - "Generating LD script $TARGET", |
1454 |
| - ), |
1455 |
| - ) |
| 1598 | + ) |
1456 | 1599 |
|
1457 | 1600 |
|
1458 | 1601 | def generate_mbedtls_bundle(sdk_config):
|
@@ -1696,8 +1839,8 @@ def get_python_exe():
|
1696 | 1839 | if not board.get("build.ldscript", ""):
|
1697 | 1840 | initial_ld_script = board.get("build.esp-idf.ldscript", str(Path(FRAMEWORK_DIR) / "components" / "esp_system" / "ld" / idf_variant / "memory.ld.in"))
|
1698 | 1841 |
|
1699 |
| - framework_version = [int(v) for v in get_framework_version().split(".")] |
1700 |
| - if framework_version[:2] > [5, 2]: |
| 1842 | + framework_version_list = [int(v) for v in get_framework_version().split(".")] |
| 1843 | + if framework_version_list[:2] > [5, 2]: |
1701 | 1844 | initial_ld_script = preprocess_linker_file(
|
1702 | 1845 | initial_ld_script,
|
1703 | 1846 | str(Path(BUILD_DIR) / "esp-idf" / "esp_system" / "ld" / "memory.ld.in")
|
@@ -1757,11 +1900,6 @@ def get_python_exe():
|
1757 | 1900 | LIBSOURCE_DIRS=[str(Path(ARDUINO_FRAMEWORK_DIR) / "libraries")]
|
1758 | 1901 | )
|
1759 | 1902 |
|
1760 |
| -# Configure ESP-IDF version environment variables for Kconfig processing |
1761 |
| -framework_version = get_framework_version() |
1762 |
| -major_version = framework_version.split('.')[0] + '.' + framework_version.split('.')[1] |
1763 |
| -os.environ["ESP_IDF_VERSION"] = major_version |
1764 |
| - |
1765 | 1903 | # Setup CMake configuration arguments
|
1766 | 1904 | extra_cmake_args = [
|
1767 | 1905 | "-DIDF_TARGET=" + idf_variant,
|
|
0 commit comments