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.lua; import com.facebook.buck.cxx.CxxBuckConfig; import com.facebook.buck.cxx.CxxPlatform; import com.facebook.buck.cxx.NativeLinkStrategy; import com.facebook.buck.cxx.NativeLinkTarget; import com.facebook.buck.cxx.NativeLinkTargetMode; import com.facebook.buck.cxx.NativeLinkable; import com.facebook.buck.cxx.NativeLinkables; 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.graph.AbstractBreadthFirstThrowingTraversal; import com.facebook.buck.io.MorePaths; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.BuildTargets; import com.facebook.buck.model.Flavor; import com.facebook.buck.model.FlavorDomain; import com.facebook.buck.model.HasBuildTarget; import com.facebook.buck.model.ImmutableFlavor; import com.facebook.buck.parser.NoSuchBuildTargetException; import com.facebook.buck.python.CxxPythonExtension; import com.facebook.buck.python.PythonBinaryDescription; import com.facebook.buck.python.PythonPackagable; import com.facebook.buck.python.PythonPackageComponents; import com.facebook.buck.python.PythonPlatform; import com.facebook.buck.rules.AbstractDescriptionArg; 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.RuleKeyObjectSink; import com.facebook.buck.rules.SourcePath; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.rules.SourcePathRuleFinder; 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.util.HumanReadableException; import com.facebook.buck.util.MoreMaps; import com.facebook.buck.util.OptionalCompat; import com.facebook.buck.versions.VersionRoot; import com.facebook.infer.annotation.SuppressFieldNotInitialized; 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.base.Suppliers; import com.google.common.collect.ImmutableCollection; 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 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; public class LuaBinaryDescription implements Description<LuaBinaryDescription.Arg>, ImplicitDepsInferringDescription<LuaBinaryDescription.Arg>, VersionRoot<LuaBinaryDescription.Arg> { private static final Flavor BINARY_FLAVOR = ImmutableFlavor.of("binary"); private final LuaConfig luaConfig; private final CxxBuckConfig cxxBuckConfig; private final CxxPlatform defaultCxxPlatform; private final FlavorDomain<CxxPlatform> cxxPlatforms; private final FlavorDomain<PythonPlatform> pythonPlatforms; public LuaBinaryDescription(LuaConfig luaConfig, CxxBuckConfig cxxBuckConfig, CxxPlatform defaultCxxPlatform, FlavorDomain<CxxPlatform> cxxPlatforms, FlavorDomain<PythonPlatform> pythonPlatforms) { this.luaConfig = luaConfig; this.cxxBuckConfig = cxxBuckConfig; this.defaultCxxPlatform = defaultCxxPlatform; this.cxxPlatforms = cxxPlatforms; this.pythonPlatforms = pythonPlatforms; } @Override public Arg createUnpopulatedConstructorArg() { return new Arg(); } @VisibleForTesting protected static BuildTarget getNativeLibsSymlinkTreeTarget(BuildTarget target) { return target.withAppendedFlavors(ImmutableFlavor.of("native-libs-link-tree")); } private static Path getNativeLibsSymlinkTreeRoot(BuildTarget target, ProjectFilesystem filesystem) { return BuildTargets.getGenPath(filesystem, getNativeLibsSymlinkTreeTarget(target), "%s"); } private static BuildTarget getModulesSymlinkTreeTarget(BuildTarget target) { return target.withAppendedFlavors(ImmutableFlavor.of("modules-link-tree")); } private static Path getModulesSymlinkTreeRoot(BuildTarget target, ProjectFilesystem filesystem) { return BuildTargets.getGenPath(filesystem, getModulesSymlinkTreeTarget(target), "%s"); } private static BuildTarget getPythonModulesSymlinkTreeTarget(BuildTarget target) { return target.withAppendedFlavors(ImmutableFlavor.of("python-modules-link-tree")); } private static Path getPythonModulesSymlinkTreeRoot(BuildTarget target, ProjectFilesystem filesystem) { return BuildTargets.getGenPath(filesystem, getPythonModulesSymlinkTreeTarget(target), "%s"); } private Path getOutputPath(BuildTarget target, ProjectFilesystem filesystem) { return BuildTargets.getGenPath(filesystem, target, "%s" + luaConfig.getExtension()); } private Iterable<BuildTarget> getNativeStarterDepTargets() { Optional<BuildTarget> nativeStarterLibrary = luaConfig.getNativeStarterLibrary(); return ImmutableSet.copyOf(nativeStarterLibrary.isPresent() ? OptionalCompat.asSet(nativeStarterLibrary) : OptionalCompat.asSet(luaConfig.getLuaCxxLibraryTarget())); } private Starter getStarter(BuildRuleParams baseParams, BuildRuleResolver ruleResolver, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, CxxPlatform cxxPlatform, 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", baseParams.getBuildTarget()); } return LuaScriptStarter.of(baseParams, ruleResolver, pathResolver, ruleFinder, luaConfig, cxxPlatform, target, output, mainModule, relativeModulesDir, relativePythonModulesDir); case NATIVE: return NativeExecutableStarter.of(baseParams, ruleResolver, pathResolver, ruleFinder, luaConfig, cxxBuckConfig, cxxPlatform, target, output, mainModule, nativeStarterLibrary, relativeModulesDir, relativePythonModulesDir, relativeNativeLibsDir); } throw new IllegalStateException(String.format("%s: unexpected starter type %s", baseParams.getBuildTarget(), luaConfig.getStarterType())); } private StarterType getStarterType(boolean mayHaveNativeCode) { return luaConfig.getStarterType().orElse(mayHaveNativeCode ? StarterType.NATIVE : StarterType.PURE); } /** * @return the {@link Starter} used to build the Lua binary entry point. */ private Starter createStarter(BuildRuleParams baseParams, BuildRuleResolver ruleResolver, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, final CxxPlatform cxxPlatform, Optional<BuildTarget> nativeStarterLibrary, String mainModule, LuaConfig.PackageStyle packageStyle, boolean mayHaveNativeCode) { Path output = getOutputPath(baseParams.getBuildTarget(), baseParams.getProjectFilesystem()); StarterType starterType = getStarterType(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 == LuaConfig.PackageStyle.INPLACE) { relativeModulesDir = Optional.of(output.getParent().relativize( getModulesSymlinkTreeRoot(baseParams.getBuildTarget(), baseParams.getProjectFilesystem()))); relativePythonModulesDir = Optional .of(output.getParent().relativize(getPythonModulesSymlinkTreeRoot(baseParams.getBuildTarget(), baseParams.getProjectFilesystem()))); // 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(baseParams.getBuildTarget(), baseParams.getProjectFilesystem()))); } } // Build the starter. return getStarter(baseParams, ruleResolver, pathResolver, ruleFinder, cxxPlatform, baseParams.getBuildTarget().withAppendedFlavors( packageStyle == LuaConfig.PackageStyle.STANDALONE ? ImmutableFlavor.of("starter") : BINARY_FLAVOR), packageStyle == LuaConfig.PackageStyle.STANDALONE ? output.resolveSibling(output.getFileName() + "-starter") : output, starterType, nativeStarterLibrary, mainModule, relativeModulesDir, relativePythonModulesDir, relativeNativeLibsDir); } private LuaBinaryPackageComponents getPackageComponentsFromDeps(BuildRuleParams baseParams, BuildRuleResolver ruleResolver, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, final CxxPlatform cxxPlatform, final PythonPlatform pythonPlatform, Optional<BuildTarget> nativeStarterLibrary, String mainModule, LuaConfig.PackageStyle packageStyle, Iterable<BuildRule> deps) throws NoSuchBuildTargetException { final LuaPackageComponents.Builder builder = LuaPackageComponents.builder(); final OmnibusRoots.Builder omnibusRoots = OmnibusRoots.builder(cxxPlatform, ImmutableSet.of()); final Map<BuildTarget, NativeLinkable> nativeLinkableRoots = new LinkedHashMap<>(); final Map<BuildTarget, CxxLuaExtension> luaExtensions = new LinkedHashMap<>(); final Map<BuildTarget, CxxPythonExtension> pythonExtensions = new LinkedHashMap<>(); // Walk the deps to find all Lua packageables and native linkables. new AbstractBreadthFirstThrowingTraversal<BuildRule, NoSuchBuildTargetException>(deps) { private final ImmutableSet<BuildRule> empty = ImmutableSet.of(); @Override public ImmutableSet<BuildRule> visit(BuildRule rule) throws NoSuchBuildTargetException { ImmutableSet<BuildRule> deps = empty; if (rule instanceof LuaPackageable) { LuaPackageable packageable = (LuaPackageable) rule; LuaPackageComponents components = packageable.getLuaPackageComponents(); LuaPackageComponents.addComponents(builder, components); if (components.hasNativeCode(cxxPlatform)) { for (BuildRule dep : rule.getDeps()) { if (dep instanceof NativeLinkable) { NativeLinkable linkable = (NativeLinkable) dep; nativeLinkableRoots.put(linkable.getBuildTarget(), linkable); omnibusRoots.addExcludedRoot(linkable); } } } deps = rule.getDeps(); } 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); builder.putAllPythonModules(MoreMaps.transformKeys(components.getModules(), Object::toString)); builder.putAllNativeLibraries( MoreMaps.transformKeys(components.getNativeLibraries(), Object::toString)); if (components.hasNativeCode(cxxPlatform)) { for (BuildRule dep : rule.getDeps()) { if (dep instanceof NativeLinkable) { NativeLinkable linkable = (NativeLinkable) dep; nativeLinkableRoots.put(linkable.getBuildTarget(), linkable); omnibusRoots.addExcludedRoot(linkable); } } } deps = rule.getDeps(); } 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(rule); } return deps; } }.start(); // Build the starter. Starter starter = createStarter(baseParams, ruleResolver, pathResolver, ruleFinder, cxxPlatform, nativeStarterLibrary, mainModule, packageStyle, !nativeLinkableRoots.isEmpty() || !omnibusRoots.isEmpty()); SourcePath starterPath = null; if (luaConfig.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(baseParams, ruleResolver, pathResolver, 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(baseParams.getBuildTarget())) { 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", baseParams.getBuildTarget(), root.getKey()); NativeLinkTargetMode mode = target.getNativeLinkTargetMode(cxxPlatform); String soname = Preconditions.checkNotNull(mode.getLibraryName().orElse(null), "%s: omnibus library for %s was built without soname", baseParams.getBuildTarget(), 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), HasBuildTarget::getBuildTarget)); } // Add in native executable deps. if (starter instanceof NativeExecutableStarter) { NativeExecutableStarter executableStarter = (NativeExecutableStarter) starter; nativeLinkableRoots.putAll( Maps.uniqueIndex(executableStarter.getNativeStarterDeps(), HasBuildTarget::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); 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), HasBuildTarget::getBuildTarget)); } // Add shared libraries from all native linkables. for (NativeLinkable nativeLinkable : NativeLinkables .getTransitiveNativeLinkables(cxxPlatform, nativeLinkableRoots.values()).values()) { NativeLinkable.Linkage linkage = nativeLinkable.getPreferredLinkage(cxxPlatform); if (linkage != NativeLinkable.Linkage.STATIC) { builder.putAllNativeLibraries(nativeLinkable.getSharedLibraries(cxxPlatform)); } } } // 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, BuildRuleParams params, BuildRuleResolver resolver, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, Path root, ImmutableMap<String, SourcePath> components) { return resolver.addToIndex(SymlinkTree.from(params.copyWithChanges(linkTreeTarget, Suppliers.ofInstance( ImmutableSortedSet.copyOf(ruleFinder.filterBuildRuleInputs(components.values()))), Suppliers.ofInstance(ImmutableSortedSet.of())), pathResolver, root, components)); } /** * @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(BuildRuleParams params, BuildRuleResolver resolver, final SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, CxxPlatform cxxPlatform, final SourcePath starter, final LuaPackageComponents components) { final List<SourcePath> extraInputs = new ArrayList<>(); final SymlinkTree modulesLinkTree = resolver.addToIndex(createSymlinkTree( getModulesSymlinkTreeTarget(params.getBuildTarget()), params, resolver, pathResolver, ruleFinder, getModulesSymlinkTreeRoot(params.getBuildTarget(), params.getProjectFilesystem()), components.getModules())); final List<SymlinkTree> pythonModulesLinktree = new ArrayList<>(); if (!components.getPythonModules().isEmpty()) { // Add in any missing init modules into the python components. SourcePath emptyInit = PythonBinaryDescription.createEmptyInitModule(params, resolver); extraInputs.add(emptyInit); ImmutableMap<String, SourcePath> pythonModules = MoreMaps .transformKeys( PythonBinaryDescription.addMissingInitModules( MoreMaps.transformKeys(components.getPythonModules(), MorePaths.toPathFn( params.getProjectFilesystem().getRootPath().getFileSystem())), emptyInit), Object::toString); final SymlinkTree symlinkTree = resolver .addToIndex(createSymlinkTree(getPythonModulesSymlinkTreeTarget(params.getBuildTarget()), params, resolver, pathResolver, ruleFinder, getPythonModulesSymlinkTreeRoot(params.getBuildTarget(), params.getProjectFilesystem()), pythonModules)); pythonModulesLinktree.add(symlinkTree); } final List<SymlinkTree> nativeLibsLinktree = new ArrayList<>(); if (!components.getNativeLibraries().isEmpty()) { SymlinkTree symlinkTree = resolver .addToIndex(createSymlinkTree(getNativeLibsSymlinkTreeTarget(params.getBuildTarget()), params, resolver, pathResolver, ruleFinder, getNativeLibsSymlinkTreeRoot(params.getBuildTarget(), params.getProjectFilesystem()), addVersionLessLibraries(cxxPlatform, components.getNativeLibraries()))); nativeLibsLinktree.add(symlinkTree); } return new Tool() { @Override public ImmutableCollection<BuildRule> getDeps(SourcePathRuleFinder ruleFinder) { return ImmutableSortedSet.<BuildRule>naturalOrder() .addAll(ruleFinder.filterBuildRuleInputs(starter)).addAll(components.getDeps(ruleFinder)) .add(modulesLinkTree).addAll(nativeLibsLinktree).addAll(pythonModulesLinktree) .addAll(ruleFinder.filterBuildRuleInputs(extraInputs)).build(); } @Override public ImmutableCollection<SourcePath> getInputs() { return ImmutableSortedSet.<SourcePath>naturalOrder().add(starter).addAll(components.getInputs()) .addAll(extraInputs).build(); } @Override public ImmutableList<String> getCommandPrefix(SourcePathResolver resolver) { return ImmutableList.of(resolver.getAbsolutePath(starter).toString()); } @Override public ImmutableMap<String, String> getEnvironment() { return ImmutableMap.of(); } @Override public void appendToRuleKey(RuleKeyObjectSink sink) { sink.setReflectively("starter", starter).setReflectively("components", components); } }; } private Tool getStandaloneBinary(BuildRuleParams params, BuildRuleResolver resolver, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, SourcePath starter, String mainModule, final LuaPackageComponents components) { Path output = getOutputPath(params.getBuildTarget(), params.getProjectFilesystem()); Tool lua = luaConfig.getLua(resolver); Tool packager = luaConfig.getPackager().resolve(resolver); LuaStandaloneBinary binary = resolver.addToIndex(new LuaStandaloneBinary( params.copyWithChanges(params.getBuildTarget().withAppendedFlavors(BINARY_FLAVOR), Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>naturalOrder() .addAll(ruleFinder.filterBuildRuleInputs(starter)) .addAll(components.getDeps(ruleFinder)).addAll(lua.getDeps(ruleFinder)) .addAll(packager.getDeps(ruleFinder)).build()), Suppliers.ofInstance(ImmutableSortedSet.of())), pathResolver, packager, ImmutableList.of(), output, Optional.of(starter), components, mainModule, lua, luaConfig.shouldCacheBinaries())); return new CommandTool.Builder() .addArg(new SourcePathArg(pathResolver, new BuildTargetSourcePath(binary.getBuildTarget()))) .build(); } private Tool getBinary(BuildRuleParams params, BuildRuleResolver resolver, final SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder, CxxPlatform cxxPlatform, String mainModule, SourcePath starter, final LuaPackageComponents components, LuaConfig.PackageStyle packageStyle) { switch (packageStyle) { case STANDALONE: return getStandaloneBinary(params, resolver, pathResolver, ruleFinder, starter, mainModule, components); case INPLACE: return getInPlaceBinary(params, resolver, pathResolver, ruleFinder, cxxPlatform, starter, components); } throw new IllegalStateException( String.format("%s: unexpected package style %s", params.getBuildTarget(), packageStyle)); } @Override public <A extends Arg> BuildRule createBuildRule(TargetGraph targetGraph, BuildRuleParams params, final BuildRuleResolver resolver, A args) throws NoSuchBuildTargetException { SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver); SourcePathResolver pathResolver = new SourcePathResolver(ruleFinder); CxxPlatform cxxPlatform = cxxPlatforms.getValue(params.getBuildTarget()).orElse(defaultCxxPlatform); PythonPlatform pythonPlatform = pythonPlatforms.getValue(params.getBuildTarget()) .orElse(pythonPlatforms.getValue(args.pythonPlatform.<Flavor>map(ImmutableFlavor::of) .orElse(pythonPlatforms.getFlavors().iterator().next()))); LuaBinaryPackageComponents components = getPackageComponentsFromDeps(params, resolver, pathResolver, ruleFinder, cxxPlatform, pythonPlatform, args.nativeStarterLibrary.map(Optional::of).orElse(luaConfig.getNativeStarterLibrary()), args.mainModule, args.packageStyle.orElse(luaConfig.getPackageStyle()), params.getDeclaredDeps().get()); LuaConfig.PackageStyle packageStyle = args.packageStyle.orElse(luaConfig.getPackageStyle()); Tool binary = getBinary(params, resolver, pathResolver, ruleFinder, cxxPlatform, args.mainModule, components.getStarter(), components.getComponents(), packageStyle); return new LuaBinary(params.appendExtraDeps(binary.getDeps(ruleFinder)), pathResolver, ruleFinder, getOutputPath(params.getBuildTarget(), params.getProjectFilesystem()), binary, args.mainModule, components.getComponents(), luaConfig.getLua(resolver), packageStyle); } @Override public Iterable<BuildTarget> findDepsForTargetFromConstructorArgs(BuildTarget buildTarget, CellPathResolver cellRoots, Arg constructorArg) { ImmutableSet.Builder<BuildTarget> targets = ImmutableSet.builder(); if (luaConfig.getPackageStyle() == LuaConfig.PackageStyle.STANDALONE) { targets.addAll(luaConfig.getPackager().getParseTimeDeps()); } targets.addAll(getNativeStarterDepTargets()); return targets.build(); } @Override public boolean isVersionRoot(ImmutableSet<Flavor> flavors) { return true; } public enum StarterType { PURE, NATIVE, } @SuppressFieldNotInitialized public static class Arg extends AbstractDescriptionArg { public String mainModule; public ImmutableSortedSet<BuildTarget> deps = ImmutableSortedSet.of(); public Optional<BuildTarget> nativeStarterLibrary; public Optional<String> pythonPlatform; public Optional<LuaConfig.PackageStyle> packageStyle; } }