I want to programmatically (from a plugin) change the "Other flags" field in the Miscellaneous settings in the Tool Settings tab for an individual file in a CDT managed build project. (See this Eclipse documentation page for a screenshot and brief description of how this change would be made using the UI.)
Note: I've updated this twice now as I approach a solution. But instead of adding an update onto the end (as I do for shorter questions), I'm revising the entire question. If it helps to see the breadcrumbs leading to where I am now, you can read the history.
The following code will result in settings written to the .cproject file (I'll go into detail on that below), but when I open the Properties dialog for the file, and click on C/C++ Build->Settings and then Miscellaneous, the changes do not appear in the "Other flags" field (as they do when I make changes using the dialog).
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow workbenchwindow = workbench.getActiveWorkbenchWindow();
IWorkbenchPage workbenchpage = workbenchwindow.getActivePage();
IEditorPart editorpart = workbenchpage.getActiveEditor();
IEditorInput editorinput = editorpart.getEditorInput();
IResource file = ((IFileEditorInput)editorinput).getFile();
IProject project = file.getProject();
IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(project);
IConfiguration[] configurations = buildInfo.getManagedProject().getConfigurations();
IConfiguration conf = configurations[0];
IFileInfo fileInfo = conf.createFileInfo(file.getFullPath());
ITool[] tools = fileInfo.getTools();
ITool tool = tools[0];
IOption option = tool.getOptionById("my.gnu.compiler.misc.other");
String oldOptionValue = option.getDefaultValue().toString();
String newOptionValue = oldOptionValue + " -eg";
ManagedBuildManager.setOption(fileInfo, tool, option, newOptionValue);
ManagedBuildManager.saveBuildInfo(project, true);
I looked at the differences between the .cproject file where I changed the tool settings manually, and in a different .cproject file after running the above code. Below are the pertinent bits from each.
Here is the XML from the .cproject file where the tool settings were changed manually:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="com.company.product.toolchain.configuration.changed.1964078554">
...
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="${ProjName}" buildProperties="" cleanCommand="rm -f" description="" id="com.company.product.toolchain.configuration.changed.1964078554" name="changed" parent="com.company.product.toolchain.configuration.changed">
...
<fileInfo id="com.company.product.toolchain.configuration.changed.1964078554.915152327" name="code.cpp" rcbsApplicability="disable" resourcePath="src/code.cpp" toolsToInvoke="com.company.product.toolchain.compiler.1643348654.1411455203">
<tool id="com.company.product.toolchain.compiler.1643348654.1411455203" name="Company GNU compilers" superClass="com.company.product.toolchain.compiler.1643348654">
<option id="company.gnu.compiler.misc.other.789167779" name="Other flags" superClass="company.gnu.compiler.misc.other" value="-c -fmessage-length=0 -eg" valueType="string"/>
<inputType id="com.company.product.toolchain.cxxinputtype.877052163" name="C++ Input" superClass="com.company.product.toolchain.cxxinputtype"/>
<inputType id="com.company.product.toolchain.cinputtype.1390394900" name="C input" superClass="com.company.product.toolchain.cinputtype"/>
</tool>
</fileInfo>
...
And here is the XML from the .cproject file where they were changed programmatically:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="com.company.product.toolchain.configuration.changed.2057644715">
...
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="${ProjName}" buildProperties="" cleanCommand="rm -f" description="" id="com.company.product.toolchain.configuration.changed.2057644715" name="changed" parent="com.company.product.toolchain.configuration.changed">
...
<fileInfo id="com.company.product.toolchain.configuration.changed.2057644715./test3/src/code.cpp" name="code.cpp" rcbsApplicability="disable" resourcePath="test3/src/code.cpp" toolsToInvoke="com.company.product.toolchain.compiler.1482360042.1005761865">
<tool id="com.company.product.toolchain.compiler.1482360042.1005761865" name="Company GNU compilers" superClass="com.company.product.toolchain.compiler.1482360042">
<option id="company.gnu.compiler.misc.other.999025984" superClass="company.gnu.compiler.misc.other" value="-c -fmessage-length=0 -eg" valueType="string"/>
<inputType id="com.company.product.toolchain.cxxinputtype.1253686787" name="C++ Input" superClass="com.company.product.toolchain.cxxinputtype"/>
<inputType id="com.company.product.toolchain.cinputtype.1141524787" name="C input" superClass="com.company.product.toolchain.cinputtype"/>
</tool>
</fileInfo>
...
Aside from the numbers, which I assume are some kind of GUIDs, there are three differences:
For some reason, the id attribute of the fileInfo
element in the programmatic changes contains the path to the file, including the project name: id="com.company.product.toolchain.configuration.changed.2057644715./test3/src/code.cpp"
The resourcePath
attribute value of the fileInfo
element contains the project name, only in the programmatic changes: resourcePath="test3/src/code.cpp"
.
The option
element in the fileInfo
element as a name attribute (name="Other flags"
) that matches the field in the dialog, only in the manual changes.
I'm guessing that one or all of these differences are preventing my programmatic changes from being "compatible" with the manual ones (so they show up in the dialog). I'm trying to figure out how to create the IFileInfo, IOption (and ITool?) objects without causing these differences. I'm trying to find how these objects are created for the dialog, but haven't yet.
Any suggestions appreciated.
Update: I got an answer from Doug Schaefer to my question on the cdt-dev mailing list. He suggested I "stick breakpoints in places and see how the UI does it." I wrote back:
I have been doing that. I set a breakpoint in org.eclipse.cdt.managedbuilder.core.ManagedBuildManager.setOption(IResourceInfo, IHoldsOptions, IOption, String)
and it triggers when I open the Properties dialog for a file, expand "C/C++ Build", select "Settings", and then "Miscellaneous" in the Tool Settings tab. I can see the arguments, and presumably if I can call setOption with the same arguments I'll get the same results in the .cproject file. But I haven't been able to figure out how to do that. Do you have any suggestions for how I figure out where those objects are created so I can set breakpoints there?
Update #2: Vladimir's answer solved my problem. While I was more concerned with difference number 3 in the two .cproject file fragments above, the key was difference 2 and the inclusion of the project name in difference 1.
I changed the code to create the IFileInfo
object to:
IFileInfo fileInfo = conf.createFileInfo(file.getProjectRelativePath());
...which resulted in the fileInfo element not having the project name:
<fileInfo id="com.company.product.toolchain.configuration.changed.838214286.src/code.cpp" name="code.cpp" rcbsApplicability="disable" resourcePath="src/code.cpp" toolsToInvoke="com.company.product.toolchain.compiler.2027651356.1970239371">
...and most importantly, resulted in the programmatic changes showing up in the "Other flags" field in the Miscellaneous settings in the Tool Settings tab for the individual file. (I guess the other differences in the .cproject files are not important.)
I suspect there might be problem in you IFileInfo creation. Here's the code that we use to obtain IResourceInfo for a translation unit to set per-file options:
protected IResourceInfo getResourceInfo(ITranslationUnit translationUnit, ICProjectDescription prjDescription) {
ICProject cProject = translationUnit.getCProject();
if (cProject != null) {
ICConfigurationDescription cfgDescription = prjDescription.getActiveConfiguration();
IConfiguration configuration = ManagedBuildManager.getConfigurationForDescription(cfgDescription);
IPath projectPath = translationUnit.getResource().getProjectRelativePath();
IResourceInfo ri = configuration.getResourceInfo(projectPath, true);
if (ri == null) {
ri = configuration.createFileInfo(projectPath);
}
return ri;
}
return null;
}
Note this line, in particular:
IPath projectPath = translationUnit.getResource().getProjectRelativePath();
Maybe, all you need is to use getProjectRelativePath() in your code?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With