diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 000000000..7ec1d6db4 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +2.1.0 diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index 25df44e03..534d1a86f 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -11,10 +11,15 @@ jobs: - name: Select Xcode 11.2 run: sudo xcode-select -s /Applications/Xcode_11.2.app - name: Install Bazel - run: brew install bazel buildifier + run: brew install bazelisk buildifier - name: Build and Test - run: bazel test //... + run: bazelisk test --local_test_jobs=2 //... + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: bazel-testlogs + path: bazel-testlogs - name: buildifier run: find . -type f \( -name 'WORKSPACE' -o -name '*.bzl' -o -name '*.bazel' \) | xargs buildifier --mode=diff - name: Check docs - run: bazel run docs --nocheck_visibility && git diff --exit-code docs + run: bazelisk run docs --nocheck_visibility && git diff --exit-code docs diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 5337cb6f8..f6698deda 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -14,6 +14,6 @@ jobs: - name: Select Xcode 11.2 run: sudo xcode-select -s /Applications/Xcode_11.2.app - name: Install Bazel - run: brew install bazel + run: brew install bazelisk - name: Build and Test - run: bazel test //... + run: bazelisk test --local_test_jobs=2 //... diff --git a/docs/library_doc.md b/docs/library_doc.md index 4c1e7be0e..d07e153f4 100755 --- a/docs/library_doc.md +++ b/docs/library_doc.md @@ -65,7 +65,7 @@ Propagates private headers, so they can be accessed if necessary ## apple_library
-apple_library(name, library_tools, export_private_headers, kwargs) +apple_library(name, library_tools, export_private_headers, namespace_is_module_name, kwargs)Create libraries for native source code on Apple platforms. @@ -82,6 +82,7 @@ reasonable defaults that mimic Xcode's behavior. | name | The base name for all of the underlying targets. | none | | library_tools | An optional dictionary containing overrides for default behaviors. |
{}
|
| export_private_headers | Whether private headers should be exported via a PrivateHeaders
provider. | True
|
+| namespace_is_module_name | Whether the module name should be used as the namespace for header imports, instead of the target name. | True
|
| kwargs | -
| none | diff --git a/rules/app.bzl b/rules/app.bzl index a06c35959..dd2d9c6fd 100644 --- a/rules/app.bzl +++ b/rules/app.bzl @@ -22,13 +22,14 @@ def ios_application(name, apple_library = apple_library, **kwargs): kwargs: Arguments passed to the apple_library and ios_application rules as appropriate. """ infoplists = kwargs.pop("infoplists", []) - application_kwargs = {arg: kwargs.pop(arg, None) for arg in _IOS_APPLICATION_KWARGS} - library = apple_library(name = name, **kwargs) + application_kwargs = {arg: kwargs.pop(arg) for arg in _IOS_APPLICATION_KWARGS if arg in kwargs} + library = apple_library(name = name, namespace_is_module_name = False, **kwargs) if not infoplists: infoplists += ["@build_bazel_rules_ios//rules/test_host_app:Info.plist"] - kwargs["families"] = kwargs.pop("families", ["iphone", "ipad"]) + application_kwargs["launch_storyboard"] = application_kwargs.pop("launch_storyboard", library.launch_screen_storyboard_name) + application_kwargs["families"] = application_kwargs.pop("families", ["iphone", "ipad"]) rules_apple_ios_application( name = name, diff --git a/rules/framework.bzl b/rules/framework.bzl index 70f0bb899..ef66556e9 100644 --- a/rules/framework.bzl +++ b/rules/framework.bzl @@ -15,7 +15,7 @@ def apple_framework(name, apple_library = apple_library, **kwargs): library = apple_library(name = name, **kwargs) apple_framework_packaging( name = name, - framework_name = library.module_name, + framework_name = library.namespace, transitive_deps = library.transitive_deps, deps = library.lib_names, visibility = kwargs.get("visibility", None), @@ -141,12 +141,18 @@ def _apple_framework_packaging_impl(ctx): destination = paths.join(framework_dir, "Headers", hdr.basename) header_out.append(destination) + if not has_header: + # only thing is the generated module map -- we don't want it + continue + + if SwiftInfo in dep and dep[SwiftInfo].direct_swiftmodules: + # apple_common.Objc.direct_module_maps is broken coming from swift_library + # (it contains one level of transitive module maps), so ignore SwiftInfo from swift_library, + # since it doesn't have a module_map field anyway + continue + # collect modulemaps for modulemap in dep[apple_common.Objc].direct_module_maps: - if not has_header: - # only thing is the generated module map -- we don't want it - continue - modulemap_in = modulemap binary_out = None diff --git a/rules/library.bzl b/rules/library.bzl index 0e4a8e053..1ac9d73ae 100644 --- a/rules/library.bzl +++ b/rules/library.bzl @@ -15,6 +15,8 @@ PrivateHeaders = provider( }, ) +_MANUAL = ["manual"] + def _private_headers_impl(ctx): return [ PrivateHeaders( @@ -107,6 +109,7 @@ module {module_name} {{ name = basename + "~", destination = destination, content = content, + tags = _MANUAL, ) return destination @@ -147,6 +150,7 @@ FOUNDATION_EXPORT const unsigned char {module_name}VersionString[]; name = basename + "~", destination = destination, content = content, + tags = _MANUAL, ) return destination @@ -161,6 +165,7 @@ def generate_resource_bundles(name, library_tools, module_name, resource_bundles "PRODUCT_BUNDLE_IDENTIFIER": "com.cocoapods.%s" % bundle_name, "PRODUCT_NAME": bundle_name, }, + tags = _MANUAL, ) apple_resource_bundle( name = target_name, @@ -169,6 +174,7 @@ def generate_resource_bundles(name, library_tools, module_name, resource_bundles library_tools["wrap_resources_in_filegroup"](name = target_name + "_resources", srcs = resource_bundles[bundle_name]), ], infoplists = [name + ".info.plist"], + tags = _MANUAL, ) bundle_target_names.append(target_name) return bundle_target_names @@ -183,7 +189,7 @@ _DefaultLibraryTools = { def _uppercase_string(s): return s.upper() -def apple_library(name, library_tools = {}, export_private_headers = True, **kwargs): +def apple_library(name, library_tools = {}, export_private_headers = True, namespace_is_module_name = True, **kwargs): """Create libraries for native source code on Apple platforms. Automatically handles mixed-source libraries and comes with @@ -195,6 +201,8 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa default behaviors. export_private_headers: Whether private headers should be exported via a `PrivateHeaders` provider. + namespace_is_module_name: Whether the module name should be used as the + namespace for header imports, instead of the target name. """ library_tools = dict(_DefaultLibraryTools, **library_tools) swift_sources = [] @@ -236,6 +244,7 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa fail("Unable to compile %s in apple_framework %s" % (f, name)) module_name = kwargs.pop("module_name", name) + namespace = module_name if namespace_is_module_name else name module_map = kwargs.pop("module_map", None) cc_copts = kwargs.pop("cc_copts", []) swift_copts = kwargs.pop("swift_copts", []) @@ -249,6 +258,8 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa pch = kwargs.pop("pch", "@build_bazel_rules_ios//rules/library:common.pch") deps = kwargs.pop("deps", []) data = kwargs.pop("data", []) + tags = kwargs.pop("tags", []) + tags_manual = tags if "manual" in tags else tags + _MANUAL internal_deps = [] lib_names = [] @@ -257,6 +268,7 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa apple_static_framework_import( name = import_name, framework_imports = native.glob(["%s/**/*" % vendored_static_framework]), + tags = _MANUAL, ) deps += [import_name] for vendored_dynamic_framework in kwargs.pop("vendored_dynamic_frameworks", []): @@ -265,6 +277,7 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa name = import_name, framework_imports = native.glob(["%s/**/*" % vendored_dynamic_framework]), deps = [], + tags = _MANUAL, ) deps += [import_name] for vendored_static_library in kwargs.pop("vendored_static_libraries", []): @@ -272,6 +285,7 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa native.objc_import( name = import_name, archives = [vendored_static_library], + tags = _MANUAL, ) deps += [import_name] for vendored_dynamic_library in kwargs.pop("vendored_dynamic_libraries", []): @@ -292,6 +306,7 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa native.filegroup( name = public_hdrs_filegroup, srcs = objc_hdrs, + tags = _MANUAL, ) # Public hmaps are for vendored static libs to export their header only. @@ -299,10 +314,11 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa # rules. headermap( name = public_hmap_name, - namespace = module_name, + namespace = namespace, hdrs = [public_hdrs_filegroup], hdr_providers = deps, flatten_headers = True, + tags = _MANUAL, ) internal_deps.append(public_hmap_name) @@ -313,24 +329,28 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa native.filegroup( name = private_hdrs_filegroup, srcs = objc_non_exported_hdrs + objc_private_hdrs + objc_hdrs, + tags = _MANUAL, ) native.filegroup( name = private_angled_hdrs_filegroup, srcs = objc_non_exported_hdrs + objc_private_hdrs, + tags = _MANUAL, ) headermap( name = private_hmap_name, - namespace = module_name, + namespace = namespace, hdrs = [private_hdrs_filegroup], flatten_headers = False, + tags = _MANUAL, ) internal_deps.append(private_hmap_name) headermap( name = private_angled_hmap_name, - namespace = module_name, + namespace = namespace, hdrs = [private_angled_hdrs_filegroup], flatten_headers = True, + tags = _MANUAL, ) internal_deps.append(private_angled_hmap_name) ## END HMAP @@ -375,7 +395,7 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa cpp_libname = "%s_cpp" % name # TODO: remove framework if set - if not module_map and (objc_hdrs or objc_private_hdrs or swift_sources): + if namespace_is_module_name and not module_map and (objc_hdrs or objc_private_hdrs or swift_sources): umbrella_header = library_tools["umbrella_header_generator"]( name = name, library_tools = library_tools, @@ -398,30 +418,39 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa ) if swift_sources: - swift_copts += [ - "-Xcc", - "-fmodule-map-file=" + "$(execpath " + module_map + ")", - "-import-underlying-module", - ] + if module_map: + swift_copts += [ + "-Xcc", + "-fmodule-map-file=" + "$(execpath " + module_map + ")", + "-import-underlying-module", + ] + swiftc_inputs = other_inputs + objc_hdrs + if module_map: + swiftc_inputs.append(module_map) + generated_header_name = module_name + "-Swift.h" swift_library( name = swift_libname, module_name = module_name, + generated_header_name = generated_header_name, srcs = swift_sources, copts = swift_copts, deps = deps + internal_deps + lib_names, - swiftc_inputs = other_inputs + objc_hdrs + [module_map], + swiftc_inputs = swiftc_inputs, features = ["swift.no_generated_module_map"], + tags = tags_manual, **kwargs ) lib_names += [swift_libname] - extend_modulemap( - name = module_map + ".extended." + name, - destination = "%s.extended.modulemap" % name, - source = module_map, - swift_header = "%s-Swift.h" % swift_libname, - module_name = module_name, - ) - module_map = "%s.extended.modulemap" % name + if module_map: + extend_modulemap( + name = module_map + ".extended." + name, + destination = "%s.extended.modulemap" % name, + source = module_map, + swift_header = generated_header_name, + module_name = module_name, + tags = _MANUAL, + ) + module_map = "%s.extended.modulemap" % name if cpp_sources and False: native.cc_library( @@ -430,9 +459,11 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa hdrs = objc_hdrs, copts = cc_copts, deps = deps, + tags = tags_manual, ) lib_names += [cpp_libname] + objc_library_data = library_tools["wrap_resources_in_filegroup"](name = objc_libname + "_data", srcs = data) native.objc_library( name = objc_libname, srcs = objc_sources + objc_private_hdrs + objc_non_exported_hdrs, @@ -446,19 +477,29 @@ def apple_library(name, library_tools = {}, export_private_headers = True, **kwa weak_sdk_frameworks = weak_sdk_frameworks, sdk_includes = sdk_includes, pch = pch, - data = [library_tools["wrap_resources_in_filegroup"](name = objc_libname + "_data", srcs = data)], + data = [objc_library_data], + tags = tags_manual, **kwargs ) + launch_screen_storyboard_name = name + "_launch_screen_storyboard" + native.filegroup( + name = launch_screen_storyboard_name, + srcs = [objc_library_data], + output_group = "launch_screen_storyboard", + tags = _MANUAL, + ) lib_names += [objc_libname] if export_private_headers: private_headers_name = "%s_private_headers" % name lib_names += [private_headers_name] - _private_headers(name = private_headers_name, headers = objc_private_hdrs) + _private_headers(name = private_headers_name, headers = objc_private_hdrs, tags = _MANUAL) return struct( lib_names = lib_names, transitive_deps = deps, deps = lib_names + deps, module_name = module_name, + launch_screen_storyboard_name = launch_screen_storyboard_name, + namespace = namespace, ) diff --git a/rules/library/resources.bzl b/rules/library/resources.bzl index cdd27cd1e..ce31a51c4 100644 --- a/rules/library/resources.bzl +++ b/rules/library/resources.bzl @@ -5,18 +5,49 @@ def _is_apple_resource_file(file, extensions_to_filter): return True def _resources_filegroup_impl(ctx): - files = [f for f in ctx.files.srcs if _is_apple_resource_file(file = f, extensions_to_filter = ctx.attr.extensions_to_filter)] - return [ + files = [] + launch_screen_storyboard = None + for f in ctx.files.srcs: + if not _is_apple_resource_file(file = f, extensions_to_filter = ctx.attr.extensions_to_filter): + continue + + if f.basename == "LaunchScreen.storyboard": + if launch_screen_storyboard: + fail( + "Specified multiple %s files in %s:\n %s\n %s" % (f.basename, launch_screen_storyboard.path, f.path), + ) + launch_screen_storyboard = f + else: + files.append(f) + + if not launch_screen_storyboard: + launch_screen_storyboard = ctx.file.default_launch_screen_storyboard + + providers = [ DefaultInfo( files = depset(items = files), ), ] + if launch_screen_storyboard: + providers.append( + OutputGroupInfo( + launch_screen_storyboard = [launch_screen_storyboard], + ), + ) + + return providers + resources_filegroup = rule( implementation = _resources_filegroup_impl, attrs = { "srcs": attr.label_list(allow_files = True, allow_empty = True), "extensions_to_filter": attr.string_list(mandatory = True, allow_empty = True), + "default_launch_screen_storyboard": attr.label( + mandatory = False, + allow_single_file = ["storyboard", "xib"], + default = Label("//rules/test_host_app:LaunchScreen.storyboard"), + ), }, doc = """Wraps a set of srcs for use as `data` in an `objc_library` or `swift_library`, or `resources` in an `apple_resource_bundle`. diff --git a/rules/repositories.bzl b/rules/repositories.bzl index 6ce2809e9..dfba3e76d 100644 --- a/rules/repositories.bzl +++ b/rules/repositories.bzl @@ -27,25 +27,25 @@ def rules_ios_dependencies(): _maybe( git_repository, name = "build_bazel_rules_apple", - commit = "96212456d3cd7be9760fe28c077673bb85d46500", + commit = "fe8cf69b058c86624ba1786e6024c2a1af1d48e9", + shallow_since = "1581368998 -0800", remote = "https://github.com/bazelbuild/rules_apple.git", - shallow_since = "1576719323 -0800", ) _maybe( git_repository, name = "build_bazel_rules_swift", - commit = "d7757c5ee9724df9454edefa3b4455a401a2ae22", + commit = "657eda57a097980848dbb3c880b94faeddaa3cd1", + shallow_since = "1580525034 -0800", remote = "https://github.com/bazelbuild/rules_swift.git", - shallow_since = "1576775454 -0800", ) _maybe( git_repository, name = "build_bazel_apple_support", - commit = "9605c3da1c5bcdddc20d1704b52415a6f3a5f422", + commit = "501b4afb27745c4813a88ffa28acd901408014e4", + shallow_since = "1577729628 -0800", remote = "https://github.com/bazelbuild/apple_support.git", - shallow_since = "1570831694 -0700", ) _maybe( diff --git a/rules/test.bzl b/rules/test.bzl index c1625c7e3..4bea405db 100644 --- a/rules/test.bzl +++ b/rules/test.bzl @@ -2,6 +2,17 @@ load("@build_bazel_rules_apple//apple:ios.bzl", rules_apple_ios_unit_test = "ios load("@bazel_skylib//lib:types.bzl", "types") load("//rules:library.bzl", "apple_library") +_IOS_UNIT_TEST_KWARGS = [ + "bundle_id", + "infoplists", + "minimum_os_version", + "test_host", + "env", + "args", + "size", + "timeout", +] + def ios_unit_test(name, apple_library = apple_library, **kwargs): """ Builds and packages iOS Unit Tests. @@ -11,9 +22,9 @@ def ios_unit_test(name, apple_library = apple_library, **kwargs): apple_library: The macro used to package sources into a library. kwargs: Arguments passed to the apple_library and ios_unit_test rules as appropriate. """ - unit_test_kwargs = {arg: kwargs.pop(arg, None) for arg in ["bundle_id", "infoplists", "minimum_os_version", "test_host", "env", "args", "size", "timeout"]} + unit_test_kwargs = {arg: kwargs.pop(arg) for arg in _IOS_UNIT_TEST_KWARGS if arg in kwargs} unit_test_kwargs["data"] = kwargs.pop("test_data", []) - if unit_test_kwargs["test_host"] == True: + if unit_test_kwargs.get("test_host", None) == True: unit_test_kwargs["test_host"] = "@build_bazel_rules_ios//rules/test_host_app:iOS-%s-AppHost" % unit_test_kwargs.get("minimum_os_version") if "runner" in kwargs and "runners" in kwargs: @@ -28,7 +39,7 @@ def ios_unit_test(name, apple_library = apple_library, **kwargs): else: unit_test_kwargs["runner"] = runner - library = apple_library(name = name, **kwargs) + library = apple_library(name = name, namespace_is_module_name = False, **kwargs) rule( name = name, diff --git a/rules/test_host_app/BUILD.bazel b/rules/test_host_app/BUILD.bazel index 48a48ab19..9ae9c4829 100644 --- a/rules/test_host_app/BUILD.bazel +++ b/rules/test_host_app/BUILD.bazel @@ -2,6 +2,7 @@ load("//rules:app.bzl", "ios_application") exports_files([ "Info.plist", + "LaunchScreen.storyboard", ]) [ diff --git a/tests/test/ios/test-imports-app/BUILD.bazel b/tests/test/ios/test-imports-app/BUILD.bazel new file mode 100644 index 000000000..c48514f0a --- /dev/null +++ b/tests/test/ios/test-imports-app/BUILD.bazel @@ -0,0 +1,45 @@ +load("//rules:app.bzl", "ios_application") +load("//rules:framework.bzl", "apple_framework_packaging") +load("//rules:test.bzl", "ios_unit_test") + +ios_application( + name = "TestImports-App", + srcs = [ + "Header.h", + "Header2.h", + "empty.swift", + "main.m", + ], + bundle_id = "com.example.TestImports-App", + minimum_os_version = "12.0", + module_name = "TestImports_App", + sdk_frameworks = ["UIKit"], +) + +# Implicitly generate a framework without a binary so tests can +# import code from their test hosts without it being double-linked. +apple_framework_packaging( + name = "TestImports-App_framework_unlinked", + framework_name = "TestImports-App", + skip_packaging = ["binary"], + transitive_deps = [], + deps = [ + ":TestImports-App_objc", + ":TestImports-App_swift", + ], +) + +ios_unit_test( + name = "TestImports-Unit-Tests", + srcs = [ + "test.m", + "test.swift", + ], + minimum_os_version = "12.0", + module_name = "TestImports_Unit_Tests", + sdk_frameworks = ["XCTest"], + test_host = ":TestImports-App", + deps = [ + ":TestImports-App_framework_unlinked", + ], +) diff --git a/tests/test/ios/test-imports-app/Header.h b/tests/test/ios/test-imports-app/Header.h new file mode 100644 index 000000000..2806ebf00 --- /dev/null +++ b/tests/test/ios/test-imports-app/Header.h @@ -0,0 +1 @@ +#import