| /* |
| * Copyright 2014-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.cxx; |
| |
| import com.facebook.buck.rules.AbstractBuildRule; |
| import com.facebook.buck.rules.BuildContext; |
| import com.facebook.buck.rules.BuildRuleParams; |
| import com.facebook.buck.rules.BuildableContext; |
| import com.facebook.buck.rules.RuleKey; |
| import com.facebook.buck.rules.SourcePath; |
| import com.facebook.buck.rules.SourcePathResolver; |
| import com.facebook.buck.step.Step; |
| import com.facebook.buck.step.fs.MkdirStep; |
| import com.google.common.base.Functions; |
| import com.google.common.base.Optional; |
| import com.google.common.collect.FluentIterable; |
| import com.google.common.collect.ImmutableCollection; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSortedSet; |
| import com.google.common.collect.Ordering; |
| |
| import java.nio.file.Path; |
| import java.util.Map; |
| |
| /** |
| * A build rule which preprocesses a C/C++ source. |
| */ |
| public class CxxPreprocess extends AbstractBuildRule { |
| |
| private final Tool preprocessor; |
| private final ImmutableList<String> flags; |
| private final Path output; |
| private final SourcePath input; |
| private final ImmutableList<Path> includeRoots; |
| private final ImmutableList<Path> systemIncludeRoots; |
| private final ImmutableList<Path> frameworkRoots; |
| private final CxxHeaders includes; |
| private final Optional<DebugPathSanitizer> sanitizer; |
| |
| public CxxPreprocess( |
| BuildRuleParams params, |
| SourcePathResolver resolver, |
| Tool preprocessor, |
| ImmutableList<String> flags, |
| Path output, |
| SourcePath input, |
| ImmutableList<Path> includeRoots, |
| ImmutableList<Path> systemIncludeRoots, |
| ImmutableList<Path> frameworkRoots, |
| CxxHeaders includes, |
| Optional<DebugPathSanitizer> sanitizer) { |
| super(params, resolver); |
| this.preprocessor = preprocessor; |
| this.flags = flags; |
| this.output = output; |
| this.input = input; |
| this.includeRoots = includeRoots; |
| this.systemIncludeRoots = systemIncludeRoots; |
| this.frameworkRoots = frameworkRoots; |
| this.includes = includes; |
| this.sanitizer = sanitizer; |
| } |
| |
| @Override |
| protected ImmutableCollection<Path> getInputsToCompareToOutput() { |
| return getResolver().filterInputsToCompareToOutput( |
| ImmutableList.<SourcePath>builder() |
| .addAll(includes.getPrefixHeaders()) |
| .add(input) |
| .build()); |
| } |
| |
| @Override |
| protected RuleKey.Builder appendDetailsToRuleKey(RuleKey.Builder builder) { |
| builder |
| .setReflectively("preprocessor", preprocessor) |
| .setReflectively("output", output.toString()); |
| |
| // Sanitize any relevant paths in the flags we pass to the preprocessor, to prevent them |
| // from contributing to the rule key. |
| ImmutableList<String> flags = this.flags; |
| if (sanitizer.isPresent()) { |
| flags = FluentIterable.from(flags) |
| .transform(sanitizer.get().sanitize(Optional.<Path>absent(), /* expandPaths */ false)) |
| .toList(); |
| } |
| builder.setReflectively("flags", flags); |
| |
| // Hash the layout of each potentially included C/C++ header file and it's contents. |
| // We do this here, rather than returning them from `getInputsToCompareToOutput` so |
| // that we can match the contents hash up with where it was laid out in the include |
| // search path, and therefore can accurately capture header file renames. |
| for (Path path : ImmutableSortedSet.copyOf(includes.getNameToPathMap().keySet())) { |
| SourcePath source = includes.getNameToPathMap().get(path); |
| builder.setReflectively("include(" + path + ")", source); |
| } |
| |
| builder.setReflectively( |
| "frameworkRoots", |
| FluentIterable.from(frameworkRoots) |
| .transform(Functions.toStringFunction()) |
| .toSortedSet(Ordering.natural())); |
| |
| return builder; |
| } |
| |
| @Override |
| public ImmutableList<Step> getBuildSteps( |
| BuildContext context, |
| BuildableContext buildableContext) { |
| buildableContext.recordArtifact(output); |
| |
| // Resolve the map of symlinks to real paths to hand off the preprocess step. |
| ImmutableMap.Builder<Path, Path> replacementPathsBuilder = ImmutableMap.builder(); |
| for (Map.Entry<Path, SourcePath> entry : includes.getFullNameToPathMap().entrySet()) { |
| replacementPathsBuilder.put(entry.getKey(), getResolver().getPath(entry.getValue())); |
| } |
| ImmutableMap<Path, Path> replacementPaths = replacementPathsBuilder.build(); |
| |
| return ImmutableList.of( |
| new MkdirStep(output.getParent()), |
| new CxxPreprocessStep( |
| preprocessor.getCommandPrefix(getResolver()), |
| flags, |
| output, |
| getResolver().getPath(input), |
| FluentIterable.from(includes.getPrefixHeaders()) |
| .transform(getResolver().getPathFunction()) |
| .toList(), |
| includeRoots, |
| systemIncludeRoots, |
| frameworkRoots, |
| replacementPaths, |
| sanitizer)); |
| } |
| |
| @Override |
| public Path getPathToOutputFile() { |
| return output; |
| } |
| |
| public Tool getPreprocessor() { |
| return preprocessor; |
| } |
| |
| public ImmutableList<String> getFlags() { |
| return flags; |
| } |
| |
| public Path getOutput() { |
| return output; |
| } |
| |
| public SourcePath getInput() { |
| return input; |
| } |
| |
| public ImmutableList<Path> getIncludeRoots() { |
| return includeRoots; |
| } |
| |
| public ImmutableList<Path> getSystemIncludeRoots() { |
| return systemIncludeRoots; |
| } |
| |
| public ImmutableList<Path> getFrameworkRoots() { |
| return frameworkRoots; |
| } |
| |
| public CxxHeaders getIncludes() { |
| return includes; |
| } |
| |
| } |