Repository navigation
fix[tools]: attach group LOCAL_CPPDEFINES to source files in Eclipse export #11930
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
Open
AZE-BlackCore
wants to merge
1
commit into
RT-Thread:master
Choose a base branch
from
AZE-BlackCore:dev
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -516,7 +516,151 @@ def HandleExcludingOption(entry, sourceEntries, excluding): | |
| SubElement(sourceEntries, 'entry', {'excluding': value, 'flags': 'VALUE_WORKSPACE_PATH|RESOLVED', 'kind':'sourcePath', 'name':""}) | ||
|
|
||
|
|
||
| def UpdateCproject(env, project, excluding, reset, prj_name): | ||
| def CollectLocalDefines(env): | ||
| """ | ||
| Collect the per-group LOCAL_CPPDEFINES and map them to the group source files. | ||
|
|
||
| Returns a dict: relative project path (str) -> list of define strings. | ||
| The Eclipse project generator only writes global CPPDEFINES into | ||
| rtconfig_preinc.h; LOCAL_CPPDEFINES must be attached to the corresponding | ||
| source files as per-file defined symbols (CDT fileInfo), so that the macro | ||
| scope stays unchanged and other source files are not affected. | ||
| """ | ||
| local_defines = {} | ||
| groups = env.get('project', []) | ||
| if not groups: | ||
| return local_defines | ||
|
|
||
| for group in groups: | ||
| if 'LOCAL_CPPDEFINES' not in group: | ||
| continue | ||
| defines = [] | ||
| for item in group['LOCAL_CPPDEFINES']: | ||
| item = str(item).strip() | ||
| if item and item not in defines: | ||
| defines.append(item) | ||
| if not defines: | ||
| continue | ||
|
|
||
| src = group.get('src') | ||
| if not src: | ||
| continue | ||
|
|
||
| for f in src: | ||
| rp = RelativeProjectPath(env, os.path.abspath(str(f))).replace('\\', '/') | ||
| if rp.startswith('.'): | ||
| continue | ||
| cur = local_defines.setdefault(rp, []) | ||
| for d in defines: | ||
| if d not in cur: | ||
| cur.append(d) | ||
|
|
||
| return local_defines | ||
|
|
||
|
|
||
| # marker used in generated per-file option ids, so they can be refreshed | ||
| # (removed and regenerated) on every 'scons --target=eclipse' run | ||
| _rtt_local_marker = '.rttlocal.' | ||
|
|
||
|
|
||
| def _IsCppFile(rp): | ||
| return rp.endswith(('.cpp', '.cc', '.cxx', '.C')) | ||
|
|
||
|
|
||
| def _GetCompilerInstanceId(configuration, rp): | ||
| """ | ||
| Return the actual compiler tool instance id that owns the source file. | ||
|
|
||
| CDT file-level <tool> nodes must reference an existing per-folder/toolchain | ||
| compiler *instance* (superClass = instance id), not the base plug-in class: | ||
| only then does the file-level tool inherit the options that | ||
| HandleToolOption() writes on the folder/toolchain instance (include paths, | ||
| '-include rtconfig_preinc.h', global defines, ...). Using the base class | ||
| would leave kernel sources without the header search paths / preinclude | ||
| and break the Studio build. | ||
| """ | ||
| def _first_compiler_tool(container): | ||
| for tool in container.findall('tool'): | ||
| sid = tool.get('superClass', '') | ||
| if 'tool.cpp.compiler' in sid: | ||
| if _IsCppFile(rp): | ||
| return tool.get('id') | ||
| elif 'tool.c.compiler' in sid and not _IsCppFile(rp): | ||
| return tool.get('id') | ||
| return None | ||
|
|
||
| # per-folder compiler instances: relative folder path -> tool instance id | ||
| # NOTE: match by 'resourcePath' (the real project-relative folder path), | ||
| # NOT by 'name'. CDT 'name' is a display name that is often just '/' | ||
| # even for sub-folder configurations (e.g. a root config with | ||
| # name="/" resourcePath="" and a sub-folder config with name="/" | ||
| # resourcePath="rt-thread/src"), so 'name' cannot distinguish folders | ||
| # and the longest-prefix match would always fall back to the root one, | ||
| # skipping the sub-folder compiler's custom options. | ||
| folders = [] | ||
| for fi in configuration.findall('folderInfo'): | ||
| d = fi.get('resourcePath', '').strip().lstrip('/') | ||
| tid = None | ||
| tc = fi.find('toolChain') | ||
| if tc is not None: | ||
| tid = _first_compiler_tool(tc) | ||
| if tid is None: | ||
| tid = _first_compiler_tool(fi) | ||
| if tid is not None: | ||
| folders.append((d, tid)) | ||
|
|
||
| # pick the folder with the longest matching directory prefix; | ||
| # covers root ('', matches everything), nested folders and files | ||
| # outside any configured folder (they fall back to the root one) | ||
| best = None | ||
| for d, tid in folders: | ||
| matched = (d == '') or rp == d or rp.startswith(d + '/') | ||
| if matched and (best is None or len(d) > len(best[0])): | ||
| best = (d, tid) | ||
| if best is not None: | ||
| return best[1] | ||
|
|
||
| # fallback: toolchain-level compiler instance | ||
| tc = configuration.find('toolChain') | ||
| if tc is not None: | ||
| tid = _first_compiler_tool(tc) | ||
| if tid is not None: | ||
| return tid | ||
| return None | ||
|
|
||
|
|
||
| def UpdateLocalDefinesFileInfo(configuration, ccfg_id, local_defines): | ||
| """ | ||
| Generate/refresh CDT per-file <fileInfo> nodes that add the group's | ||
| LOCAL_CPPDEFINES as defined symbols on the corresponding source files. | ||
| """ | ||
| # remove previously generated fileInfo nodes | ||
| for fi in configuration.findall('fileInfo'): | ||
| if _rtt_local_marker in fi.get('id', ''): | ||
| configuration.remove(fi) | ||
|
|
||
| for rp, defines in local_defines.items(): | ||
| fi_id = ccfg_id + _rtt_local_marker + rp.replace('/', '.').strip('.') | ||
| # 'resourcePath' is required by CDT to associate the file (getPath()); | ||
| # 'name' alone cannot replace it, otherwise the project configuration | ||
| # fails to load (addResourceConfiguration -> getPath().segmentCount()). | ||
| fi = SubElement(configuration, 'fileInfo', | ||
| {'id': fi_id, 'name': '/' + rp, 'resourcePath': rp}) | ||
| # inherit the real compiler instance so folder/toolchain options | ||
| # (-I, '-include rtconfig_preinc.h', global defines) are kept | ||
| compiler_id = _GetCompilerInstanceId(configuration, rp) | ||
| if compiler_id is None: | ||
| compiler_id = 'ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler' | ||
| tool = SubElement(fi, 'tool', {'id': fi_id + '.tool', | ||
| 'superClass': compiler_id}) | ||
| option = SubElement(tool, 'option', {'id': fi_id + '.defs', | ||
| 'superClass': 'ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.defs', | ||
| 'useByScannerDiscovery': 'true'}) | ||
| for d in defines: | ||
| SubElement(option, 'listOptionValue', {'builtIn': 'false', 'value': d}) | ||
|
Comment on lines
+656
to
+660
Member
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. [P2] 添加局部宏时保留原有宏列表 如果用户在 Studio 的工程或目录属性中配置了宏,这里新建的 请先取得该文件原本有效的宏列表,再合并 |
||
|
|
||
|
|
||
| def UpdateCproject(env, project, excluding, reset, prj_name, local_defines=None): | ||
| excluding = sorted(excluding) | ||
|
|
||
| cproject = etree.parse('.cproject') | ||
|
|
@@ -527,6 +671,11 @@ def UpdateCproject(env, project, excluding, reset, prj_name): | |
| tools = cconfiguration.findall('storageModule/configuration/folderInfo/toolChain/tool') | ||
| HandleToolOption(tools, env, project, reset) | ||
|
|
||
| # per-file LOCAL_CPPDEFINES: attach them to the corresponding source files | ||
| cfg = cconfiguration.find('storageModule[@moduleId="cdtBuildSystem"]/configuration') | ||
| if cfg is not None: | ||
| UpdateLocalDefinesFileInfo(cfg, cconfiguration.get('id'), local_defines or {}) | ||
|
|
||
| sourceEntries = cconfiguration.find('storageModule/configuration/sourceEntries') | ||
| if sourceEntries != None: | ||
| entry = sourceEntries.find('entry') | ||
|
|
@@ -603,7 +752,7 @@ def TargetEclipse(env, reset=False, prj_name=None): | |
| excluding = GenExcluding(env, project) | ||
|
|
||
| # update the project configuration on '.cproject' file | ||
| UpdateCproject(env, project, excluding, reset, prj_name) | ||
| UpdateCproject(env, project, excluding, reset, prj_name, CollectLocalDefines(env)) | ||
|
|
||
| print('done!') | ||
|
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
[P2] 复用已有文件级配置,保留用户设置
如果用户已为
clock.c设置文件级编译选项,例如-fno-builtin,这里仍会追加一个相同resourcePath的fileInfo。CDT 按路径保存配置,后加载的新节点会覆盖原节点,原有选项随之失效。另外,用户在本函数生成的节点上通过 Studio 修改选项后,下次导出又会在第 638–640 行将整个节点删除,这些修改也会丢失。
请按
resourcePath查找并复用已有节点,只更新导出器管理的宏,保留用户的其他选项。首次导出和重复导出都需要覆盖这两种情况。