Skip to content

Commit c601f1b

Browse files
committed
Cmake: add defconfig preprocess capability in Cmake build environment(recursively expand #include)
Add: cmake/nuttx_process_config.cmake tools/process_config.py Update nuttx/CMakeLists.txt to call process_config defined in nuttx_process_config.cmake to process defconfig before actually using it
1 parent e87c43b commit c601f1b

File tree

3 files changed

+169
-0
lines changed

3 files changed

+169
-0
lines changed

CMakeLists.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,22 @@ if(NOT EXISTS "${NUTTX_DEFCONFIG}")
158158
message(FATAL_ERROR "No config file found at ${NUTTX_DEFCONFIG}")
159159
endif()
160160

161+
# Process initial defconfig ###################################################
162+
# Process initial defconfig to recursively expand #include in it
163+
164+
include(nuttx_process_config)
165+
get_filename_component(NUTTX_DEFCONFIG_DIR "${NUTTX_DEFCONFIG}" DIRECTORY)
166+
process_config(
167+
${CMAKE_BINARY_DIR}/.defconfig.processed
168+
${NUTTX_DEFCONFIG}
169+
INCLUDE_PATHS
170+
${NUTTX_DEFCONFIG_DIR}/../../common/configs
171+
${NUTTX_DEFCONFIG_DIR}/../common
172+
${NUTTX_DEFCONFIG_DIR}
173+
${NUTTX_DIR}/../apps
174+
${NUTTX_DIR}/../nuttx-apps)
175+
set(NUTTX_DEFCONFIG ${CMAKE_BINARY_DIR}/.defconfig.processed)
176+
161177
# Generate initial .config ###################################################
162178
# This is needed right before any other configure step so that we can source
163179
# Kconfig variables into CMake variables

cmake/nuttx_process_config.cmake

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# ##############################################################################
2+
# cmake/nuttx_process_config.cmake
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
7+
# license agreements. See the NOTICE file distributed with this work for
8+
# additional information regarding copyright ownership. The ASF licenses this
9+
# file to you under the Apache License, Version 2.0 (the "License"); you may not
10+
# use this file except in compliance with the License. You may obtain a copy of
11+
# the License at
12+
#
13+
# http://www.apache.org/licenses/LICENSE-2.0
14+
#
15+
# Unless required by applicable law or agreed to in writing, software
16+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18+
# License for the specific language governing permissions and limitations under
19+
# the License.
20+
#
21+
# ##############################################################################
22+
23+
function(process_config OUTPUT INPUT)
24+
set(options)
25+
set(oneValueArgs)
26+
set(multiValueArgs INCLUDE_PATHS)
27+
cmake_parse_arguments(PARSE_ARGV 2 PROCESS_INCLUDES "${options}"
28+
"${oneValueArgs}" "${multiValueArgs}")
29+
30+
find_package(Python3 REQUIRED COMPONENTS Interpreter)
31+
32+
set(include_args "")
33+
foreach(path IN LISTS PROCESS_INCLUDES_INCLUDE_PATHS)
34+
list(APPEND include_args "${path}")
35+
endforeach()
36+
37+
message(STATUS "Processing includes: ${INPUT}${OUTPUT}")
38+
execute_process(
39+
COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/process_config.py
40+
${OUTPUT} ${INPUT} ${include_args} COMMAND_ECHO STDOUT
41+
RESULT_VARIABLE result
42+
OUTPUT_VARIABLE out
43+
ERROR_VARIABLE err)
44+
45+
if(NOT result EQUAL 0)
46+
message(FATAL_ERROR "Failed to process includes:\n${err}")
47+
endif()
48+
endfunction()

tools/process_config.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/usr/bin/env python3
2+
# tools/parsecallstack.py
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
# Licensed to the Apache Software Foundation (ASF) under one or more
7+
# contributor license agreements. See the NOTICE file distributed with
8+
# this work for additional information regarding copyright ownership. The
9+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
10+
# "License"); you may not use this file except in compliance with the
11+
# License. You may obtain a copy of the License at
12+
#
13+
# http://www.apache.org/licenses/LICENSE-2.0
14+
#
15+
# Unless required by applicable law or agreed to in writing, software
16+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18+
# License for the specific language governing permissions and limitations
19+
# under the License.
20+
#
21+
22+
import re
23+
import sys
24+
from pathlib import Path
25+
26+
27+
def expand_file(input_path, include_paths, processed=None):
28+
"""
29+
Recursively expand the file, returning its contents in order as a list of lines.
30+
"""
31+
if processed is None:
32+
processed = set()
33+
34+
input_path = Path(input_path).resolve()
35+
if input_path in processed:
36+
return [] # Already processed, avoid duplicate includes
37+
processed.add(input_path)
38+
39+
expanded_lines = []
40+
41+
with input_path.open("r", encoding="utf-8") as f:
42+
lines = f.readlines()
43+
44+
for line in lines:
45+
line_strip = line.strip()
46+
match = re.match(r'#include\s*[<"]([^">]+)[">]', line_strip)
47+
if match:
48+
include_file = match.group(1)
49+
found = False
50+
51+
# Check the current directory first
52+
53+
direct_path = input_path.parent / include_file
54+
if direct_path.exists():
55+
expanded_lines.extend(
56+
expand_file(direct_path, include_paths, processed)
57+
)
58+
found = True
59+
else:
60+
# Then check in the include paths
61+
62+
for path in include_paths:
63+
candidate = Path(path) / include_file
64+
if candidate.exists():
65+
expanded_lines.extend(
66+
expand_file(candidate, include_paths, processed)
67+
)
68+
found = True
69+
break
70+
71+
if not found:
72+
print(
73+
f'ERROR: Cannot find "{include_file}" from {input_path}',
74+
file=sys.stderr,
75+
)
76+
sys.exit(1)
77+
else:
78+
expanded_lines.append(line)
79+
80+
expanded_lines.append("\n") # Keep separation between files
81+
return expanded_lines
82+
83+
84+
def process_file(output_path, input_path, include_paths):
85+
lines = expand_file(input_path, include_paths)
86+
with open(output_path, "w", encoding="utf-8") as out:
87+
out.writelines(lines)
88+
89+
90+
if __name__ == "__main__":
91+
if len(sys.argv) < 3:
92+
print(
93+
"Usage: process_includes.py <output_file> <input_file> [include_paths...]",
94+
file=sys.stderr,
95+
)
96+
sys.exit(1)
97+
98+
output_file = Path(sys.argv[1])
99+
input_file = sys.argv[2]
100+
include_dirs = sys.argv[3:]
101+
102+
if output_file.exists():
103+
output_file.unlink()
104+
105+
process_file(output_file, input_file, include_dirs)

0 commit comments

Comments
 (0)