/*
* Copyright 2016-present Facebook, Inc.
*
* 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.facebook.buck.go;
import com.facebook.buck.io.MorePaths;
import com.facebook.buck.model.BuildTargets;
import com.facebook.buck.rules.AbstractBuildRule;
import com.facebook.buck.rules.AddToRuleKey;
import com.facebook.buck.rules.BuildContext;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildableContext;
import com.facebook.buck.rules.BuildableProperties;
import com.facebook.buck.rules.ExplicitBuildTargetSourcePath;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SymlinkTree;
import com.facebook.buck.rules.Tool;
import com.facebook.buck.step.Step;
import com.facebook.buck.step.fs.MakeCleanDirectoryStep;
import com.facebook.buck.step.fs.MkdirStep;
import com.facebook.buck.step.fs.SymlinkFileStep;
import com.facebook.buck.step.fs.TouchStep;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.nio.file.Path;
import java.util.Optional;
public class GoCompile extends AbstractBuildRule {
@AddToRuleKey private final Tool compiler;
@AddToRuleKey private final Tool assembler;
@AddToRuleKey private final Tool packer;
@AddToRuleKey(stringify = true)
private final Path packageName;
@AddToRuleKey private final ImmutableSet<SourcePath> srcs;
@AddToRuleKey private final ImmutableList<String> compilerFlags;
@AddToRuleKey private final ImmutableList<String> assemblerFlags;
@AddToRuleKey private final GoPlatform platform;
// TODO(mikekap): Make these part of the rule key.
private final ImmutableList<Path> assemblerIncludeDirs;
private final ImmutableMap<Path, Path> importPathMap;
private final SymlinkTree symlinkTree;
private final Path output;
public GoCompile(
BuildRuleParams params,
SymlinkTree symlinkTree,
Path packageName,
ImmutableMap<Path, Path> importPathMap,
ImmutableSet<SourcePath> srcs,
ImmutableList<String> compilerFlags,
Tool compiler,
ImmutableList<String> assemblerFlags,
ImmutableList<Path> assemblerIncludeDirs,
Tool assembler,
Tool packer,
GoPlatform platform) {
super(params);
this.importPathMap = importPathMap;
this.srcs = srcs;
this.symlinkTree = symlinkTree;
this.packageName = packageName;
this.compilerFlags = compilerFlags;
this.compiler = compiler;
this.assemblerFlags = assemblerFlags;
this.assemblerIncludeDirs = assemblerIncludeDirs;
this.assembler = assembler;
this.packer = packer;
this.platform = platform;
this.output =
BuildTargets.getGenPath(
getProjectFilesystem(),
getBuildTarget(),
"%s/" + getBuildTarget().getShortName() + ".a");
}
@Override
public ImmutableList<Step> getBuildSteps(
BuildContext context, BuildableContext buildableContext) {
buildableContext.recordArtifact(output);
ImmutableList.Builder<Path> compileSrcListBuilder = ImmutableList.builder();
ImmutableList.Builder<Path> headerSrcListBuilder = ImmutableList.builder();
ImmutableList.Builder<Path> asmSrcListBuilder = ImmutableList.builder();
for (SourcePath path : srcs) {
Path srcPath = context.getSourcePathResolver().getAbsolutePath(path);
String extension = MorePaths.getFileExtension(srcPath).toLowerCase();
if (extension.equals("s")) {
asmSrcListBuilder.add(srcPath);
} else if (extension.equals("go")) {
compileSrcListBuilder.add(srcPath);
} else {
headerSrcListBuilder.add(srcPath);
}
}
ImmutableList<Path> compileSrcs = compileSrcListBuilder.build();
ImmutableList<Path> headerSrcs = headerSrcListBuilder.build();
ImmutableList<Path> asmSrcs = asmSrcListBuilder.build();
ImmutableList.Builder<Step> steps = ImmutableList.builder();
steps.add(MkdirStep.of(getProjectFilesystem(), output.getParent()));
Optional<Path> asmHeaderPath;
if (!asmSrcs.isEmpty()) {
asmHeaderPath =
Optional.of(
BuildTargets.getScratchPath(
getProjectFilesystem(),
getBuildTarget(),
"%s/" + getBuildTarget().getShortName() + "__asm_hdr")
.resolve("go_asm.h"));
steps.add(MkdirStep.of(getProjectFilesystem(), asmHeaderPath.get().getParent()));
} else {
asmHeaderPath = Optional.empty();
}
boolean allowExternalReferences = !asmSrcs.isEmpty();
if (compileSrcs.isEmpty()) {
steps.add(new TouchStep(getProjectFilesystem(), output));
} else {
steps.add(
new GoCompileStep(
getProjectFilesystem().getRootPath(),
compiler.getEnvironment(context.getSourcePathResolver()),
compiler.getCommandPrefix(context.getSourcePathResolver()),
compilerFlags,
packageName,
compileSrcs,
importPathMap,
ImmutableList.of(symlinkTree.getRoot()),
asmHeaderPath,
allowExternalReferences,
platform,
output));
}
if (!asmSrcs.isEmpty()) {
Path asmIncludeDir =
BuildTargets.getScratchPath(
getProjectFilesystem(),
getBuildTarget(),
"%s/" + getBuildTarget().getShortName() + "__asm_includes");
steps.addAll(MakeCleanDirectoryStep.of(getProjectFilesystem(), asmIncludeDir));
if (!headerSrcs.isEmpty()) {
// TODO(mikekap): Allow header-map style input.
for (Path header : FluentIterable.from(headerSrcs).append(asmSrcs)) {
steps.add(
SymlinkFileStep.builder()
.setFilesystem(getProjectFilesystem())
.setExistingFile(header)
.setDesiredLink(asmIncludeDir.resolve(header.getFileName()))
.build());
}
}
Path asmOutputDir =
BuildTargets.getScratchPath(
getProjectFilesystem(),
getBuildTarget(),
"%s/" + getBuildTarget().getShortName() + "__asm_compile");
steps.addAll(MakeCleanDirectoryStep.of(getProjectFilesystem(), asmOutputDir));
ImmutableList.Builder<Path> asmOutputs = ImmutableList.builder();
for (Path asmSrc : asmSrcs) {
Path outputPath =
asmOutputDir.resolve(asmSrc.getFileName().toString().replaceAll("\\.[sS]$", ".o"));
steps.add(
new GoAssembleStep(
getProjectFilesystem().getRootPath(),
assembler.getEnvironment(context.getSourcePathResolver()),
assembler.getCommandPrefix(context.getSourcePathResolver()),
assemblerFlags,
asmSrc,
ImmutableList.<Path>builder()
.addAll(assemblerIncludeDirs)
.add(asmHeaderPath.get().getParent())
.add(asmIncludeDir)
.build(),
platform,
outputPath));
asmOutputs.add(outputPath);
}
steps.add(
new GoPackStep(
getProjectFilesystem().getRootPath(),
packer.getEnvironment(context.getSourcePathResolver()),
packer.getCommandPrefix(context.getSourcePathResolver()),
GoPackStep.Operation.APPEND,
asmOutputs.build(),
output));
}
return steps.build();
}
@Override
public SourcePath getSourcePathToOutput() {
return new ExplicitBuildTargetSourcePath(getBuildTarget(), output);
}
@Override
public BuildableProperties getProperties() {
return new BuildableProperties(BuildableProperties.Kind.LIBRARY);
}
}