-
Notifications
You must be signed in to change notification settings - Fork 5.3k
[tool]: 允许通过rtconfig.py自定义工程名与链接文件夹,增强eclipse脚本处理 #10648
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 3 commits
6d61514
0fc5f25
27bcc3e
85e9c7f
26dd8ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ | |
# 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 | ||
# 2025-09-01 wdfk-prog Add project-name option for custom project naming in IDE targets | ||
|
||
import os | ||
import sys | ||
|
@@ -802,19 +803,21 @@ def local_group(group, objects): | |
|
||
EndBuilding(target, program) | ||
|
||
def GenTargetProject(program = None): | ||
def GenTargetProject(program = None, project_name = None): | ||
if project_name is None: | ||
project_name = GetOption('project-name') | ||
|
||
if GetOption('target') in ['mdk', 'mdk4', 'mdk5']: | ||
from targets.keil import MDK2Project, MDK4Project, MDK5Project, ARMCC_Version | ||
|
||
if os.path.isfile('template.uvprojx') and GetOption('target') not in ['mdk4']: # Keil5 | ||
MDK5Project(Env, GetOption('project-name') + '.uvprojx', Projects) | ||
MDK5Project(Env, project_name + '.uvprojx', Projects) | ||
print("Keil5 project is generating...") | ||
elif os.path.isfile('template.uvproj') and GetOption('target') not in ['mdk5']: # Keil4 | ||
MDK4Project(Env, GetOption('project-name') + '.uvproj', Projects) | ||
MDK4Project(Env, project_name + '.uvproj', Projects) | ||
print("Keil4 project is generating...") | ||
elif os.path.isfile('template.Uv2') and GetOption('target') not in ['mdk4', 'mdk5']: # Keil2 | ||
MDK2Project(Env, GetOption('project-name') + '.Uv2', Projects) | ||
MDK2Project(Env, project_name + '.Uv2', Projects) | ||
print("Keil2 project is generating...") | ||
else: | ||
print ('No template project file found.') | ||
|
@@ -825,20 +828,20 @@ def GenTargetProject(program = None): | |
if GetOption('target') == 'iar': | ||
from targets.iar import IARProject, IARVersion | ||
print("IAR Version: " + IARVersion()) | ||
IARProject(Env, GetOption('project-name') + '.ewp', Projects) | ||
IARProject(Env, project_name + '.ewp', Projects) | ||
print("IAR project has generated successfully!") | ||
|
||
if GetOption('target') == 'vs': | ||
from targets.vs import VSProject | ||
VSProject(GetOption('project-name') + '.vcproj', Projects, program) | ||
VSProject(project_name + '.vcproj', Projects, program) | ||
|
||
if GetOption('target') == 'vs2012': | ||
from targets.vs2012 import VS2012Project | ||
VS2012Project(GetOption('project-name') + '.vcxproj', Projects, program) | ||
VS2012Project(project_name + '.vcxproj', Projects, program) | ||
|
||
if GetOption('target') == 'cb': | ||
from targets.codeblocks import CBProject | ||
CBProject(GetOption('project-name') + '.cbp', Projects, program) | ||
CBProject(project_name + '.cbp', Projects, program) | ||
|
||
if GetOption('target') == 'ua': | ||
from targets.ua import PrepareUA | ||
|
@@ -857,7 +860,7 @@ def GenTargetProject(program = None): | |
|
||
if GetOption('target') == 'cdk': | ||
from targets.cdk import CDKProject | ||
CDKProject(GetOption('project-name') + '.cdkproj', Projects) | ||
CDKProject(project_name + '.cdkproj', Projects) | ||
|
||
if GetOption('target') == 'ses': | ||
from targets.ses import SESProject | ||
|
@@ -869,15 +872,17 @@ def GenTargetProject(program = None): | |
|
||
if GetOption('target') == 'eclipse': | ||
from targets.eclipse import TargetEclipse | ||
TargetEclipse(Env, GetOption('reset-project-config'), GetOption('project-name')) | ||
from utils import ProjectInfo | ||
project = ProjectInfo(Env) | ||
TargetEclipse(Env, project, GetOption('reset-project-config'), project_name) | ||
|
||
if GetOption('target') == 'codelite': | ||
from targets.codelite import TargetCodelite | ||
TargetCodelite(Projects, program) | ||
|
||
if GetOption('target') == 'cmake' or GetOption('target') == 'cmake-armclang': | ||
from targets.cmake import CMakeProject | ||
CMakeProject(Env, Projects, GetOption('project-name')) | ||
CMakeProject(Env, Projects, project_name) | ||
|
||
if GetOption('target') == 'xmake': | ||
from targets.xmake import XMakeProject | ||
|
@@ -912,13 +917,20 @@ def EndBuilding(target, program = None): | |
Clean(target, 'rtua.pyc') | ||
Clean(target, '.sconsign.dblite') | ||
|
||
# Priority: 1. PROJECT_NAME in rtconfig.py -> | ||
# 2. --project-name command line option -> | ||
# 3. SCons default value ('project') | ||
project_name = GetOption('project-name') | ||
if hasattr(rtconfig, 'PROJECT_NAME') and rtconfig.PROJECT_NAME: | ||
project_name = rtconfig.PROJECT_NAME | ||
|
||
|
||
if GetOption('target'): | ||
Comment on lines
+924
to
928
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. English: There are unnecessary blank lines (lines 926-927) that should be reduced to a single blank line for better code formatting. Chinese: 有不必要的空行(第926-927行),应该减少为单个空行以获得更好的代码格式。 Copilot generated this review using guidance from repository custom instructions. Positive FeedbackNegative Feedback |
||
GenTargetProject(program) | ||
GenTargetProject(program, project_name) | ||
need_exit = True | ||
|
||
BSP_ROOT = Dir('#').abspath | ||
|
||
project_name = GetOption('project-name') | ||
project_path = GetOption('project-path') | ||
|
||
# 合并处理打包相关选项 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
# Date Author Notes | ||
# 2019-03-21 Bernard the first version | ||
# 2019-04-15 armink fix project update error | ||
# 2025-09-01 wdfk-prog Add project-name support for Eclipse target and enhance folder linking | ||
# | ||
|
||
import glob | ||
|
@@ -355,32 +356,73 @@ def HandleToolOption(tools, env, project, reset): | |
|
||
return | ||
|
||
|
||
def UpdateProjectStructure(env, prj_name): | ||
bsp_root = env['BSP_ROOT'] | ||
rtt_root = env['RTT_ROOT'] | ||
|
||
project = etree.parse('.project') | ||
root = project.getroot() | ||
|
||
if rtt_root.startswith(bsp_root): | ||
linkedResources = root.find('linkedResources') | ||
if linkedResources == None: | ||
linkedResources = SubElement(root, 'linkedResources') | ||
|
||
links = linkedResources.findall('link') | ||
# delete all RT-Thread folder links | ||
for link in links: | ||
if link.find('name').text.startswith('rt-thread'): | ||
linkedResources.remove(link) | ||
|
||
if prj_name: | ||
name = root.find('name') | ||
if name == None: | ||
name = SubElement(root, 'name') | ||
name.text = prj_name | ||
""" | ||
Updates the .project file to link any external/specified folders from | ||
PROJECT_SOURCE_FOLDERS in rtconfig.py. This version correctly handles | ||
all specified paths, regardless of their physical location. | ||
""" | ||
bsp_root = os.path.abspath(env['BSP_ROOT']) | ||
|
||
# --- 1. Read the list of folders to be linked from rtconfig.py --- | ||
folders_to_link = [] | ||
try: | ||
import rtconfig | ||
if hasattr(rtconfig, 'PROJECT_SOURCE_FOLDERS') and rtconfig.PROJECT_SOURCE_FOLDERS: | ||
folders_to_link = rtconfig.PROJECT_SOURCE_FOLDERS | ||
except ImportError: | ||
pass # It's okay if the file or variable doesn't exist. | ||
|
||
out = open('.project', 'w') | ||
if not os.path.exists('.project'): | ||
print("Error: .project file not found. Cannot update.") | ||
return | ||
|
||
project_xml = etree.parse('.project') | ||
root = project_xml.getroot() | ||
|
||
# --- 2. Ensure the <linkedResources> node exists --- | ||
linkedResources = root.find('linkedResources') | ||
if linkedResources is None: | ||
linkedResources = SubElement(root, 'linkedResources') | ||
|
||
# --- 3. Clean up previously managed links to prevent duplicates --- | ||
managed_link_names = [os.path.basename(p) for p in folders_to_link] | ||
for link in list(linkedResources.findall('link')): # Use list() to safely remove items while iterating | ||
name_element = link.find('name') | ||
if name_element is not None and name_element.text in managed_link_names: | ||
linkedResources.remove(link) | ||
print(f"Removed existing linked resource '{name_element.text}' to regenerate it.") | ||
|
||
# --- 4. Create new links for each folder specified by the user --- | ||
for folder_path in folders_to_link: | ||
# The link name in the IDE will be the directory's base name. | ||
link_name = os.path.basename(folder_path) | ||
|
||
# Resolve the absolute path of the folder to be linked. | ||
abs_folder_path = os.path.abspath(os.path.join(bsp_root, folder_path)) | ||
|
||
print(f"Creating linked resource for '{link_name}' pointing to '{abs_folder_path}'...") | ||
|
||
# Calculate the URI relative to the Eclipse ${PROJECT_LOC} variable. | ||
# This works for both internal and external folders. | ||
relative_link_path = os.path.relpath(abs_folder_path, bsp_root).replace('\\', '/') | ||
|
||
# Use Eclipse path variables for robustness. PARENT_LOC is more standard for external folders. | ||
if relative_link_path.startswith('../'): | ||
# Count how many levels up | ||
levels_up = relative_link_path.count('../') | ||
clean_path = relative_link_path.replace('../', '') | ||
location_uri = f'PARENT-{levels_up}-PROJECT_LOC/{clean_path}' | ||
Comment on lines
+412
to
+415
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. English: The indentation is inconsistent. Line 413 has extra spaces before the comment, while line 415 has proper indentation. Chinese: 缩进不一致。第413行注释前有额外的空格,而第415行有正确的缩进。 Copilot generated this review using guidance from repository custom instructions. Positive FeedbackNegative Feedback |
||
else: | ||
location_uri = f'PROJECT_LOC/{relative_link_path}' | ||
|
||
link_element = SubElement(linkedResources, 'link') | ||
SubElement(link_element, 'name').text = link_name | ||
SubElement(link_element, 'type').text = '2' # Type 2 means a folder link. | ||
SubElement(link_element, 'locationURI').text = location_uri | ||
|
||
# --- 5. Write the updated content back to the .project file --- | ||
out = open('.project', 'w', encoding='utf-8') | ||
out.write('<?xml version="1.0" encoding="UTF-8"?>\n') | ||
xml_indent(root) | ||
out.write(etree.tostring(root, encoding='utf-8').decode('utf-8')) | ||
|
@@ -492,6 +534,57 @@ def HandleExcludingOption(entry, sourceEntries, excluding): | |
|
||
SubElement(sourceEntries, 'entry', {'excluding': value, 'flags': 'VALUE_WORKSPACE_PATH|RESOLVED', 'kind':'sourcePath', 'name':""}) | ||
|
||
def UpdateProjectName(prj_name): | ||
""" | ||
Regardless of whether the .project file exists, make sure its name is correct. | ||
""" | ||
if not prj_name: | ||
return | ||
|
||
try: | ||
if not os.path.exists('.project'): | ||
if rt_studio.gen_project_file(os.path.abspath(".project"), prj_name) is False: | ||
print('Fail!') | ||
return | ||
print("Generated .project file with name:", prj_name) | ||
|
||
project_tree = etree.parse('.project') | ||
root = project_tree.getroot() | ||
name_element = root.find('name') | ||
|
||
if name_element is not None and name_element.text != prj_name: | ||
print(f"Updating project name from '{name_element.text}' to '{prj_name}'...") | ||
name_element.text = prj_name | ||
|
||
project_tree.write('.project', encoding='UTF-8', xml_declaration=True) | ||
xml_indent(root) | ||
with open('.project', 'w', encoding='utf-8') as f: | ||
f.write('<?xml version="1.0" encoding="UTF-8"?>\n') | ||
f.write(etree.tostring(root, encoding='utf-8').decode('utf-8')) | ||
Comment on lines
+595
to
+598
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. English: Line 562 has extra spaces before the f.write call, creating inconsistent indentation within the with block. Chinese: 第562行在f.write调用前有额外的空格,在with块内创建了不一致的缩进。 Copilot generated this review using guidance from repository custom instructions. Positive FeedbackNegative Feedback |
||
|
||
except Exception as e: | ||
print("Error updating .project file:", e) | ||
|
||
def HandleSourceEntries_Global(sourceEntries, excluding): | ||
""" | ||
Configure the project to include the root folder ("") and exclude all | ||
files/folders in the 'excluding' list. This makes all project folders | ||
visible in the IDE. | ||
""" | ||
# To keep the configuration clean, first remove all existing entries | ||
for entry in sourceEntries.findall('entry'): | ||
sourceEntries.remove(entry) | ||
|
||
# Join the exclusion list into a single string with the '|' separator | ||
excluding_str = '|'.join(sorted(excluding)) | ||
|
||
# Create a new, single entry for the project root directory | ||
SubElement(sourceEntries, 'entry', { | ||
'flags': 'VALUE_WORKSPACE_PATH|RESOLVED', | ||
'kind': 'sourcePath', | ||
'name': "", # An empty string "" represents the project root | ||
'excluding': excluding_str | ||
}) | ||
|
||
def UpdateCproject(env, project, excluding, reset, prj_name): | ||
excluding = sorted(excluding) | ||
|
@@ -504,31 +597,39 @@ def UpdateCproject(env, project, excluding, reset, prj_name): | |
tools = cconfiguration.findall('storageModule/configuration/folderInfo/toolChain/tool') | ||
HandleToolOption(tools, env, project, reset) | ||
|
||
if prj_name: | ||
config_element = cconfiguration.find('storageModule/configuration') | ||
if config_element is not None: | ||
config_element.set('artifactName', prj_name) | ||
|
||
sourceEntries = cconfiguration.find('storageModule/configuration/sourceEntries') | ||
if sourceEntries != None: | ||
entry = sourceEntries.find('entry') | ||
HandleExcludingOption(entry, sourceEntries, excluding) | ||
# update refreshScope | ||
if sourceEntries is not None: | ||
# Call the new global handler function for source entries | ||
HandleSourceEntries_Global(sourceEntries, excluding) | ||
|
||
# update refreshScope to ensure the project refreshes correctly | ||
if prj_name: | ||
prj_name = '/' + prj_name | ||
prj_name_for_path = '/' + prj_name | ||
configurations = root.findall('storageModule/configuration') | ||
for configuration in configurations: | ||
resource = configuration.find('resource') | ||
configuration.remove(resource) | ||
SubElement(configuration, 'resource', {'resourceType': "PROJECT", 'workspacePath': prj_name}) | ||
if resource is not None: | ||
configuration.remove(resource) | ||
SubElement(configuration, 'resource', {'resourceType': "PROJECT", 'workspacePath': prj_name_for_path}) | ||
|
||
# write back to .cproject | ||
# write back to .cproject file | ||
out = open('.cproject', 'w') | ||
out.write('<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n') | ||
out.write('<?fileVersion 4.0.0?>') | ||
xml_indent(root) | ||
out.write(etree.tostring(root, encoding='utf-8').decode('utf-8')) | ||
out.close() | ||
|
||
|
||
def TargetEclipse(env, reset=False, prj_name=None): | ||
def TargetEclipse(env, project, reset=False, prj_name=None): | ||
global source_pattern | ||
|
||
UpdateProjectName(prj_name) | ||
|
||
print('Update eclipse setting...') | ||
|
||
# generate cproject file | ||
|
@@ -561,7 +662,7 @@ def TargetEclipse(env, reset=False, prj_name=None): | |
# enable lowwer .s file compiled in eclipse cdt | ||
if not os.path.exists('.settings/org.eclipse.core.runtime.prefs'): | ||
if rt_studio.gen_org_eclipse_core_runtime_prefs( | ||
os.path.abspath(".settings/org.eclipse.core.runtime.prefs")) is False: | ||
os.path.abspath(".settings/org.eclipse.core.runtime.prefs")) is False: | ||
print('Fail!') | ||
return | ||
|
||
|
@@ -571,8 +672,6 @@ def TargetEclipse(env, reset=False, prj_name=None): | |
print('Fail!') | ||
return | ||
|
||
project = ProjectInfo(env) | ||
|
||
# update the project file structure info on '.project' file | ||
UpdateProjectStructure(env, prj_name) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
English: The comment describes priority logic that doesn't match the implementation. The code sets project_name from GetOption first, then overwrites it if rtconfig.PROJECT_NAME exists, which makes rtconfig.PROJECT_NAME higher priority, not GetOption. Chinese: 注释描述的优先级逻辑与实现不匹配。代码首先从GetOption设置project_name,然后如果rtconfig.PROJECT_NAME存在就覆盖它,这使得rtconfig.PROJECT_NAME具有更高的优先级,而不是GetOption。
Copilot generated this review using guidance from repository custom instructions.