Java tutorial
/* * Copyright 2015-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.features.halide; import com.facebook.buck.apple.AppleCustomLinkingDepsDescription; import com.facebook.buck.core.cell.CellPathResolver; import com.facebook.buck.core.description.arg.CommonDescriptionArg; import com.facebook.buck.core.exceptions.HumanReadableException; import com.facebook.buck.core.model.BuildTarget; import com.facebook.buck.core.model.Flavor; import com.facebook.buck.core.model.FlavorDomain; import com.facebook.buck.core.model.Flavored; import com.facebook.buck.core.model.InternalFlavor; import com.facebook.buck.core.model.targetgraph.BuildRuleCreationContextWithTargetGraph; import com.facebook.buck.core.model.targetgraph.DescriptionWithTargetGraph; import com.facebook.buck.core.rules.ActionGraphBuilder; import com.facebook.buck.core.rules.BuildRule; import com.facebook.buck.core.rules.BuildRuleParams; import com.facebook.buck.core.rules.SourcePathRuleFinder; import com.facebook.buck.core.rules.common.BuildableSupport; import com.facebook.buck.core.rules.impl.NoopBuildRuleWithDeclaredAndExtraDeps; import com.facebook.buck.core.sourcepath.ExplicitBuildTargetSourcePath; import com.facebook.buck.core.sourcepath.SourcePath; import com.facebook.buck.core.sourcepath.SourceWithFlags; import com.facebook.buck.core.sourcepath.resolver.SourcePathResolver; import com.facebook.buck.core.sourcepath.resolver.impl.DefaultSourcePathResolver; import com.facebook.buck.core.toolchain.ToolchainProvider; import com.facebook.buck.core.util.immutables.BuckStyleImmutable; import com.facebook.buck.cxx.Archive; import com.facebook.buck.cxx.CxxBinary; import com.facebook.buck.cxx.CxxBinaryDescription; import com.facebook.buck.cxx.CxxDescriptionEnhancer; import com.facebook.buck.cxx.CxxFlags.TranslateMacrosFunction; import com.facebook.buck.cxx.CxxLinkAndCompileRules; import com.facebook.buck.cxx.CxxLinkOptions; import com.facebook.buck.cxx.CxxSource; import com.facebook.buck.cxx.CxxStrip; import com.facebook.buck.cxx.toolchain.CxxBuckConfig; import com.facebook.buck.cxx.toolchain.CxxPlatform; import com.facebook.buck.cxx.toolchain.CxxPlatforms; import com.facebook.buck.cxx.toolchain.CxxPlatformsProvider; import com.facebook.buck.cxx.toolchain.HeaderVisibility; import com.facebook.buck.cxx.toolchain.LinkerMapMode; import com.facebook.buck.cxx.toolchain.PicType; import com.facebook.buck.cxx.toolchain.StripStyle; import com.facebook.buck.cxx.toolchain.UnresolvedCxxPlatform; import com.facebook.buck.cxx.toolchain.linker.Linker; import com.facebook.buck.io.filesystem.ProjectFilesystem; import com.facebook.buck.rules.args.AddsToRuleKeyFunction; import com.facebook.buck.rules.coercer.PatternMatchedCollection; import com.facebook.buck.rules.macros.StringWithMacros; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedSet; import java.nio.file.Path; import java.util.Optional; import java.util.regex.Pattern; import org.immutables.value.Value; public class HalideLibraryDescription implements DescriptionWithTargetGraph<HalideLibraryDescriptionArg>, Flavored, AppleCustomLinkingDepsDescription { public static final Flavor HALIDE_COMPILER_FLAVOR = InternalFlavor.of("halide-compiler"); public static final Flavor HALIDE_COMPILE_FLAVOR = InternalFlavor.of("halide-compile"); private final ToolchainProvider toolchainProvider; private final CxxBuckConfig cxxBuckConfig; private final HalideBuckConfig halideBuckConfig; public HalideLibraryDescription(ToolchainProvider toolchainProvider, CxxBuckConfig cxxBuckConfig, HalideBuckConfig halideBuckConfig) { this.toolchainProvider = toolchainProvider; this.cxxBuckConfig = cxxBuckConfig; this.halideBuckConfig = halideBuckConfig; } @Override public boolean hasFlavors(ImmutableSet<Flavor> flavors) { return getCxxPlatformsProvider().getUnresolvedCxxPlatforms().containsAnyOf(flavors) || flavors.contains(HALIDE_COMPILE_FLAVOR) || flavors.contains(HALIDE_COMPILER_FLAVOR) || StripStyle.FLAVOR_DOMAIN.containsAnyOf(flavors); } @Override public Class<HalideLibraryDescriptionArg> getConstructorArgType() { return HalideLibraryDescriptionArg.class; } public static BuildTarget createHalideCompilerBuildTarget(BuildTarget target) { return target.withFlavors(HALIDE_COMPILER_FLAVOR); } public static boolean isPlatformSupported(HalideLibraryDescriptionArg arg, CxxPlatform cxxPlatform) { return !arg.getSupportedPlatformsRegex().isPresent() || arg.getSupportedPlatformsRegex().get().matcher(cxxPlatform.getFlavor().toString()).find(); } private CxxBinary createHalideCompiler(BuildTarget buildTarget, ProjectFilesystem projectFilesystem, BuildRuleParams params, ActionGraphBuilder graphBuilder, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, CellPathResolver cellRoots, CxxPlatformsProvider cxxPlatformsProvider, CxxPlatform cxxPlatform, ImmutableSortedSet<SourceWithFlags> halideSources, ImmutableList<StringWithMacros> compilerFlags, PatternMatchedCollection<ImmutableList<StringWithMacros>> platformCompilerFlags, ImmutableMap<CxxSource.Type, ImmutableList<StringWithMacros>> langCompilerFlags, ImmutableList<StringWithMacros> linkerFlags, PatternMatchedCollection<ImmutableList<StringWithMacros>> platformLinkerFlags, ImmutableSortedSet<SourcePath> rawHeaders) { Optional<StripStyle> flavoredStripStyle = StripStyle.FLAVOR_DOMAIN.getValue(buildTarget); Optional<LinkerMapMode> flavoredLinkerMapMode = LinkerMapMode.FLAVOR_DOMAIN.getValue(buildTarget); buildTarget = CxxStrip.removeStripStyleFlavorInTarget(buildTarget, flavoredStripStyle); buildTarget = LinkerMapMode.removeLinkerMapModeFlavorInTarget(buildTarget, flavoredLinkerMapMode); ImmutableMap<String, CxxSource> srcs = CxxDescriptionEnhancer.parseCxxSources(buildTarget, graphBuilder, ruleFinder, pathResolver, cxxPlatform, halideSources, PatternMatchedCollection.of()); CxxLinkAndCompileRules cxxLinkAndCompileRules = CxxDescriptionEnhancer.createBuildRulesForCxxBinary( buildTarget, projectFilesystem, graphBuilder, cellRoots, cxxBuckConfig, cxxPlatform, srcs, /* headers */ ImmutableMap.of(), params.getBuildDeps(), ImmutableSet.of(), flavoredStripStyle, flavoredLinkerMapMode, Linker.LinkableDepType.STATIC, CxxLinkOptions.of(), ImmutableList.of(), PatternMatchedCollection.of(), ImmutableMap.of(), ImmutableMap.of(), ImmutableSortedSet.of(), ImmutableSortedSet.of(), compilerFlags, langCompilerFlags, platformCompilerFlags, ImmutableMap.of(), Optional.empty(), Optional.empty(), linkerFlags, ImmutableList.of(), platformLinkerFlags, Optional.empty(), rawHeaders, Optional.empty()); buildTarget = CxxStrip.restoreStripStyleFlavorInTarget(buildTarget, flavoredStripStyle); buildTarget = LinkerMapMode.restoreLinkerMapModeFlavorInTarget(buildTarget, flavoredLinkerMapMode); return new CxxBinary(buildTarget, projectFilesystem, params.copyAppendingExtraDeps( BuildableSupport.getDepsCollection(cxxLinkAndCompileRules.executable, ruleFinder)), cxxPlatform, cxxLinkAndCompileRules.getBinaryRule(), cxxLinkAndCompileRules.executable, ImmutableSortedSet.of(), ImmutableSortedSet.of(), buildTarget.withoutFlavors(cxxPlatformsProvider.getUnresolvedCxxPlatforms().getFlavors()), cxxBuckConfig.shouldCacheBinaries()); } private BuildRule createHalideStaticLibrary(BuildTarget buildTarget, ProjectFilesystem projectFilesystem, BuildRuleParams params, ActionGraphBuilder graphBuilder, SourcePathRuleFinder ruleFinder, CxxPlatform platform, HalideLibraryDescriptionArg args) { if (!isPlatformSupported(args, platform)) { return new NoopBuildRuleWithDeclaredAndExtraDeps(buildTarget, projectFilesystem, params); } BuildRule halideCompile = graphBuilder .requireRule(buildTarget.withFlavors(HALIDE_COMPILE_FLAVOR, platform.getFlavor())); BuildTarget halideCompileBuildTarget = halideCompile.getBuildTarget(); return Archive.from(buildTarget, projectFilesystem, graphBuilder, ruleFinder, platform, CxxDescriptionEnhancer.getStaticLibraryPath(projectFilesystem, buildTarget, platform.getFlavor(), PicType.PIC, Optional.empty(), platform.getStaticLibraryExtension(), cxxBuckConfig .isUniqueLibraryNameEnabled()), ImmutableList.of(ExplicitBuildTargetSourcePath.of(halideCompileBuildTarget, HalideCompile .objectOutputPath(halideCompileBuildTarget, projectFilesystem, args.getFunctionName()))), /* cacheable */ true); } private Optional<ImmutableList<String>> expandInvocationFlags(Optional<ImmutableList<String>> optionalFlags, CxxPlatform platform) { if (optionalFlags.isPresent()) { AddsToRuleKeyFunction<String, String> macroMapper = new TranslateMacrosFunction( ImmutableSortedMap.copyOf(platform.getFlagMacros()), platform); ImmutableList<String> flags = optionalFlags.get(); ImmutableList.Builder<String> builder = ImmutableList.builder(); for (String flag : flags) { builder.add(macroMapper.apply(flag)); } optionalFlags = Optional.of(builder.build()); } return optionalFlags; } private BuildRule createHalideCompile(BuildTarget buildTarget, ProjectFilesystem projectFilesystem, BuildRuleParams params, ActionGraphBuilder graphBuilder, CxxPlatform platform, Optional<ImmutableList<String>> compilerInvocationFlags, Optional<String> functionName) { CxxBinary halideCompiler = (CxxBinary) graphBuilder .requireRule(buildTarget.withFlavors(HALIDE_COMPILER_FLAVOR)); return new HalideCompile(buildTarget, projectFilesystem, params.withExtraDeps(ImmutableSortedSet.of(halideCompiler)), halideCompiler.getExecutableCommand(), halideBuckConfig.getHalideTargetForPlatform(platform), expandInvocationFlags(compilerInvocationFlags, platform), functionName); } @Override public BuildRule createBuildRule(BuildRuleCreationContextWithTargetGraph context, BuildTarget buildTarget, BuildRuleParams params, HalideLibraryDescriptionArg args) { CxxPlatformsProvider cxxPlatformsProvider = getCxxPlatformsProvider(); FlavorDomain<UnresolvedCxxPlatform> cxxPlatforms = cxxPlatformsProvider.getUnresolvedCxxPlatforms(); ActionGraphBuilder graphBuilder = context.getActionGraphBuilder(); SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(graphBuilder); SourcePathResolver pathResolver = DefaultSourcePathResolver.from(ruleFinder); ImmutableSet<Flavor> flavors = ImmutableSet.copyOf(buildTarget.getFlavors()); // TODO(cjhopman): This description doesn't handle parse time deps correctly. CxxPlatform cxxPlatform = cxxPlatforms.getValue(flavors) .orElse(cxxPlatformsProvider.getDefaultUnresolvedCxxPlatform()).resolve(graphBuilder); ProjectFilesystem projectFilesystem = context.getProjectFilesystem(); if (flavors.contains(CxxDescriptionEnhancer.EXPORTED_HEADER_SYMLINK_TREE_FLAVOR)) { ImmutableMap.Builder<Path, SourcePath> headersBuilder = ImmutableMap.builder(); BuildTarget compileTarget = graphBuilder .requireRule(buildTarget.withFlavors(HALIDE_COMPILE_FLAVOR, cxxPlatform.getFlavor())) .getBuildTarget(); Path outputPath = HalideCompile.headerOutputPath(compileTarget, projectFilesystem, args.getFunctionName()); headersBuilder.put(outputPath.getFileName(), ExplicitBuildTargetSourcePath.of(compileTarget, outputPath)); return CxxDescriptionEnhancer.createHeaderSymlinkTree(buildTarget, projectFilesystem, ruleFinder, graphBuilder, cxxPlatform, headersBuilder.build(), HeaderVisibility.PUBLIC, true); } else if (flavors.contains(HALIDE_COMPILER_FLAVOR)) { // We always want to build the halide "compiler" for the host platform, so // we use the host flavor here, regardless of the flavors on the build // target. CxxPlatform hostCxxPlatform = cxxPlatforms.getValue(CxxPlatforms.getHostFlavor()).resolve(graphBuilder); ImmutableSortedSet<BuildTarget> compilerDeps = args.getCompilerDeps(); return createHalideCompiler(buildTarget, projectFilesystem, params.withDeclaredDeps(graphBuilder.getAllRules(compilerDeps)).withoutExtraDeps(), graphBuilder, pathResolver, ruleFinder, context.getCellPathResolver(), cxxPlatformsProvider, hostCxxPlatform, args.getSrcs(), args.getCompilerFlags(), args.getPlatformCompilerFlags(), args.getLangCompilerFlags(), args.getLinkerFlags(), args.getPlatformLinkerFlags(), args.getRawHeaders()); } else if (flavors.contains(CxxDescriptionEnhancer.STATIC_FLAVOR) || flavors.contains(CxxDescriptionEnhancer.STATIC_PIC_FLAVOR)) { // Halide always output PIC, so it's output can be used for both cases. // See: https://github.com/halide/Halide/blob/e3c301f3/src/LLVM_Output.cpp#L152 return createHalideStaticLibrary(buildTarget, projectFilesystem, params, graphBuilder, ruleFinder, cxxPlatform, args); } else if (flavors.contains(CxxDescriptionEnhancer.SHARED_FLAVOR)) { throw new HumanReadableException("halide_library '%s' does not support shared libraries as output", buildTarget); } else if (flavors.contains(HALIDE_COMPILE_FLAVOR)) { return createHalideCompile(buildTarget, projectFilesystem, params.withoutDeclaredDeps().withoutExtraDeps(), graphBuilder, cxxPlatform, Optional.of(args.getCompilerInvocationFlags()), args.getFunctionName()); } return new HalideLibrary(buildTarget, projectFilesystem, params, graphBuilder, args.getSupportedPlatformsRegex()); } private CxxPlatformsProvider getCxxPlatformsProvider() { return toolchainProvider.getByName(CxxPlatformsProvider.DEFAULT_NAME, CxxPlatformsProvider.class); } @Override public ImmutableSortedSet<BuildTarget> getCustomLinkingDeps(CommonDescriptionArg args) { return ((HalideLibraryDescriptionArg) args).getDeps(); } @BuckStyleImmutable @Value.Immutable(copy = true) interface AbstractHalideLibraryDescriptionArg extends CxxBinaryDescription.CommonArg { @Value.NaturalOrder ImmutableSortedSet<BuildTarget> getCompilerDeps(); @Value.NaturalOrder ImmutableSortedMap<String, ImmutableMap<String, String>> getConfigs(); Optional<Pattern> getSupportedPlatformsRegex(); ImmutableList<String> getCompilerInvocationFlags(); Optional<String> getFunctionName(); } }