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.lua; import com.facebook.buck.core.cell.CellPathResolver; import com.facebook.buck.core.description.arg.CommonDescriptionArg; import com.facebook.buck.core.description.arg.HasDeclaredDeps; import com.facebook.buck.core.description.attr.ImplicitDepsInferringDescription; 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.InternalFlavor; import com.facebook.buck.core.model.impl.BuildTargetPaths; import com.facebook.buck.core.model.targetgraph.BuildRuleCreationContextWithTargetGraph; import com.facebook.buck.core.model.targetgraph.DescriptionWithTargetGraph; import com.facebook.buck.core.rulekey.AddToRuleKey; 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.SymlinkTree; import com.facebook.buck.core.sourcepath.NonHashableSourcePathContainer; import com.facebook.buck.core.sourcepath.SourcePath; 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.toolchain.tool.Tool; import com.facebook.buck.core.toolchain.tool.impl.CommandTool; import com.facebook.buck.core.util.graph.AbstractBreadthFirstTraversal; import com.facebook.buck.core.util.immutables.BuckStyleImmutable; import com.facebook.buck.cxx.Omnibus; import com.facebook.buck.cxx.OmnibusLibraries; import com.facebook.buck.cxx.OmnibusLibrary; import com.facebook.buck.cxx.OmnibusRoot; import com.facebook.buck.cxx.OmnibusRoots; import com.facebook.buck.cxx.toolchain.CxxBuckConfig; import com.facebook.buck.cxx.toolchain.CxxPlatform; import com.facebook.buck.cxx.toolchain.nativelink.NativeLinkStrategy; import com.facebook.buck.cxx.toolchain.nativelink.NativeLinkTarget; import com.facebook.buck.cxx.toolchain.nativelink.NativeLinkTargetMode; import com.facebook.buck.cxx.toolchain.nativelink.NativeLinkable; import com.facebook.buck.cxx.toolchain.nativelink.NativeLinkables; import com.facebook.buck.features.python.CxxPythonExtension; import com.facebook.buck.features.python.PythonBinaryDescription; import com.facebook.buck.features.python.PythonPackagable; import com.facebook.buck.features.python.PythonPackageComponents; import com.facebook.buck.features.python.toolchain.PythonPlatform; import com.facebook.buck.features.python.toolchain.PythonPlatformsProvider; import com.facebook.buck.io.file.MorePaths; import com.facebook.buck.io.filesystem.ProjectFilesystem; import com.facebook.buck.rules.args.SourcePathArg; import com.facebook.buck.rules.coercer.PatternMatchedCollection; import com.facebook.buck.util.MoreMaps; import com.facebook.buck.util.Optionals; import com.facebook.buck.versions.VersionRoot; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.immutables.value.Value; public class LuaBinaryDescription implements DescriptionWithTargetGraph<LuaBinaryDescriptionArg>, ImplicitDepsInferringDescription<LuaBinaryDescription.AbstractLuaBinaryDescriptionArg>, VersionRoot<LuaBinaryDescriptionArg> { private static final Flavor BINARY_FLAVOR = InternalFlavor.of("binary"); private final ToolchainProvider toolchainProvider; private final CxxBuckConfig cxxBuckConfig; public LuaBinaryDescription(ToolchainProvider toolchainProvider, CxxBuckConfig cxxBuckConfig) { this.toolchainProvider = toolchainProvider; this.cxxBuckConfig = cxxBuckConfig; } @Override public Class<LuaBinaryDescriptionArg> getConstructorArgType() { return LuaBinaryDescriptionArg.class; } @VisibleForTesting protected static BuildTarget getNativeLibsSymlinkTreeTarget(BuildTarget target) { return target.withAppendedFlavors(InternalFlavor.of("native-libs-link-tree")); } private static Path getNativeLibsSymlinkTreeRoot(BuildTarget target, ProjectFilesystem filesystem) { return BuildTargetPaths.getGenPath(filesystem, getNativeLibsSymlinkTreeTarget(target), "%s"); } private static BuildTarget getModulesSymlinkTreeTarget(BuildTarget target) { return target.withAppendedFlavors(InternalFlavor.of("modules-link-tree")); } private static Path getModulesSymlinkTreeRoot(BuildTarget target, ProjectFilesystem filesystem) { return BuildTargetPaths.getGenPath(filesystem, getModulesSymlinkTreeTarget(target), "%s"); } private static BuildTarget getPythonModulesSymlinkTreeTarget(BuildTarget target) { return target.withAppendedFlavors(InternalFlavor.of("python-modules-link-tree")); } private static Path getPythonModulesSymlinkTreeRoot(BuildTarget target, ProjectFilesystem filesystem) { return BuildTargetPaths.getGenPath(filesystem, getPythonModulesSymlinkTreeTarget(target), "%s"); } private Path getOutputPath(BuildTarget target, ProjectFilesystem filesystem, LuaPlatform luaPlatform) { return BuildTargetPaths.getGenPath(filesystem, target, "%s" + luaPlatform.getExtension()); } private Iterable<BuildTarget> getNativeStarterDepTargets(LuaPlatform luaPlatform) { Optional<BuildTarget> nativeStarterLibrary = luaPlatform.getNativeStarterLibrary(); return nativeStarterLibrary.isPresent() ? ImmutableSet.of(nativeStarterLibrary.get()) : Optionals.toStream(luaPlatform.getLuaCxxLibraryTarget()).collect(ImmutableSet.toImmutableSet()); } private Starter getStarter(CellPathResolver cellPathResolver, ProjectFilesystem projectFilesystem, BuildTarget baseTarget, BuildRuleParams baseParams, ActionGraphBuilder graphBuilder, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, LuaPlatform luaPlatform, BuildTarget target, Path output, StarterType starterType, Optional<BuildTarget> nativeStarterLibrary, String mainModule, Optional<Path> relativeModulesDir, Optional<Path> relativePythonModulesDir, Optional<Path> relativeNativeLibsDir) { switch (starterType) { case PURE: if (relativeNativeLibsDir.isPresent()) { throw new HumanReadableException("%s: cannot use pure starter with native libraries", baseTarget); } return LuaScriptStarter.of(projectFilesystem, baseTarget, baseParams, graphBuilder, pathResolver, ruleFinder, luaPlatform, target, output, mainModule, relativeModulesDir, relativePythonModulesDir); case NATIVE: return NativeExecutableStarter.of(projectFilesystem, baseTarget, baseParams, graphBuilder, pathResolver, ruleFinder, cellPathResolver, luaPlatform, cxxBuckConfig, target, output, mainModule, nativeStarterLibrary, relativeModulesDir, relativePythonModulesDir, relativeNativeLibsDir); } throw new IllegalStateException( String.format("%s: unexpected starter type %s", baseTarget, luaPlatform.getStarterType())); } private StarterType getStarterType(LuaPlatform luaPlatform, boolean mayHaveNativeCode) { return luaPlatform.getStarterType().orElse(mayHaveNativeCode ? StarterType.NATIVE : StarterType.PURE); } /** @return the {@link Starter} used to build the Lua binary entry point. */ private Starter createStarter(CellPathResolver cellPathResolver, ProjectFilesystem projectFilesystem, BuildTarget baseTarget, BuildRuleParams baseParams, ActionGraphBuilder graphBuilder, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, LuaPlatform luaPlatform, Optional<BuildTarget> nativeStarterLibrary, String mainModule, LuaPlatform.PackageStyle packageStyle, boolean mayHaveNativeCode) { Path output = getOutputPath(baseTarget, projectFilesystem, luaPlatform); StarterType starterType = getStarterType(luaPlatform, mayHaveNativeCode); // The relative paths from the starter to the various components. Optional<Path> relativeModulesDir = Optional.empty(); Optional<Path> relativePythonModulesDir = Optional.empty(); Optional<Path> relativeNativeLibsDir = Optional.empty(); // For in-place binaries, set the relative paths to the symlink trees holding the components. if (packageStyle == LuaPlatform.PackageStyle.INPLACE) { relativeModulesDir = Optional .of(output.getParent().relativize(getModulesSymlinkTreeRoot(baseTarget, projectFilesystem))); relativePythonModulesDir = Optional.of( output.getParent().relativize(getPythonModulesSymlinkTreeRoot(baseTarget, projectFilesystem))); // We only need to setup a native lib link tree if we're using a native starter. if (starterType == StarterType.NATIVE) { relativeNativeLibsDir = Optional.of( output.getParent().relativize(getNativeLibsSymlinkTreeRoot(baseTarget, projectFilesystem))); } } // Build the starter. return getStarter(cellPathResolver, projectFilesystem, baseTarget, baseParams, graphBuilder, pathResolver, ruleFinder, luaPlatform, baseTarget.withAppendedFlavors( packageStyle == LuaPlatform.PackageStyle.STANDALONE ? InternalFlavor.of("starter") : BINARY_FLAVOR), packageStyle == LuaPlatform.PackageStyle.STANDALONE ? output.resolveSibling(output.getFileName() + "-starter") : output, starterType, nativeStarterLibrary, mainModule, relativeModulesDir, relativePythonModulesDir, relativeNativeLibsDir); } private LuaBinaryPackageComponents getPackageComponentsFromDeps(BuildTarget buildTarget, ProjectFilesystem projectFilesystem, BuildRuleParams baseParams, ActionGraphBuilder graphBuilder, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, LuaPlatform luaPlatform, PythonPlatform pythonPlatform, Optional<BuildTarget> nativeStarterLibrary, String mainModule, LuaPlatform.PackageStyle packageStyle, Iterable<BuildRule> deps, CellPathResolver cellPathResolver) { CxxPlatform cxxPlatform = luaPlatform.getCxxPlatform(); LuaPackageComponents.Builder builder = LuaPackageComponents.builder(); OmnibusRoots.Builder omnibusRoots = OmnibusRoots.builder(cxxPlatform, ImmutableSet.of(), graphBuilder); Map<BuildTarget, NativeLinkable> nativeLinkableRoots = new LinkedHashMap<>(); Map<BuildTarget, CxxLuaExtension> luaExtensions = new LinkedHashMap<>(); Map<BuildTarget, CxxPythonExtension> pythonExtensions = new LinkedHashMap<>(); // Walk the deps to find all Lua packageables and native linkables. new AbstractBreadthFirstTraversal<BuildRule>(deps) { private final ImmutableSet<BuildRule> empty = ImmutableSet.of(); @Override public Iterable<BuildRule> visit(BuildRule rule) { Iterable<BuildRule> deps = empty; if (rule instanceof LuaPackageable) { LuaPackageable packageable = (LuaPackageable) rule; LuaPackageComponents components = packageable.getLuaPackageComponents(pathResolver); LuaPackageComponents.addComponents(builder, components); deps = packageable.getLuaPackageDeps(cxxPlatform, graphBuilder); if (components.hasNativeCode(cxxPlatform)) { for (BuildRule dep : deps) { if (dep instanceof NativeLinkable) { NativeLinkable linkable = (NativeLinkable) dep; nativeLinkableRoots.put(linkable.getBuildTarget(), linkable); omnibusRoots.addExcludedRoot(linkable); } } } } else if (rule instanceof CxxPythonExtension) { CxxPythonExtension extension = (CxxPythonExtension) rule; NativeLinkTarget target = extension.getNativeLinkTarget(pythonPlatform); pythonExtensions.put(target.getBuildTarget(), (CxxPythonExtension) rule); omnibusRoots.addIncludedRoot(target); } else if (rule instanceof PythonPackagable) { PythonPackagable packageable = (PythonPackagable) rule; PythonPackageComponents components = packageable.getPythonPackageComponents(pythonPlatform, cxxPlatform, graphBuilder); builder.putAllPythonModules(MoreMaps.transformKeys(components.getModules(), Object::toString)); builder.putAllNativeLibraries( MoreMaps.transformKeys(components.getNativeLibraries(), Object::toString)); deps = packageable.getPythonPackageDeps(pythonPlatform, cxxPlatform, graphBuilder); if (components.hasNativeCode(cxxPlatform)) { for (BuildRule dep : deps) { if (dep instanceof NativeLinkable) { NativeLinkable linkable = (NativeLinkable) dep; nativeLinkableRoots.put(linkable.getBuildTarget(), linkable); omnibusRoots.addExcludedRoot(linkable); } } } } else if (rule instanceof CxxLuaExtension) { CxxLuaExtension extension = (CxxLuaExtension) rule; luaExtensions.put(extension.getBuildTarget(), extension); omnibusRoots.addIncludedRoot(extension); } else if (rule instanceof NativeLinkable) { NativeLinkable linkable = (NativeLinkable) rule; nativeLinkableRoots.put(linkable.getBuildTarget(), linkable); omnibusRoots.addPotentialRoot(linkable); } return deps; } }.start(); // Build the starter. Starter starter = createStarter(cellPathResolver, projectFilesystem, buildTarget, baseParams, graphBuilder, pathResolver, ruleFinder, luaPlatform, nativeStarterLibrary, mainModule, packageStyle, !nativeLinkableRoots.isEmpty() || !omnibusRoots.isEmpty()); SourcePath starterPath = null; if (luaPlatform.getNativeLinkStrategy() == NativeLinkStrategy.MERGED) { // If we're using a native starter, include it in omnibus linking. if (starter instanceof NativeExecutableStarter) { NativeExecutableStarter nativeStarter = (NativeExecutableStarter) starter; omnibusRoots.addIncludedRoot(nativeStarter); } // Build the omnibus libraries. OmnibusRoots roots = omnibusRoots.build(); OmnibusLibraries libraries = Omnibus.getSharedLibraries(buildTarget, projectFilesystem, baseParams, cellPathResolver, graphBuilder, ruleFinder, cxxBuckConfig, cxxPlatform, ImmutableList.of(), roots.getIncludedRoots().values(), roots.getExcludedRoots().values()); // Add all the roots from the omnibus link. If it's an extension, add it as a module. for (Map.Entry<BuildTarget, OmnibusRoot> root : libraries.getRoots().entrySet()) { // If it's a Lua extension add it as a module. CxxLuaExtension luaExtension = luaExtensions.get(root.getKey()); if (luaExtension != null) { builder.putModules(luaExtension.getModule(cxxPlatform), root.getValue().getPath()); continue; } // If it's a Python extension, add it as a python module. CxxPythonExtension pythonExtension = pythonExtensions.get(root.getKey()); if (pythonExtension != null) { builder.putPythonModules(pythonExtension.getModule().toString(), root.getValue().getPath()); continue; } // A root named after the top-level target is our native starter. if (root.getKey().equals(buildTarget)) { starterPath = root.getValue().getPath(); continue; } // Otherwise, add it as a native library. NativeLinkTarget target = Preconditions.checkNotNull(roots.getIncludedRoots().get(root.getKey()), "%s: linked unexpected omnibus root: %s", buildTarget, root.getKey()); NativeLinkTargetMode mode = target.getNativeLinkTargetMode(cxxPlatform); String soname = Preconditions.checkNotNull(mode.getLibraryName().orElse(null), "%s: omnibus library for %s was built without soname", buildTarget, root.getKey()); builder.putNativeLibraries(soname, root.getValue().getPath()); } // Add all remaining libraries as native libraries. for (OmnibusLibrary library : libraries.getLibraries()) { builder.putNativeLibraries(library.getSoname(), library.getPath()); } } else { // For regular linking, add all Lua extensions as modules and their deps as native linkable // roots. for (Map.Entry<BuildTarget, CxxLuaExtension> entry : luaExtensions.entrySet()) { CxxLuaExtension extension = entry.getValue(); builder.putModules(extension.getModule(cxxPlatform), extension.getExtension(cxxPlatform)); nativeLinkableRoots .putAll(Maps.uniqueIndex(extension.getNativeLinkTargetDeps(cxxPlatform, graphBuilder), NativeLinkable::getBuildTarget)); } // Add in native executable deps. if (starter instanceof NativeExecutableStarter) { NativeExecutableStarter executableStarter = (NativeExecutableStarter) starter; nativeLinkableRoots.putAll( Maps.uniqueIndex(executableStarter.getNativeStarterDeps(), NativeLinkable::getBuildTarget)); } // For regular linking, add all extensions via the package components interface and their // python-platform specific deps to the native linkables. for (Map.Entry<BuildTarget, CxxPythonExtension> entry : pythonExtensions.entrySet()) { PythonPackageComponents components = entry.getValue().getPythonPackageComponents(pythonPlatform, cxxPlatform, graphBuilder); builder.putAllPythonModules(MoreMaps.transformKeys(components.getModules(), Object::toString)); builder.putAllNativeLibraries( MoreMaps.transformKeys(components.getNativeLibraries(), Object::toString)); nativeLinkableRoots.putAll(Maps.uniqueIndex(entry.getValue().getNativeLinkTarget(pythonPlatform) .getNativeLinkTargetDeps(cxxPlatform, graphBuilder), NativeLinkable::getBuildTarget)); } // Add shared libraries from all native linkables. for (NativeLinkable nativeLinkable : NativeLinkables .getTransitiveNativeLinkables(cxxPlatform, graphBuilder, nativeLinkableRoots.values()) .values()) { NativeLinkable.Linkage linkage = nativeLinkable.getPreferredLinkage(cxxPlatform, graphBuilder); if (linkage != NativeLinkable.Linkage.STATIC) { builder.putAllNativeLibraries(nativeLinkable.getSharedLibraries(cxxPlatform, graphBuilder)); } } } // If an explicit starter path override hasn't been set (e.g. from omnibus linking), default to // building one directly from the starter. if (starterPath == null) { starterPath = starter.build(); } return LuaBinaryPackageComponents.of(starterPath, builder.build()); } private SymlinkTree createSymlinkTree(BuildTarget linkTreeTarget, ProjectFilesystem filesystem, ActionGraphBuilder graphBuilder, SourcePathRuleFinder ruleFinder, Path root, ImmutableMap<String, SourcePath> components) { return graphBuilder.addToIndex(new SymlinkTree("lua_binary", linkTreeTarget, filesystem, root, MoreMaps.transformKeys(components, MorePaths.toPathFn(root.getFileSystem())), ImmutableMultimap.of(), ruleFinder)); } /** * @return the native library map with additional entries for library names with the version * suffix stripped (e.g. libfoo.so.1.0 -> libfoo.so) to appease LuaJIT, which wants to load * libraries using the build-time name. */ private ImmutableSortedMap<String, SourcePath> addVersionLessLibraries(CxxPlatform cxxPlatform, ImmutableSortedMap<String, SourcePath> libraries) { Pattern versionedExtension = Pattern.compile(Joiner.on("[.\\d]*") .join(Iterables.transform( Splitter.on("%s").split(cxxPlatform.getSharedLibraryVersionedExtensionFormat()), input -> input.isEmpty() ? input : Pattern.quote(input)))); Map<String, SourcePath> librariesPaths = new HashMap<>(); for (Map.Entry<String, SourcePath> ent : libraries.entrySet()) { String name = ent.getKey(); if (librariesPaths.containsKey(name) && librariesPaths.get(name) != ent.getValue()) { throw new HumanReadableException("Library %s has multiple possible paths: %s and %s", name, ent.getValue(), librariesPaths.get(name)); } librariesPaths.put(name, ent.getValue()); Matcher matcher = versionedExtension.matcher(name); String versionLessName = matcher.replaceAll(cxxPlatform.getSharedLibraryExtension()); if (!versionLessName.equals(ent.getKey()) && !libraries.containsKey(versionLessName)) { librariesPaths.put(versionLessName, ent.getValue()); } } return ImmutableSortedMap.copyOf(librariesPaths); } private Tool getInPlaceBinary(BuildTarget buildTarget, ProjectFilesystem projectFilesystem, ActionGraphBuilder graphBuilder, SourcePathRuleFinder ruleFinder, CxxPlatform cxxPlatform, SourcePath starter, LuaPackageComponents components) { List<SourcePath> extraInputs = new ArrayList<>(); SymlinkTree modulesLinkTree = graphBuilder.addToIndex(createSymlinkTree( getModulesSymlinkTreeTarget(buildTarget), projectFilesystem, graphBuilder, ruleFinder, getModulesSymlinkTreeRoot(buildTarget, projectFilesystem), components.getModules())); List<SymlinkTree> pythonModulesLinktree = new ArrayList<>(); if (!components.getPythonModules().isEmpty()) { // Add in any missing init modules into the python components. SourcePath emptyInit = PythonBinaryDescription.createEmptyInitModule(buildTarget, projectFilesystem, graphBuilder); extraInputs.add(emptyInit); ImmutableMap<String, SourcePath> pythonModules = MoreMaps .transformKeys( PythonBinaryDescription .addMissingInitModules( MoreMaps.transformKeys(components.getPythonModules(), MorePaths.toPathFn( projectFilesystem.getRootPath().getFileSystem())), emptyInit), Object::toString); SymlinkTree symlinkTree = graphBuilder.addToIndex(createSymlinkTree( getPythonModulesSymlinkTreeTarget(buildTarget), projectFilesystem, graphBuilder, ruleFinder, getPythonModulesSymlinkTreeRoot(buildTarget, projectFilesystem), pythonModules)); pythonModulesLinktree.add(symlinkTree); } List<SymlinkTree> nativeLibsLinktree = new ArrayList<>(); if (!components.getNativeLibraries().isEmpty()) { SymlinkTree symlinkTree = graphBuilder .addToIndex(createSymlinkTree(getNativeLibsSymlinkTreeTarget(buildTarget), projectFilesystem, graphBuilder, ruleFinder, getNativeLibsSymlinkTreeRoot(buildTarget, projectFilesystem), addVersionLessLibraries(cxxPlatform, components.getNativeLibraries()))); nativeLibsLinktree.add(symlinkTree); } return new Tool() { @AddToRuleKey private final LuaPackageComponents toolComponents = components; @AddToRuleKey private final SourcePath toolStarter = starter; @AddToRuleKey private final NonHashableSourcePathContainer toolModulesLinkTree = new NonHashableSourcePathContainer( modulesLinkTree.getSourcePathToOutput()); @AddToRuleKey private final List<NonHashableSourcePathContainer> toolNativeLibsLinkTree = nativeLibsLinktree.stream() .map(linkTree -> new NonHashableSourcePathContainer(linkTree.getSourcePathToOutput())) .collect(ImmutableList.toImmutableList()); @AddToRuleKey private final List<NonHashableSourcePathContainer> toolPythonModulesLinktree = pythonModulesLinktree .stream().map(linkTree -> new NonHashableSourcePathContainer(linkTree.getSourcePathToOutput())) .collect(ImmutableList.toImmutableList()); @AddToRuleKey private final List<SourcePath> toolExtraInputs = extraInputs; @Override public ImmutableList<String> getCommandPrefix(SourcePathResolver resolver) { return ImmutableList.of(resolver.getAbsolutePath(starter).toString()); } @Override public ImmutableMap<String, String> getEnvironment(SourcePathResolver resolver) { return ImmutableMap.of(); } }; } private Tool getStandaloneBinary(BuildTarget buildTarget, ProjectFilesystem projectFilesystem, BuildRuleParams params, ActionGraphBuilder graphBuilder, SourcePathRuleFinder ruleFinder, LuaPlatform luaPlatform, SourcePath starter, String mainModule, LuaPackageComponents components) { Path output = getOutputPath(buildTarget, projectFilesystem, luaPlatform); Tool lua = luaPlatform.getLua().resolve(graphBuilder); Tool packager = luaPlatform.getPackager().resolve(graphBuilder); LuaStandaloneBinary binary = graphBuilder.addToIndex(new LuaStandaloneBinary( buildTarget.withAppendedFlavors(BINARY_FLAVOR), projectFilesystem, params.withDeclaredDeps(ImmutableSortedSet.<BuildRule>naturalOrder() .addAll(ruleFinder.filterBuildRuleInputs(starter)).addAll(components.getDeps(ruleFinder)) .addAll(BuildableSupport.getDepsCollection(lua, ruleFinder)) .addAll(BuildableSupport.getDepsCollection(packager, ruleFinder)).build()) .withoutExtraDeps(), packager, ImmutableList.of(), output, Optional.of(starter), components, mainModule, lua, luaPlatform.shouldCacheBinaries())); return new CommandTool.Builder().addArg(SourcePathArg.of(binary.getSourcePathToOutput())).build(); } private Tool getBinary(BuildTarget buildTarget, ProjectFilesystem projectFilesystem, BuildRuleParams params, ActionGraphBuilder graphBuilder, SourcePathRuleFinder ruleFinder, LuaPlatform luaPlatform, String mainModule, SourcePath starter, LuaPackageComponents components, LuaPlatform.PackageStyle packageStyle) { switch (packageStyle) { case STANDALONE: return getStandaloneBinary(buildTarget, projectFilesystem, params, graphBuilder, ruleFinder, luaPlatform, starter, mainModule, components); case INPLACE: return getInPlaceBinary(buildTarget, projectFilesystem, graphBuilder, ruleFinder, luaPlatform.getCxxPlatform(), starter, components); } throw new IllegalStateException( String.format("%s: unexpected package style %s", buildTarget, packageStyle)); } // Return the C/C++ platform to build against. private LuaPlatform getPlatform(BuildTarget target, AbstractLuaBinaryDescriptionArg arg) { LuaPlatformsProvider luaPlatformsProvider = toolchainProvider.getByName(LuaPlatformsProvider.DEFAULT_NAME, LuaPlatformsProvider.class); FlavorDomain<LuaPlatform> luaPlatforms = luaPlatformsProvider.getLuaPlatforms(); Optional<LuaPlatform> flavorPlatform = luaPlatforms.getValue(target); if (flavorPlatform.isPresent()) { return flavorPlatform.get(); } if (arg.getPlatform().isPresent()) { return luaPlatforms.getValue(arg.getPlatform().get()); } return luaPlatformsProvider.getDefaultLuaPlatform(); } @Override public BuildRule createBuildRule(BuildRuleCreationContextWithTargetGraph context, BuildTarget buildTarget, BuildRuleParams params, LuaBinaryDescriptionArg args) { ActionGraphBuilder graphBuilder = context.getActionGraphBuilder(); SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(graphBuilder); SourcePathResolver pathResolver = DefaultSourcePathResolver.from(ruleFinder); LuaPlatform luaPlatform = getPlatform(buildTarget, args); ProjectFilesystem projectFilesystem = context.getProjectFilesystem(); FlavorDomain<PythonPlatform> pythonPlatforms = toolchainProvider .getByName(PythonPlatformsProvider.DEFAULT_NAME, PythonPlatformsProvider.class) .getPythonPlatforms(); PythonPlatform pythonPlatform = pythonPlatforms.getValue(buildTarget) .orElse(pythonPlatforms.getValue(args.getPythonPlatform().<Flavor>map(InternalFlavor::of) .orElse(pythonPlatforms.getFlavors().iterator().next()))); LuaBinaryPackageComponents components = getPackageComponentsFromDeps(buildTarget, projectFilesystem, params, graphBuilder, pathResolver, ruleFinder, luaPlatform, pythonPlatform, args.getNativeStarterLibrary().map(Optional::of).orElse(luaPlatform.getNativeStarterLibrary()), args.getMainModule(), args.getPackageStyle().orElse(luaPlatform.getPackageStyle()), graphBuilder.getAllRules( LuaUtil.getDeps(luaPlatform.getCxxPlatform(), args.getDeps(), args.getPlatformDeps())), context.getCellPathResolver()); LuaPlatform.PackageStyle packageStyle = args.getPackageStyle().orElse(luaPlatform.getPackageStyle()); Tool binary = getBinary(buildTarget, projectFilesystem, params, graphBuilder, ruleFinder, luaPlatform, args.getMainModule(), components.getStarter(), components.getComponents(), packageStyle); return new LuaBinary(buildTarget, projectFilesystem, params.copyAppendingExtraDeps(BuildableSupport.getDepsCollection(binary, ruleFinder)), getOutputPath(buildTarget, projectFilesystem, luaPlatform), binary, args.getMainModule(), components.getComponents(), luaPlatform.getLua().resolve(graphBuilder), packageStyle); } @Override public void findDepsForTargetFromConstructorArgs(BuildTarget buildTarget, CellPathResolver cellRoots, AbstractLuaBinaryDescriptionArg constructorArg, ImmutableCollection.Builder<BuildTarget> extraDepsBuilder, ImmutableCollection.Builder<BuildTarget> targetGraphOnlyDepsBuilder) { LuaPlatform luaPlatform = getPlatform(buildTarget, constructorArg); if (luaPlatform.getPackageStyle() == LuaPlatform.PackageStyle.STANDALONE) { extraDepsBuilder.addAll(luaPlatform.getPackager().getParseTimeDeps()); } extraDepsBuilder.addAll(getNativeStarterDepTargets(luaPlatform)); } public enum StarterType { PURE, NATIVE, } @BuckStyleImmutable @Value.Immutable interface AbstractLuaBinaryDescriptionArg extends CommonDescriptionArg, HasDeclaredDeps { String getMainModule(); Optional<BuildTarget> getNativeStarterLibrary(); Optional<String> getPythonPlatform(); Optional<Flavor> getPlatform(); Optional<LuaPlatform.PackageStyle> getPackageStyle(); @Value.Default default PatternMatchedCollection<ImmutableSortedSet<BuildTarget>> getPlatformDeps() { return PatternMatchedCollection.of(); } } }