Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provider refactoring, make REPL work with bin targets #186

Merged
merged 1 commit into from
Mar 15, 2018
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
228 changes: 135 additions & 93 deletions haskell/actions.bzl

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions haskell/cc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ These rules are temporary and will be deprecated in the future.
"""

load(":providers.bzl",
"HaskellPackageInfo",
"HaskellBuildInfo",
"CcSkylarkApiProviderHacked",
)

Expand Down Expand Up @@ -94,18 +94,18 @@ Example:
"""

def _cc_haskell_import(ctx):
if HaskellPackageInfo in ctx.attr.dep:
if HaskellBuildInfo in ctx.attr.dep:
return [DefaultInfo(
files = set.to_depset(ctx.attr.dep[HaskellPackageInfo].dynamic_libraries)
files = set.to_depset(ctx.attr.dep[HaskellBuildInfo].dynamic_libraries)
)]
else:
fail("{0} has to provide HaskellPackageInfo".format(ctx.attr.dep.label.name))
fail("{0} has to provide HaskellBuildInfo".format(ctx.attr.dep.label.name))

cc_haskell_import = rule(
_cc_haskell_import,
attrs = {
"dep": attr.label(
doc = "Target providing a `HaskellPackageInfo`, such as `haskell_library`."
doc = "Target providing a `HaskellBuildInfo`, such as `haskell_library`."
),
},
)
Expand Down
48 changes: 35 additions & 13 deletions haskell/ghci-repl.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ load("@bazel_skylib//:lib.bzl",
)

load(":providers.bzl",
"HaskellPackageInfo",
"HaskellBuildInfo",
"HaskellLibraryInfo",
"HaskellBinaryInfo",
)

