Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions .bazelci/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,16 @@ x_defaults:
- "-//test:output_file_map_default"
windows_common: &windows_common
platform: windows
build_flags:
# Override 'sandboxed' strategy set in .bazelrc because it's not
# available on Windows
- "--strategy=SwiftCompile="
build_targets:
- "//tools/..."
# Cross-platform Swift examples that exercise the Windows host toolchain:
# a `swift_binary` executable and a `linkshared` Windows DLL.
- "//examples/xplatform/hello_world"
- "//examples/xplatform/shared_library"
test_targets:
# Exercises XCTest discovery, the test runner, and `swift_test` execution
# on Windows.
- "//examples/xplatform/xctest"

tasks:
macos_latest:
Expand Down Expand Up @@ -97,11 +101,31 @@ tasks:
- "curl https://download.swift.org/swift-${SWIFT_VERSION}-release/ubuntu2204/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE-ubuntu22.04.tar.gz | tar xvz --strip-components=1 -C $SWIFT_HOME"
<<: *linux_common

# TODO: re-enable when Windows in Bazel CI is properly configured for Swift.
# windows_last_green:
# name: "Last Green Bazel"
# bazel: last_green
# <<: *windows_common
windows:
name: "Current LTS"
bazel: latest
# Expose the installed Swift toolchain and the MSVC/Windows SDK environment to
# the build. The swift.org installer (`batch_commands` below) records its
# Toolchains/Runtimes bin on the user's Path and sets SDKROOT, and a Visual
# Studio "developer prompt" (vcvars) would set INCLUDE/LIB for swiftc's clang
# to find the C headers (errno.h, ...) and for the linker — but none of that
# reaches the already-running CI process. Set it all here. BazelCI expands
# these with os.path.expandvars, so %VAR% resolves and earlier keys (listed
# first) are available to later ones. The VS/SDK versions are pinned to the
# Bazel CI Windows image; update them if `vcvars64.bat`'s output changes.
environment:
SWIFT_VERSION: "6.3.2"
VCToolsInstallDir: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\VC\\Tools\\MSVC\\14.39.33519"
WindowsSdkDir: "C:\\Program Files (x86)\\Windows Kits\\10"
WindowsSDKVersion: "10.0.26100.0"
Path: "%LOCALAPPDATA%\\Programs\\Swift\\Toolchains\\%SWIFT_VERSION%+Asserts\\usr\\bin;%LOCALAPPDATA%\\Programs\\Swift\\Runtimes\\%SWIFT_VERSION%\\usr\\bin;%LOCALAPPDATA%\\Programs\\Swift\\Tools\\%SWIFT_VERSION%;%VCToolsInstallDir%\\bin\\Hostx64\\x64;%WindowsSdkDir%\\bin\\%WindowsSDKVersion%\\x64;%PATH%"
SDKROOT: "%LOCALAPPDATA%\\Programs\\Swift\\Platforms\\%SWIFT_VERSION%\\Windows.platform\\Developer\\SDKs\\Windows.sdk"
INCLUDE: "%VCToolsInstallDir%\\include;%WindowsSdkDir%\\include\\%WindowsSDKVersion%\\ucrt;%WindowsSdkDir%\\include\\%WindowsSDKVersion%\\shared;%WindowsSdkDir%\\include\\%WindowsSDKVersion%\\um;%WindowsSdkDir%\\include\\%WindowsSDKVersion%\\winrt;%WindowsSdkDir%\\include\\%WindowsSDKVersion%\\cppwinrt"
LIB: "%VCToolsInstallDir%\\lib\\x64;%WindowsSdkDir%\\lib\\%WindowsSDKVersion%\\ucrt\\x64;%WindowsSdkDir%\\lib\\%WindowsSDKVersion%\\um\\x64"
batch_commands:
- "curl -sSL -o %TEMP%\\swift-installer.exe https://download.swift.org/swift-%SWIFT_VERSION%-release/windows10/swift-%SWIFT_VERSION%-RELEASE/swift-%SWIFT_VERSION%-RELEASE-windows10.exe"
- "%TEMP%\\swift-installer.exe -q"
<<: *windows_common

doc_tests:
name: "Doc tests"
Expand Down
6 changes: 6 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ common:linux --repo_env=CC=clang
build:linux --cxxopt='-std=c++17' --host_cxxopt='-std=c++17'
common:linux --//test:apple_build_tests=False

