diff --git a/haskell/actions.bzl b/haskell/actions.bzl index d24249eb6..0d94bc4f9 100644 --- a/haskell/actions.bzl +++ b/haskell/actions.bzl @@ -447,6 +447,16 @@ def create_ghc_package(ctx, interfaces_dir, static_library, dynamic_library): conf_file = ctx.actions.declare_file(paths.join(pkg_db_dir.basename, "{0}.conf".format(get_pkg_id(ctx)))) cache_file = ctx.actions.declare_file("package.cache", sibling=conf_file) + # Infer collection of public modules in the library. + + hidden_modules = set.from_list(ctx.attr.hidden_modules) + public_modules = [] + + for f in _hs_srcs(ctx): + mname = module_name(ctx, f) + if not set.is_member(hidden_modules, mname): + public_modules.append(mname) + # Create a file from which ghc-pkg will create the actual package from. registration_file = ctx.actions.declare_file(target_unique_name(ctx, "registration-file")) registration_file_entries = { @@ -455,8 +465,8 @@ def create_ghc_package(ctx, interfaces_dir, static_library, dynamic_library): "id": get_pkg_id(ctx), "key": get_pkg_id(ctx), "exposed": "True", - "exposed-modules": - " ".join([module_name(ctx, f) for f in _hs_srcs(ctx)]), + "exposed-modules": " ".join(public_modules), + "hidden-modules": " ".join(ctx.attr.hidden_modules), "import-dirs": paths.join("${pkgroot}", interfaces_dir.basename), "library-dirs": "${pkgroot}", "dynamic-library-dirs": "${pkgroot}", diff --git a/haskell/haskell.bzl b/haskell/haskell.bzl index 5fd9168e1..fe6979a2e 100644 --- a/haskell/haskell.bzl +++ b/haskell/haskell.bzl @@ -43,7 +43,7 @@ _haskell_common_attrs = { ), "srcs": attr.label_list( allow_files = FileType([".hs", ".hsc", ".lhs", ".hs-boot", ".lhs-boot", ".h"]), - doc = "Haskell source files", + doc = "Haskell source files.", ), "deps": attr.label_list( doc = "List of other Haskell libraries to be linked to this target.", @@ -177,7 +177,11 @@ def _haskell_library_impl(ctx): haskell_library = rule( _haskell_library_impl, - attrs = _haskell_common_attrs, + attrs = dict( + _haskell_common_attrs, + hidden_modules = attr.string_list( + doc = "Modules that should be made unavailable for import by dependencies." + )), host_fragments = ["cpp"], toolchains = ["@io_tweag_rules_haskell//haskell:toolchain"], ) diff --git a/haskell/set.bzl b/haskell/set.bzl index 8afcb3c36..f705aa3f8 100644 --- a/haskell/set.bzl +++ b/haskell/set.bzl @@ -20,7 +20,7 @@ def _is_member(s, e): Result: Bool, true if `e` is in `s`, false otherwise. """ - e in s._set_items + return e in s._set_items def _insert(s, e): """Insert an element into the set. diff --git a/tests/BUILD b/tests/BUILD index 36299b6b1..6d6d21540 100644 --- a/tests/BUILD +++ b/tests/BUILD @@ -111,7 +111,17 @@ rule_test( rule_test( name = "test-haskell_test", generates = ["haskell_test"], - rule = "//tests/haskell_test", + rule = "//tests/haskell_test:haskell_test", + size = "small", +) + +rule_test( + name = "test-hidden-modules", + generates = [ + "lib-c-1.0.0/lib-c-1.0.0.conf", + "lib-c-1.0.0/package.cache" + ], + rule = "//tests/hidden-modules:lib-c", size = "small", ) diff --git a/tests/hidden-modules/BUILD b/tests/hidden-modules/BUILD new file mode 100644 index 000000000..e7a9a21ae --- /dev/null +++ b/tests/hidden-modules/BUILD @@ -0,0 +1,28 @@ +package(default_testonly = 1, default_visibility = ["//visibility:public"]) + +load("@io_tweag_rules_haskell//haskell:haskell.bzl", + "haskell_library", +) + +haskell_library( + name = "lib-a", + src_strip_prefix = "lib-a", + srcs = glob(["lib-a/*.hs"]), + hidden_modules = ["Foo"], + prebuilt_dependencies = ["base"], +) + +haskell_library( + name = "lib-b", + src_strip_prefix = "lib-b", + srcs = glob(["lib-b/*.hs"]), + prebuilt_dependencies = ["base"], +) + +haskell_library( + name = "lib-c", + src_strip_prefix = "lib-c", + srcs = glob(["lib-c/*.hs"]), + prebuilt_dependencies = ["base"], + deps = [":lib-a", ":lib-b"], +) diff --git a/tests/hidden-modules/lib-a/Bar.hs b/tests/hidden-modules/lib-a/Bar.hs new file mode 100644 index 000000000..5bc9c6889 --- /dev/null +++ b/tests/hidden-modules/lib-a/Bar.hs @@ -0,0 +1,6 @@ +module Bar (bar) where + +import Foo (foo) + +bar :: Int +bar = foo * 2 diff --git a/tests/hidden-modules/lib-a/Foo.hs b/tests/hidden-modules/lib-a/Foo.hs new file mode 100644 index 000000000..664be00d5 --- /dev/null +++ b/tests/hidden-modules/lib-a/Foo.hs @@ -0,0 +1,4 @@ +module Foo (foo) where + +foo :: Int +foo = 15 diff --git a/tests/hidden-modules/lib-b/Foo.hs b/tests/hidden-modules/lib-b/Foo.hs new file mode 100644 index 000000000..6fdd42f9a --- /dev/null +++ b/tests/hidden-modules/lib-b/Foo.hs @@ -0,0 +1,4 @@ +module Foo (foo) where + +foo :: Int +foo = 16 diff --git a/tests/hidden-modules/lib-c/Baz.hs b/tests/hidden-modules/lib-c/Baz.hs new file mode 100644 index 000000000..055b2e80a --- /dev/null +++ b/tests/hidden-modules/lib-c/Baz.hs @@ -0,0 +1,7 @@ +module Baz (bar) where + +import Foo (foo) +import Bar (bar) + +baz :: Int +baz = foo + bar