com.facebook.buck.apple.PrebuiltAppleFramework.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.apple.PrebuiltAppleFramework.java

Source

/*
 * Copyright 2014-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.apple;

import com.facebook.buck.cxx.CxxPlatform;
import com.facebook.buck.cxx.CxxPreprocessables;
import com.facebook.buck.cxx.CxxPreprocessorDep;
import com.facebook.buck.cxx.CxxPreprocessorInput;
import com.facebook.buck.cxx.HeaderSymlinkTree;
import com.facebook.buck.cxx.HeaderVisibility;
import com.facebook.buck.cxx.ImmutableCxxPreprocessorInputCacheKey;
import com.facebook.buck.cxx.Linker;
import com.facebook.buck.cxx.NativeLinkable;
import com.facebook.buck.cxx.NativeLinkableInput;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargets;
import com.facebook.buck.model.Flavor;
import com.facebook.buck.model.HasOutputName;
import com.facebook.buck.model.Pair;
import com.facebook.buck.parser.NoSuchBuildTargetException;
import com.facebook.buck.rules.AbstractBuildRuleWithResolver;
import com.facebook.buck.rules.AddToRuleKey;
import com.facebook.buck.rules.BuildContext;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.BuildTargetSourcePath;
import com.facebook.buck.rules.BuildableContext;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.args.Arg;
import com.facebook.buck.rules.args.StringArg;
import com.facebook.buck.rules.coercer.FrameworkPath;
import com.facebook.buck.step.Step;
import com.facebook.buck.step.fs.CopyStep;
import com.facebook.buck.step.fs.MkdirStep;
import com.facebook.buck.step.fs.RmStep;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;

public class PrebuiltAppleFramework extends AbstractBuildRuleWithResolver
        implements CxxPreprocessorDep, NativeLinkable, HasOutputName {

    @AddToRuleKey(stringify = true)
    private final Path out;

    @AddToRuleKey
    private final NativeLinkable.Linkage preferredLinkage;

    private final BuildRuleResolver ruleResolver;
    private final SourcePath frameworkPath;
    private final String frameworkName;
    private final Function<? super CxxPlatform, ImmutableList<String>> exportedLinkerFlags;
    private final ImmutableSet<FrameworkPath> frameworks;
    private final Optional<Pattern> supportedPlatformsRegex;

    private final Map<Pair<Flavor, Linker.LinkableDepType>, NativeLinkableInput> nativeLinkableCache = new HashMap<>();

    private final LoadingCache<CxxPreprocessables.CxxPreprocessorInputCacheKey, ImmutableMap<BuildTarget, CxxPreprocessorInput>> transitiveCxxPreprocessorInputCache = CxxPreprocessables
            .getTransitiveCxxPreprocessorInputCache(this);

    public PrebuiltAppleFramework(BuildRuleParams params, BuildRuleResolver ruleResolver,
            SourcePathResolver pathResolver, SourcePath frameworkPath, Linkage preferredLinkage,
            ImmutableSet<FrameworkPath> frameworks, Optional<Pattern> supportedPlatformsRegex,
            Function<? super CxxPlatform, ImmutableList<String>> exportedLinkerFlags) {
        super(params, pathResolver);
        this.frameworkPath = frameworkPath;
        this.ruleResolver = ruleResolver;
        this.exportedLinkerFlags = exportedLinkerFlags;
        this.preferredLinkage = preferredLinkage;
        this.frameworks = frameworks;
        this.supportedPlatformsRegex = supportedPlatformsRegex;

        BuildTarget target = params.getBuildTarget();
        this.frameworkName = pathResolver.getAbsolutePath(frameworkPath).getFileName().toString();
        this.out = BuildTargets.getGenPath(getProjectFilesystem(), target, "%s").resolve(frameworkName);
    }

    private boolean isPlatformSupported(CxxPlatform cxxPlatform) {
        return !supportedPlatformsRegex.isPresent()
                || supportedPlatformsRegex.get().matcher(cxxPlatform.getFlavor().toString()).find();
    }

    @Override
    public ImmutableList<Step> getBuildSteps(BuildContext context, BuildableContext buildableContext) {
        // This file is copied rather than symlinked so that when it is included in an archive zip and
        // unpacked on another machine, it is an ordinary file in both scenarios.
        ImmutableList.Builder<Step> builder = ImmutableList.builder();
        builder.add(new MkdirStep(getProjectFilesystem(), out.getParent()));
        builder.add(new RmStep(getProjectFilesystem(), out, RmStep.Mode.FORCED, RmStep.Mode.RECURSIVE));
        builder.add(CopyStep.forDirectory(getProjectFilesystem(),
                context.getSourcePathResolver().getAbsolutePath(frameworkPath), out,
                CopyStep.DirectoryMode.CONTENTS_ONLY));

        buildableContext.recordArtifact(out);
        return builder.build();
    }

    @Override
    public Path getPathToOutput() {
        return out;
    }

    @Override
    public String getOutputName() {
        return this.frameworkName;
    }

    @Override
    public Iterable<? extends CxxPreprocessorDep> getCxxPreprocessorDeps(CxxPlatform cxxPlatform) {
        if (!isPlatformSupported(cxxPlatform)) {
            return ImmutableList.of();
        }
        return FluentIterable.from(getDeps()).filter(CxxPreprocessorDep.class);
    }

    @Override
    public CxxPreprocessorInput getCxxPreprocessorInput(final CxxPlatform cxxPlatform,
            HeaderVisibility headerVisibility) throws NoSuchBuildTargetException {
        CxxPreprocessorInput.Builder builder = CxxPreprocessorInput.builder();

        switch (headerVisibility) {
        case PUBLIC:
            if (isPlatformSupported(cxxPlatform)) {
                builder.addAllFrameworks(frameworks);

                ruleResolver.requireRule(this.getBuildTarget());
                builder.addFrameworks(FrameworkPath.ofSourcePath(new BuildTargetSourcePath(this.getBuildTarget())));
            }
            return builder.build();
        case PRIVATE:
            return builder.build();
        }

        throw new RuntimeException("Invalid header visibility: " + headerVisibility);
    }

    @Override
    public Optional<HeaderSymlinkTree> getExportedHeaderSymlinkTree(CxxPlatform cxxPlatform) {
        return Optional.empty();
    }

    @Override
    public ImmutableMap<BuildTarget, CxxPreprocessorInput> getTransitiveCxxPreprocessorInput(
            CxxPlatform cxxPlatform, HeaderVisibility headerVisibility) throws NoSuchBuildTargetException {
        return transitiveCxxPreprocessorInputCache
                .getUnchecked(ImmutableCxxPreprocessorInputCacheKey.of(cxxPlatform, headerVisibility));
    }

    @Override
    public Iterable<NativeLinkable> getNativeLinkableDeps() {
        return FluentIterable.from(getDeclaredDeps()).filter(NativeLinkable.class);
    }

    @Override
    public Iterable<NativeLinkable> getNativeLinkableDepsForPlatform(CxxPlatform cxxPlatform) {
        if (!isPlatformSupported(cxxPlatform)) {
            return ImmutableList.of();
        }
        return getNativeLinkableDeps();
    }

    @Override
    public Iterable<? extends NativeLinkable> getNativeLinkableExportedDeps() {
        return ImmutableList.of();
    }

    private NativeLinkableInput getNativeLinkableInputUncached(CxxPlatform cxxPlatform,
            Linker.LinkableDepType type) {
        if (!isPlatformSupported(cxxPlatform)) {
            return NativeLinkableInput.of();
        }
        ImmutableList.Builder<Arg> linkerArgsBuilder = ImmutableList.builder();
        linkerArgsBuilder
                .addAll(StringArg.from(Preconditions.checkNotNull(exportedLinkerFlags.apply(cxxPlatform))));

        ImmutableSet.Builder<FrameworkPath> frameworkPaths = ImmutableSet.builder();
        frameworkPaths.addAll(Preconditions.checkNotNull(frameworks));

        frameworkPaths.add(FrameworkPath.ofSourcePath(new BuildTargetSourcePath(this.getBuildTarget())));
        if (type == Linker.LinkableDepType.SHARED) {
            linkerArgsBuilder.addAll(
                    StringArg.from("-rpath", "@loader_path/Frameworks", "-rpath", "@executable_path/Frameworks"));
        }

        final ImmutableList<Arg> linkerArgs = linkerArgsBuilder.build();
        return NativeLinkableInput.of(linkerArgs, frameworkPaths.build(), Collections.emptySet());
    }

    @Override
    public NativeLinkableInput getNativeLinkableInput(CxxPlatform cxxPlatform, Linker.LinkableDepType type)
            throws NoSuchBuildTargetException {
        Pair<Flavor, Linker.LinkableDepType> key = new Pair<>(cxxPlatform.getFlavor(), type);
        NativeLinkableInput input = nativeLinkableCache.get(key);
        if (input == null) {
            input = getNativeLinkableInputUncached(cxxPlatform, type);
            nativeLinkableCache.put(key, input);
        }
        return input;
    }

    @Override
    public NativeLinkable.Linkage getPreferredLinkage(CxxPlatform cxxPlatform) {
        return this.preferredLinkage;
    }

    @Override
    public ImmutableMap<String, SourcePath> getSharedLibraries(CxxPlatform cxxPlatform)
            throws NoSuchBuildTargetException {
        return ImmutableMap.of();
    }

}