Java tutorial
/* * 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.cxx.toolchain; import com.facebook.buck.core.rulekey.AddToRuleKey; import com.facebook.buck.core.rules.modern.annotations.CustomFieldBehavior; import com.facebook.buck.io.file.MorePaths; import com.facebook.buck.util.RichStream; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import java.nio.file.Path; import java.util.AbstractMap; import java.util.Comparator; import java.util.Map; import java.util.Optional; import java.util.stream.Stream; /** * This sanitizer works by depending on the compiler's -fdebug-prefix-map flag to properly ensure * that the output only contains references to the mapped-to paths (i.e. the fake paths). */ public class PrefixMapDebugPathSanitizer extends DebugPathSanitizer { @AddToRuleKey private final String fakeCompilationDirectory; @CustomFieldBehavior(OtherSerialization.class) private final ImmutableBiMap<Path, String> other; public PrefixMapDebugPathSanitizer(String fakeCompilationDirectory, ImmutableBiMap<Path, String> other, boolean useUnixPathSeparator) { super(useUnixPathSeparator); this.fakeCompilationDirectory = fakeCompilationDirectory; this.other = other; } public PrefixMapDebugPathSanitizer(String fakeCompilationDirectory, ImmutableBiMap<Path, String> other) { this(fakeCompilationDirectory, other, false); } @Override public String getCompilationDirectory() { return useUnixPathSeparator ? MorePaths.pathWithUnixSeparators(fakeCompilationDirectory) : fakeCompilationDirectory; } @Override public ImmutableMap<String, String> getCompilationEnvironment(Path workingDir, boolean shouldSanitize) { return ImmutableMap.of("PWD", useUnixPathSeparator ? MorePaths.pathWithUnixSeparators(workingDir.toString()) : workingDir.toString()); } @Override public void restoreCompilationDirectory(Path path, Path workingDir) { // There should be nothing to sanitize in the compilation directory because the compilation // flags took care of it. } @Override public ImmutableList<String> getCompilationFlags(Compiler compiler, Path workingDir, ImmutableMap<Path, Path> prefixMap) { if (compiler instanceof WindowsCompiler) { return ImmutableList.of(); } ImmutableList.Builder<String> flags = ImmutableList.builder(); // As these replacements are processed one at a time, if one is a prefix (or actually is just // contained in) another, it must be processed after that other one. To ensure that we can // process them in the correct order, they are inserted into allPaths in order of length // (shortest first) so that prefixes will be handled correctly. RichStream.<Map.Entry<Path, String>>empty() // GCC has a bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71850) where it won't // properly pass arguments down to subprograms using argsfiles, which can make it prone to // argument list too long errors, so avoid adding `-fdebug-prefix-map` flags for each // `prefixMap` entry. .concat(compiler instanceof GccCompiler ? Stream.empty() : prefixMap.entrySet().stream().map(e -> new AbstractMap.SimpleEntry<>(e.getKey(), useUnixPathSeparator ? MorePaths.pathWithUnixSeparators(e.getValue().toString()) : e.getValue().toString()))) .concat(RichStream.from(getAllPaths(Optional.of(workingDir)))) .sorted(Comparator.<Map.Entry<Path, String>>comparingInt( entry -> entry.getKey().toString().length()).thenComparing(entry -> entry.getKey())) .map(p -> getDebugPrefixMapFlag(p.getKey(), p.getValue())).forEach(flags::add); if (compiler instanceof GccCompiler) { // If we recorded switches in the debug info, the -fdebug-prefix-map values would contain the // unsanitized paths. flags.add("-gno-record-gcc-switches"); } return flags.build(); } private String getDebugPrefixMapFlag(Path realPath, String fakePath) { String realPathStr = useUnixPathSeparator ? MorePaths.pathWithUnixSeparators(realPath) : realPath.toString(); // If we're replacing the real path with an empty fake path, then also remove the trailing `/` // to prevent forming an absolute path. if (fakePath.isEmpty()) { realPathStr += "/"; } return String.format("-fdebug-prefix-map=%s=%s", realPathStr, fakePath); } @Override protected Iterable<Map.Entry<Path, String>> getAllPaths(Optional<Path> workingDir) { if (!workingDir.isPresent()) { return other.entrySet(); } return Iterables.concat(other.entrySet(), ImmutableList.of(new AbstractMap.SimpleEntry<>(workingDir.get(), useUnixPathSeparator ? MorePaths.pathWithUnixSeparators(fakeCompilationDirectory) : fakeCompilationDirectory))); } }