فهرست منبع

[scons] code cleanup for scons script. (#10429)

* [scons] move project_generation to targets; code clean for building.py.
Bernard Xiong 1 ماه پیش
والد
کامیت
5a2352eb64

+ 0 - 3
tools/WCS.py

@@ -426,9 +426,6 @@ def main():
     # Print A Nice Message With Each Function and the WCS
     print_all_fxns(call_graph)
 
-
-
-
 def ThreadStackStaticAnalysis(env):
     print('Start thread stack static analysis...')
 

+ 22 - 98
tools/building.py

@@ -26,6 +26,7 @@
 # 2024-04-21     Bernard      Add toolchain detection in sdk packages
 # 2025-01-05     Bernard      Add logging as Env['log']
 # 2025-03-02     ZhaoCake     Add MkDist_Strip
+# 2025-01-05     Assistant    Refactor SCons PreProcessor patch to independent class
 
 import os
 import sys
@@ -39,90 +40,14 @@ from SCons.Script import *
 from utils import _make_path_relative
 from mkdist import do_copy_file
 from options import AddOptions
+from preprocessor import create_preprocessor_instance
+from win32spawn import Win32Spawn
 
 BuildOptions = {}
 Projects = []
 Rtt_Root = ''
 Env = None
 
-# SCons PreProcessor patch
-def start_handling_includes(self, t=None):
-    """
-    Causes the PreProcessor object to start processing #import,
-    #include and #include_next lines.
-
-    This method will be called when a #if, #ifdef, #ifndef or #elif
-    evaluates True, or when we reach the #else in a #if, #ifdef,
-    #ifndef or #elif block where a condition already evaluated
-    False.
-
-    """
-    d = self.dispatch_table
-    p = self.stack[-1] if self.stack else self.default_table
-
-    for k in ('import', 'include', 'include_next', 'define'):
-        d[k] = p[k]
-
-def stop_handling_includes(self, t=None):
-    """
-    Causes the PreProcessor object to stop processing #import,
-    #include and #include_next lines.
-
-    This method will be called when a #if, #ifdef, #ifndef or #elif
-    evaluates False, or when we reach the #else in a #if, #ifdef,
-    #ifndef or #elif block where a condition already evaluated True.
-    """
-    d = self.dispatch_table
-    d['import'] = self.do_nothing
-    d['include'] =  self.do_nothing
-    d['include_next'] =  self.do_nothing
-    d['define'] =  self.do_nothing
-
-PatchedPreProcessor = SCons.cpp.PreProcessor
-PatchedPreProcessor.start_handling_includes = start_handling_includes
-PatchedPreProcessor.stop_handling_includes = stop_handling_includes
-
-class Win32Spawn:
-    def spawn(self, sh, escape, cmd, args, env):
-        # deal with the cmd build-in commands which cannot be used in
-        # subprocess.Popen
-        if cmd == 'del':
-            for f in args[1:]:
-                try:
-                    os.remove(f)
-                except Exception as e:
-                    print('Error removing file: ' + e)
-                    return -1
-            return 0
-
-        import subprocess
-
-        newargs = ' '.join(args[1:])
-        cmdline = cmd + " " + newargs
-
-        # Make sure the env is constructed by strings
-        _e = dict([(k, str(v)) for k, v in env.items()])
-
-        # Windows(tm) CreateProcess does not use the env passed to it to find
-        # the executables. So we have to modify our own PATH to make Popen
-        # work.
-        old_path = os.environ['PATH']
-        os.environ['PATH'] = _e['PATH']
-
-        try:
-            proc = subprocess.Popen(cmdline, env=_e, shell=False)
-        except Exception as e:
-            print('Error in calling command:' + cmdline.split(' ')[0])
-            print('Exception: ' + os.strerror(e.errno))
-            if (os.strerror(e.errno) == "No such file or directory"):
-                print ("\nPlease check Toolchains PATH setting.\n")
-
-            return e.errno
-        finally:
-            os.environ['PATH'] = old_path
-
-        return proc.wait()
-
 def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = []):
 
     global BuildOptions
