Skip to content

Commit

Permalink
Merge pull request #2 from tweag/rules
Browse files Browse the repository at this point in the history
Basic binary build with a library dependency.
  • Loading branch information
Fuuzetsu authored Nov 14, 2017
2 parents fd610cb + 44cf931 commit 774648f
Show file tree
Hide file tree
Showing 18 changed files with 402 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ cabal.sandbox.config
.stack-work/
cabal.project.local
.HTF/
/bazel-bin
/bazel-genfiles
/bazel-out
/bazel-rules_haskell
/bazel-testlogs
5 changes: 5 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
workspace(name = "io_tweag_rules_haskell")

local_repository(
name = "examples",
path = "examples"
)
Empty file removed examples/BUILD
Empty file.
1 change: 1 addition & 0 deletions examples/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
workspace(name = "examples")
15 changes: 15 additions & 0 deletions examples/hello-lib/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package(default_visibility = ["//visibility:public"])

load(
"@io_tweag_rules_haskell//haskell:haskell.bzl",
"haskell_library",
)

haskell_library(
name = 'hello-lib',
srcs = [
'MsgType.hs',
'Unused.hs',
'Lib.hs'
]
)
6 changes: 6 additions & 0 deletions examples/hello-lib/Lib.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Lib (libText) where

import MsgType (Msg)

libText :: Msg
libText = "hello world"
4 changes: 4 additions & 0 deletions examples/hello-lib/MsgType.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module MsgType (Msg) where


type Msg = String
4 changes: 4 additions & 0 deletions examples/hello-lib/Unused.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Unused (someInt) where

someInt :: Int
someInt = 9
12 changes: 12 additions & 0 deletions examples/hello-world/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package(default_visibility = ["//visibility:public"])

load(
"@io_tweag_rules_haskell//haskell:haskell.bzl",
"haskell_binary"
)

haskell_binary(
name = "hello-world",
srcs = ["Main.hs"],
deps = ["@examples//hello-lib:hello-lib"]
)
6 changes: 6 additions & 0 deletions examples/hello-world/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Main (main) where

import Lib (libText)

main :: IO ()
main = putStrLn libText
6 changes: 6 additions & 0 deletions haskell/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package(default_visibility = ["//visibility:public"])

exports_files([
"haskell.bzl",
"toolchain.bzl",
])
142 changes: 112 additions & 30 deletions haskell/haskell.bzl
Original file line number Diff line number Diff line change
@@ -1,38 +1,120 @@
HASKELL_FILETYPE = FileType([".hs"])
load(":toolchain.bzl",
"HaskellPackageInfo",
"ar_args",
"ghc_bin_link_args",
"ghc_bin_obj_args",
"ghc_lib_args",
"mk_registration_file",
"register_package",
"src_to_ext",
)

def _haskell_binary_impl(ctx):
depInputs = []
systemLibs = []
for d in ctx.attr.deps:
# depend on output of deps, i.e. package file
depInputs += d.files.to_list()
# We need interface files of the package for compilation
depInputs += d[HaskellPackageInfo].interfaceFiles
# Lastly we need library object for linking
systemLibs.append(d[HaskellPackageInfo].systemLib)

objDir = ctx.actions.declare_directory("objects")
binObjs = [ctx.actions.declare_file(src_to_ext(ctx, s, "o", directory=objDir))
for s in ctx.files.srcs]

# Compile sources of the binary.
ctx.actions.run(
inputs = ctx.files.srcs + depInputs + systemLibs,
outputs = binObjs + [objDir],
use_default_shell_env = True,
progress_message = "Building {0}".format(ctx.attr.name),
executable = "ghc",
arguments = [ghc_bin_obj_args(ctx, objDir)],
)

# Link everything together
linkTarget, linkArgs = ghc_bin_link_args(ctx, binObjs, systemLibs)
ctx.actions.run(
inputs = binObjs + systemLibs + [linkTarget],
outputs = [ctx.outputs.executable],
use_default_shell_env = True,
progress_message = "Linking {0}".format(ctx.outputs.executable),
executable = "ghc",
arguments = [linkArgs],
)

def _haskell_library_impl(ctx):

# TODO
haskell_library = 1
objDir = ctx.actions.declare_directory("objects")
objectFiles = [ctx.actions.declare_file(src_to_ext(ctx, s, "o", directory=objDir))
for s in ctx.files.srcs]

ifaceDir = ctx.actions.declare_directory("interfaces")
interfaceFiles = [ctx.actions.declare_file(src_to_ext(ctx, s, "hi", directory=ifaceDir))
for s in ctx.files.srcs ]

# Compile library files
#
# TODO: Library deps
ctx.actions.run(
inputs = ctx.files.srcs,
outputs = [ifaceDir, objDir] + objectFiles + interfaceFiles,
use_default_shell_env = True,
progress_message = "Compiling {0}".format(ctx.attr.name),
executable = "ghc",
arguments = [ghc_lib_args(ctx, objDir, ifaceDir)]
)

# Make library archive; currently only static
#
# TODO: configurable shared &c. see various scenarios in buck
libDir = ctx.actions.declare_directory("lib")
systemLib = ctx.actions.declare_file("{0}/lib{1}.a".format(libDir.basename, ctx.attr.name))

ctx.actions.run(
inputs = objectFiles,
outputs = [systemLib, libDir],
use_default_shell_env = True,
executable = "ar",
arguments = [ar_args(ctx, systemLib, objectFiles)],
)

# Create and register ghc package.
pkgId = "{0}-{1}".format(ctx.attr.name, ctx.attr.version)
confFile = ctx.actions.declare_file("{0}.conf".format(pkgId))
cacheFile = ctx.actions.declare_file("package.cache")
registrationFile = mk_registration_file(ctx, pkgId, ifaceDir, libDir)
ctx.actions.run_shell(
inputs = [systemLib, ifaceDir, registrationFile],
outputs = [confFile, cacheFile],
use_default_shell_env = True,
command = register_package(ifaceDir, registrationFile, confFile.dirname)
)
return [HaskellPackageInfo( packageName = pkgId,
pkgDb = confFile.dirname,
systemLib = systemLib,
interfaceFiles = interfaceFiles)]

_haskell_common_attrs = {
"srcs": attr.label_list(allow_files = HASKELL_FILETYPE),
"deps": attr.label_list(),
"srcs": attr.label_list(allow_files = FileType([".hs"])),
"deps": attr.label_list(),
}

def _haskell_binary_impl(ctx):
haskell_binary = ctx.outputs.executable

compile_inputs = ctx.files.srcs

ctx.actions.run(
inputs = compile_inputs,
outputs = [haskell_binary],
mnemonic = "Ghc",
executable = "ghc",
arguments = [
"-o",
haskell_binary.path,
] + [
src.path for src in compile_inputs
],
use_default_shell_env = True,
progress_message = ("Compiling Haskell binary %s (%d files)"
% (ctx.label.name, len(ctx.files.srcs))))

return struct(haskell_srcs = ctx.files.srcs,
haskell_deps = ctx.attr.deps)
haskell_library = rule(
_haskell_library_impl,
outputs = {
"conf": "%{name}-%{version}.conf",
"packageCache": "package.cache"
},
attrs = _haskell_common_attrs + {
"version": attr.string(default="1.0.0"),
}
)

haskell_binary = rule(
_haskell_binary_impl,
attrs = _haskell_common_attrs,
executable = True,
_haskell_binary_impl,
executable = True,
attrs = _haskell_common_attrs,
)
Loading

0 comments on commit 774648f

Please sign in to comment.