/* * Copyright 2012-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.android; import com.facebook.buck.io.ExecutableFinder; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.shell.ShellStep; import com.facebook.buck.step.ExecutionContext; import com.facebook.buck.util.HumanReadableException; import com.facebook.buck.util.Verbosity; import com.facebook.buck.util.concurrent.ConcurrencyLimit; import com.facebook.buck.util.environment.Platform; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; public class NdkBuildStep extends ShellStep { private final ProjectFilesystem filesystem; private final Path root; private final Path makefile; private final Path buildArtifactsDirectory; private final Path binDirectory; private final ImmutableList<String> flags; private final Function<String, String> macroExpander; public NdkBuildStep( ProjectFilesystem filesystem, Path root, Path makefile, Path buildArtifactsDirectory, Path binDirectory, Iterable<String> flags, Function<String, String> macroExpander) { super(filesystem.getRootPath()); this.filesystem = filesystem; this.root = root; this.makefile = makefile; this.buildArtifactsDirectory = buildArtifactsDirectory; this.binDirectory = binDirectory; this.flags = ImmutableList.copyOf(flags); this.macroExpander = macroExpander; } @Override public String getShortName() { return "ndk_build"; } @Override protected boolean shouldPrintStderr(Verbosity verbosity) { return verbosity.shouldPrintStandardInformation(); } @Override protected ImmutableList<String> getShellCommandInternal(ExecutionContext context) { Optional<Path> ndkBuild = new ExecutableFinder() .getOptionalExecutable( Paths.get("ndk-build"), context.getAndroidPlatformTarget().checkNdkDirectory()); if (!ndkBuild.isPresent()) { throw new HumanReadableException("Unable to find ndk-build"); } ConcurrencyLimit concurrencyLimit = context.getConcurrencyLimit(); ImmutableList.Builder<String> builder = ImmutableList.builder(); builder.add( ndkBuild.get().toAbsolutePath().toString(), "-j", // TODO(dancol): using -j here is wrong. It lets make run too many work when we do // other work in parallel. Instead, implement the GNU Make job server so make and Buck can // coordinate job concurrency. Integer.toString(concurrencyLimit.threadLimit), "-C", this.root.toString()); Iterable<String> flags = Iterables.transform(this.flags, macroExpander); builder.addAll(flags); // We want relative, not absolute, paths in the debug-info for binaries we build using // ndk_library. Absolute paths are machine-specific, but relative ones should be the // same everywhere. Path relativePathToProject = filesystem.resolve(root).relativize(filesystem.getRootPath()); builder.add( "APP_PROJECT_PATH=" + filesystem.resolve(buildArtifactsDirectory) + File.separatorChar, "APP_BUILD_SCRIPT=" + filesystem.resolve(makefile), "NDK_OUT=" + filesystem.resolve(buildArtifactsDirectory) + File.separatorChar, "NDK_LIBS_OUT=" + filesystem.resolve(binDirectory), "BUCK_PROJECT_DIR=" + relativePathToProject); // Suppress the custom build step messages (e.g. "Compile++ ..."). if (Platform.detect() == Platform.WINDOWS) { builder.add("host-echo-build-step=@REM"); } else { builder.add("host-echo-build-step=@#"); } // If we're running verbosely, force all the subcommands from the ndk build to be printed out. if (context.getVerbosity().shouldPrintCommand()) { builder.add("V=1"); // Otherwise, suppress everything, including the "make: entering directory..." messages. } else { builder.add("--silent"); } return builder.build(); } // The ndk-build command delegates to `make` to run a lot of subcommands, so print them as they // happen. @Override protected boolean shouldFlushStdOutErrAsProgressIsMade(Verbosity verbosity) { return verbosity.shouldPrintCommand(); } }