@@ -294,7 +219,7 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [
     Env.Append(BUILDERS = {'BuildLib': bld})
 
     # parse rtconfig.h to get used component
-    PreProcessor = PatchedPreProcessor()
+    PreProcessor = create_preprocessor_instance()
     f = open('rtconfig.h', 'r')
     contents = f.read()
     f.close()
@@ -433,7 +358,7 @@ def PrepareModuleBuilding(env, root_directory, bsp_directory):
     Rtt_Root = root_directory
 
     # parse bsp rtconfig.h to get used component
-    PreProcessor = PatchedPreProcessor()
+    PreProcessor = create_preprocessor_instance()
     f = open(bsp_directory + '/rtconfig.h', 'r')
     contents = f.read()
     f.close()
@@ -877,7 +802,7 @@ def DoBuilding(target, objects):
 def GenTargetProject(program = None):
 
     if GetOption('target') in ['mdk', 'mdk4', 'mdk5']:
-        from keil import MDK2Project, MDK4Project, MDK5Project, ARMCC_Version
+        from targets.keil import MDK2Project, MDK4Project, MDK5Project, ARMCC_Version
 
         if os.path.isfile('template.uvprojx') and GetOption('target') not in ['mdk4']: # Keil5
             MDK5Project(GetOption('project-name') + '.uvprojx', Projects)
@@ -895,68 +820,68 @@ def GenTargetProject(program = None):
         print("Keil-MDK project has generated successfully!")
 
     if GetOption('target') == 'iar':
-        from iar import IARProject, IARVersion
+        from targets.iar import IARProject, IARVersion
         print("IAR Version: " + IARVersion())
         IARProject(GetOption('project-name') + '.ewp', Projects)
         print("IAR project has generated successfully!")
 
     if GetOption('target') == 'vs':
-        from vs import VSProject
+        from targets.vs import VSProject
         VSProject(GetOption('project-name') + '.vcproj', Projects, program)
 
     if GetOption('target') == 'vs2012':
-        from vs2012 import VS2012Project
+        from targets.vs2012 import VS2012Project
         VS2012Project(GetOption('project-name') + '.vcxproj', Projects, program)
 
     if GetOption('target') == 'cb':
-        from codeblocks import CBProject
+        from targets.codeblocks import CBProject
         CBProject(GetOption('project-name') + '.cbp', Projects, program)
 
     if GetOption('target') == 'ua':
-        from ua import PrepareUA
+        from targets.ua import PrepareUA
         PrepareUA(Projects, Rtt_Root, str(Dir('#')))
 
     if GetOption('target') == 'vsc':
-        from vsc import GenerateVSCode
+        from targets.vsc import GenerateVSCode
         GenerateVSCode(Env)
         if GetOption('cmsispack'):
             from vscpyocd import GenerateVSCodePyocdConfig
             GenerateVSCodePyocdConfig(GetOption('cmsispack'))
 
     if GetOption('target') == 'cdk':
-        from cdk import CDKProject
+        from targets.cdk import CDKProject
         CDKProject(GetOption('project-name') + '.cdkproj', Projects)
 
     if GetOption('target') == 'ses':
-        from ses import SESProject
+        from targets.ses import SESProject
         SESProject(Env)
 
     if GetOption('target') == 'makefile':
-        from makefile import TargetMakefile
+        from targets.makefile import TargetMakefile
         TargetMakefile(Env)
 
     if GetOption('target') == 'eclipse':
-        from eclipse import TargetEclipse
+        from targets.eclipse import TargetEclipse
         TargetEclipse(Env, GetOption('reset-project-config'), GetOption('project-name'))
 
     if GetOption('target') == 'codelite':
-        from codelite import TargetCodelite
+        from targets.codelite import TargetCodelite
         TargetCodelite(Projects, program)
 
     if GetOption('target') == 'cmake' or GetOption('target') == 'cmake-armclang':
-        from cmake import CMakeProject
+        from targets.cmake import CMakeProject
         CMakeProject(Env, Projects, GetOption('project-name'))
 
     if GetOption('target') == 'xmake':
-        from xmake import XMakeProject
+        from targets.xmake import XMakeProject
         XMakeProject(Env, Projects)
 
     if GetOption('target') == 'esp-idf':
-        from esp_idf import ESPIDFProject
+        from targets.esp_idf import ESPIDFProject
         ESPIDFProject(Env, Projects)
 
     if GetOption('target') == 'zig':
-        from zigbuild import ZigBuildProject
+        from targets.zigbuild import ZigBuildProject
         ZigBuildProject(Env, Projects)
 
 def EndBuilding(target, program = None):
@@ -1069,7 +994,7 @@ def GetVersion():
     rtdef = os.path.join(Rtt_Root, 'include', 'rtdef.h')
 
     # parse rtdef.h to get RT-Thread version
-    prepcessor = PatchedPreProcessor()
+    prepcessor = create_preprocessor_instance()
     f = open(rtdef, 'r')
     contents = f.read()
     f.close()
@@ -1109,4 +1034,3 @@ def PackageSConscript(package):
     from package import BuildPackage
 
     return BuildPackage(package)
-

+ 49 - 0
tools/hello/README.md

@@ -0,0 +1,49 @@
+# Hello Component
+
+这是一个使用package.json配置的RT-Thread组件示例,展示了如何使用package.json来替代传统的SConscript中DefineGroup的方式。
+
+## 文件结构
+
+```
+hello/
+├── hello.h          # 头文件
+├── hello.c          # 源文件
+├── package.json     # 组件配置文件
+├── SConscript       # 构建脚本
+└── README.md        # 说明文档
+```
+
+## package.json配置说明
+
+package.json文件包含了组件的所有构建信息:
+
+- `name`: 组件名称
+- `version`: 版本号
+- `description`: 组件描述
+- `author`: 作者信息
+- `license`: 许可证
+- `source_files`: 源文件列表
+- `CPPPATH`: 头文件搜索路径
+- `CPPDEFINES`: 预定义宏
+- `depends`: 依赖的组件
+
+## 使用方法
+
+1. 将hello文件夹复制到你的RT-Thread项目的components目录下
+2. 在应用代码中包含头文件:
+   ```c
+   #include "hello.h"
+   ```
+3. 调用hello_world函数:
+   ```c
+   hello_world();  // 输出: Hello World!
+   ```
+
+## 构建过程
+
+SConscript文件会:
+1. 导入package.py模块
+2. 调用BuildPackage函数处理package.json
+3. 自动创建DefineGroup并返回构建对象
+
+这种方式比传统的SConscript更加简洁和易于维护。 

+ 4 - 0
tools/hello/SConscript

@@ -0,0 +1,4 @@
+from package import *
+
+objs = BuildPackage()
+Return('objs')

+ 22 - 0
tools/hello/hello.c

@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2025-06-21     Bernard      First version
+ */
+
+#include <rtthread.h>
+#include "hello.h"
+
+/**
+ * @brief Hello world function implementation
+ *
+ * This function prints "Hello World!" to the console using rt_kprintf
+ */
+void hello_world(void)
+{
+    rt_kprintf("Hello World!\n");
+}

+ 29 - 0
tools/hello/hello.h

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2025-06-21     Bernard      First version
+ */
+
+#ifndef __HELLO_H__
+#define __HELLO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Hello world function
+ *
+ * This function prints "Hello World!" to the console
+ */
+void hello_world(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HELLO_H__ */

+ 20 - 0
tools/hello/package.json

@@ -0,0 +1,20 @@
+{
+    "name": "hello",
+    "version": "1.0.0",
+    "description": "Hello World component for RT-Thread",
+    "author": "RT-Thread Development Team",
+    "license": "Apache-2.0",
+    "type": "rt-package",
+    "source_files": [
+        "hello.c"
+    ],
+    "CPPPATH": [
+        "."
+    ],
+    "CPPDEFINES": [
+        "HELLO"
+    ],
+    "depends": [
+        ""
+    ]
+}

+ 11 - 3
tools/package.py

@@ -24,6 +24,8 @@
 
 # this script is used to build group with package.json instead of SConscript
 import os
+import json
+
 from building import *
 
 def ExtendPackageVar(package, var):
@@ -36,8 +38,14 @@ def ExtendPackageVar(package, var):
 
     return v
 
-def BuildPackage(package):
-    import json
+def BuildPackage(package = None):
+    if package is None:
+        package = os.path.join(GetCurrentDir(), 'package.json')
+
+    if not os.path.isfile(package):
+        print("%s/package.json not found" % GetCurrentDir())
+        return []
+
     f = open(package)
     package_json = f.read()
 
@@ -47,7 +55,7 @@ def BuildPackage(package):
     package = json.loads(package_json)
 
     # check package name
-    if 'name' not in package:
+    if 'name' not in package or 'type' not in package or package['type'] != 'rt-package':
         return []
 
     # get depends

+ 89 - 0
tools/preprocessor.py

@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+#
+# File      : preprocessor.py
+# This file is part of RT-Thread RTOS
+# COPYRIGHT (C) 2006 - 2025, RT-Thread Development Team
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Change Logs:
+# Date           Author       Notes
+# 2025-01-05     Assistant    Extract SCons PreProcessor patch to independent class
+
+from SCons.Script import *
+
+class SConsPreProcessorPatch:
+    """
+    SCons PreProcessor patch class
+    
+    This class provides methods to patch the SCons PreProcessor
+    to handle conditional compilation directives properly.
+    """
+    
+    def __init__(self):
+        """Initialize the PreProcessor patch"""
+        self._patched_preprocessor = None
+        self._apply_patch()
+    
+    def _apply_patch(self):
+        """
+        Apply the patch to SCons PreProcessor
+        
+        This method patches the SCons.cpp.PreProcessor class with
+        custom methods for handling includes during conditional compilation.
+        """
+        from SCons import cpp
+        
+        # Store reference to original PreProcessor
+        self._patched_preprocessor = cpp.PreProcessor
+        
+        # Create bound methods for the patch
+        def start_handling_includes(preprocessor_self, t=None):
+            d = preprocessor_self.dispatch_table
+            p = preprocessor_self.stack[-1] if preprocessor_self.stack else preprocessor_self.default_table
+            for k in ('import', 'include', 'include_next', 'define'):
+                d[k] = p[k]
+        
+        def stop_handling_includes(preprocessor_self, t=None):
+            d = preprocessor_self.dispatch_table
+            d['import'] = preprocessor_self.do_nothing
+            d['include'] = preprocessor_self.do_nothing
+            d['include_next'] = preprocessor_self.do_nothing
+            d['define'] = preprocessor_self.do_nothing
+        
+        # Apply the patch methods
+        self._patched_preprocessor.start_handling_includes = start_handling_includes
+        self._patched_preprocessor.stop_handling_includes = stop_handling_includes
+    
+    def get_patched_preprocessor(self):
+        return self._patched_preprocessor
+    
+    def create_preprocessor_instance(self):
+        return self._patched_preprocessor()
+
+# Global instance for easy access
+_preprocessor_patch = None
+
+def get_patched_preprocessor():
+    global _preprocessor_patch
+    if _preprocessor_patch is None:
+        _preprocessor_patch = SConsPreProcessorPatch()
+    return _preprocessor_patch.get_patched_preprocessor()
+
+def create_preprocessor_instance():
+    global _preprocessor_patch
+    if _preprocessor_patch is None:
+        _preprocessor_patch = SConsPreProcessorPatch()
+    return _preprocessor_patch.create_preprocessor_instance() 

+ 0 - 1
tools/release/buildbot.py

@@ -33,7 +33,6 @@ def update_project_file(project_dir):
         command = ' --target=iar -s'
         os.system('scons --directory=' + project_dir + command + ' > 1.txt')
 
-
 def update_all_project_files(root_path):
     # current path is dir
     if os.path.isdir(root_path):

+ 79 - 0
tools/targets/__init__.py

@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+#
+# File      : __init__.py
+# This file is part of RT-Thread RTOS
+# COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Change Logs:
+# Date           Author       Notes
+# 2025-01-XX     Bernard      Create targets module for IDE project generators
+
+# Import all target generators
+from . import keil
+from . import iar
+from . import vs
+from . import vs2012
+from . import codeblocks
+from . import ua
+from . import vsc
+from . import cdk
+from . import ses
+from . import eclipse
+from . import codelite
+from . import cmake
+from . import xmake
+from . import esp_idf
+from . import zigbuild
+from . import makefile
+from . import rt_studio
+
+# Export all target generator functions
+__all__ = [
+    # Keil MDK
+    'keil',
+    # IAR
+    'iar', 
+    # Visual Studio
+    'vs',
+    'vs2012',
+    # Code::Blocks
+    'codeblocks',
+    # Universal ARM
+    'ua',
+    # VSCode
+    'vsc',
+    # CDK
+    'cdk',
+    # SEGGER Embedded Studio
+    'ses',
+    # Eclipse
+    'eclipse',
+    # CodeLite
+    'codelite',
+    # CMake
+    'cmake',
+    # XMake
+    'xmake',
+    # ESP-IDF
+    'esp_idf',
+    # Zig
+    'zigbuild',
+    # Make
+    'makefile',
+    # RT-Studio
+    'rt_studio'
+] 

+ 0 - 0
tools/cdk.py → tools/targets/cdk.py


+ 0 - 0
tools/cmake.py → tools/targets/cmake.py


+ 7 - 4
tools/codeblocks.py → tools/targets/codeblocks.py

@@ -25,14 +25,17 @@
 import os
 import sys
 import string
-import building
-
-import xml.etree.ElementTree as etree
+import uuid
+import utils
 from xml.etree.ElementTree import SubElement
 from utils import _make_path_relative
 from utils import xml_indent
 
-import utils
+# Add parent directory to path to import building
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+import building
+
+import xml.etree.ElementTree as etree
 
 fs_encoding = sys.getfilesystemencoding()
 

+ 7 - 5
tools/codelite.py → tools/targets/codelite.py

@@ -25,15 +25,17 @@
 import os
 import sys
 import string
-import building
-import rtconfig
-
-import xml.etree.ElementTree as etree
+import uuid
+import utils
 from xml.etree.ElementTree import SubElement
 from utils import _make_path_relative
 from utils import xml_indent
 
-import utils
+# Add parent directory to path to import building
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+import building
+
+import xml.etree.ElementTree as etree
 
 fs_encoding = sys.getfilesystemencoding()
 

+ 0 - 0
tools/codelite_template.project → tools/targets/codelite_template.project


+ 0 - 0
tools/codelite_template.workspace → tools/targets/codelite_template.workspace


+ 6 - 1
tools/eclipse.py → tools/targets/eclipse.py

@@ -13,7 +13,12 @@ import glob
 import xml.etree.ElementTree as etree
 from xml.etree.ElementTree import SubElement
 
-import rt_studio
+from . import rt_studio
+import sys
+import os
+
+# Add parent directory to path to import building and utils
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 from building import *
 from utils import *
 from utils import _make_path_relative

+ 2 - 2
tools/esp_idf.py → tools/targets/esp_idf.py

@@ -22,8 +22,8 @@ def GenerateCFiles(env,project):
                 cm_file.write( "\t" + path.replace("\\", "/") + "\n" ) 
                 src = open(f.rfile().abspath, 'r')
                 for line in src.readlines():
-                    if re.match('INIT_(BOARD|PREV|DEVICE|COMPONENT|ENV|APP)_EXPORT\(.+\)', line):
-                        init_export.append(re.search('\(.+\)', line).group(0)[1:-1])
+                    if re.match(r'INIT_(BOARD|PREV|DEVICE|COMPONENT|ENV|APP)_EXPORT\(.+\)', line):
+                        init_export.append(re.search(r'\(.+\)', line).group(0)[1:-1])
                 src.close()
 
         cm_file.write("\n")

+ 2 - 2
tools/iar.py → tools/targets/iar.py

@@ -36,7 +36,7 @@ from utils import xml_indent
 
 fs_encoding = sys.getfilesystemencoding()
 
-iar_workspace = '''<?xml version="1.0" encoding="iso-8859-1"?>
+iar_workspace = r'''<?xml version="1.0" encoding="iso-8859-1"?>
 
 <workspace>
   <project>
@@ -208,5 +208,5 @@ def IARVersion():
     if not isinstance(stdout, str):
         stdout = str(stdout, 'utf8') # Patch for Python 3
     # example stdout: IAR ANSI C/C++ Compiler V8.20.1.14183/W32 for ARM
-    iar_version = re.search('[\d\.]+', stdout).group(0)
+    iar_version = re.search(r'[\d\.]+', stdout).group(0)
     return iar_version

+ 6 - 12
tools/keil.py → tools/targets/keil.py

@@ -283,19 +283,13 @@ def MDK45Project(tree, target, script):
 
         # get each group's LIBS flags
         if 'LIBS' in group and group['LIBS']:
-            for item in group['LIBS']:
-                lib_path = ''
-                for path_item in group['LIBPATH']:
-                    full_path = os.path.join(path_item, item + '.lib')
-                    if os.path.isfile(full_path): # has this library
-                        lib_path = full_path
-                        break
-
-                if lib_path != '':
+            for item in group['LIBPATH']:
+                full_path = os.path.join(item, group['name'] + '.lib')
+                if os.path.isfile(full_path): # has this library
                     if group_tree != None:
-                        MDK4AddLibToGroup(ProjectFiles, group_tree, group['name'], lib_path, project_path)
+                        MDK4AddLibToGroup(ProjectFiles, group_tree, group['name'], full_path, project_path)
                     else:
-                        group_tree = MDK4AddGroupForFN(ProjectFiles, groups, group['name'], lib_path, project_path)
+                        group_tree = MDK4AddGroupForFN(ProjectFiles, groups, group['name'], full_path, project_path)
 
     # write include path, definitions and link flags
     IncludePath = tree.find('Targets/Target/TargetOption/TargetArmAds/Cads/VariousControls/IncludePath')
@@ -394,7 +388,7 @@ def MDK5Project(target, script):
             print('UV4.exe is not available, please check your keil installation')
 
 def MDK2Project(target, script):
-    template = open('template.Uv2', "r")
+    template = open(os.path.join(os.path.dirname(__file__), 'template.Uv2'), 'r')
     lines = template.readlines()
 
     project = open(target, "w")

+ 25 - 0
tools/makefile.py → tools/targets/makefile.py

@@ -1,6 +1,31 @@
+#
+# File      : makefile.py
+# This file is part of RT-Thread RTOS
+# COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Change Logs:
+# Date           Author       Notes
+# 2015-01-20     Bernard      Add copyright information
+
 import os
 import sys
 
+# Add parent directory to path to import utils
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 from utils import *
 from utils import _make_path_relative
 import rtconfig

+ 9 - 2
tools/rt_studio.py → tools/targets/rt_studio.py

@@ -2,7 +2,14 @@ import os
 import re
 from string import Template
 
-import rtconfig
+try:
+    import rtconfig
+except ImportError:
+    # Mock rtconfig for testing
+    class MockRtconfig:
+        pass
+    rtconfig = MockRtconfig()
+
 import shutil
 import time
 
@@ -275,7 +282,7 @@ def gen_org_eclipse_core_runtime_prefs(output_file_path):
 
 
 def gen_cproject_file(output_file_path):
-    template_file_path = os.path.join(os.path.dirname(output_file_path), "template.cproject")
+    template_file_path = os.path.join(os.path.dirname(__file__), 'template.cproject')
     if os.path.exists(template_file_path):
         try:
             shutil.copy(template_file_path, output_file_path)

+ 0 - 0
tools/ses.py → tools/targets/ses.py


+ 0 - 0
tools/template.cbp → tools/targets/template.cbp


+ 0 - 0
tools/ua.py → tools/targets/ua.py


+ 7 - 3
tools/vs.py → tools/targets/vs.py

@@ -25,13 +25,17 @@
 import os
 import sys
 import string
-import building
+import uuid
 import utils
-
-import xml.etree.ElementTree as etree
 from xml.etree.ElementTree import SubElement
 from utils import _make_path_relative
 from utils import xml_indent
+
+# Add parent directory to path to import building
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+import building
+
+import xml.etree.ElementTree as etree
 fs_encoding = sys.getfilesystemencoding()
 
 def VS_AddGroup(ProjectFiles, parent, name, files, libs, project_path):

+ 7 - 4
tools/vs2012.py → tools/targets/vs2012.py

@@ -25,14 +25,17 @@
 import os
 import sys
 import string
-import building
 import uuid
-
-import xml.etree.ElementTree as etree
+import utils
 from xml.etree.ElementTree import SubElement
 from utils import _make_path_relative
 from utils import xml_indent
-import utils
+
+# Add parent directory to path to import building
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+import building
+
+import xml.etree.ElementTree as etree
 
 fs_encoding = sys.getfilesystemencoding()
 

+ 0 - 0
tools/vsc.py → tools/targets/vsc.py


+ 145 - 0
tools/targets/xmake.lua

@@ -0,0 +1,145 @@
+add_rules("mode.debug", "mode.release")
+
+toolchain("arm-none-eabi")
+    set_kind("standalone")
+    set_sdkdir("/home/bernard/.env/tools/scripts/packages/arm-none-eabi-gcc-v13.2.rel1")
+toolchain_end()
+
+target("rt-thread")
+    set_kind("binary")
+    set_toolchains("arm-none-eabi")
+
+    add_files(
+        	"applications/main.c",
+	"../../../components/libc/compilers/common/cctype.c",
+	"../../../components/libc/compilers/common/cstdlib.c",
+	"../../../components/libc/compilers/common/cstring.c",
+	"../../../components/libc/compilers/common/ctime.c",
+	"../../../components/libc/compilers/common/cunistd.c",
+	"../../../components/libc/compilers/common/cwchar.c",
+	"../../../components/libc/compilers/newlib/syscalls.c",
+	"../../../components/drivers/core/device.c",
+	"../../../components/drivers/ipc/completion_comm.c",
+	"../../../components/drivers/ipc/completion_up.c",
+	"../../../components/drivers/ipc/condvar.c",
+	"../../../components/drivers/ipc/dataqueue.c",
+	"../../../components/drivers/ipc/pipe.c",
+	"../../../components/drivers/ipc/ringblk_buf.c",
+	"../../../components/drivers/ipc/ringbuffer.c",
+	"../../../components/drivers/ipc/waitqueue.c",
+	"../../../components/drivers/ipc/workqueue.c",
+	"../../../components/drivers/pin/dev_pin.c",
+	"../../../components/drivers/serial/dev_serial.c",
+	"../libraries/HAL_Drivers/drivers/drv_gpio.c",
+	"../libraries/HAL_Drivers/drivers/drv_usart.c",
+	"../libraries/HAL_Drivers/drv_common.c",
+	"board/CubeMX_Config/Src/stm32f4xx_hal_msp.c",
+	"board/board.c",
+	"../../../components/finsh/shell.c",
+	"../../../components/finsh/msh.c",
+	"../../../components/finsh/msh_parse.c",
+	"../../../components/finsh/cmd.c",
+	"../../../src/clock.c",
+	"../../../src/components.c",
+	"../../../src/cpu_up.c",
+	"../../../src/defunct.c",
+	"../../../src/idle.c",
+	"../../../src/ipc.c",
+	"../../../src/irq.c",
+	"../../../src/kservice.c",
+	"../../../src/mem.c",
+	"../../../src/mempool.c",
+	"../../../src/object.c",
+	"../../../src/scheduler_comm.c",
+	"../../../src/scheduler_up.c",
+	"../../../src/thread.c",
+	"../../../src/timer.c",
+	"../../../src/klibc/kstring.c",
+	"../../../src/klibc/rt_vsscanf.c",
+	"../../../src/klibc/kstdio.c",
+	"../../../src/klibc/rt_vsnprintf_tiny.c",
+	"../../../src/klibc/kerrno.c",
+	"../../../libcpu/arm/common/atomic_arm.c",
+	"../../../libcpu/arm/common/div0.c",
+	"../../../libcpu/arm/common/showmem.c",
+	"../../../libcpu/arm/cortex-m4/context_gcc.S",
+	"../../../libcpu/arm/cortex-m4/cpuport.c",
+	"packages/stm32f4_cmsis_driver-latest/Source/Templates/gcc/startup_stm32f412zx.s",
+	"packages/stm32f4_cmsis_driver-latest/Source/Templates/system_stm32f4xx.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_dma_ex.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_usart.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_pwr_ex.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_cryp.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_gpio.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_rcc.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_cortex.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_pwr.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_cec.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_cryp_ex.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_dma.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_uart.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_rcc_ex.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_crc.c",
+	"packages/stm32f4_hal_driver-latest/Src/stm32f4xx_hal_rng.c"
+    )
+
+    add_includedirs(
+        	"applications",
+	"packages/CMSIS-Core-latest/Include",
+	"../../../components/libc/compilers/newlib",
+	"../../../components/libc/compilers/common/include",
+	"../../../components/drivers/include",
+	"../../../components/drivers/smp_call",
+	"../../../components/drivers/phy",
+	"board",
+	"board/CubeMX_Config/Inc",
+	"../libraries/HAL_Drivers/drivers",
+	"../libraries/HAL_Drivers/drivers/config",
+	"../libraries/HAL_Drivers",
+	"../../../components/finsh",
+	".",
+	"../../../include",
+	"../../../libcpu/arm/common",
+	"../../../libcpu/arm/cortex-m4",
+	"../../../components/libc/posix/ipc",
+	"../../../components/libc/posix/io/poll",
+	"../../../components/libc/posix/io/eventfd",
+	"../../../components/libc/posix/io/epoll",
+	"packages/stm32f4_cmsis_driver-latest/Include",
+	"packages/stm32f4_hal_driver-latest/Inc",
+	"packages/stm32f4_hal_driver-latest/Inc/Legacy"
+    )
+
+    add_defines(
+        	"RT_USING_LIBC",
+	"RT_USING_NEWLIBC",
+	"STM32F412Zx",
+	"USE_HAL_DRIVER",
+	"_POSIX_C_SOURCE=1",
+	"__RTTHREAD__"
+    )
+
+    add_cflags(
+        " -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -Dgcc -O0 -gdwarf-2 -g" ,{force = true}
+    )
+    add_cxxflags(
+        " -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -Dgcc -O0 -gdwarf-2 -g" ,{force = true}
+    )
+
+    add_asflags(
+        " -c -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -x assembler-with-cpp -Wa,-mimplicit-it=thumb  -gdwarf-2" ,{force = true}
+    )
+
+    add_ldflags(
+        " -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -Wl,--gc-sections,-Map=rt-thread.map,-cref,-u,Reset_Handler -T board/linker_scripts/link.lds" ,{force = true}
+    )
+
+    set_targetdir("./")
+    set_filename("rtthread.elf")
+
+    after_build(function(target)
+        os.exec("/home/bernard/.env/tools/scripts/packages/arm-none-eabi-gcc-v13.2.rel1/bin/arm-none-eabi-objcopy -O ihex rtthread.elf rtthread.hex")
+        os.exec("/home/bernard/.env/tools/scripts/packages/arm-none-eabi-gcc-v13.2.rel1/bin/arm-none-eabi-objcopy -O binary rtthread.elf rtthread.bin")
+        os.exec("/home/bernard/.env/tools/scripts/packages/arm-none-eabi-gcc-v13.2.rel1/bin/arm-none-eabi-size rtthread.elf")
+    end)

+ 2 - 2
tools/xmake.py → tools/targets/xmake.py

@@ -69,14 +69,14 @@ class XmakeProject:
         else:
             RTT_ROOT = os.path.normpath(os.getcwd() + '/../../..')
 
-        template_path = os.path.join(RTT_ROOT, "tools", "xmake.lua")
+        template_path = os.path.join(RTT_ROOT, "tools", "targets", "xmake.lua")
         with open(template_path, "r") as f:
             data = f.read()
         data = Template(data)
         data = data.safe_substitute(toolchain=self.toolchain, sdkdir=self.sdkdir, bindir=self.bindir, src_path=self.src_path, inc_path=self.inc_path,
                                     define=self.define, cflags=self.cflags, cxxflags=self.cxxflags, asflags=self.asflags,
                                     ldflags=self.ldflags, target="rt-thread")
-        with open("xmake.lua", "w") as f:
+        with open(os.path.join(os.path.dirname(__file__), "xmake.lua"), "w") as f:
             f.write(data)
 
 

+ 0 - 0
tools/zigbuild.py → tools/targets/zigbuild.py


+ 32 - 0
tools/testcases/README.md

@@ -0,0 +1,32 @@
+# 测试用例目录
+
+本目录包含 RT-Thread 工具的测试脚本。
+
+## 测试脚本
+
+### test_preprocessor.py
+SCons PreProcessor 补丁功能测试脚本。测试与 building.py 的集成,验证预处理器补丁是否正常工作。
+
+### test_refactor.py
+验证目标模块重构是否成功的测试脚本。测试内容包括:
+- 目标模块导入
+- Building.py 导入
+- 目标函数调用
+
+### mock_rtconfig.py
+用于测试的模拟 rtconfig 模块。在实际 rtconfig 不可用的测试场景中提供模拟的 rtconfig 模块。
+
+## 使用方法
+
+要运行测试,请导航到此目录并执行:
+
+```bash
+python test_preprocessor.py
+python test_refactor.py
+```
+
+## 说明
+
+- 这些测试脚本用于验证 RT-Thread 工具的功能
+- 可以独立运行或作为测试套件的一部分
+- mock_rtconfig.py 文件被其他测试脚本用来模拟 rtconfig 模块 

+ 35 - 0
tools/testcases/mock_rtconfig.py

@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+#
+# Mock rtconfig module for testing purposes
+#
+
+# Mock configuration variables
+CROSS_TOOL = 'gcc'
+PLATFORM = 'gcc'
+CC = 'gcc'
+CXX = 'g++'
+AS = 'as'
+AR = 'ar'
+LINK = 'gcc'
+EXEC_PATH = '/usr/bin'
+
+# Mock functions
+def GetDepend(depend):
+    return True
+
+# Mock environment
+class MockEnv:
+    def __init__(self):
+        self.CPPPATH = []
+        self.CPPDEFINES = []
+        self.LIBS = []
+        self.LIBPATH = []
+        self.CFLAGS = []
+        self.CXXFLAGS = []
+        self.LINKFLAGS = []
+        self.ASFLAGS = []
+
+# Global variables
+Env = MockEnv()
+Rtt_Root = '/mock/rt-thread'
+Projects = [] 

+ 116 - 0
tools/testcases/test_preprocessor.py

@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# File      : test_preprocessor_patch.py
+# This file is part of RT-Thread RTOS
+# COPYRIGHT (C) 2006 - 2025, RT-Thread Development Team
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Change Logs:
+# Date           Author       Notes
+# 2025-01-05     Assistant    Test file for SCons PreProcessor patch
+
+import sys
+import os
+
+# Add current directory to path for imports
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
+def test_preprocessor_patch():
+    """Test the SCons PreProcessor patch functionality"""
+    try:
+        from scons_preprocessor_patch import SConsPreProcessorPatch, create_preprocessor_instance
+        
+        print("Testing SCons PreProcessor patch...")
+        
+        # Test creating patch instance
+        patch = SConsPreProcessorPatch()
+        print("✓ SConsPreProcessorPatch instance created successfully")
+        
+        # Test getting patched preprocessor
+        patched_class = patch.get_patched_preprocessor()
+        print("✓ Patched PreProcessor class retrieved successfully")
+        
+        # Test creating preprocessor instance
+        preprocessor = create_preprocessor_instance()
+        print("✓ PreProcessor instance created successfully")
+        
+        # Test basic functionality
+        test_content = """
+        #define TEST_MACRO 1
+        #ifdef TEST_MACRO
+        #define ENABLED_FEATURE 1
+        #else
+        #define DISABLED_FEATURE 1
+        #endif
+        """
+        
+        preprocessor.process_contents(test_content)
+        namespace = preprocessor.cpp_namespace
+        
+        print("✓ PreProcessor processed test content successfully")
+        print(f"  - TEST_MACRO: {namespace.get('TEST_MACRO', 'Not found')}")
+        print(f"  - ENABLED_FEATURE: {namespace.get('ENABLED_FEATURE', 'Not found')}")
+        print(f"  - DISABLED_FEATURE: {namespace.get('DISABLED_FEATURE', 'Not found')}")
+        
+        print("\n✓ All tests passed! SCons PreProcessor patch is working correctly.")
+        return True
+        
+    except ImportError as e:
+        print(f"✗ Import error: {e}")
+        print("Make sure SCons is available in the environment")
+        return False
+    except Exception as e:
+        print(f"✗ Test failed: {e}")
+        return False
+
+def test_building_integration():
+    """Test integration with building.py"""
+    try:
+        # Test that the function is available from the patch module
+        from scons_preprocessor_patch import create_preprocessor_instance
+        
+        print("\nTesting scons_preprocessor_patch integration...")
+        
+        # Test that the function is available
+        preprocessor = create_preprocessor_instance()
+        print("✓ create_preprocessor_instance function works from scons_preprocessor_patch")
+        
+        # Test basic processing
+        test_content = "#define BUILD_TEST 1"
+        preprocessor.process_contents(test_content)
+        namespace = preprocessor.cpp_namespace
+        
+        print(f"✓ Integration test passed: BUILD_TEST = {namespace.get('BUILD_TEST', 'Not found')}")
+        return True
+        
+    except Exception as e:
+        print(f"✗ Integration test failed: {e}")
+        return False
+
+if __name__ == "__main__":
+    print("SCons PreProcessor Patch Test Suite")
+    print("=" * 40)
+    
+    success1 = test_preprocessor_patch()
+    success2 = test_building_integration()
+    
+    if success1 and success2:
+        print("\n🎉 All tests passed! The refactoring was successful.")
+        sys.exit(0)
+    else:
+        print("\n❌ Some tests failed. Please check the implementation.")
+        sys.exit(1) 

+ 121 - 0
tools/testcases/test_refactor.py

@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Test script to verify the refactoring is successful
+
+import sys
+import os
+
+# Add current directory to path
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
+# Mock rtconfig module for testing
+import mock_rtconfig
+sys.modules['rtconfig'] = mock_rtconfig
+
+def test_targets_import():
+    """Test if all target modules can be imported successfully"""
+    print("Testing targets module imports...")
+    
+    try:
+        # Test importing targets module
+        import targets
+        print("✓ targets module imported successfully")
+        
+        # Test importing individual target modules
+        target_modules = [
+            'keil', 'iar', 'vs', 'vs2012', 'codeblocks', 'ua', 
+            'vsc', 'cdk', 'ses', 'eclipse', 'codelite', 
+            'cmake', 'xmake', 'esp_idf', 'zigbuild', 'makefile', 'rt_studio'
+        ]
+        
+        for module_name in target_modules:
+            try:
+                module = getattr(targets, module_name)
+                print(f"✓ {module_name} module imported successfully")
+            except AttributeError as e:
+                print(f"✗ Failed to import {module_name}: {e}")
+                return False
+        
+        return True
+        
+    except ImportError as e:
+        print(f"✗ Failed to import targets module: {e}")
+        return False
+
+def test_building_import():
+    """Test if building.py can import target modules"""
+    print("\nTesting building.py imports...")
+    
+    try:
+        # Test importing building module
+        import building
+        print("✓ building module imported successfully")
+        
+        # Test if GenTargetProject function exists
+        if hasattr(building, 'GenTargetProject'):
+            print("✓ GenTargetProject function found")
+        else:
+            print("✗ GenTargetProject function not found")
+            return False
+            
+        return True
+        
+    except ImportError as e:
+        print(f"✗ Failed to import building module: {e}")
+        return False
+
+def test_target_functions():
+    """Test if target functions can be called"""
+    print("\nTesting target function calls...")
+    
+    try:
+        # Test importing specific target functions
+        from targets.keil import MDK4Project, MDK5Project
+        print("✓ Keil target functions imported successfully")
+        
+        from targets.iar import IARProject
+        print("✓ IAR target functions imported successfully")
+        
+        from targets.eclipse import TargetEclipse
+        print("✓ Eclipse target functions imported successfully")
+        
+        from targets.cmake import CMakeProject
+        print("✓ CMake target functions imported successfully")
+        
+        import targets.rt_studio
+        print("✓ RT-Studio target functions imported successfully")
+        
+        return True
+        
+    except ImportError as e:
+        print(f"✗ Failed to import target functions: {e}")
+        return False
+
+def main():
+    """Main test function"""
+    print("RT-Thread Tools Refactoring Test")
+    print("=" * 40)
+    
+    success = True
+    
+    # Run all tests
+    if not test_targets_import():
+        success = False
+    
+    if not test_building_import():
+        success = False
+        
+    if not test_target_functions():
+        success = False
+    
+    print("\n" + "=" * 40)
+    if success:
+        print("✓ All tests passed! Refactoring is successful.")
+        return 0
+    else:
+        print("✗ Some tests failed. Please check the errors above.")
+        return 1
+
+if __name__ == '__main__':
+    sys.exit(main()) 

+ 41 - 161
tools/win32spawn.py

@@ -1,7 +1,7 @@
 #
 # File      : win32spawn.py
 # This file is part of RT-Thread RTOS
-# COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team
+# COPYRIGHT (C) 2006 - 2025, RT-Thread Development Team
 #
 #  This program is free software; you can redistribute it and/or modify
 #  it under the terms of the GNU General Public License as published by
@@ -23,163 +23,43 @@
 #
 
 import os
-import threading
-import sys
-
-_PY2 = sys.version_info[0] < 3
-if _PY2:
-    import Queue
-else:
-    import queue as Queue
-
-# Windows import
-import win32file
-import win32pipe
-import win32api
-import win32con
-import win32security
-import win32process
-import win32event
-
-class Win32Spawn(object):
-    def __init__(self, cmd, shell=False):
-        self.queue = Queue.Queue()
-        self.is_terminated = False
-        self.wake_up_event = win32event.CreateEvent(None, 0, 0, None)
-
-        exec_dir = os.getcwd()
-        comspec = os.environ.get("COMSPEC", "cmd.exe")
-        cmd = comspec + ' /c ' + cmd
-
-        win32event.ResetEvent(self.wake_up_event)
-
-        currproc = win32api.GetCurrentProcess()
-
-        sa = win32security.SECURITY_ATTRIBUTES()
-        sa.bInheritHandle = 1
-
-        child_stdout_rd, child_stdout_wr = win32pipe.CreatePipe(sa, 0)
-        child_stdout_rd_dup = win32api.DuplicateHandle(currproc, child_stdout_rd, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
-        win32file.CloseHandle(child_stdout_rd)
-
-        child_stderr_rd, child_stderr_wr = win32pipe.CreatePipe(sa, 0)
-        child_stderr_rd_dup = win32api.DuplicateHandle(currproc, child_stderr_rd, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
-        win32file.CloseHandle(child_stderr_rd)
-
-        child_stdin_rd, child_stdin_wr = win32pipe.CreatePipe(sa, 0)
-        child_stdin_wr_dup = win32api.DuplicateHandle(currproc, child_stdin_wr, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
-        win32file.CloseHandle(child_stdin_wr)
-
-        startup_info = win32process.STARTUPINFO()
-        startup_info.hStdInput = child_stdin_rd
-        startup_info.hStdOutput = child_stdout_wr
-        startup_info.hStdError = child_stderr_wr
-        startup_info.dwFlags = win32process.STARTF_USESTDHANDLES
-
-        cr_flags = 0
-        cr_flags = win32process.CREATE_NEW_PROCESS_GROUP
-
-        env = os.environ.copy()
-        self.h_process, h_thread, dw_pid, dw_tid = win32process.CreateProcess(None, cmd, None, None, 1,
-                                                                              cr_flags, env, os.path.abspath(exec_dir),
-                                                                              startup_info)
-
-        win32api.CloseHandle(h_thread)
-
-        win32file.CloseHandle(child_stdin_rd)
-        win32file.CloseHandle(child_stdout_wr)
-        win32file.CloseHandle(child_stderr_wr)
-
-        self.__child_stdout = child_stdout_rd_dup
-        self.__child_stderr = child_stderr_rd_dup
-        self.__child_stdin = child_stdin_wr_dup
-
-        self.exit_code = -1
-
-    def close(self):
-        win32file.CloseHandle(self.__child_stdout)
-        win32file.CloseHandle(self.__child_stderr)
-        win32file.CloseHandle(self.__child_stdin)
-        win32api.CloseHandle(self.h_process)
-        win32api.CloseHandle(self.wake_up_event)
-
-    def kill_subprocess():
-        win32event.SetEvent(self.wake_up_event)
-
-    def sleep(secs):
-        win32event.ResetEvent(self.wake_up_event)
-        timeout = int(1000 * secs)
-        val = win32event.WaitForSingleObject(self.wake_up_event, timeout)
-        if val == win32event.WAIT_TIMEOUT:
-            return True
-        else:
-            # The wake_up_event must have been signalled
-            return False
-
-    def get(self, block=True, timeout=None):
-        return self.queue.get(block=block, timeout=timeout)
-
-    def qsize(self):
-        return self.queue.qsize()
-
-    def __wait_for_child(self):
-        # kick off threads to read from stdout and stderr of the child process
-        threading.Thread(target=self.__do_read, args=(self.__child_stdout, )).start()
-        threading.Thread(target=self.__do_read, args=(self.__child_stderr, )).start()
-
-        while True:
-            # block waiting for the process to finish or the interrupt to happen
-            handles = (self.wake_up_event, self.h_process)
-            val = win32event.WaitForMultipleObjects(handles, 0, win32event.INFINITE)
-
-            if val >= win32event.WAIT_OBJECT_0 and val < win32event.WAIT_OBJECT_0 + len(handles):
-                handle = handles[val - win32event.WAIT_OBJECT_0]
-                if handle == self.wake_up_event:
-                    win32api.TerminateProcess(self.h_process, 1)
-                    win32event.ResetEvent(self.wake_up_event)
-                    return False
-                elif handle == self.h_process:
-                    # the process has ended naturally
-                    return True
-                else:
-                    assert False, "Unknown handle fired"
-            else:
-                assert False, "Unexpected return from WaitForMultipleObjects"
-
-    # Wait for job to finish. Since this method blocks, it can to be called from another thread.
-    # If the application wants to kill the process, it should call kill_subprocess().
-    def wait(self):
-        if not self.__wait_for_child():
-            # it's been killed
-            result = False
-        else:
-            # normal termination
-            self.exit_code = win32process.GetExitCodeProcess(self.h_process)
-            result = self.exit_code == 0
-        self.close()
-        self.is_terminated = True
-
-        return result
-
-    # This method gets called on a worker thread to read from either a stderr
-    # or stdout thread from the child process.
-    def __do_read(self, handle):
-        bytesToRead = 1024
-        while 1:
-            try:
-                finished = 0
-                hr, data = win32file.ReadFile(handle, bytesToRead, None)
-                if data:
-                    self.queue.put_nowait(data)
-            except win32api.error:
-                finished = 1
-
-            if finished:
-                return
-
-    def start_pipe(self):
-        def worker(pipe):
-            return pipe.wait()
-
-        thrd = threading.Thread(target=worker, args=(self, ))
-        thrd.start()
+import subprocess
+
+class Win32Spawn:
+    def spawn(self, sh, escape, cmd, args, env):
+        # deal with the cmd build-in commands which cannot be used in
+        # subprocess.Popen
+        if cmd == 'del':
+            for f in args[1:]:
+                try:
+                    os.remove(f)
+                except Exception as e:
+                    print('Error removing file: ' + e)
+                    return -1
+            return 0
+
+        newargs = ' '.join(args[1:])
+        cmdline = cmd + " " + newargs
+
+        # Make sure the env is constructed by strings
+        _e = dict([(k, str(v)) for k, v in env.items()])
+
+        # Windows(tm) CreateProcess does not use the env passed to it to find
+        # the executables. So we have to modify our own PATH to make Popen
+        # work.
+        old_path = os.environ['PATH']
+        os.environ['PATH'] = _e['PATH']
+
+        try:
+            proc = subprocess.Popen(cmdline, env=_e, shell=False)
+        except Exception as e:
+            print('Error in calling command:' + cmdline.split(' ')[0])
+            print('Exception: ' + os.strerror(e.errno))
+            if (os.strerror(e.errno) == "No such file or directory"):
+                print ("\nPlease check Toolchains PATH setting.\n")
+
+            return e.errno
+        finally:
+            os.environ['PATH'] = old_path
+
+        return proc.wait()

+ 0 - 46
tools/xmake.lua

@@ -1,46 +0,0 @@
-add_rules("mode.debug", "mode.release")
-
-toolchain("${toolchain}")
-    set_kind("standalone")
-    set_sdkdir("${sdkdir}")
-toolchain_end()
-
-target("${target}")
-    set_kind("binary")
-    set_toolchains("${toolchain}")
-
-    add_files(
-        ${src_path}
-    )
-
-    add_includedirs(
-        ${inc_path}
-    )
-
-    add_defines(
-        ${define}
-    )
-
-    add_cflags(
-        "${cflags}" ,{force = true}
-    )
-    add_cxxflags(
-        "${cxxflags}" ,{force = true}
-    )
-
-    add_asflags(
-        "${asflags}" ,{force = true}
-    )
-
-    add_ldflags(
-        "${ldflags}" ,{force = true}
-    )
-
-    set_targetdir("./")
-    set_filename("rtthread.elf")
-
-    after_build(function(target)
-        os.exec("${bindir}/${toolchain}-objcopy -O ihex rtthread.elf rtthread.hex")
-        os.exec("${bindir}/${toolchain}-objcopy -O binary rtthread.elf rtthread.bin")
-        os.exec("${bindir}/${toolchain}-size rtthread.elf")
-    end)