# Worker sandboxing copies the worker into a sandbox exec root and cleans it
# between invocations. On Windows a running/recently-run executable cannot be
# deleted, so that cleanup fails with "Permission denied". Run Swift workers
# unsandboxed on Windows.
build:windows --noworker_sandboxing

# This C2K warning causes zlib to fail to compile.
# There is an open issue about it on the zlib repository here:
# https://github.com/madler/zlib/issues/633
Expand Down
4 changes: 3 additions & 1 deletion swift/internal/compiling.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1667,7 +1667,9 @@ def _declare_per_source_output_file(actions, extension, target_name, src):
The declared `File`.
"""
objs_dir = "{}_objs".format(target_name)
owner_rel_path = owner_relative_path(src)

# Spaces in object file paths break response-file parsing on Windows
owner_rel_path = owner_relative_path(src).replace(" ", "_")
basename = paths.basename(owner_rel_path)
dirname = paths.join(objs_dir, paths.dirname(owner_rel_path))

Expand Down
67 changes: 55 additions & 12 deletions swift/internal/swift_autoconfiguration.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,22 @@ def _normalized_linux_cpu(cpu):
return "x86_64"
return cpu

def _normalized_windows_cpu(cpu):
"""Normalizes a host CPU name to the value Swift uses on Windows.

The returned value is used both as the toolchain's `arch` and as the
architecture component of the Swift SDK's library layout (for example
`usr/lib/swift/windows/x86_64`) and the target triple.
"""
cpu = cpu.lower()
if cpu in ("amd64", "x86_64", "x64"):
return "x86_64"
if cpu in ("arm64", "aarch64"):
return "aarch64"
if cpu in ("x86", "i686"):
return "i686"
return cpu

def _resolve_toolchain_root(repository_ctx, swiftc_path):
"""Returns the Swift toolchain root directory for `swiftc_path`.

Expand Down Expand Up @@ -269,15 +285,28 @@ xcode_swift_toolchain(
]),
)

def _python_executable_works(repository_ctx, python_bin):
"""Returns True if `python_bin` is a real, runnable Python 3 interpreter.

On Windows, `python3.exe`/`python.exe` found on `PATH` are frequently the
Microsoft Store "App execution alias" stubs rather than real interpreters:
when run non-interactively they print a message pointing at the Store and
exit nonzero. Probe the candidate so those stubs are skipped in favor of a
working interpreter later on `PATH`. We also confirm it is Python 3, since
the caller needs the Python 3 `plistlib` API.
"""
result = repository_ctx.execute(
[python_bin, "-c", "import sys; print('ok' if sys.version_info[0] == 3 else 'no')"],
)
return result.return_code == 0 and result.stdout.strip() == "ok"

def _get_python_bin(repository_ctx):
if "PYTHON_BIN_PATH" in repository_ctx.os.environ:
return repository_ctx.os.environ.get("PYTHON_BIN_PATH").strip()
out = repository_ctx.which("python3.exe")
if out:
return out
out = repository_ctx.which("python.exe")
if out:
return out
for name in ("python3.exe", "python3", "python.exe", "python"):
candidate = repository_ctx.which(name)
if candidate and _python_executable_works(repository_ctx, candidate):
return candidate
return None

