blob: 14196ab0f6d65ef3f3bf44043fac33dee169709e [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.royale.compiler.internal.targets;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.royale.compiler.config.RSLSettings;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.targets.ITargetSettings;
import org.apache.royale.compiler.units.ICompilationUnit;
import org.apache.royale.compiler.units.ICompilationUnit.UnitType;
import org.apache.royale.compiler.workspaces.IWorkspace;
/**
* Class to handle all of the checks for external linkage.
*/
public class LinkageChecker
{
/**
* Constructor.
*
* @param project The project.
* @param targetSettings The target settings.
*/
public LinkageChecker(ICompilerProject project,
ITargetSettings targetSettings)
{
this.project = project;
this.targetSettings = targetSettings;
}
private ICompilerProject project;
private ITargetSettings targetSettings;
private Set<String> externs;
/**
* Test if a compilation is should be included in the target or not.
*
* @param cu The compilation unit to test.
* @return true if the compilation should be excluded from the target,
* false otherwise.
*/
public boolean isExternal(ICompilationUnit cu) throws InterruptedException
{
if (externs == null)
initExterns();
// All names in a cu should have the same linkage so just
// check the first name.
List<String> qnames = cu.getQualifiedNames();
if (!qnames.isEmpty() &&
externs.contains(qnames.get(0)))
{
return true;
}
return false;
}
/**
* Initialize the externs set. Combine the symbols explicitly externed by
* the user together with the symbols in each of the libraries on the
* external library path. We use the symbols from external libraries instead
* of just checking if the compilation unit comes from an external library
* to fix the case where we would include a symbol like "mx_internal"
* because it was in both an external library and a "normal" library. With
* "mx_internal" in the externs table the compilation unit will be excluded
* no matter which library it is found in. This in being done to match the
* behavior of the old compiler.
*
* @throws InterruptedException if implementation throws one
*/
public void initExterns() throws InterruptedException
{
if (externs != null) return;
// using a temporary local variable instead of adding to the externs
// member variable directly. isExternal() checks if the member variable
// is null. since isExternal() may be called by multiple threads, we
// don't want to set the member variable before all externs are added,
// or the isExternal() method could return the wrong result
HashSet<String> foundExterns = new HashSet<String>(4096);
// first add the user defined externals
foundExterns.addAll(targetSettings.getExterns());
// next add all of the symbols from external libraries
IWorkspace w = project.getWorkspace();
Collection<File> extLibs = targetSettings.getExternalLibraryPath();
List<RSLSettings> rsls = targetSettings.getRuntimeSharedLibraryPath();
List<File> libraries = new ArrayList<File>(
((extLibs == null) ? 0 : extLibs.size()) +
((rsls == null) ? 0 : rsls.size()));
if (extLibs != null)
libraries.addAll(targetSettings.getExternalLibraryPath());
if (rsls != null)
{
for (RSLSettings settings : targetSettings.getRuntimeSharedLibraryPath())
{
libraries.add(settings.getLibraryFile());
}
}
for (File library : libraries)
{
Collection<ICompilationUnit> units = null;
units = w.getCompilationUnits(library.getAbsolutePath(), project);
for (ICompilationUnit unit : units)
{
// Don't allow embed units to be extern'd. Rely on the class
// containing the embed to either pull in or extern the embed.
// Royale is different from the old compiler in that embed
// compilation units generated from files in a SWC have
// their qname associated with the SWC. This led to
// externing the embed compilation unit when the SWC was on
// the external library path.
ICompilationUnit.UnitType type = unit.getCompilationUnitType();
if (type != UnitType.EMBED_UNIT)
foundExterns.addAll(unit.getQualifiedNames());
}
}
// -includes-classes (compc only) is allow to override externs for
// monkey patching.
foundExterns.removeAll(targetSettings.getIncludeClasses());
externs = foundExterns;
}
}