Java tutorial
/* * Copyright 2017-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.core.cell.CellPathResolver; import com.facebook.buck.core.model.BuildTarget; import com.facebook.buck.core.model.Flavor; import com.facebook.buck.core.rules.ActionGraphBuilder; import com.facebook.buck.core.toolchain.ToolchainProvider; import com.facebook.buck.cxx.CxxLibraryDescription.CommonArg; import com.facebook.buck.cxx.CxxPreprocessorInput.Builder; import com.facebook.buck.cxx.toolchain.CxxPlatform; import com.facebook.buck.cxx.toolchain.CxxPlatformsProvider; import com.facebook.buck.cxx.toolchain.HeaderMode; import com.facebook.buck.cxx.toolchain.HeaderSymlinkTree; import com.facebook.buck.cxx.toolchain.HeaderVisibility; import com.facebook.buck.cxx.toolchain.UnresolvedCxxPlatform; import com.facebook.buck.rules.args.Arg; import com.facebook.buck.rules.macros.StringWithMacros; import com.google.common.base.Function; import com.google.common.collect.Multimaps; import java.util.Map; import java.util.Optional; public class CxxLibraryMetadataFactory { private final ToolchainProvider toolchainProvider; public CxxLibraryMetadataFactory(ToolchainProvider toolchainProvider) { this.toolchainProvider = toolchainProvider; } public <U> Optional<U> createMetadata(BuildTarget buildTarget, ActionGraphBuilder graphBuilder, CellPathResolver cellRoots, CxxLibraryDescriptionArg args, Class<U> metadataClass) { Map.Entry<Flavor, CxxLibraryDescription.MetadataType> type = CxxLibraryDescription.METADATA_TYPE .getFlavorAndValue(buildTarget).orElseThrow(IllegalArgumentException::new); BuildTarget baseTarget = buildTarget.withoutFlavors(type.getKey()); switch (type.getValue()) { case CXX_HEADERS: { Optional<CxxHeaders> symlinkTree = Optional.empty(); if (!args.getExportedHeaders().isEmpty()) { HeaderMode mode = CxxLibraryDescription.HEADER_MODE.getRequiredValue(buildTarget); baseTarget = baseTarget.withoutFlavors(mode.getFlavor()); symlinkTree = Optional.of(CxxSymlinkTreeHeaders.from((HeaderSymlinkTree) graphBuilder .requireRule(baseTarget.withoutFlavors(CxxLibraryDescription.LIBRARY_TYPE.getFlavors()) .withAppendedFlavors(CxxLibraryDescription.Type.EXPORTED_HEADERS.getFlavor(), mode.getFlavor())), CxxPreprocessables.IncludeType.LOCAL)); } return symlinkTree.map(metadataClass::cast); } case CXX_PREPROCESSOR_INPUT: { Map.Entry<Flavor, UnresolvedCxxPlatform> platform = getCxxPlatformsProvider() .getUnresolvedCxxPlatforms().getFlavorAndValue(buildTarget) .orElseThrow(() -> new IllegalArgumentException(String.format( "%s: cannot extract platform from target flavors (available platforms: %s)", buildTarget, getCxxPlatformsProvider().getUnresolvedCxxPlatforms().getFlavors()))); Map.Entry<Flavor, HeaderVisibility> visibility = CxxLibraryDescription.HEADER_VISIBILITY .getFlavorAndValue(buildTarget) .orElseThrow(() -> new IllegalArgumentException(String.format( "%s: cannot extract visibility from target flavors (available options: %s)", buildTarget, CxxLibraryDescription.HEADER_VISIBILITY.getFlavors()))); baseTarget = baseTarget.withoutFlavors(platform.getKey(), visibility.getKey()); CxxPreprocessorInput.Builder cxxPreprocessorInputBuilder = CxxPreprocessorInput.builder(); // TODO(agallagher): We currently always add exported flags and frameworks to the // preprocessor input to mimic existing behavior, but this should likely be fixed. CxxPlatform cxxPlatform = platform.getValue().resolve(graphBuilder); addCxxPreprocessorInputFromArgs(cxxPreprocessorInputBuilder, args, cxxPlatform, f -> CxxDescriptionEnhancer.toStringWithMacrosArgs(buildTarget, cellRoots, graphBuilder, cxxPlatform, f)); if (visibility.getValue() == HeaderVisibility.PRIVATE && !args.getHeaders().isEmpty()) { HeaderSymlinkTree symlinkTree = (HeaderSymlinkTree) graphBuilder.requireRule(baseTarget .withAppendedFlavors(platform.getKey(), CxxLibraryDescription.Type.HEADERS.getFlavor())); cxxPreprocessorInputBuilder .addIncludes(CxxSymlinkTreeHeaders.from(symlinkTree, CxxPreprocessables.IncludeType.LOCAL)); } if (visibility.getValue() == HeaderVisibility.PUBLIC) { // Add platform-agnostic headers. queryMetadataCxxHeaders(graphBuilder, baseTarget, CxxDescriptionEnhancer.getHeaderModeForPlatform(graphBuilder, cxxPlatform, args.getXcodePublicHeadersSymlinks() .orElse(cxxPlatform.getPublicHeadersSymlinksEnabled()))) .ifPresent(cxxPreprocessorInputBuilder::addIncludes); // Add platform-specific headers. if (!args.getExportedPlatformHeaders().getMatchingValues(platform.getKey().toString()).isEmpty()) { HeaderSymlinkTree symlinkTree = (HeaderSymlinkTree) graphBuilder.requireRule(baseTarget .withoutFlavors(CxxLibraryDescription.LIBRARY_TYPE.getFlavors()).withAppendedFlavors( CxxLibraryDescription.Type.EXPORTED_HEADERS.getFlavor(), platform.getKey())); cxxPreprocessorInputBuilder.addIncludes( CxxSymlinkTreeHeaders.from(symlinkTree, CxxPreprocessables.IncludeType.LOCAL)); } if (!args.getRawHeaders().isEmpty()) { cxxPreprocessorInputBuilder.addIncludes(CxxRawHeaders.of(args.getRawHeaders())); } } CxxPreprocessorInput cxxPreprocessorInput = cxxPreprocessorInputBuilder.build(); return Optional.of(cxxPreprocessorInput).map(metadataClass::cast); } } throw new IllegalStateException(String.format("unhandled metadata type: %s", type.getValue())); } public static void addCxxPreprocessorInputFromArgs(Builder cxxPreprocessorInputBuilder, CommonArg args, CxxPlatform platform, Function<StringWithMacros, Arg> stringWithMacrosArgFunction) { cxxPreprocessorInputBuilder.putAllPreprocessorFlags( Multimaps.transformValues(CxxFlags.getLanguageFlagsWithMacros(args.getExportedPreprocessorFlags(), args.getExportedPlatformPreprocessorFlags(), args.getExportedLangPreprocessorFlags(), args.getExportedLangPlatformPreprocessorFlags(), platform), stringWithMacrosArgFunction)); cxxPreprocessorInputBuilder.addAllFrameworks(args.getFrameworks()); } /** * Convenience function to query the {@link CxxHeaders} metadata of a target. * * <p>Use this function instead of constructing the BuildTarget manually. */ private static Optional<CxxHeaders> queryMetadataCxxHeaders(ActionGraphBuilder graphBuilder, BuildTarget baseTarget, HeaderMode mode) { return graphBuilder.requireMetadata(baseTarget.withAppendedFlavors( CxxLibraryDescription.MetadataType.CXX_HEADERS.getFlavor(), mode.getFlavor()), CxxHeaders.class); } private CxxPlatformsProvider getCxxPlatformsProvider() { return toolchainProvider.getByName(CxxPlatformsProvider.DEFAULT_NAME, CxxPlatformsProvider.class); } }