load(":path_utils.bzl",
Expand All @@ -29,22 +31,23 @@ load(":utils.bzl",

def _haskell_repl_impl(ctx):

target = ctx.attr.target[HaskellPackageInfo]
target = ctx.attr.target[HaskellBuildInfo]
lib_target = ctx.attr.target[HaskellLibraryInfo] if HaskellLibraryInfo in ctx.attr.target else None
bin_target = ctx.attr.target[HaskellBinaryInfo] if HaskellBinaryInfo in ctx.attr.target else None

# Bring packages in scope.
args = ["-hide-all-packages"]
for dep in set.to_list(target.prebuilt_dependencies):
args += ["-package ", dep]
for name in set.to_list(target.names):
if not (ctx.attr.interpreted and name == target.name):
args += ["-package", name]
for cache in set.to_list(target.caches):
for package in set.to_list(target.package_names):
if not (ctx.attr.interpreted and lib_target != None and package == lib_target.package_name):
args += ["-package", package]
for cache in set.to_list(target.package_caches):
args += ["-package-db", cache.dirname]

# Import dirs in interpreted mode.
if ctx.attr.interpreted:
for idir in set.to_list(target.import_dirs):
args += ["-i{0}".format(idir)]
# Specify import directory for library in interpreted mode.
if ctx.attr.interpreted and lib_target != None:
args += ["-i{0}".format(lib_target.import_dir)]

# External libraries.
seen_libs = set.empty()
Expand All @@ -59,14 +62,33 @@ def _haskell_repl_impl(ctx):

ghci_script = ctx.actions.declare_file(target_unique_name(ctx, "ghci-repl-script"))

interpreted_modules = set.to_list(target.exposed_modules if ctx.attr.interpreted else set.empty())
visible_modules = set.to_list(target.exposed_modules)
add_modules = []
if lib_target != None:
# If we have a library, we put names of its exposed modules here but
# only if we're in interpreted mode.
add_modules = set.to_list(
lib_target.exposed_modules if ctx.attr.interpreted else set.empty()
)
elif bin_target != None:
# Otherwise we put paths to module files, mostly because it also works
# and Main module may be in a file with name that's impossible for GHC
# to infer.
add_modules = [f.path for f in set.to_list(bin_target.source_files)]

visible_modules = []
if lib_target != None:
# If we have a library, we put names of its exposed modules here.
visible_modules = set.to_list(lib_target.exposed_modules)
elif bin_target != None:
# Otherwise we do rougly the same by using modules from
# HaskellBinaryInfo.
visible_modules = set.to_list(bin_target.modules)

ctx.actions.expand_template(
template = ctx.file._ghci_script,
output = ghci_script,
substitutions = {
"{INTERPRETED_MODULES}": " ".join(interpreted_modules),
"{ADD_MODULES}": " ".join(add_modules),
"{VISIBLE_MODULES}": " ".join(visible_modules),
},
)
Expand Down
2 changes: 1 addition & 1 deletion haskell/ghci-script
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
:add {INTERPRETED_MODULES}
:add {ADD_MODULES}
:module + {VISIBLE_MODULES}
11 changes: 6 additions & 5 deletions haskell/haddock.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ load(":tools.bzl",
)

load(":providers.bzl",
"HaskellPackageInfo",
"HaskellBuildInfo",
"HaskellLibraryInfo",
"HaddockInfo",
)

load("@bazel_skylib//:lib.bzl", "paths")

def _haskell_doc_aspect_impl(target, ctx):
if HaskellPackageInfo not in target:
if HaskellBuildInfo not in target or HaskellLibraryInfo not in target:
return []

pkg_id = "{0}-{1}".format(ctx.rule.attr.name, ctx.rule.attr.version)
Expand Down Expand Up @@ -90,8 +91,8 @@ def _haskell_doc_aspect_impl(target, ctx):

ctx.actions.run(
inputs = depset(transitive = [
set.to_depset(target[HaskellPackageInfo].caches),
set.to_depset(target[HaskellPackageInfo].interface_files),
set.to_depset(target[HaskellBuildInfo].package_caches),
set.to_depset(target[HaskellBuildInfo].interface_files),
set.to_depset(dep_interfaces),
depset(input_sources),
]),
Expand All @@ -100,7 +101,7 @@ def _haskell_doc_aspect_impl(target, ctx):
executable = tools(ctx).haddock,
arguments = [
args,
target[HaskellPackageInfo].haddock_ghc_args,
target[HaskellLibraryInfo].haddock_args,
],
)

Expand Down
120 changes: 43 additions & 77 deletions haskell/haskell.bzl
Original file line number Diff line number Diff line change
@@ -1,46 +1,44 @@
"""Core Haskell rules"""

load(":providers.bzl",
"HaskellPackageInfo",
"HaskellBuildInfo",
"HaskellLibraryInfo",
"HaskellBinaryInfo",
"CcSkylarkApiProviderHacked",
)

load(":actions.bzl",
"compile_haskell_bin",
"link_haskell_bin",
"compile_haskell_lib",
"create_dynamic_library",
"link_static_lib",
"link_dynamic_lib",
"create_ghc_package",
"create_static_library",
"gather_dependency_information",
"get_pkg_id",
"link_haskell_bin",
"gather_dep_info",
"infer_lib_info",
"infer_bin_info",
)

# Re-export haskell_doc
load(":set.bzl", "set")

# For re-exports:
load(":haddock.bzl",
_haskell_doc = "haskell_doc",
)

# Re-export haskell_toolchain
load(":toolchain.bzl",
_haskell_toolchain = "haskell_toolchain",
)

load (":ghc_bindist.bzl",
_ghc_bindist = "ghc_bindist",
)

load(":ghci-repl.bzl",
_haskell_repl = "haskell_repl",
)

load(":cc.bzl",
_haskell_cc_import = "haskell_cc_import",
_cc_haskell_import = "cc_haskell_import",
)

load(":set.bzl", "set")

_haskell_common_attrs = {
"src_strip_prefix": attr.string(
doc = "Directory in which module hierarchy starts.",
Expand Down Expand Up @@ -77,25 +75,12 @@ _haskell_common_attrs = {
def _haskell_binary_impl(ctx):
object_files = compile_haskell_bin(ctx)
default_info = link_haskell_bin(ctx, object_files)

dep_info = gather_dependency_information(ctx)

return [HaskellPackageInfo(
name = dep_info.name,
names = set.insert(dep_info.names, get_pkg_id(ctx)),
confs = dep_info.confs,
caches = dep_info.caches,
static_libraries = dep_info.static_libraries,
dynamic_libraries = dep_info.dynamic_libraries,
interface_files = dep_info.interface_files,
prebuilt_dependencies = dep_info.prebuilt_dependencies,
external_libraries = dep_info.external_libraries,
import_dirs = dep_info.import_dirs,
exposed_modules = dep_info.exposed_modules,
hidden_modules = set.empty(),
haddock_ghc_args = ctx.actions.args(),
),
default_info,
dep_info = gather_dep_info(ctx)
bin_info = infer_bin_info(ctx)
return [
dep_info, # HaskellBuildInfo
bin_info, # HaskellBinaryInfo
default_info, # DefaultInfo
]

def _mk_binary_rule(**kwargs):
Expand Down Expand Up @@ -155,66 +140,47 @@ Example:
def _haskell_library_impl(ctx):
interfaces_dir, interface_files, object_files, object_dyn_files, haddock_args = compile_haskell_lib(ctx)

static_library = create_static_library(
ctx, object_files
)
static_library = link_static_lib(ctx, object_files)
dynamic_library = link_dynamic_lib(ctx, object_dyn_files)

dynamic_library = create_dynamic_library(
ctx, object_dyn_files
)

# Create and register ghc package.
conf_file, cache_file = create_ghc_package(
ctx,
interfaces_dir,
static_library,
dynamic_library,
)

dep_info = gather_dependency_information(ctx)

return [HaskellPackageInfo(
name = dep_info.name,
# TODO this is somewhat useless now, we shouldn't be abusing
# HaskellPackageInfo to carry information only relevant during
# build just to throw it away later as upstream doesn't need this.
# Technically Haddock rule relies on this but it should gather its
# own info.
names = set.insert(dep_info.names, get_pkg_id(ctx)),
confs = set.insert(dep_info.confs, conf_file),
caches = set.insert(dep_info.caches, cache_file),
# We have to use lists for static libraries because the order is
# important for linker. Linker searches for unresolved symbols to the
# left, i.e. you first feed a library which has unresolved symbols and
# then you feed the library which resolves the symbols.
static_libraries = [static_library] + dep_info.static_libraries,
dynamic_libraries = set.insert(dep_info.dynamic_libraries, dynamic_library),
interface_files = set.union(dep_info.interface_files, set.from_list(interface_files)),
prebuilt_dependencies = set.union(
dep_info.prebuilt_dependencies,
set.from_list(ctx.attr.prebuilt_dependencies)
dep_info = gather_dep_info(ctx)
lib_info = infer_lib_info(ctx, haddock_args=haddock_args)

return [
HaskellBuildInfo(
package_names = set.insert(dep_info.package_names, lib_info.package_name),
package_confs = set.insert(dep_info.package_confs, conf_file),
package_caches = set.insert(dep_info.package_caches, cache_file),
# NOTE We have to use lists for static libraries because the order is
# important for linker. Linker searches for unresolved symbols to the
# left, i.e. you first feed a library which has unresolved symbols and
# then you feed the library which resolves the symbols.
static_libraries = [static_library] + dep_info.static_libraries,
dynamic_libraries = set.insert(dep_info.dynamic_libraries, dynamic_library),
interface_files = set.union(dep_info.interface_files, set.from_list(interface_files)),
prebuilt_dependencies = dep_info.prebuilt_dependencies,
external_libraries = dep_info.external_libraries,
),
lib_info, # HaskellLibraryInfo
DefaultInfo(
files = depset([conf_file, cache_file]),
runfiles = ctx.runfiles(collect_data = True),
),
external_libraries = dep_info.external_libraries,
import_dirs = dep_info.import_dirs,
exposed_modules = dep_info.exposed_modules,
hidden_modules = dep_info.hidden_modules,
haddock_ghc_args = haddock_args,
),
DefaultInfo(
files = depset([
conf_file,
cache_file,
]),
runfiles = ctx.runfiles(collect_data = True),
),
]

haskell_library = rule(
_haskell_library_impl,
attrs = dict(
_haskell_common_attrs,
hidden_modules = attr.string_list(
doc = "Modules that should be made unavailable for import by dependencies."
doc = "Modules that should be unavailable for import by dependencies."
)),
host_fragments = ["cpp"],
toolchains = ["@io_tweag_rules_haskell//haskell:toolchain"],
Expand Down
6 changes: 3 additions & 3 deletions haskell/hsc2hs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ def _make_ghc_defs_dump(ctx):
Returns:
File: The file with GHC definitions.
"""
raw_filename = "ghc-defs-dump-{0}-{1}.hs".format(ctx.attr.name, ctx.attr.version)
dummy_src = ctx.actions.declare_file(raw_filename)
raw_filename = "ghc-defs-dump-{0}-{1}.hs".format(ctx.attr.name, ctx.attr.version)
dummy_src = ctx.actions.declare_file(raw_filename)
ghc_defs_dump_raw = ctx.actions.declare_file(paths.replace_extension(raw_filename, ".hspp"))
ghc_defs_dump = ctx.actions.declare_file(paths.replace_extension(raw_filename, ".h"))
ghc_defs_dump = ctx.actions.declare_file(paths.replace_extension(raw_filename, ".h"))

ctx.actions.write(dummy_src, "")
args = ctx.actions.args()
Expand Down
Loading