Skip to content

Commit 7f20e7e

Browse files
committed
examples/elf: Add CMake nxpkg fixture generation.
Add the matching CMake fixture generation for the ELF nxpkg\nvalidation flow so the example is covered by both supported\nbuild systems.\n\nThis generates the symtab and ROMFS sources in the CMake path\nand keeps the fixture behavior aligned with the existing Makefile\nimplementation. Signed-off-by: aviralgarg05 <gargaviral99@gmail.com>
1 parent 4429450 commit 7f20e7e

3 files changed

Lines changed: 229 additions & 1 deletion

File tree

examples/elf/main/CMakeLists.txt

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,90 @@
1919
# ##############################################################################
2020

2121
if(CONFIG_EXAMPLES_ELF)
22-
nuttx_add_application(NAME elf SRCS elf_main.c)
22+
set(ELF_SYMTAB ${CMAKE_CURRENT_BINARY_DIR}/test_symtab.c)
23+
set(ELF_ROMFS_IMG ${CMAKE_CURRENT_BINARY_DIR}/elf_romfs.img)
24+
set(ELF_ROMFS_SRC ${CMAKE_CURRENT_BINARY_DIR}/elf_romfs.c)
25+
set(ELF_GEN_SYMTAB ${CMAKE_CURRENT_SOURCE_DIR}/gen_symtab.py)
26+
set(ELF_GEN_ROMFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gen_romfs_source.py)
27+
28+
set(ELFNAME_BASE hello)
29+
30+
set(ELF_BINARY_FILES)
31+
set(ELF_BINARY_TARGETS)
32+
foreach(ELFNAME IN LISTS ELFNAME_BASE)
33+
list(APPEND ELF_BINARY_FILES ${CMAKE_BINARY_DIR}/bin/${ELFNAME})
34+
35+
if(CMAKE_C_ELF_COMPILER)
36+
list(APPEND ELF_BINARY_TARGETS ${ELFNAME})
37+
else()
38+
list(APPEND ELF_BINARY_TARGETS ELF_${ELFNAME})
39+
endif()
40+
endforeach()
41+
42+
add_custom_command(
43+
OUTPUT ${ELF_SYMTAB}
44+
COMMAND ${Python3_EXECUTABLE} ${ELF_GEN_SYMTAB} ${ELF_BINARY_FILES} g_elf
45+
${ELF_SYMTAB}
46+
DEPENDS ${ELF_BINARY_TARGETS} ${ELF_GEN_SYMTAB}
47+
VERBATIM)
48+
49+
set_source_files_properties(${ELF_SYMTAB} PROPERTIES GENERATED TRUE)
50+
51+
set(ELF_GENERATED_OUTPUTS ${ELF_SYMTAB})
52+
set(ELF_SRCS elf_main.c ${ELF_SYMTAB})
53+
54+
if(CONFIG_EXAMPLES_ELF_ROMFS)
55+
set(ELF_ROMFS_DEPS ${ELF_BINARY_TARGETS})
56+
57+
if(CONFIG_SYSTEM_NXPKG)
58+
set(ELF_INDEX_JSON ${CMAKE_BINARY_DIR}/bin/index.json)
59+
set(ELF_BAD_INDEX_JSON ${CMAKE_BINARY_DIR}/bin/bad-index.json)
60+
set(ELF_PKGTEST ${CMAKE_BINARY_DIR}/bin/pkgtest.nsh)
61+
set(ELF_PKGFAIL ${CMAKE_BINARY_DIR}/bin/pkgfail.nsh)
62+
set(ELF_HELLO_BIN ${CMAKE_BINARY_DIR}/bin/hello)
63+
set(ELF_HELLO_TARGET hello)
64+
65+
if(NOT CMAKE_C_ELF_COMPILER)
66+
set(ELF_HELLO_TARGET ELF_hello)
67+
endif()
68+
69+
add_custom_command(
70+
OUTPUT ${ELF_INDEX_JSON} ${ELF_BAD_INDEX_JSON} ${ELF_PKGTEST}
71+
${ELF_PKGFAIL}
72+
COMMAND
73+
${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/mk_pkg_fixture.py
74+
${ELF_HELLO_BIN} ${ELF_INDEX_JSON} ${ELF_BAD_INDEX_JSON}
75+
${ELF_PKGTEST} ${ELF_PKGFAIL} ${CONFIG_ARCH} ${CONFIG_ARCH_BOARD}
76+
DEPENDS ${ELF_HELLO_TARGET}
77+
${CMAKE_CURRENT_SOURCE_DIR}/mk_pkg_fixture.py
78+
VERBATIM)
79+
80+
list(APPEND ELF_ROMFS_DEPS ${ELF_INDEX_JSON} ${ELF_BAD_INDEX_JSON}
81+
${ELF_PKGTEST} ${ELF_PKGFAIL})
82+
endif()
83+
84+
add_custom_command(
85+
OUTPUT ${ELF_ROMFS_IMG}
86+
COMMAND genromfs -f ${ELF_ROMFS_IMG} -d ${CMAKE_BINARY_DIR}/bin
87+
DEPENDS ${ELF_ROMFS_DEPS}
88+
VERBATIM)
89+
90+
add_custom_command(
91+
OUTPUT ${ELF_ROMFS_SRC}
92+
COMMAND ${Python3_EXECUTABLE} ${ELF_GEN_ROMFS_SRC} ${ELF_ROMFS_IMG}
93+
${ELF_ROMFS_SRC}
94+
DEPENDS ${ELF_ROMFS_IMG} ${ELF_GEN_ROMFS_SRC}
95+
VERBATIM)
96+
97+
set_source_files_properties(${ELF_ROMFS_SRC} PROPERTIES GENERATED TRUE)
98+
99+
list(APPEND ELF_GENERATED_OUTPUTS ${ELF_ROMFS_SRC})
100+
list(APPEND ELF_SRCS ${ELF_ROMFS_SRC})
101+
endif()
102+
103+
add_custom_target(elf_artifacts DEPENDS ${ELF_GENERATED_OUTPUTS})
104+
105+
nuttx_add_application(NAME elf SRCS ${ELF_SRCS} DEPENDS elf_artifacts)
23106

24107
# TODO: tests
25108

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env python3
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
import pathlib
6+
import sys
7+
8+
9+
def usage() -> int:
10+
print("usage: gen_romfs_source.py <input> <output>", file=sys.stderr)
11+
return 1
12+
13+
14+
def symbol_from_path(path: pathlib.Path) -> str:
15+
return path.name.replace(".", "_")
16+
17+
18+
def format_bytes(data: bytes) -> str:
19+
rows = []
20+
for index in range(0, len(data), 12):
21+
chunk = data[index : index + 12]
22+
rows.append(" " + ", ".join(f"0x{byte:02x}" for byte in chunk))
23+
return ",\n".join(rows)
24+
25+
26+
def write_output(input_path: pathlib.Path, output_path: pathlib.Path) -> None:
27+
symbol = symbol_from_path(input_path)
28+
data = input_path.read_bytes()
29+
text = "\n".join(
30+
[
31+
"#include <nuttx/compiler.h>",
32+
"",
33+
f"const unsigned char aligned_data(4) {symbol}[] = {{",
34+
format_bytes(data),
35+
"};",
36+
f"const unsigned int {symbol}_len = {len(data)};",
37+
"",
38+
]
39+
)
40+
41+
if output_path.exists() and output_path.read_text(encoding="utf-8") == text:
42+
return
43+
44+
output_path.write_text(text, encoding="utf-8")
45+
46+
47+
def main() -> int:
48+
if len(sys.argv) != 3:
49+
return usage()
50+
51+
input_path = pathlib.Path(sys.argv[1])
52+
output_path = pathlib.Path(sys.argv[2])
53+
write_output(input_path, output_path)
54+
return 0
55+
56+
57+
if __name__ == "__main__":
58+
raise SystemExit(main())

examples/elf/main/gen_symtab.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env python3
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
import pathlib
6+
import subprocess
7+
import sys
8+
9+
10+
def usage() -> int:
11+
print(
12+
"usage: gen_symtab.py <input> [<input> ...] <prefix> <output>",
13+
file=sys.stderr,
14+
)
15+
return 1
16+
17+
18+
def symbol_name(line: str) -> str:
19+
return line.split()[-1].replace('"', "")
20+
21+
22+
def collect_symbols(paths):
23+
undefined: set[str] = set()
24+
defined: set[str] = set()
25+
26+
for path in paths:
27+
result = subprocess.run(
28+
["nm", str(path)],
29+
check=False,
30+
text=True,
31+
capture_output=True,
32+
)
33+
if result.returncode not in (0, 1):
34+
raise RuntimeError(result.stderr.strip() or f"nm failed for {path}")
35+
36+
for line in result.stdout.splitlines():
37+
if " U " in line:
38+
undefined.add(symbol_name(line))
39+
elif line and not line.endswith(":"):
40+
defined.add(symbol_name(line))
41+
42+
return sorted(undefined - defined)
43+
44+
45+
def write_output(path: pathlib.Path, prefix: str, symbols) -> None:
46+
lines = [
47+
"#include <nuttx/compiler.h>",
48+
"#include <nuttx/symtab.h>",
49+
"",
50+
]
51+
52+
for symbol in symbols:
53+
lines.append(f"extern void *{symbol};")
54+
55+
lines.append("")
56+
lines.append(f"const struct symtab_s {prefix}_exports[] = ")
57+
lines.append("{")
58+
59+
for symbol in symbols:
60+
lines.append(f' {{"{symbol}", &{symbol}}},')
61+
62+
lines.append("};")
63+
lines.append("")
64+
lines.append(
65+
f"const int {prefix}_nexports = sizeof({prefix}_exports) / sizeof(struct symtab_s);"
66+
)
67+
lines.append("")
68+
69+
text = "\n".join(lines)
70+
if path.exists() and path.read_text(encoding="utf-8") == text:
71+
return
72+
73+
path.write_text(text, encoding="utf-8")
74+
75+
76+
def main() -> int:
77+
if len(sys.argv) < 4:
78+
return usage()
79+
80+
*input_paths, prefix, output = sys.argv[1:]
81+
symbols = collect_symbols([pathlib.Path(item) for item in input_paths])
82+
write_output(pathlib.Path(output), prefix, symbols)
83+
return 0
84+
85+
86+
if __name__ == "__main__":
87+
raise SystemExit(main())

0 commit comments

Comments
 (0)