2626import shutil
2727from shutil import ignore_patterns
2828from SCons .Script import *
29+ import time
2930
3031def do_copy_file (src , dst ):
3132 # check source file
@@ -40,7 +41,6 @@ def do_copy_file(src, dst):
4041 shutil .copy2 (src , dst )
4142
4243def do_copy_folder (src_dir , dst_dir , ignore = None ):
43- import shutil
4444 # check source directory
4545 if not os .path .exists (src_dir ):
4646 return
@@ -171,6 +171,215 @@ def zip_dist(dist_dir, dist_name):
171171
172172 zip .close ()
173173
174+ def get_system_features ():
175+ """获取系统内置特性列表"""
176+ return {
177+ # 内核特性
178+ 'components_init' ,
179+ 'console' ,
180+ 'cpu_usage_tracer' ,
181+ 'heap' ,
182+ 'slab' ,
183+ 'mempool' ,
184+ 'memtrace' ,
185+ 'timer_soft' ,
186+ 'event' ,
187+ 'mailbox' ,
188+ 'messagequeue' ,
189+ 'mutex' ,
190+ 'semaphore' ,
191+ 'signals' ,
192+ 'hook' ,
193+ 'idle_hook' ,
194+ 'thread' ,
195+ 'cache' ,
196+ 'debug' ,
197+ 'device_ops' ,
198+ 'overflow_check' ,
199+ 'slab_as_heap' ,
200+ 'user_main' ,
201+ 'stdc_atomic' ,
202+ }
203+
204+ def parse_components_from_config (config_file ):
205+ """从 .config 文件解析启用的组件"""
206+ enabled_components = set ()
207+
208+ if not os .path .exists (config_file ):
209+ print (f"Error: { config_file } does not exist" )
210+ return enabled_components
211+
212+ with open (config_file , 'r' ) as f :
213+ for line in f :
214+ line = line .strip ()
215+ if line .startswith ('CONFIG_' ):
216+ if '=' in line :
217+ config = line .split ('=' )[0 ][7 :] # 去掉 CONFIG_ 前缀
218+ if config .startswith ('RT_USING_' ):
219+ component = config [9 :].lower () # 去掉 RT_USING_ 前缀
220+ enabled_components .add (component )
221+ return enabled_components
222+
223+ def scan_components_dir (RTT_ROOT ):
224+ """扫描组件目录结构,生成组件映射表"""
225+ components_map = {}
226+ components_root = os .path .join (RTT_ROOT , 'components' )
227+
228+ def parse_kconfig (kconfig_file ):
229+ """解析 Kconfig 文件中的配置选项"""
230+ components = set ()
231+ try :
232+ with open (kconfig_file , 'r' ) as f :
233+ content = f .read ()
234+ # 查找 config RT_USING_XXX 形式的配置
235+ import re
236+ matches = re .finditer (r'config\s+RT_USING_(\w+)' , content )
237+ for match in matches :
238+ component_name = match .group (1 ).lower ()
239+ components .add (component_name )
240+ except Exception as e :
241+ print (f"Warning: Failed to parse { kconfig_file } : { str (e )} " )
242+ return components
243+
244+ def get_relative_path (full_path ):
245+ """获取相对于 RTT_ROOT 的路径"""
246+ return os .path .relpath (os .path .dirname (full_path ), RTT_ROOT )
247+
248+ # 扫描所有组件目录
249+ for root , dirs , files in os .walk (components_root ):
250+ if 'Kconfig' in files :
251+ kconfig_path = os .path .join (root , 'Kconfig' )
252+ component_configs = parse_kconfig (kconfig_path )
253+ rel_path = get_relative_path (kconfig_path )
254+
255+ # 将组件名称与路径关联
256+ for comp_name in component_configs :
257+ components_map [comp_name ] = rel_path
258+
259+ return components_map
260+
261+ def get_component_path (component_name , RTT_ROOT ):
262+ """获取组件的实际路径"""
263+ # 获取动态组件映射
264+ dynamic_map = scan_components_dir (RTT_ROOT )
265+ return dynamic_map .get (component_name )
266+
267+ def generate_dist_doc (dist_dir , enabled_components , project_name , BSP_ROOT , RTT_ROOT ):
268+ """Generate distribution package documentation"""
269+ doc_lines = [] # Store document content in a list
270+
271+ # Basic information
272+ doc_lines .extend ([
273+ "# RT-Thread Distribution Package\n " ,
274+ "\n ## Basic Information\n \n " ,
275+ f"- Project Name: { project_name } \n " ,
276+ f"- Generation Time: { time .strftime ('%Y-%m-%d %H:%M:%S' )} \n " ,
277+ f"- BSP: { os .path .basename (BSP_ROOT )} \n " ,
278+ "\n ## Components\n \n " ,
279+ "### Included Components:\n \n "
280+ ])
281+
282+ # Add component information
283+ for comp in sorted (enabled_components ):
284+ path = get_component_path (comp , RTT_ROOT )
285+ if path :
286+ doc_lines .append (f"- { comp } \n - Path: { path } \n " )
287+
288+ # Add configuration information
289+ doc_lines .extend (["\n ## Configuration\n \n " ])
290+ config_file = os .path .join (BSP_ROOT , '.config' )
291+ if os .path .exists (config_file ):
292+ doc_lines .extend ([
293+ "### Main Configuration Items:\n \n ```\n "
294+ ])
295+ with open (config_file , 'r' ) as f :
296+ for line in f :
297+ if line .startswith ('CONFIG_' ):
298+ doc_lines .append (line )
299+ doc_lines .append ("```\n " )
300+
301+ # Add simplified directory structure
302+ doc_lines .extend (["\n ## Directory Structure\n \n ```\n " ])
303+
304+ # Show only top-level directories
305+ items = os .listdir (dist_dir )
306+ items .sort ()
307+ for item in items :
308+ if item .startswith ('.' ) or item == 'dist' :
309+ continue
310+ path = os .path .join (dist_dir , item )
311+ if os .path .isdir (path ):
312+ doc_lines .append (f"├── { item } /\n " )
313+ else :
314+ doc_lines .append (f"├── { item } \n " )
315+
316+ doc_lines .append ("```\n " )
317+
318+ # Add build instructions
319+ doc_lines .extend (["""
320+ ## Build Instructions
321+
322+ 1. Requirements:
323+ - Python 3.x
324+ - SCons build tool
325+ - Appropriate cross-compiler toolchain
326+
327+ 2. Build Steps:
328+ ```bash
329+ scons
330+ ```
331+
332+ 3. Clean Build:
333+ ```bash
334+ scons -c
335+ ```
336+
337+ ## Notes
338+
339+ 1. Make sure the toolchain environment variables are properly set
340+ 2. To modify configuration, use menuconfig:
341+ ```bash
342+ scons --menuconfig
343+ ```
344+
345+ ## License
346+
347+ See `COPYING` file for details.
348+ """ ])
349+
350+ # Write documentation
351+ doc_file = os .path .join (dist_dir , 'dist_readme.md' )
352+ with open (doc_file , 'w' , encoding = 'utf-8' ) as f :
353+ f .writelines (doc_lines )
354+
355+ print (f"=> Generated distribution documentation: { doc_file } " )
356+
357+ def components_copy_files (RTT_ROOT , rtt_dir_path , config_file ):
358+ """根据配置复制组件"""
359+ print ('=> components (selective copy)' )
360+
361+ # 获取启用的组件
362+ enabled_components = parse_components_from_config (config_file )
363+ if not enabled_components :
364+ print ("Warning: No components found in config file" )
365+ return enabled_components
366+
367+ # 复制每个启用的组件
368+ for comp_name in enabled_components :
369+ comp_path = get_component_path (comp_name , RTT_ROOT )
370+ if comp_path :
371+ src_path = os .path .join (RTT_ROOT , comp_path )
372+ dst_path = os .path .join (rtt_dir_path , comp_path )
373+ if os .path .exists (src_path ):
374+ print (f' => copying { comp_name } from { comp_path } ' )
375+ do_copy_folder (src_path , dst_path )
376+ else :
377+ print (f"Warning: Component path not found: { src_path } " )
378+ else :
379+ print (f"Note: Skipping system feature: { comp_name } " )
380+
381+ return enabled_components
382+
174383def MkDist (program , BSP_ROOT , RTT_ROOT , Env , project_name , project_path ):
175384 print ('make distribution....' )
176385
@@ -191,10 +400,10 @@ def MkDist(program, BSP_ROOT, RTT_ROOT, Env, project_name, project_path):
191400 dist_handle = Env ['dist_handle' ]
192401 dist_handle (BSP_ROOT , dist_dir )
193402
194- # copy tools directory
195- print ( '=> components ' )
196- do_copy_folder ( os . path . join ( RTT_ROOT , 'components' ), os . path . join ( rtt_dir_path , 'components' ) )
197-
403+ # 使用新的组件复制函数并获取启用的组件列表
404+ config_file = os . path . join ( BSP_ROOT , '.config ' )
405+ enabled_components = components_copy_files ( RTT_ROOT , rtt_dir_path , config_file )
406+
198407 # skip documentation directory
199408 # skip examples
200409
@@ -247,4 +456,7 @@ def MkDist(program, BSP_ROOT, RTT_ROOT, Env, project_name, project_path):
247456 if project_path == None :
248457 zip_dist (dist_dir , project_name )
249458
459+ # 生成说明文档
460+ generate_dist_doc (dist_dir , enabled_components , project_name + '-dist' , BSP_ROOT , RTT_ROOT )
461+
250462 print ('dist project successfully!' )
0 commit comments