2009/11/26 Chris Recoskie
<recoskie@xxxxxxxxxx>
> - The language setting entries are used by managed build for
> storing it's paths and preproc symbols. If you use this method on
> managed projects you'll be changing the set of includes / macros
> that are passed to the compiler, won't you?
Hmmm.... well they are stored in the build model IOption elements as well. I think only the IOption data is actually passed to the compiler. I will make sure I test that scenario. For now I have committed it for XLC.
In the new build system the ICLanguageSettingsEntries are the cdt.core manifestation of IOption values. The magic for this happens in ManagedBuild's BuildLanguageData which hangs off CLanguageData. There's the method #getSupportedEntryKinds() which tells cdt.core what kinds of setting entries the build system's toolchain supports.
This drives the kind of settings entries that core will allow to persist, which tabs are visible in C/C++ General / Paths & Symbols, etc. Amusingly, if managedbuild's toolchain doesn't have a tool with a MACROS option, say, then any MACRO setting entries set using this API will simply be lost...
You should see if you add a path to the C/C++ General > Paths & Symbols page, it also appears in C/C++ Build > Settings && is stored in as an option value in the .cproject file? Obviously for Makefile projects you don't get the tool settings tab in Build > Settings, but the option value should still be stored under the respective tool in the .cproject file.
If there isn't a managedbuild Configuration Data Provider registered, cdt.core provides its own persistence mechanism for the language settings entries.
To me, the benefits far outweighed the outstanding issues, as it's not acceptable for us to have the user
I agree, and I use this mechanism as well. It's just that the it has pitfalls, one being managed projects.
In ManagedBuild what I did was to use scanner discovery to provide compiler built-ins, and I added some hooks to force clear these entries on compiler change, etc. As the user provides the other build settings themselves, this seems to work well.
> - There's no way to distinguish between paths you added and paths
> contributed from elsewhere, be it user UI or ManagedBuild. I notice
> in your code you only every add entries. This means that, if you
> change compiler, or change an include directory on a file, you'll
> end up retaining the older entries
Yep... it sucks but I couldn't find a way around it.
This is easier using the Dwarf parser as you get the full debug info for the binary rather than incremental output from the build
Ideally yes. However, my brain exploded when I tried to figure out how to create new configs. And it didn't
:) Code for how I did this below. In updateResourceConfigurations resource descriptions are created if they don't exist from the parent resource desc. There's complete code for doing this on the dwarf settings bug:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=236872
> There are tricks to get around this, but it's not pretty.
That's a general issue though with the project description. I haven't done anything to make that worse :-P
It gets worse if you do what I did and try to annotate the model per-File rather than per-Project. In the end aggregating macros per-Folder worked and produces a very good approximation of what was built.
Cheers,
James
protected void updateResourceConfigurations(IProject project, ICConfigurationDescription cfgDesc/*String cfgID*/, Map<IPath, LinkedHashSet> pathToDebugObjSet)
throws CoreException {
int resourceConfigCount = 0;
for (Map.Entry<IPath, LinkedHashSet> e : pathToDebugObjSet.entrySet()) {
// All extenders to specify a set of paths they want to be annotated with these attributes
for (IPath path : getRelevantPaths(project, e.getKey())) {
++resourceConfigCount;
ICResourceDescription resDesc = cfgDesc.getResourceDescription(path, true);
if (resDesc == null) {
// Ensure the resource exists...
if (project.findMember(path) == null || !project.findMember(path).exists()) {
reportInfo("Resource " + path + " not found!");
continue;
}
// Find parent ICResourceDescription
IPath parentPath = path.removeLastSegments(1);
ICResourceDescription parentDesc = cfgDesc.getResourceDescription(parentPath, false);
// Create the resource configuration for the file / directory based on the parent
switch (project.findMember(path).getType()) {
case IResource.FILE:
resDesc = cfgDesc.createFileDescription(path, parentDesc);
break;
case IResource.FOLDER:
case IResource.PROJECT:
resDesc = cfgDesc.createFolderDescription(path, (ICFolderDescription)parentDesc);
break;
default:
reportError("Resource type " + project.findMember(path).getType() + " unhandled!");
}
}
// Convert Macros/Includes attributes to Settings entries
LinkedHashSet<ICLanguageSettingEntry> newSettings = dwarfObjToSettingEntrys(e.getKey(), e.getValue());
List<ICLanguageSetting> langs = new ArrayList<ICLanguageSetting>(3);
if (resDesc instanceof ICFileDescription)
langs.add(((ICFileDescription)resDesc).getLanguageSetting());
else {
for (ICLanguageSetting lang : ((ICFolderDescription)resDesc).getLanguageSettings()) {
if (lang.supportsEntryKind(kind))
langs.add(lang);
}
}
for (ICLanguageSetting lang : langs) {
if ((kind & ICSettingEntry.INCLUDE_PATH) != 0) {
newSettings.addAll(lang.getSettingEntriesList(ICSettingEntry.INCLUDE_PATH));
removeScannerDiscoveryProvidedInfo(newSettings);
lang.setSettingEntries(ICSettingEntry.INCLUDE_PATH, newSettings.toArray(new ICLanguageSettingEntry[newSettings.size()]));
}
if ((kind & ICSettingEntry.MACRO) != 0) {
newSettings.addAll(lang.getSettingEntriesList(ICSettingEntry.MACRO));
removeScannerDiscoveryProvidedInfo(newSettings);
lang.setSettingEntries(ICSettingEntry.MACRO, newSettings.toArray(new ICLanguageSettingEntry[newSettings.size()]));
}
}
}
}
if (Debug.DWARF_PROVIDER) {
System.out.println("Number of resource configs set on: " + cfgDesc.getId() + " was " + resourceConfigCount);
}
}