// Copyright 2015 The Bazel Authors. All rights reserved. // // 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.google.devtools.build.lib.bazel.rules.android; import static com.google.devtools.build.lib.packages.Attribute.attr; import static com.google.devtools.build.lib.syntax.Type.INTEGER; import static com.google.devtools.build.lib.syntax.Type.STRING; import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClass.Builder; import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; import com.google.devtools.build.lib.rules.repository.WorkspaceBaseRule; import com.google.devtools.build.lib.rules.repository.WorkspaceConfiguredTargetFactory; import java.util.Map; import javax.annotation.Nullable; /** * Definition of the {@code android_sdk_repository} rule. */ public class AndroidSdkRepositoryRule implements RuleDefinition { public static final String NAME = "android_sdk_repository"; private static final Function<? super Rule, Map<String, Label>> BINDINGS_FUNCTION = new Function<Rule, Map<String, Label>>() { @Nullable @Override public Map<String, Label> apply(Rule rule) { String prefix = "@" + rule.getName() + "//:"; ImmutableMap.Builder<String, Label> builder = ImmutableMap.builder(); builder.put("android/sdk", Label.parseAbsoluteUnchecked(prefix + "sdk")); builder.put( "android/dx_jar_import", Label.parseAbsoluteUnchecked(prefix + "dx_jar_import")); builder.put("android_sdk_for_testing", Label.parseAbsoluteUnchecked(prefix + "files")); return builder.build(); } }; @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { return builder .setWorkspaceOnly() .setExternalBindingsFunction(BINDINGS_FUNCTION) /* <!-- #BLAZE_RULE(android_sdk_repository).ATTRIBUTE(path) --> An absolute or relative path to an Android SDK. Either this attribute or the <code>$ANDROID_HOME</code> environment variable must be set. <p>The Android SDK can be downloaded from <a href='https://developer.android.com'>the Android developer site</a>. <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ .add(attr("path", STRING).nonconfigurable("WORKSPACE rule")) // This is technically the directory for the build tools in $sdk/build-tools. In particular, // preview SDKs are in "$sdk/build-tools/x.y.z-preview", but the version is typically // actually "x.y.z-rcN". E.g., for 24, the directory is "$sdk/build-tools/24.0.0-preview", // but the version is e.g. "24 rc3". The android_sdk rule that is generated from // android_sdk_repository would need the real version ("24 rc3"). /* <!-- #BLAZE_RULE(android_sdk_repository).ATTRIBUTE(build_tools_version) --> The version of the Android build tools to use from within the Android SDK. If not specified, the latest build tools version installed will be used. <p>Bazel requires build tools version 24.0.3 or later. <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ .add(attr("build_tools_version", STRING).nonconfigurable("WORKSPACE rule")) /* <!-- #BLAZE_RULE(android_sdk_repository).ATTRIBUTE(api_level) --> The Android API level to build against by default. If not specified, the highest API level installed will be used. <p>The API level used for a given build can be overridden by the <code>android_sdk</code> flag. <code>android_sdk_repository</code> creates an <code>android_sdk</code> target for each API level installed in the SDK with name <code>@androidsdk//:sdk-${level}</code>, whether or not this attribute is specified. For example, to build against a non-default API level: <code>bazel build --android_sdk=@androidsdk//:sdk-19 //java/com/example:app</code>. <p>To view all <code>android_sdk</code> targets generated by <code>android_sdk_repository </code>, you can run <code>bazel query "kind(android_sdk, @androidsdk//...)"</code>. <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ .add(attr("api_level", INTEGER).nonconfigurable("WORKSPACE rule")) .build(); } @Override public Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name(AndroidSdkRepositoryRule.NAME) .type(RuleClassType.WORKSPACE) .ancestors(WorkspaceBaseRule.class) .factoryClass(WorkspaceConfiguredTargetFactory.class) .build(); } } /*<!-- #BLAZE_RULE (NAME=android_sdk_repository, TYPE=OTHER, FAMILY=Workspace)[GENERIC_RULE] --> <p>Configures Bazel to use a local Android SDK to support building Android targets.</p> <h4 id="android_sdk_repository_examples">Examples</h4> The minimum to set up an Android SDK for Bazel is to put an <code>android_sdk_repository</code> rule named "androidsdk" in your <code>WORKSPACE</code> file and set the <code>$ANDROID_HOME</code> environment variable to the path of your Android SDK. Bazel will use the highest Android API level and build tools version installed in the Android SDK by default. <pre class="code"> android_sdk_repository( name = "androidsdk", ) </pre> <p>To ensure reproducible builds, the <code>path</code>, <code>api_level</code> and <code>build_tools_version</code> attributes can be set to specific values. The build will fail if the Android SDK does not have the specified API level or build tools version installed. <pre class="code"> android_sdk_repository( name = "androidsdk", path = "./sdk", api_level = 19, build_tools_version = "25.0.0", ) </pre> <p>The above example also demonstrates using a workspace-relative path to the Android SDK. This is useful if the Android SDK is part of your Bazel workspace (e.g. if it is checked into version control). <h4 id="android_sdk_repository_support_libraries">Support Libraries</h4> <p>The Support Libraries are available in the Android SDK Manager as "Android Support Repository". This is a versioned set of common Android libraries, such as the Support and AppCompat libraries, that is packaged as a local Maven repository. <code>android_sdk_repository</code> generates Bazel targets for each of these libraries that can be used in the dependencies of <code>android_binary</code> and <code>android_library</code> targets. <p>The names of the generated targets are derived from the Maven coordinates of the libraries in the Android Support Repository, formatted as <code>@androidsdk//${group}:${artifact}-${version}</code>. The following example shows how an <code>android_library</code> can depend on version 25.0.0 of the v7 appcompat library. <pre class="code"> android_library( name = "lib", srcs = glob(["*.java"]), manifest = "AndroidManifest.xml", resource_files = glob(["res/**"]), deps = ["@androidsdk//com.android.support:appcompat-v7-25.0.0"], ) </pre> <!-- #END_BLAZE_RULE -->*/