From 2036dbd666a3e6430480bcbe333c77376d35bc63 Mon Sep 17 00:00:00 2001 From: Dmitry Shevchenko Date: Fri, 22 Apr 2016 20:46:07 +0000 Subject: Add a Skylark rule to build Swift modules. * Adds a swift_library rule that produces a (.a, .swiftmodule) pair. It can handle dependencies between modules and can be used as a dependency of objc_binary. * Does not work with Objective-C yet. -- MOS_MIGRATED_REVID=120578875 --- examples/BUILD | 1 + examples/swift/BUILD | 19 ++++++ examples/swift/BarLib/BUILD | 15 +++++ examples/swift/BarLib/mul.swift | 8 +++ examples/swift/constants.swift | 4 ++ examples/swift/foo.swift | 9 +++ src/test/shell/bazel/BUILD | 10 +++ src/test/shell/bazel/bazel_apple_test.sh | 42 ++++++++++++ tools/BUILD | 2 + tools/build_defs/apple/shared.bzl | 19 ++++++ tools/build_defs/apple/swift.bzl | 110 +++++++++++++++++++++++++++++++ 11 files changed, 239 insertions(+) create mode 100644 examples/swift/BUILD create mode 100644 examples/swift/BarLib/BUILD create mode 100644 examples/swift/BarLib/mul.swift create mode 100644 examples/swift/constants.swift create mode 100644 examples/swift/foo.swift create mode 100755 src/test/shell/bazel/bazel_apple_test.sh create mode 100644 tools/build_defs/apple/swift.bzl diff --git a/examples/BUILD b/examples/BUILD index 8bfbc19524..781c81a46c 100644 --- a/examples/BUILD +++ b/examples/BUILD @@ -11,5 +11,6 @@ filegroup( "//examples/py:srcs", "//examples/py_native:srcs", "//examples/shell:srcs", + "//examples/swift:srcs", ], ) diff --git a/examples/swift/BUILD b/examples/swift/BUILD new file mode 100644 index 0000000000..e2cbb195e2 --- /dev/null +++ b/examples/swift/BUILD @@ -0,0 +1,19 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) # Apache 2.0 + +load("//tools/build_defs/apple:swift.bzl", "swift_library") + +swift_library( + name = "swift_lib", + srcs = glob(["*.swift"]), + deps = ["//examples/swift/BarLib"], +) + +filegroup( + name = "srcs", + srcs = glob(["**"]) + [ + "//examples/swift/BarLib:srcs", + ], + visibility = ["//examples:__pkg__"], +) diff --git a/examples/swift/BarLib/BUILD b/examples/swift/BarLib/BUILD new file mode 100644 index 0000000000..d575a879f1 --- /dev/null +++ b/examples/swift/BarLib/BUILD @@ -0,0 +1,15 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) # Apache 2.0 + +load("//tools/build_defs/apple:swift.bzl", "swift_library") + +swift_library( + name = "BarLib", + srcs = ["mul.swift"], +) + +filegroup( + name = "srcs", + srcs = glob(["**"]), +) diff --git a/examples/swift/BarLib/mul.swift b/examples/swift/BarLib/mul.swift new file mode 100644 index 0000000000..1f1df40512 --- /dev/null +++ b/examples/swift/BarLib/mul.swift @@ -0,0 +1,8 @@ +/// Class used to multiply stuff. +public class Multiplier { + public init() {} + + public func multiply(a: Int, _ b: Int) -> Int { + return a * b + } +} diff --git a/examples/swift/constants.swift b/examples/swift/constants.swift new file mode 100644 index 0000000000..6c16d34a82 --- /dev/null +++ b/examples/swift/constants.swift @@ -0,0 +1,4 @@ +class Constants { + static var x = 2 + static var y = 3 +} \ No newline at end of file diff --git a/examples/swift/foo.swift b/examples/swift/foo.swift new file mode 100644 index 0000000000..067c6730cd --- /dev/null +++ b/examples/swift/foo.swift @@ -0,0 +1,9 @@ +import class BarLib.Multiplier + +public class Foo { + public init() {} + + public func multiply() -> Int { + return Multiplier().multiply(Constants.x, Constants.y) + } +} diff --git a/src/test/shell/bazel/BUILD b/src/test/shell/bazel/BUILD index 49112206f4..cccd7874e6 100644 --- a/src/test/shell/bazel/BUILD +++ b/src/test/shell/bazel/BUILD @@ -93,6 +93,16 @@ sh_test( data = [":test-deps"], ) +sh_test( + name = "bazel_apple_test", + srcs = ["bazel_apple_test.sh"], + data = [ + ":objc-deps", + ":test-deps", + "//:workspace-file", + ], +) + sh_test( name = "bazel_rules_test", size = "large", diff --git a/src/test/shell/bazel/bazel_apple_test.sh b/src/test/shell/bazel/bazel_apple_test.sh new file mode 100755 index 0000000000..89141110a3 --- /dev/null +++ b/src/test/shell/bazel/bazel_apple_test.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# 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. +# +# Tests the examples provided in Bazel +# + +# Load test environment +source $(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/test-setup.sh \ + || { echo "test-setup.sh not found!" >&2; exit 1; } + +if [ "${PLATFORM}" != "darwin" ]; then + echo "This test suite requires running on OS X" >&2 + exit 0 +fi + +function set_up() { + copy_examples +} + +function test_swift_library() { + rm WORKSPACE + ln -sv ${workspace_file} WORKSPACE + + local swift_lib_pkg=examples/swift + assert_build_output ./bazel-bin/${swift_lib_pkg}/swift_lib.a ${swift_lib_pkg}:swift_lib + assert_build_output ./bazel-bin/${swift_lib_pkg}/swift_lib.swiftmodule ${swift_lib_pkg}:swift_lib +} + +run_suite "apple_tests" diff --git a/tools/BUILD b/tools/BUILD index 302e3b7766..c55c0ad9e1 100644 --- a/tools/BUILD +++ b/tools/BUILD @@ -10,6 +10,7 @@ filegroup( "//tools/android:srcs", "//tools/android/jack:srcs", "//tools/buildstamp:srcs", + "//tools/build_defs/apple:srcs", "//tools/build_defs/docker:srcs", "//tools/build_defs/jsonnet:srcs", "//tools/build_defs/pkg:srcs", @@ -34,6 +35,7 @@ filegroup( srcs = glob(["**"]) + [ "//tools/android/jack:srcs", "//tools/android:srcs", + "//tools/build_defs/apple:srcs", "//tools/build_defs/docker:srcs", "//tools/build_defs/jsonnet:srcs", "//tools/build_defs/pkg:srcs", diff --git a/tools/build_defs/apple/shared.bzl b/tools/build_defs/apple/shared.bzl index 70c6ae6239..bebfb7a9ad 100644 --- a/tools/build_defs/apple/shared.bzl +++ b/tools/build_defs/apple/shared.bzl @@ -37,6 +37,9 @@ DARWIN_EXECUTION_REQUIREMENTS = {"requires-darwin": ""} See :func:`apple_action`.""" +XCRUNWRAPPER_LABEL = "//external:xcrunwrapper" +"""The label for xcrunwrapper tool.""" + def apple_action(ctx, **kw): """Creates an action that only runs on MacOS/Darwin. @@ -49,3 +52,19 @@ def apple_action(ctx, **kw): ctx.action(**kw) +def xcrun_action(ctx, **kw): + """Creates an apple action that executes xcrunwrapper. + + args: + ctx: The context of the rule that owns this action. + + This method takes the same keyword arguments as ctx.action, however you don't + need to specify the executable. + """ + platform = ctx.fragments.apple.ios_cpu_platform() + action_env = ctx.fragments.apple.target_apple_env(platform) \ + + ctx.fragments.apple.apple_host_system_env() + env = kw.get('env', {}) + kw['env'] = env + action_env + + apple_action(ctx, executable=ctx.executable._xcrunwrapper, **kw) diff --git a/tools/build_defs/apple/swift.bzl b/tools/build_defs/apple/swift.bzl new file mode 100644 index 0000000000..8f0eda18bb --- /dev/null +++ b/tools/build_defs/apple/swift.bzl @@ -0,0 +1,110 @@ +# 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. + +"""Skylark rules for Swift.""" + +load("shared", "xcrun_action", "XCRUNWRAPPER_LABEL") + +def _swift_target(cpu, sdk_version): + """Returns a target triplet for Swift compiler.""" + return "%s-apple-ios%s" % (cpu, sdk_version) + +def _swift_library_impl(ctx): + """Implementation for swift_library Skylark rule.""" + cpu = ctx.fragments.apple.ios_cpu() + platform = ctx.fragments.apple.ios_cpu_platform() + sdk_version = ctx.fragments.apple.sdk_version_for_platform(platform) + target = _swift_target(cpu, sdk_version) + + # Collect transitive dependecies. + dep_modules = [] + dep_libs = [] + for x in ctx.attr.deps: + swift_provider = x.swift + dep_libs.append(swift_provider.library) + dep_libs += swift_provider.transitive_libs + + dep_modules.append(swift_provider.module) + dep_modules += swift_provider.transitive_modules + + # TODO(b/28005753): Currently this is not really a library, but an object + # file, does not matter to the linker, but should be replaced with proper ar + # call. + output_lib = ctx.outputs.swift_lib + output_module = ctx.outputs.swift_module + + srcs_args = [f.path for f in ctx.files.srcs] + + # TODO(b/28005582): Instead of including a dir for each dependecy, output to + # a shared dir and include that? + include_dirs = set([x.dirname for x in dep_modules]) + include_args = ["-I%s" % d for d in include_dirs] + + args = [ + "swift", + "-frontend", + "-emit-object", + "-emit-module-path", output_module.path, + "-module-name", ctx.label.name, + "-parse-as-library", + "-target", target, + # TODO(b/28049126): Replace this value with apple_toolchain call. + "-sdk", "__BAZEL_XCODE_SDKROOT__", + "-o", output_lib.path, + ] + srcs_args + include_args + + xcrun_action(ctx, + inputs = ctx.files.srcs + dep_modules + dep_libs, + outputs = (output_lib, output_module), + mnemonic = 'SwiftCompile', + arguments = args, + use_default_shell_env = False, + progress_message = ("Compiling Swift module %s (%d files)" + % (ctx.label.name, len(ctx.files.srcs)))) + + return struct( + swift=struct( + library=output_lib, + module=output_module, + transitive_libs=dep_libs, + transitive_modules=dep_modules), + objc_export=struct( + library=set([output_lib] + dep_libs), + ) + ) + +swift_library = rule( + _swift_library_impl, + attrs = { + "srcs": attr.label_list(allow_files = FileType([".swift"])), + "deps": attr.label_list(providers=["swift"]), + "_xcrunwrapper": attr.label( + executable=True, + default=Label(XCRUNWRAPPER_LABEL))}, + fragments = ["apple"], + outputs = { + "swift_lib": "%{name}.a", + "swift_module": "%{name}.swiftmodule", + }, +) +""" +Builds a Swift module. + +A module is a pair of static library (.a) + module header (.swiftmodule). +Dependant targets can import this module as "import RuleName". + +Args: + srcs: Swift sources that comprise this module. + deps: Other Swift modules. +""" -- cgit v1.2.3