blob: db08fb11556cebf5680377dec0d4d4c207f51360 [file] [log] [blame]
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed 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 com.google.devtools.build.lib.rules.objc;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ArtifactRoot;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.rules.cpp.CppModuleMap;
import com.google.devtools.build.lib.rules.cpp.CppModuleMap.UmbrellaHeaderStrategy;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
/**
* Factory class for generating artifacts which are used as intermediate output.
*/
// TODO(bazel-team): This should really be named DerivedArtifacts as it contains methods for
// final as well as intermediate artifacts.
public final class IntermediateArtifacts {
static final String LINKMAP_SUFFIX = ".linkmap";
private final RuleContext ruleContext;
private final BuildConfiguration buildConfiguration;
private final String archiveFileNameSuffix;
private final String outputPrefix;
private final UmbrellaHeaderStrategy umbrellaHeaderStrategy;
IntermediateArtifacts(RuleContext ruleContext, String archiveFileNameSuffix,
String outputPrefix) {
this(ruleContext, archiveFileNameSuffix, outputPrefix, ruleContext.getConfiguration(),
UmbrellaHeaderStrategy.DO_NOT_GENERATE);
}
IntermediateArtifacts(RuleContext ruleContext, String archiveFileNameSuffix) {
this(ruleContext, archiveFileNameSuffix, "", ruleContext.getConfiguration(),
UmbrellaHeaderStrategy.DO_NOT_GENERATE);
}
IntermediateArtifacts(RuleContext ruleContext, String archiveFileNameSuffix,
UmbrellaHeaderStrategy umbrellaHeaderStrategy) {
this(ruleContext, archiveFileNameSuffix, "", ruleContext.getConfiguration(),
umbrellaHeaderStrategy);
}
IntermediateArtifacts(RuleContext ruleContext, String archiveFileNameSuffix, String outputPrefix,
BuildConfiguration buildConfiguration) {
this(ruleContext, archiveFileNameSuffix, outputPrefix, buildConfiguration,
UmbrellaHeaderStrategy.DO_NOT_GENERATE);
}
IntermediateArtifacts(RuleContext ruleContext, String archiveFileNameSuffix, String outputPrefix,
BuildConfiguration buildConfiguration, UmbrellaHeaderStrategy umbrellaHeaderStrategy) {
this.ruleContext = ruleContext;
this.buildConfiguration = buildConfiguration;
this.archiveFileNameSuffix = Preconditions.checkNotNull(archiveFileNameSuffix);
this.outputPrefix = Preconditions.checkNotNull(outputPrefix);
this.umbrellaHeaderStrategy = umbrellaHeaderStrategy;
}
/**
* Returns the archive file name suffix.
*/
public String archiveFileNameSuffix() {
return archiveFileNameSuffix;
}
/**
* Returns a derived artifact in the bin directory obtained by appending some extension to the end
* of the {@link PathFragment} corresponding to the owner {@link Label}.
*/
private Artifact appendExtension(String extension) {
PathFragment name = PathFragment.create(ruleContext.getLabel().getName());
return scopedArtifact(name.replaceName(addOutputPrefix(name.getBaseName(), extension)));
}
/**
* Returns a derived artifact in the genfiles directory obtained by appending some extension to
* the end of the {@link PathFragment} corresponding to the owner {@link Label}.
*/
private Artifact appendExtensionInGenfiles(String extension) {
PathFragment name = PathFragment.create(ruleContext.getLabel().getName());
return scopedArtifact(
name.replaceName(addOutputPrefix(name.getBaseName(), extension)), /* inGenfiles = */ true);
}
/**
* The .objlist file, which contains a list of paths of object files to archive and is read by
* clang (via -filelist flag) in the link action (for binary creation).
*/
public Artifact linkerObjList() {
return appendExtension("-linker.objlist");
}
/**
* The .objlist file, which contains a list of paths of object files to archive and is read by
* libtool (via -filelist flag) in the archive action.
*/
public Artifact archiveObjList() {
return appendExtension("-archive.objlist");
}
/**
* The artifact which is the binary (or library) which is comprised of one or more .a files linked
* together. Compared to the artifact returned by {@link #unstrippedSingleArchitectureBinary},
* this artifact is stripped of symbol table when --compilation_mode=opt and
* --objc_enable_binary_stripping are specified.
*/
public Artifact strippedSingleArchitectureBinary() {
return appendExtension("_bin");
}
/**
* The artifact which is the fully-linked static library comprised of statically linking compiled
* sources and dependencies together.
*/
public Artifact strippedSingleArchitectureLibrary() {
return appendExtension("-fl.a");
}
/**
* The artifact which is the binary (or library) which is comprised of one or more .a files linked
* together. It also contains full debug symbol information, compared to the artifact returned
* by {@link #strippedSingleArchitectureBinary}. This artifact will serve as input for the symbol
* strip action and is only created when --compilation_mode=opt and
* --objc_enable_binary_stripping are specified.
*/
public Artifact unstrippedSingleArchitectureBinary() {
return appendExtension("_bin_unstripped");
}
/**
* Lipo binary generated by combining one or more linked binaries. This binary is the one included
* in generated bundles and invoked as entry point to the application.
*/
public Artifact combinedArchitectureBinary() {
return appendExtension("_lipobin");
}
/**
* Lipo archive generated by combining one or more linked archives.
*/
public Artifact combinedArchitectureArchive() {
return appendExtension("_lipo.a");
}
/**
* Lipo'ed dynamic library generated by combining one or more single-architecture linked dynamic
* libraries.
*/
public Artifact combinedArchitectureDylib() {
return appendExtension("_lipo.dylib");
}
private Artifact scopedArtifact(PathFragment scopeRelative, boolean inGenfiles) {
ArtifactRoot root =
inGenfiles
? buildConfiguration.getGenfilesDirectory(ruleContext.getRule().getRepository())
: buildConfiguration.getBinDirectory(ruleContext.getRule().getRepository());
// The path of this artifact will be RULE_PACKAGE/SCOPERELATIVE
return ruleContext.getPackageRelativeArtifact(scopeRelative, root);
}
private Artifact scopedArtifact(PathFragment scopeRelative) {
return scopedArtifact(scopeRelative, /* inGenfiles = */ false);
}
/**
* The {@code .a} file which contains all the compiled sources for a rule.
*/
public Artifact archive() {
// The path will be {RULE_PACKAGE}/lib{RULEBASENAME}{SUFFIX}.a
String basename = PathFragment.create(ruleContext.getLabel().getName()).getBaseName();
return scopedArtifact(PathFragment.create(String.format(
"lib%s%s.a", basename, archiveFileNameSuffix)));
}
/**
* Debug symbol file generated for a stripped linked binary.
*
* <p>The name of the debug symbol file matches that of stripped binary plus that of the debug
* symbol file extension (.dwarf), so we must know if the binary has been stripped
* or not as that will modify its name.
*/
public Artifact dsymSymbolForStrippedBinary() {
return dsymSymbol("bin");
}
/**
* Debug symbol file generated for an unstripped linked binary.
*
* <p>The name of the debug symbol file matches that of unstripped binary plus that of the debug
* symbol file extension (.dwarf).
*/
public Artifact dsymSymbolForUnstrippedBinary() {
return dsymSymbol("bin_unstripped");
}
/**
* Debug symbol file generated for a linked binary, for a specific architecture.
*/
private Artifact dsymSymbol(String suffix) {
return appendExtension(String.format("_%s.dwarf", suffix));
}
/** Bitcode symbol map generated for a linked binary, for a specific architecture. */
public Artifact bitcodeSymbolMap() {
return appendExtension(".bcsymbolmap");
}
/** Representation for a specific architecture. */
private Artifact architectureRepresentation(String arch, String suffix) {
return appendExtension(String.format("_%s%s", arch, suffix));
}
/**
* Linkmap representation
*/
public Artifact linkmap() {
return appendExtension(LINKMAP_SUFFIX);
}
/**
* Linkmap representation for a specific architecture.
*/
public Artifact linkmap(String arch) {
return architectureRepresentation(arch, LINKMAP_SUFFIX);
}
/**
* {@link CppModuleMap} that provides the clang module map for this target.
*/
public CppModuleMap moduleMap() {
String moduleName;
if (ruleContext.attributes().isAttributeValueExplicitlySpecified("module_name")) {
moduleName = ruleContext.attributes().get("module_name", Type.STRING);
} else {
moduleName =
ruleContext
.getLabel()
.toString()
.replace("//", "")
.replace("@", "")
.replace("-", "_")
.replace("/", "_")
.replace(":", "_");
}
Optional<Artifact> customModuleMap = CompilationSupport.getCustomModuleMap(ruleContext);
if (customModuleMap.isPresent()) {
return new CppModuleMap(customModuleMap.get(), moduleName);
} else if (umbrellaHeaderStrategy == UmbrellaHeaderStrategy.GENERATE) {
// To get Swift to pick up module maps, we need to name them "module.modulemap" and have their
// parent directory in the module map search paths.
return new CppModuleMap(
appendExtensionInGenfiles(".modulemaps/module.modulemap"),
appendExtensionInGenfiles(".modulemaps/umbrella.h"),
moduleName);
} else {
return new CppModuleMap(
appendExtensionInGenfiles(".modulemaps/module.modulemap"), moduleName);
}
}
/**
* Returns a static library archive with dead code/objects removed by J2ObjC dead code removal,
* given the original unpruned static library containing J2ObjC-translated code.
*/
public Artifact j2objcPrunedArchive(Artifact unprunedArchive) {
PathFragment prunedSourceArtifactPath = FileSystemUtils.appendWithoutExtension(
unprunedArchive.getRootRelativePath(), "_pruned");
return ruleContext.getUniqueDirectoryArtifact(
"_j2objc_pruned",
prunedSourceArtifactPath,
buildConfiguration.getBinDirectory(ruleContext.getRule().getRepository()));
}
/**
* Returns artifact name prefixed with an output prefix if specified.
*/
private String addOutputPrefix(String baseName, String artifactName) {
if (!outputPrefix.isEmpty()) {
return String.format("%s-%s%s", baseName, outputPrefix, artifactName);
}
return String.format("%s%s", baseName, artifactName);
}
}