From 131459f779b1a98bf354663298637589a2860fff Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Tue, 4 Dec 2012 18:34:43 -0800 Subject: Support package conflicts between app and libs. If 2 libraries share the same package name, this is now a build breakage, unless all libraries share the same package. This is because the libraries R classes only contain the resources declared in the libraries themselves (plus dependencies). Since two libraries could share the same package name without depending on one another, it's possible to ensure that creating only one R class would work for both. (Merging both R class might be possible but is too risky for a quick fix like this). If all the libraries share the same package, then a single R class is created for that package that contains all the symbol of the app (simpler than merging all the symbols for now) If a library and the app share the same package name, the R class for the library is not created (since the R class for the app contains all resources). This already worked in ADT, so this changeset only fixes Ant. Change-Id: I95f0b734ba263051961268d960d59749f5b6e1a5 --- .../build/builders/PreCompilerBuilder.java | 93 +++++++++++++++++++--- 1 file changed, 81 insertions(+), 12 deletions(-) (limited to 'eclipse') diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java index 25b16e4..ba23c95 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java @@ -56,6 +56,8 @@ import com.android.utils.ILogger; import com.android.utils.Pair; import com.android.xml.AndroidManifest; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; @@ -78,6 +80,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import javax.xml.parsers.ParserConfigurationException; @@ -1156,18 +1159,71 @@ public class PreCompilerBuilder extends BaseBuilder { File rFile = new File(outputFolder, SdkConstants.FN_RESOURCE_TEXT); // if the project has no resources, the file could not exist. if (rFile.isFile()) { - SymbolLoader symbolValues = new SymbolLoader(rFile); - symbolValues.load(); - - for (Pair libData : libRFiles) { - File libRFile = libData.getFirst(); - if (libRFile.isFile()) { - SymbolLoader symbols = new SymbolLoader(libRFile); - symbols.load(); - - SymbolWriter writer = new SymbolWriter(osOutputPath, - libData.getSecond(), symbols, symbolValues); - writer.write(); + // Load the full symbols from the full R.txt file. + SymbolLoader fullSymbols = new SymbolLoader(rFile); + fullSymbols.load(); + + // simpler case of a single library + if (libRFiles.size() == 1) { + Pair lib = libRFiles.get(0); + createRClass(fullSymbols, lib.getFirst(), lib.getSecond(), osOutputPath); + + } else { + Map libPackages = Maps.newHashMapWithExpectedSize( + libRFiles.size()); + Set duplicatePackages = Sets.newHashSet(); + + // preprocessing to figure out if there are dups in the package names of + // the libraries + for (Pair lib : libRFiles) { + String libPackage = lib.getSecond(); + File existingPkg = libPackages.get(libPackage); + if (existingPkg != null) { + // record the dup package and keep going, in case there are all + // the same + duplicatePackages.add(libPackage); + continue; + } + + libPackages.put(libPackage, lib.getFirst()); + } + + // check if we have duplicate but all files are the same. + if (duplicatePackages.size() > 0) { + // possible conflict! + // detect case of all libraries == same package. + if (duplicatePackages.size() == 1 && libPackages.size() == 1 && + duplicatePackages.iterator().next().equals(libPackages.keySet().iterator().next())) { + // this is ok, all libraries have the same package. + // Make a copy of the full R class. + SymbolWriter writer = new SymbolWriter(osOutputPath, + duplicatePackages.iterator().next(), + fullSymbols, fullSymbols); + writer.write(); + } else { + StringBuilder sb = new StringBuilder(); + sb.append("The following packages have been found to be used by two or more libraries:"); + for (String pkg : duplicatePackages) { + sb.append("\n\t").append(pkg); + } + sb.append("\nNo libraries must share the same package, unless all libraries share the same packages."); + + String msg = sb.toString(); + markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); + + AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, + msg); + + throw new AbortBuildException(); + } + } else { + // no dups, all libraries have different packages. + // Conflicts with the main package have been removed already. + // Just process all the libraries. + for (Pair lib : libRFiles) { + createRClass(fullSymbols, lib.getFirst(), lib.getSecond(), + osOutputPath); + } } } } @@ -1227,6 +1283,19 @@ public class PreCompilerBuilder extends BaseBuilder { } } + private void createRClass(SymbolLoader fullSymbols, File libRTxtFile, String libPackage, + String osOutputPath) throws IOException { + if (libRTxtFile.isFile()) { + SymbolLoader libSymbols = new SymbolLoader(libRTxtFile); + libSymbols.load(); + + SymbolWriter writer = new SymbolWriter(osOutputPath, libPackage, libSymbols, + fullSymbols); + writer.write(); + } + } + + /** * Creates a relative {@link IPath} from a java package. * @param javaPackageName the java package. -- cgit v1.1