aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rwxr-xr-xscripts/bootstrap/compile.sh9
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/xcode_configure.WORKSPACE2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java17
-rw-r--r--src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java3
-rwxr-xr-xsrc/test/shell/bazel/bazel_apple_test.sh32
-rw-r--r--tools/osx/xcode_configure.bzl152
7 files changed, 209 insertions, 8 deletions
diff --git a/scripts/bootstrap/compile.sh b/scripts/bootstrap/compile.sh
index bf1da4dd81..1948943e1f 100755
--- a/scripts/bootstrap/compile.sh
+++ b/scripts/bootstrap/compile.sh
@@ -254,7 +254,14 @@ chmod 0755 ${ARCHIVE_DIR}/_embedded_binaries/process-wrapper${EXE_EXT}
cp src/main/tools/build_interface_so ${ARCHIVE_DIR}/_embedded_binaries/build_interface_so
cp src/main/tools/jdk.BUILD ${ARCHIVE_DIR}/_embedded_binaries/jdk.BUILD
cp $OUTPUT_DIR/libblaze.jar ${ARCHIVE_DIR}
-cp tools/osx/xcode_locator_stub.sh ${ARCHIVE_DIR}/_embedded_binaries/xcode-locator
+
+# TODO(b/28965185): Remove when xcode-locator is no longer required in embedded_binaries.
+log "Compiling xcode-locator..."
+if [[ $PLATFORM == "darwin" ]]; then
+ run /usr/bin/xcrun clang -fobjc-arc -framework CoreServices -framework Foundation -o ${ARCHIVE_DIR}/_embedded_binaries/xcode-locator tools/osx/xcode_locator.m
+else
+ cp tools/osx/xcode_locator_stub.sh ${ARCHIVE_DIR}/_embedded_binaries/xcode-locator
+fi
# bazel build using bootstrap version
function bootstrap_build() {
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java
index 4cf042b782..26fd3af4b5 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java
@@ -188,6 +188,8 @@ public class BazelRulesModule extends BlazeModule {
// will not be loaded for our Java tests.
builder.addWorkspaceFileSuffix(
ResourceFileLoader.loadResource(BazelCppRuleClasses.class, "cc_configure.WORKSPACE"));
+ builder.addWorkspaceFileSuffix(
+ ResourceFileLoader.loadResource(BazelRulesModule.class, "xcode_configure.WORKSPACE"));
} catch (IOException e) {
throw new IllegalStateException(e);
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/xcode_configure.WORKSPACE b/src/main/java/com/google/devtools/build/lib/bazel/rules/xcode_configure.WORKSPACE
new file mode 100644
index 0000000000..efc6fe6e36
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/xcode_configure.WORKSPACE
@@ -0,0 +1,2 @@
+load("@bazel_tools//tools/osx:xcode_configure.bzl", "xcode_configure")
+xcode_configure("@bazel_tools//tools/osx:xcode_locator.m")
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java
index c110cbbd49..b014ecc7fd 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java
@@ -26,7 +26,6 @@ import com.google.devtools.build.lib.rules.apple.Platform.PlatformType;
import com.google.devtools.common.options.Converters.CommaSeparatedOptionListConverter;
import com.google.devtools.common.options.EnumConverter;
import com.google.devtools.common.options.Option;
-
import java.util.List;
/**
@@ -150,18 +149,22 @@ public class AppleCommandLineOptions extends FragmentOptions {
converter = DefaultProvisioningProfileConverter.class)
public Label defaultProvisioningProfile;
- @Option(name = "xcode_version_config",
- defaultValue = "@bazel_tools" + DEFAULT_XCODE_VERSION_CONFIG_LABEL,
- category = "undocumented",
- converter = LabelConverter.class,
- help = "The label of the xcode_config rule to be used for selecting the xcode version "
- + "in the build configuration")
+ @Option(
+ name = "xcode_version_config",
+ defaultValue = "@local_config_xcode//:host_xcodes",
+ category = "undocumented",
+ converter = LabelConverter.class,
+ help =
+ "The label of the xcode_config rule to be used for selecting the xcode version "
+ + "in the build configuration"
+ )
public Label xcodeVersionConfig;
/**
* The default label of the build-wide {@code xcode_config} configuration rule. This can be
* changed from the default using the {@code xcode_version_config} build flag.
*/
+ // TODO(cparsons): Update all callers to reference the actual xcode_version_config flag value.
static final String DEFAULT_XCODE_VERSION_CONFIG_LABEL = "//tools/objc:host_xcodes";
/** Converter for --default_ios_provisioning_profile. */
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
index a17305be3f..5b47d44f86 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
@@ -64,6 +64,7 @@ public final class BazelAnalysisMock extends AnalysisMock {
new ArrayList<>(
ImmutableList.of(
"local_repository(name = 'bazel_tools', path = '" + bazelToolWorkspace + "')",
+ "local_repository(name = 'local_config_xcode', path = '/local_config_xcode')",
"bind(",
" name = 'objc_proto_lib',",
" actual = '//objcproto:ProtocolBuffers_lib',",
@@ -79,6 +80,8 @@ public final class BazelAnalysisMock extends AnalysisMock {
"bind(name = 'android/sdk', actual='@bazel_tools//tools/android:sdk')",
"bind(name = 'tools/python', actual='//tools/python')"));
+ config.create(
+ "/local_config_xcode/BUILD", "xcode_config(name = 'host_xcodes')");
config.overwrite("WORKSPACE", workspaceContents.toArray(new String[workspaceContents.size()]));
config.create("/bazel_tools_workspace/WORKSPACE", "workspace(name = 'bazel_tools')");
config.create(
diff --git a/src/test/shell/bazel/bazel_apple_test.sh b/src/test/shell/bazel/bazel_apple_test.sh
index 8495c15dba..3c35f9813b 100755
--- a/src/test/shell/bazel/bazel_apple_test.sh
+++ b/src/test/shell/bazel/bazel_apple_test.sh
@@ -547,4 +547,36 @@ apple_watch2_extension(
EOF
}
+function test_host_xcodes() {
+ XCODE_VERSION=$(xcodebuild -version | grep "Xcode" \
+ | sed -E "s/Xcode (([0-9]|.)+).*/\1/")
+ IOS_SDK=$(xcodebuild -version -sdk | grep iphoneos \
+ | sed -E "s/.*\(iphoneos(([0-9]|.)+)\).*/\1/")
+ MACOSX_SDK=$(xcodebuild -version -sdk | grep macosx \
+ | sed -E "s/.*\(macosx(([0-9]|.)+)\).*/\1/" | head -n 1)
+
+ # Unfortunately xcodebuild -version doesn't always pad with trailing .0, so,
+ # for example, may produce "6.4", which is bad for this test.
+ if [[ ! $XCODE_VERSION =~ [0-9].[0-9].[0-9] ]]
+ then
+ XCODE_VERSION="${XCODE_VERSION}.0"
+ fi
+
+ bazel build @local_config_xcode//:host_xcodes >"${TEST_log}" 2>&1 \
+ || fail "Expected host_xcodes to build"
+
+ bazel query "attr(version, $XCODE_VERSION, \
+ attr(default_ios_sdk_version, $IOS_SDK, \
+ attr(default_macosx_sdk_version, $MACOSX_SDK, \
+ labels('versions', '@local_config_xcode//:host_xcodes'))))" \
+ > xcode_version_target
+
+ assert_contains "local_config_xcode" xcode_version_target
+
+ DEFAULT_LABEL=$(bazel query \
+ "labels('default', '@local_config_xcode//:host_xcodes')")
+
+ assert_equals $DEFAULT_LABEL $(cat xcode_version_target)
+}
+
run_suite "apple_tests"
diff --git a/tools/osx/xcode_configure.bzl b/tools/osx/xcode_configure.bzl
new file mode 100644
index 0000000000..4315a045ed
--- /dev/null
+++ b/tools/osx/xcode_configure.bzl
@@ -0,0 +1,152 @@
+# Copyright 2016 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.
+"""Repository rule to generate host xcode_config and xcode_version targets.
+
+ The xcode_config and xcode_version targets are configured for xcodes/SDKs
+ installed on the local host.
+"""
+
+
+def _search_string(fullstring, prefix, suffix):
+ """Returns the substring between two given substrings of a larger string.
+
+ Args:
+ fullstring: The larger string to search.
+ prefix: The substring that should occur directly before the returned string.
+ suffix: The substring that should occur direclty after the returned string.
+ Returns:
+ A string occurring in fullstring exactly prefixed by prefix, and exactly
+ terminated by suffix. For example, ("hello goodbye", "lo ", " bye") will
+ return "good". If there is no such string, returns the empty string.
+ """
+
+ prefix_index = fullstring.find(prefix)
+ if (prefix_index < 0):
+ return ""
+ result_start_index = prefix_index + len(prefix)
+ suffix_index = fullstring.find(suffix, result_start_index)
+ if (suffix_index < 0):
+ return ""
+ return fullstring[result_start_index:suffix_index]
+
+
+def _search_sdk_output(output, sdkname):
+ """Returns the sdk version given xcodebuild stdout and an sdkname."""
+ return _search_string(output, "(%s" % sdkname, ")")
+
+
+def _xcode_version_output(repository_ctx, name, version, aliases, developer_dir):
+ """Returns a string containing an xcode_version build target."""
+ build_contents = ""
+ decorated_aliases = []
+ for alias in aliases:
+ decorated_aliases.append("'%s'" % alias)
+ xcodebuild_result = repository_ctx.execute(["xcodebuild", "-version", "-sdk"], 5, {"DEVELOPER_DIR": developer_dir})
+ if (xcodebuild_result.return_code != 0):
+ print("Invoking xcodebuild failed, return code %s, stderr: %s", xcodebuild_result.return_code, xcodebuild_result.stderr)
+ ios_sdk_version = _search_sdk_output(xcodebuild_result.stdout, "iphoneos")
+ tvos_sdk_version = _search_sdk_output(xcodebuild_result.stdout, "appletvos")
+ macosx_sdk_version = _search_sdk_output(xcodebuild_result.stdout, "macosx")
+ watchos_sdk_version = _search_sdk_output(xcodebuild_result.stdout, "watchos")
+ build_contents += "xcode_version(\n name = '%s'," % name
+ build_contents += "\n version = '%s'," % version
+ if aliases:
+ build_contents += "\n aliases = [%s]," % " ,".join(decorated_aliases)
+ if ios_sdk_version:
+ build_contents += "\n default_ios_sdk_version = '%s'," % ios_sdk_version
+ if tvos_sdk_version:
+ build_contents += "\n default_tvos_sdk_version = '%s'," % tvos_sdk_version
+ if macosx_sdk_version:
+ build_contents += "\n default_macosx_sdk_version = '%s'," % macosx_sdk_version
+ if watchos_sdk_version:
+ build_contents += "\n default_watchos_sdk_version = '%s'," % watchos_sdk_version
+ build_contents += "\n)\n"
+ return build_contents
+
+
+def _darwin_build_file(repository_ctx):
+ """Evaluates local system state to create xcode_config and xcode_version targets."""
+ xcodeloc_src_path = str(repository_ctx.path(Label(repository_ctx.attr.xcode_locator)))
+ repository_ctx.execute(["xcrun", "clang", "-fobjc-arc", "-framework", "CoreServices", "-framework", "Foundation", "-o", "xcode-locator-bin", xcodeloc_src_path])
+
+ xcode_locator_result = repository_ctx.execute(["./xcode-locator-bin", "-v"])
+ if (xcode_locator_result.return_code != 0):
+ print("Invoking xcode-locator failed, return code %s, stderr: %s", xcode_locator_result.return_code, xcode_locator_result.stderr)
+ xcodebuild_result = repository_ctx.execute(["xcodebuild", "-version"])
+ if (xcodebuild_result.return_code != 0):
+ print("Invoking xcodebuild failed, return code %s, stderr: %s", xcodebuild_result.return_code, xcodebuild_result.stderr)
+
+ default_xcode_version = _search_string(xcodebuild_result.stdout, "Xcode ", "\n")
+ default_xcode_target = ""
+ target_names = []
+ buildcontents = ""
+
+ # xcode_dump is comprised of newlines with different installed xcode versions,
+ # each line of the form <version>:<comma_separated_aliases>:<developer_dir>.
+ xcode_dump = xcode_locator_result.stdout
+ for xcodeversion in xcode_dump.split("\n"):
+ if ":" in xcodeversion:
+ infosplit = xcodeversion.split(":")
+ version = infosplit[0]
+ aliases = infosplit[1].split(",")
+ developer_dir = infosplit[2]
+ target_name = "version%s" % version.replace(".", "_")
+ buildcontents += _xcode_version_output(repository_ctx, target_name, version, aliases, developer_dir)
+ target_names.append("':%s'" % target_name)
+ if (version == default_xcode_version or default_xcode_version in aliases):
+ default_xcode_target = target_name
+ buildcontents += "xcode_config(name = 'host_xcodes',"
+ if target_names:
+ buildcontents += "\n versions = [%s]," % ", ".join(target_names)
+ if default_xcode_target:
+ buildcontents += "\n default = ':%s'," % default_xcode_target
+ buildcontents += "\n)\n"
+ return buildcontents
+
+
+def _impl(repository_ctx):
+ """Implementation for the local_config_xcode repository rule.
+
+ Generates a BUILD file containing a root xcode_config target named 'host_xcodes',
+ which points to an xcode_version target for each version of xcode installed on
+ the local host machine. If no versions of xcode are present on the machine
+ (for instance, if this is a non-darwin OS), creates a stub target.
+
+ Args:
+ repository_ctx: The repository context.
+ """
+
+ os_name = repository_ctx.os.name.lower()
+ build_contents = "package(default_visibility = ['//visibility:public'])\n\n"
+ if (os_name.startswith("mac os")):
+ build_contents += _darwin_build_file(repository_ctx)
+ else:
+ build_contents += "xcode_config(name = 'host_xcodes')"
+ repository_ctx.file("BUILD", build_contents)
+
+xcode_autoconf = repository_rule(
+ implementation=_impl,
+ local=True,
+ attrs={
+ "xcode_locator": attr.string(),
+ }
+)
+
+
+def xcode_configure(xcode_locator_label):
+ """Generates a repository containing host xcode version information."""
+ xcode_autoconf(
+ name="local_config_xcode",
+ xcode_locator=xcode_locator_label
+ )