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.haskell; import com.facebook.buck.cxx.CxxDescriptionEnhancer; import com.facebook.buck.cxx.CxxPlatform; import com.facebook.buck.cxx.Linker; import com.facebook.buck.cxx.Linkers; import com.facebook.buck.cxx.NativeLinkable; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.Flavor; import com.facebook.buck.model.FlavorConvertible; import com.facebook.buck.model.FlavorDomain; import com.facebook.buck.model.Flavored; import com.facebook.buck.model.ImmutableFlavor; import com.facebook.buck.parser.NoSuchBuildTargetException; import com.facebook.buck.rules.BinaryWrapperRule; import com.facebook.buck.rules.BuildRule; import com.facebook.buck.rules.BuildRuleParams; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.BuildTargetSourcePath; import com.facebook.buck.rules.CellPathResolver; import com.facebook.buck.rules.CommandTool; import com.facebook.buck.rules.Description; import com.facebook.buck.rules.ImplicitDepsInferringDescription; import com.facebook.buck.rules.SourcePathRuleFinder; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.rules.SymlinkTree; import com.facebook.buck.rules.TargetGraph; import com.facebook.buck.rules.Tool; import com.facebook.buck.rules.args.SourcePathArg; import com.facebook.buck.rules.coercer.SourceList; import com.facebook.buck.util.MoreIterables; import com.facebook.buck.versions.VersionRoot; import com.facebook.infer.annotation.SuppressFieldNotInitialized; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import java.nio.file.Path; import java.util.Optional; public class HaskellBinaryDescription implements Description<HaskellBinaryDescription.Arg>, ImplicitDepsInferringDescription<HaskellBinaryDescription.Arg>, Flavored, VersionRoot<HaskellBinaryDescription.Arg> { private static final FlavorDomain<Type> BINARY_TYPE = FlavorDomain.from("Haskell Binary Type", Type.class); private final HaskellConfig haskellConfig; private final FlavorDomain<CxxPlatform> cxxPlatforms; private final CxxPlatform defaultCxxPlatform; public HaskellBinaryDescription(HaskellConfig haskellConfig, FlavorDomain<CxxPlatform> cxxPlatforms, CxxPlatform defaultCxxPlatform) { this.haskellConfig = haskellConfig; this.cxxPlatforms = cxxPlatforms; this.defaultCxxPlatform = defaultCxxPlatform; } @Override public Arg createUnpopulatedConstructorArg() { return new Arg(); } private Linker.LinkableDepType getLinkStyle(BuildTarget target, Arg arg) { Optional<Type> type = BINARY_TYPE.getValue(target); if (type.isPresent()) { return type.get().getLinkStyle(); } if (arg.linkStyle.isPresent()) { return arg.linkStyle.get(); } return Linker.LinkableDepType.STATIC; } @Override public <A extends Arg> BuildRule createBuildRule(TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) throws NoSuchBuildTargetException { SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver); SourcePathResolver pathResolver = new SourcePathResolver(ruleFinder); CxxPlatform cxxPlatform = cxxPlatforms.getValue(params.getBuildTarget()).orElse(defaultCxxPlatform); Linker.LinkableDepType depType = getLinkStyle(params.getBuildTarget(), args); // The target to use for the link rule. BuildTarget binaryTarget = params.getBuildTarget().withFlavors(cxxPlatform.getFlavor(), ImmutableFlavor.of("binary")); ImmutableList.Builder<String> linkFlagsBuilder = ImmutableList.builder(); ImmutableList.Builder<com.facebook.buck.rules.args.Arg> linkArgsBuilder = ImmutableList.builder(); CommandTool.Builder executableBuilder = new CommandTool.Builder(); // Add the binary as the first argument. executableBuilder.addArg(new SourcePathArg(pathResolver, new BuildTargetSourcePath(binaryTarget))); // Special handling for dynamically linked binaries. if (depType == Linker.LinkableDepType.SHARED) { // Create a symlink tree with for all shared libraries needed by this binary. SymlinkTree sharedLibraries = resolver.addToIndex(CxxDescriptionEnhancer.createSharedLibrarySymlinkTree( params, pathResolver, cxxPlatform, params.getDeps(), NativeLinkable.class::isInstance)); // Embed a origin-relative library path into the binary so it can find the shared libraries. // The shared libraries root is absolute. Also need an absolute path to the linkOutput Path absBinaryDir = params.getBuildTarget().getCellPath() .resolve(HaskellLinkRule.getOutputDir(binaryTarget, params.getProjectFilesystem())); linkFlagsBuilder.addAll(MoreIterables.zipAndConcat(Iterables.cycle("-optl"), Linkers.iXlinker("-rpath", String.format("%s/%s", cxxPlatform.getLd().resolve(resolver).origin(), absBinaryDir.relativize(sharedLibraries.getRoot()).toString())))); // Add all the shared libraries and the symlink tree as inputs to the tool that represents // this binary, so that users can attach the proper deps. executableBuilder.addDep(sharedLibraries); executableBuilder.addInputs(sharedLibraries.getLinks().values()); } // Generate the compile rule and add its objects to the link. HaskellCompileRule compileRule = resolver.addToIndex(HaskellDescriptionUtils.requireCompileRule(params, resolver, pathResolver, ruleFinder, cxxPlatform, haskellConfig, depType, args.main, Optional.empty(), args.compilerFlags, HaskellSources.from(params.getBuildTarget(), resolver, pathResolver, ruleFinder, cxxPlatform, "srcs", args.srcs))); linkArgsBuilder.addAll(SourcePathArg.from(pathResolver, compileRule.getObjects())); ImmutableList<String> linkFlags = linkFlagsBuilder.build(); ImmutableList<com.facebook.buck.rules.args.Arg> linkArgs = linkArgsBuilder.build(); final CommandTool executable = executableBuilder.build(); final HaskellLinkRule linkRule = HaskellDescriptionUtils.createLinkRule(binaryTarget, params, resolver, pathResolver, ruleFinder, cxxPlatform, haskellConfig, Linker.LinkType.EXECUTABLE, linkFlags, linkArgs, FluentIterable.from(params.getDeps()).filter(NativeLinkable.class), depType); return new BinaryWrapperRule(params.appendExtraDeps(linkRule), pathResolver, ruleFinder) { @Override public Tool getExecutableCommand() { return executable; } @Override public Path getPathToOutput() { return linkRule.getPathToOutput(); } }; } @Override public Iterable<BuildTarget> findDepsForTargetFromConstructorArgs(BuildTarget buildTarget, CellPathResolver cellRoots, Arg constructorArg) { return HaskellDescriptionUtils.getParseTimeDeps(haskellConfig, ImmutableList.of(cxxPlatforms.getValue(buildTarget.getFlavors()).orElse(defaultCxxPlatform))); } @Override public boolean hasFlavors(ImmutableSet<Flavor> flavors) { if (cxxPlatforms.containsAnyOf(flavors)) { return true; } for (Type type : Type.values()) { if (flavors.contains(type.getFlavor())) { return true; } } return false; } @Override public boolean isVersionRoot(ImmutableSet<Flavor> flavors) { return true; } protected enum Type implements FlavorConvertible { SHARED(CxxDescriptionEnhancer.SHARED_FLAVOR, Linker.LinkableDepType.SHARED), STATIC_PIC( CxxDescriptionEnhancer.STATIC_PIC_FLAVOR, Linker.LinkableDepType.STATIC_PIC), STATIC( CxxDescriptionEnhancer.STATIC_FLAVOR, Linker.LinkableDepType.STATIC),; private final Flavor flavor; private final Linker.LinkableDepType linkStyle; Type(Flavor flavor, Linker.LinkableDepType linkStyle) { this.flavor = flavor; this.linkStyle = linkStyle; } @Override public Flavor getFlavor() { return flavor; } public Linker.LinkableDepType getLinkStyle() { return linkStyle; } } @SuppressFieldNotInitialized public static class Arg { public SourceList srcs = SourceList.EMPTY; public ImmutableList<String> compilerFlags = ImmutableList.of(); public ImmutableSortedSet<BuildTarget> deps = ImmutableSortedSet.of(); public Optional<String> main; public Optional<Linker.LinkableDepType> linkStyle; } }