-
Notifications
You must be signed in to change notification settings - Fork 81
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Solves #1096 by not needing access to the standard unix tools (and also make it easier to maintain)
- Loading branch information
Showing
5 changed files
with
218 additions
and
223 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
load(":private/context.bzl", "haskell_context", "render_env") | ||
load(":cc.bzl", "cc_interop_info") | ||
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") | ||
|
||
def _cabal_wrapper_impl(ctx): | ||
hs = haskell_context(ctx) | ||
hs_toolchain = ctx.toolchains["@rules_haskell//haskell:toolchain"] | ||
cc_toolchain = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo] | ||
|
||
cabal_wrapper_tpl = ctx.file._cabal_wrapper_tpl | ||
cabal_wrapper = hs.actions.declare_file("cabal_wrapper.py") | ||
hs.actions.expand_template( | ||
template = cabal_wrapper_tpl, | ||
output = cabal_wrapper, | ||
is_executable = True, | ||
substitutions = { | ||
"%{ghc}": hs.tools.ghc.path, | ||
"%{ghc_pkg}": hs.tools.ghc_pkg.path, | ||
"%{runghc}": hs.tools.runghc.path, | ||
"%{ar}": cc_toolchain.ar_executable(), | ||
"%{strip}": cc_toolchain.strip_executable(), | ||
"%{is_windows}": str(hs.toolchain.is_windows), | ||
}, | ||
) | ||
return [DefaultInfo( | ||
files = depset([cabal_wrapper]), | ||
)] | ||
|
||
_cabal_wrapper = rule( | ||
implementation = _cabal_wrapper_impl, | ||
attrs = { | ||
"_cabal_wrapper_tpl": attr.label( | ||
allow_single_file = True, | ||
default = Label("@rules_haskell//haskell:private/cabal_wrapper.py.tpl"), | ||
), | ||
"_cc_toolchain": attr.label( | ||
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), | ||
), | ||
}, | ||
toolchains = ["@rules_haskell//haskell:toolchain"], | ||
fragments = ["cpp"], | ||
) | ||
|
||
def cabal_wrapper(name, **kwargs): | ||
_cabal_wrapper( | ||
name = name + ".py", | ||
) | ||
native.py_binary( | ||
name = name, | ||
srcs = [name + ".py"], | ||
python_version = "PY3", | ||
deps = [ | ||
"@bazel_tools//tools/python/runfiles", | ||
], | ||
**kwargs | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
#!/usr/bin/env python3 | ||
|
||
from glob import glob | ||
import os | ||
import os.path | ||
import re | ||
import shlex | ||
import subprocess | ||
import sys | ||
import tempfile | ||
|
||
def run(cmd, *args, **kwargs): | ||
# print("+ " + " ".join([shlex.quote(arg) for arg in cmd]), file=sys.stderr) | ||
# sys.stderr.flush() | ||
subprocess.run(cmd, *args, **kwargs) | ||
|
||
def canonicalize_path(path): | ||
return ":".join([ | ||
os.path.abspath(entry) | ||
for entry in path.split(":") | ||
if entry != "" | ||
]) | ||
|
||
# Remove any relative entries, because we'll be changing CWD shortly. | ||
os.environ["LD_LIBRARY_PATH"] = canonicalize_path(os.getenv("LD_LIBRARY_PATH", "")) | ||
os.environ["LIBRARY_PATH"] = canonicalize_path(os.getenv("LIBRARY_PATH", "")) | ||
os.environ["PATH"] = canonicalize_path(os.getenv("PATH", "")) | ||
|
||
component = sys.argv.pop(1) | ||
name = sys.argv.pop(1) | ||
execroot = os.getcwd() | ||
setup = os.path.join(execroot, sys.argv.pop(1)) | ||
srcdir = os.path.join(execroot, sys.argv.pop(1)) | ||
pkgroot = os.path.realpath(os.path.join(execroot, os.path.dirname(sys.argv.pop(1)))) | ||
libdir = os.path.join(pkgroot, "iface") | ||
dynlibdir = os.path.join(pkgroot, "lib") | ||
bindir = os.path.join(pkgroot, "bin") | ||
datadir = os.path.join(pkgroot, "data") | ||
package_database = os.path.join(pkgroot, "package.conf.d") | ||
|
||
ghc_pkg = "%{ghc_pkg}" | ||
runghc = os.path.join(execroot, "%{runghc}") | ||
ghc = os.path.join(execroot, "%{ghc}") | ||
ghc_pkg = os.path.join(execroot, "%{ghc_pkg}") | ||
|
||
extra_args = [] | ||
current_arg = sys.argv.pop(1) | ||
while current_arg != "--": | ||
extra_args.append(current_arg) | ||
current_arg = sys.argv.pop(1) | ||
|
||
path_args = sys.argv[1:] | ||
|
||
ar = os.path.realpath("%{ar}") | ||
strip = os.path.realpath("%{strip}") | ||
|
||
def recache_db(): | ||
run([ghc_pkg, "recache", "--package-db=" + package_database]) | ||
|
||
recache_db() | ||
|
||
with tempfile.TemporaryDirectory() as distdir: | ||
enable_relocatable_flags = ["--enable-relocatable"] \ | ||
if "%{is_windows}" != "True" else [] | ||
|
||
old_cwd = os.getcwd() | ||
os.chdir(srcdir) | ||
os.putenv("HOME", "/var/empty") | ||
run([runghc, setup, "configure", \ | ||
component, \ | ||
"--verbose=0", \ | ||
"--user", \ | ||
"--with-compiler=" + ghc, | ||
"--with-hc-pkg=" + ghc_pkg, | ||
"--with-ar=" + ar, | ||
"--with-strip=" + strip, | ||
"--enable-deterministic", \ | ||
"--builddir=" + distdir, \ | ||
"--prefix=" + pkgroot, \ | ||
"--libdir=" + libdir, \ | ||
"--dynlibdir=" + dynlibdir, \ | ||
"--libsubdir=", \ | ||
"--bindir=" + bindir, \ | ||
"--datadir=" + datadir, \ | ||
"--package-db=clear", \ | ||
"--package-db=global", \ | ||
] + \ | ||
enable_relocatable_flags + \ | ||
extra_args + \ | ||
[ arg.replace("=", "=" + execroot + "/") for arg in path_args ] + \ | ||
[ "--package-db=" + package_database ], # This arg must come last. | ||
) | ||
run([runghc, setup, "build", "--verbose=0", "--builddir=" + distdir]) | ||
run([runghc, setup, "install", "--verbose=0", "--builddir=" + distdir]) | ||
os.chdir(old_cwd) | ||
|
||
# XXX Cabal has a bizarre layout that we can't control directly. It | ||
# confounds the library-dir and the import-dir (but not the | ||
# dynamic-library-dir). That's pretty annoying, because Bazel won't | ||
# allow overlap in the path to the interface files directory and the | ||
# path to the static library. So we move the static library elsewhere | ||
# and patch the .conf file accordingly. | ||
# | ||
# There were plans for controlling this, but they died. See: | ||
# https://github.com/haskell/cabal/pull/3982#issuecomment-254038734 | ||
libraries=glob(os.path.join(libdir, "libHS*.a")) | ||
package_conf_file = os.path.join(package_database, name + ".conf") | ||
|
||
def make_relocatable_paths(line): | ||
line = re.sub("library-dirs:.*", "library-dirs: ${pkgroot}/lib", line) | ||
|
||
def make_relative_to_pkgroot(matchobj): | ||
abspath=matchobj.group(0) | ||
return os.path.join("${pkgroot}", os.path.relpath(abspath, start=pkgroot)) | ||
|
||
line = re.sub(execroot + '\S*', make_relative_to_pkgroot, line) | ||
return line | ||
|
||
if libraries != [] and os.path.isfile(package_conf_file): | ||
for lib in libraries: | ||
os.rename(lib, os.path.join(dynlibdir, os.path.basename(lib))) | ||
|
||
tmp_package_conf_file = package_conf_file + ".tmp" | ||
with open(package_conf_file, 'r') as package_conf: | ||
with open(tmp_package_conf_file, 'w') as tmp_package_conf: | ||
for line in package_conf.readlines(): | ||
print(make_relocatable_paths(line), file=tmp_package_conf) | ||
os.remove(package_conf_file) | ||
os.rename(tmp_package_conf_file, package_conf_file) | ||
recache_db() |
Oops, something went wrong.