Skip to content

Commit

Permalink
Make Xcode setup more resilient
Browse files Browse the repository at this point in the history
Previously if you tried to build a project from a entirely clean bazel
state, and ctrl-c'd while bazel was fetching the local_config_xcode
information, you would end up in a state where the
local_config_xcode/BUILD file contained error information, which made
the Apple crosstool unusable until you did a `clean --expunge`. Now the
Xcode setup calls `fail()` in those cases, which makes bazel re-run it
again the next time you try to build.

It is still possible to reproduce if you ctrl-c while the `xcodebuild
-version` command that determines if you have Xcode installed at all
runs. Because we want to support users who don't have Xcode installed on
macOS, we cannot fail in that case.

Fixes #6056

Closes #7519.

PiperOrigin-RevId: 235997257
  • Loading branch information
keith authored and copybara-github committed Feb 27, 2019
1 parent ac6d4fd commit d03dcfb
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 22 deletions.
4 changes: 1 addition & 3 deletions tools/cpp/osx_cc_configure.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def configure_osx_toolchain(repository_ctx, overriden_tools):
])

xcode_toolchains = []
(xcode_toolchains, xcodeloc_err) = run_xcode_locator(
xcode_toolchains = run_xcode_locator(
repository_ctx,
paths["@bazel_tools//tools/osx:xcode_locator.m"],
)
Expand Down Expand Up @@ -133,8 +133,6 @@ def configure_osx_toolchain(repository_ctx, overriden_tools):
escaped_cxx_include_directories = []
for path in escaped_include_paths:
escaped_cxx_include_directories.append((" \"%s\"," % path))
if xcodeloc_err:
escaped_cxx_include_directories.append("# Error: " + xcodeloc_err + "\n")
repository_ctx.template(
"cc_toolchain_config.bzl",
paths["@bazel_tools//tools/osx/crosstool:cc_toolchain_config.bzl.tpl"],
Expand Down
144 changes: 144 additions & 0 deletions tools/cpp/osx_cc_configure.bzl.orig
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# pylint: disable=g-bad-file-header

This comment has been minimized.

Copy link
@keith

keith Feb 28, 2019

Author Member
# 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.
"""Configuring the C++ toolchain on macOS."""

load("@bazel_tools//tools/osx:xcode_configure.bzl", "run_xcode_locator")
load(
"@bazel_tools//tools/cpp:lib_cc_configure.bzl",
"escape_string",
"resolve_labels",
)
load(
"@bazel_tools//tools/cpp:unix_cc_configure.bzl",
"configure_unix_toolchain",
"find_cc",
"get_env",
"get_escaped_cxx_inc_directories",
)

def _get_escaped_xcode_cxx_inc_directories(repository_ctx, cc, xcode_toolchains):
"""Compute the list of default C++ include paths on Xcode-enabled darwin.

Args:
repository_ctx: The repository context.
cc: The default C++ compiler on the local system.
xcode_toolchains: A list containing the xcode toolchains available
Returns:
include_paths: A list of builtin include paths.
"""

# TODO(cparsons): Falling back to the default C++ compiler builtin include
# paths shouldn't be unnecessary once all actions are using xcrun.
include_dirs = get_escaped_cxx_inc_directories(repository_ctx, cc, "-xc++")
for toolchain in xcode_toolchains:
include_dirs.append(escape_string(toolchain.developer_dir))
return include_dirs

def configure_osx_toolchain(repository_ctx, overriden_tools):
"""Configure C++ toolchain on macOS."""
paths = resolve_labels(repository_ctx, [
"@bazel_tools//tools/cpp:osx_cc_wrapper.sh.tpl",
"@bazel_tools//tools/objc:libtool.sh",
"@bazel_tools//tools/objc:make_hashed_objlist.py",
"@bazel_tools//tools/objc:xcrunwrapper.sh",
"@bazel_tools//tools/osx/crosstool:BUILD.tpl",
"@bazel_tools//tools/osx/crosstool:cc_toolchain_config.bzl.tpl",
"@bazel_tools//tools/osx/crosstool:osx_archs.bzl",
"@bazel_tools//tools/osx/crosstool:wrapped_ar.tpl",
"@bazel_tools//tools/osx/crosstool:wrapped_clang.cc",
"@bazel_tools//tools/osx:xcode_locator.m",
])

xcode_toolchains = []
(xcode_toolchains, xcodeloc_err) = run_xcode_locator(
repository_ctx,
paths["@bazel_tools//tools/osx:xcode_locator.m"],
)
if xcode_toolchains:
cc = find_cc(repository_ctx, overriden_tools = {})
repository_ctx.template(
"cc_wrapper.sh",
paths["@bazel_tools//tools/cpp:osx_cc_wrapper.sh.tpl"],
{
"%{cc}": escape_string(str(cc)),
"%{env}": escape_string(get_env(repository_ctx)),
},
)
repository_ctx.symlink(
paths["@bazel_tools//tools/objc:xcrunwrapper.sh"],
"xcrunwrapper.sh",
)
repository_ctx.symlink(
paths["@bazel_tools//tools/objc:libtool.sh"],
"libtool",
)
repository_ctx.symlink(
paths["@bazel_tools//tools/objc:make_hashed_objlist.py"],
"make_hashed_objlist.py",
)
repository_ctx.symlink(
paths["@bazel_tools//tools/osx/crosstool:wrapped_ar.tpl"],
"wrapped_ar",
)
repository_ctx.symlink(
paths["@bazel_tools//tools/osx/crosstool:BUILD.tpl"],
"BUILD",
)
repository_ctx.symlink(
paths["@bazel_tools//tools/osx/crosstool:osx_archs.bzl"],
"osx_archs.bzl",
)

wrapped_clang_src_path = str(repository_ctx.path(
paths["@bazel_tools//tools/osx/crosstool:wrapped_clang.cc"],
))
xcrun_result = repository_ctx.execute([
"env",
"-i",
"xcrun",
"clang",
"-std=c++11",
"-lc++",
"-o",
"wrapped_clang",
wrapped_clang_src_path,
], 30)
if (xcrun_result.return_code == 0):
repository_ctx.symlink("wrapped_clang", "wrapped_clang_pp")
else:
error_msg = (
"return code {code}, stderr: {err}, stdout: {out}"
).format(
code = xcrun_result.return_code,
err = xcrun_result.stderr,
out = xcrun_result.stdout,
)
fail("wrapped_clang failed to generate. Please file an issue at " +
"https://github.com/bazelbuild/bazel/issues with the following:\n" +
error_msg)

escaped_include_paths = _get_escaped_xcode_cxx_inc_directories(repository_ctx, cc, xcode_toolchains)
escaped_cxx_include_directories = []
for path in escaped_include_paths:
escaped_cxx_include_directories.append((" \"%s\"," % path))
if xcodeloc_err:
escaped_cxx_include_directories.append("# Error: " + xcodeloc_err + "\n")
repository_ctx.template(
"cc_toolchain_config.bzl",
paths["@bazel_tools//tools/osx/crosstool:cc_toolchain_config.bzl.tpl"],
{"%{cxx_builtin_include_directories}": "\n".join(escaped_cxx_include_directories)},
)
else:
configure_unix_toolchain(repository_ctx, cpu_value = "darwin", overriden_tools = overriden_tools)
32 changes: 13 additions & 19 deletions tools/osx/xcode_configure.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ def _xcode_version_output(repository_ctx, name, version, aliases, developer_dir)
"""Returns a string containing an xcode_version build target."""
build_contents = ""
decorated_aliases = []
error_msg = ""
for alias in aliases:
decorated_aliases.append("'%s'" % alias)
xcodebuild_result = repository_ctx.execute(
Expand All @@ -65,6 +64,8 @@ def _xcode_version_output(repository_ctx, name, version, aliases, developer_dir)
err = xcodebuild_result.stderr,
out = xcodebuild_result.stdout,
)
print(error_msg)
fail(error_msg)
ios_sdk_version = _search_sdk_output(xcodebuild_result.stdout, "iphoneos")
tvos_sdk_version = _search_sdk_output(xcodebuild_result.stdout, "appletvos")
macos_sdk_version = _search_sdk_output(xcodebuild_result.stdout, "macosx")
Expand All @@ -82,9 +83,6 @@ def _xcode_version_output(repository_ctx, name, version, aliases, developer_dir)
if watchos_sdk_version:
build_contents += "\n default_watchos_sdk_version = '%s'," % watchos_sdk_version
build_contents += "\n)\n"
if error_msg:
build_contents += "\n# Error: " + error_msg.replace("\n", " ") + "\n"
print(error_msg)
return build_contents

VERSION_CONFIG_STUB = "xcode_config(name = 'host_xcodes')"
Expand All @@ -104,13 +102,10 @@ def run_xcode_locator(repository_ctx, xcode_locator_src_label):
repository_ctx: The repository context.
xcode_locator_src_label: The label of the source file for xcode-locator.
Returns:
A 2-tuple containing:
output: A list representing installed xcode toolchain information. Each
element of the list is a struct containing information for one installed
toolchain. This is an empty list if there was an error building or
running xcode-locator.
err: An error string describing the error that occurred when attempting
to build and run xcode-locator, or None if the run was successful.
A list representing installed xcode toolchain information. Each
element of the list is a struct containing information for one installed
toolchain. This is an empty list if there was an error building or
running xcode-locator.
"""
xcodeloc_src_path = str(repository_ctx.path(xcode_locator_src_label))
xcrun_result = repository_ctx.execute([
Expand Down Expand Up @@ -142,7 +137,8 @@ def run_xcode_locator(repository_ctx, xcode_locator_src_label):
err = xcrun_result.stderr,
out = xcrun_result.stdout,
)
return ([], error_msg.replace("\n", " "))
print(error_msg)
fail(error_msg)

xcode_locator_result = repository_ctx.execute(["./xcode-locator-bin", "-v"], 30)
if (xcode_locator_result.return_code != 0):
Expand All @@ -153,8 +149,9 @@ def run_xcode_locator(repository_ctx, xcode_locator_src_label):
code = xcode_locator_result.return_code,
err = xcode_locator_result.stderr,
out = xcode_locator_result.stdout,
)
return ([], error_msg.replace("\n", " "))
).replace("\n", " ")
print(error_msg)
fail(error_msg)
xcode_toolchains = []

# xcode_dump is comprised of newlines with different installed xcode versions,
Expand All @@ -169,7 +166,7 @@ def run_xcode_locator(repository_ctx, xcode_locator_src_label):
developer_dir = infosplit[2],
)
xcode_toolchains.append(toolchain)
return (xcode_toolchains, None)
return xcode_toolchains

def _darwin_build_file(repository_ctx):
"""Evaluates local system state to create xcode_config and xcode_version targets."""
Expand All @@ -189,14 +186,11 @@ def _darwin_build_file(repository_ctx):
)
return VERSION_CONFIG_STUB + "\n# Error: " + error_msg.replace("\n", " ") + "\n"

(toolchains, xcodeloc_err) = run_xcode_locator(
toolchains = run_xcode_locator(
repository_ctx,
Label(repository_ctx.attr.xcode_locator),
)

if xcodeloc_err:
return VERSION_CONFIG_STUB + "\n# Error: " + xcodeloc_err + "\n"

default_xcode_version = _search_string(xcodebuild_result.stdout, "Xcode ", "\n")
default_xcode_target = ""
target_names = []
Expand Down

0 comments on commit d03dcfb

Please sign in to comment.