def _create_windows_toolchain(*, repository_ctx):
Expand All @@ -294,6 +323,7 @@ Swift toolchain.
"""

root = path_to_swiftc.dirname.dirname
arch = _normalized_windows_cpu(repository_ctx.os.arch)
enabled_features = [
SWIFT_FEATURE_CODEVIEW_DEBUG_INFO,
SWIFT_FEATURE_DECLARE_SWIFTSOURCEINFO,
Expand All @@ -305,22 +335,34 @@ Swift toolchain.
disabled_features = []

version_file, parsed_version = _write_swift_version(repository_ctx, path_to_swiftc)

# Normalize SDKROOT to forward slashes with no trailing separator: the raw
# environment value typically ends in a backslash, which is both invalid at
# the end of a Python raw-string literal (used below) and produces doubled
# separators when joined.
sdkroot = repository_ctx.os.environ["SDKROOT"].replace("\\", "/").rstrip("/")

info_plist = sdkroot + "/../../../Info.plist"
python_bin = _get_python_bin(repository_ctx)
if not python_bin:
fail("Could not find a working Python 3 interpreter on PATH; it is " +
"required to read the XCTest version from the Swift SDK's Info.plist.")
xctest_version = repository_ctx.execute([
_get_python_bin(repository_ctx),
python_bin,
"-c",
"import os, plistlib; " +
"print(plistlib.loads(open(os.path.join(r'{}', '..', '..', '..', 'Info.plist'), 'rb').read(), fmt=plistlib.FMT_XML)['DefaultProperties']['XCTEST_VERSION'])".format(repository_ctx.os.environ["SDKROOT"]),
"import plistlib; " +
"print(plistlib.load(open(r'{}', 'rb'))['DefaultProperties']['XCTEST_VERSION'])".format(info_plist),
])

env = {
"Path": repository_ctx.os.environ["Path"] if "Path" in repository_ctx.os.environ else repository_ctx.os.environ["PATH"],
"ProgramData": repository_ctx.os.environ["ProgramData"],
"ProgramData": repository_ctx.os.environ.get("ProgramData", "C:\\ProgramData"),
}

return """\
swift_toolchain(
name = "windows-toolchain",
arch = "x86_64",
arch = "{arch}",
features = [{features}],
os = "windows",
root = "{root}",
Expand All @@ -332,11 +374,12 @@ swift_toolchain(
xctest_version = "{xctest_version}",
)
""".format(
arch = arch,
features = ", ".join(['"{}"'.format(feature) for feature in enabled_features] + ['"-{}"'.format(feature) for feature in disabled_features]),
root = root,
env = env,
parsed_version = parsed_version,
sdkroot = repository_ctx.os.environ["SDKROOT"].replace("\\", "/"),
sdkroot = sdkroot,
xctest_version = xctest_version.stdout.rstrip(),
version_file = version_file,
)
Expand Down
6 changes: 6 additions & 0 deletions swift/swift_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def _generate_test_discovery_srcs(
*,
actions,
deps,
env = {},
name,
objc_test_discovery,
owner_module_name,
Expand All @@ -109,6 +110,9 @@ def _generate_test_discovery_srcs(
Args:
actions: The context's actions object.
deps: The list of direct dependencies of the test target.
env: Environment variables to set when running the discovery tool. On
Comment thread
keith marked this conversation as resolved.
Windows this must include a `Path` that contains the Swift runtime
DLLs, otherwise the (Swift) discovery executable fails to launch.
name: The name of the target being built, which will be used to derive
the basename of the directory containing the generated files.
objc_test_discovery: If `True`, the runner should use Objective-C-based
Expand Down Expand Up @@ -197,6 +201,7 @@ def _generate_test_discovery_srcs(

actions.run(
arguments = [args],
env = env,
executable = test_discoverer,
exec_group = _DISCOVER_TESTS_EXEC_GROUP,
inputs = inputs,
Expand Down Expand Up @@ -411,6 +416,7 @@ def _swift_test_impl(ctx):
discovery_srcs = _generate_test_discovery_srcs(
actions = ctx.actions,
deps = ctx.attr.deps,
env = toolchains.swift.test_configuration.env,
name = ctx.label.name,
objc_test_discovery = objc_test_discovery,
owner_module_name = module_name,
Expand Down
15 changes: 15 additions & 0 deletions swift/toolchains/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,21 @@ toolchain(
visibility = ["//visibility:public"],
)

toolchain(
name = "windows-swift-toolchain-aarch64",
exec_compatible_with = [
"@platforms//os:windows",
"@platforms//cpu:aarch64",
],
target_compatible_with = [
"@platforms//os:windows",
"@platforms//cpu:aarch64",
],
toolchain = "@rules_swift_local_config//:windows-toolchain",
toolchain_type = "//toolchains:toolchain_type",
visibility = ["//visibility:public"],
)

# Consumed by Bazel integration tests.
filegroup(
name = "for_bazel_tests",
Expand Down
32 changes: 29 additions & 3 deletions swift/toolchains/swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ def _all_action_configs(os, arch, target_triple, sdkroot, xctest_version, additi
actions = all_compile_action_names() + [
SWIFT_ACTION_DUMP_AST,
SWIFT_ACTION_PRECOMPILE_C_MODULE,
SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT,
],
configurators = [
add_arg(
Expand Down Expand Up @@ -294,6 +295,7 @@ def _all_action_configs(os, arch, target_triple, sdkroot, xctest_version, additi
actions = all_compile_action_names() + [
SWIFT_ACTION_DUMP_AST,
SWIFT_ACTION_PRECOMPILE_C_MODULE,
SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT,
],
configurators = [
add_arg(
Expand Down Expand Up @@ -364,6 +366,13 @@ def _swift_windows_linkopts_cc_info(
"-LIBPATH:{}".format(platform_lib_dir),
"-LIBPATH:{}".format(paths.join(sdkroot, "..", "..", "Library", "XCTest-{}".format(xctest_version), "usr", "lib", "swift", "windows", arch)),
runtime_object_path,
# Swift marks references to symbols in other modules (for example the
# type metadata accessors a generated test runner references via
# `@testable import`) as `dllimport`. Bazel links everything statically,
# so those symbols resolve locally and `link.exe` emits LNK4217. The
# warning is benign for static linking; suppress it so it is not fatal
# under `/WX` (treat-warnings-as-errors).
"-IGNORE:4217",
]

return CcInfo(
Expand Down Expand Up @@ -480,6 +489,17 @@ def _entry_point_linkopts_provider(*, entry_point_name):
linkopts = ["-Wl,--defsym,main={}".format(entry_point_name)],
)

def _windows_entry_point_linkopts_provider(*, entry_point_name):
"""Returns linkopts to customize the entry point of a binary on Windows.

MSVC `link.exe` does not understand the GNU `ld` `--defsym` alias used on
other platforms; `/ALTERNATENAME` is the equivalent, resolving the
CRT-referenced `main` symbol to the renamed Swift entry point.
"""
return struct(
linkopts = ["/ALTERNATENAME:main={}".format(entry_point_name)],
)

def _parse_target_system_name(*, arch, os, target_system_name):
"""Returns the target system name set by the CC toolchain or attempts to create one based on the OS and arch."""

Expand All @@ -488,6 +508,10 @@ def _parse_target_system_name(*, arch, os, target_system_name):

if os == "linux":
return "%s-unknown-linux-gnu" % arch
elif os == "windows":
# The MSVC cc toolchain reports a `target_gnu_system_name` of "local",
# so synthesize the triple.
return "%s-unknown-windows-msvc" % arch
else:
return "%s-unknown-%s" % (arch, os)

Expand Down Expand Up @@ -520,7 +544,7 @@ def _swift_toolchain_impl(ctx):
target_triples.parse(ctx.var.get("CC_TARGET_TRIPLE") or target_system_name),
)

if "clang" not in cc_toolchain.compiler and "llvm" not in cc_toolchain.compiler:
if ctx.attr.os != "windows" and "clang" not in cc_toolchain.compiler and "llvm" not in cc_toolchain.compiler:
Comment thread
keith marked this conversation as resolved.
fail("Swift requires the configured CC toolchain use clang. " +
"Either use the locally installed LLVM by setting `CC=clang` in your environment " +
"before invoking Bazel, or configure a Bazel LLVM CC toolchain. " +
Expand Down Expand Up @@ -646,7 +670,7 @@ def _swift_toolchain_impl(ctx):
bindir = "bin64"
elif ctx.attr.arch == "i686":
bindir = "bin32"
elif ctx.attr.arch == "arm64":
elif ctx.attr.arch in ("aarch64", "arm64"):
bindir = "bin64a"
else:
fail("unsupported arch `{}`".format(ctx.attr.arch))
Expand All @@ -672,7 +696,9 @@ def _swift_toolchain_impl(ctx):
cross_import_overlays = collect_cross_import_overlays(ctx.attr.cross_import_overlays),
debug_outputs_provider = None,
developer_dirs = [],
entry_point_linkopts_provider = _entry_point_linkopts_provider,
entry_point_linkopts_provider = (
_windows_entry_point_linkopts_provider if ctx.attr.os == "windows" else _entry_point_linkopts_provider
),
feature_allowlists = [
target[SwiftFeatureAllowlistInfo]
for target in ctx.attr.feature_allowlists
Expand Down
2 changes: 1 addition & 1 deletion tools/test_observer/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ swift_library(
"BazelXMLTestObserver.swift",
"Concurrency.swift",
"JSON.swift",
"LinuxXCTestRunner.swift",
"Locked.swift",
"ObjectiveCXCTestRunner.swift",
"ShardingFilteringTestCollector.swift",
"StringInterpolation+XMLEscaping.swift",
"SwiftCorelibsXCTestRunner.swift",
"SwiftTestingRunner.swift",
"XUnitTestRecorder.swift",
],
Expand Down
Loading
Loading