2020-09-21 17:47:08 +00:00
|
|
|
BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR = "BAZEL_LIB_ADDITIONAL_PATHS"
|
|
|
|
BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR = "BAZEL_LIB_OVERRIDE_PATHS"
|
|
|
|
BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR = "BAZEL_INCLUDE_ADDITIONAL_PATHS"
|
|
|
|
BAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR = "BAZEL_INCLUDE_OVERRIDE_PATHS"
|
|
|
|
ENV_VAR_SEPARATOR = ","
|
|
|
|
ENV_VAR_ASSIGNMENT = "="
|
|
|
|
|
|
|
|
def _make_flags(array_of_strings, prefix):
|
|
|
|
flags = []
|
|
|
|
if array_of_strings:
|
|
|
|
for s in array_of_strings:
|
|
|
|
flags.append(prefix + s)
|
|
|
|
return " ".join(flags)
|
|
|
|
|
|
|
|
def _split_env_var(repo_ctx, var_name):
|
|
|
|
value = repo_ctx.os.environ.get(var_name)
|
|
|
|
if value:
|
|
|
|
assignments = value.split(ENV_VAR_SEPARATOR)
|
|
|
|
dict = {}
|
|
|
|
for assignment in assignments:
|
|
|
|
pair = assignment.split(ENV_VAR_ASSIGNMENT)
|
|
|
|
if len(pair) != 2:
|
|
|
|
fail(
|
2020-09-22 08:18:25 +00:00
|
|
|
"Assignments should have form 'name=value', " +
|
|
|
|
"but encountered {} in env variable {}"
|
2020-09-21 17:47:08 +00:00
|
|
|
.format(assignment, var_name),
|
|
|
|
)
|
|
|
|
key, value = pair[0], pair[1]
|
|
|
|
if not dict.get(key):
|
|
|
|
dict[key] = []
|
|
|
|
dict[key].append(value)
|
|
|
|
return dict
|
|
|
|
else:
|
|
|
|
return {}
|
|
|
|
|
|
|
|
def _get_list_from_env_var(repo_ctx, var_name, key):
|
|
|
|
return _split_env_var(repo_ctx, var_name).get(key, default = [])
|
|
|
|
|
|
|
|
def _execute_bash(repo_ctx, cmd):
|
|
|
|
return repo_ctx.execute(["/bin/bash", "-c", cmd]).stdout.replace("\n", "")
|
|
|
|
|
|
|
|
def _find_linker(repo_ctx):
|
|
|
|
ld = _execute_bash(repo_ctx, "which ld")
|
|
|
|
lld = _execute_bash(repo_ctx, "which lld")
|
|
|
|
if ld:
|
|
|
|
return ld
|
|
|
|
elif lld:
|
|
|
|
return lld
|
|
|
|
else:
|
|
|
|
fail("No linker found")
|
|
|
|
|
|
|
|
def _find_compiler(repo_ctx):
|
|
|
|
gcc = _execute_bash(repo_ctx, "which g++")
|
|
|
|
clang = _execute_bash(repo_ctx, "which clang++")
|
|
|
|
if gcc:
|
|
|
|
return gcc
|
|
|
|
elif clang:
|
|
|
|
return clang
|
|
|
|
else:
|
|
|
|
fail("No compiler found")
|
|
|
|
|
|
|
|
def _find_lib_path(repo_ctx, lib_name, archive_names, lib_path_hints):
|
2020-09-22 08:18:25 +00:00
|
|
|
override_paths = _get_list_from_env_var(
|
|
|
|
repo_ctx,
|
|
|
|
BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR,
|
|
|
|
lib_name,
|
|
|
|
)
|
|
|
|
additional_paths = _get_list_from_env_var(
|
|
|
|
repo_ctx,
|
|
|
|
BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR,
|
|
|
|
lib_name,
|
|
|
|
)
|
2020-09-21 17:47:08 +00:00
|
|
|
|
|
|
|
# Directories will be searched in order
|
2020-09-22 08:18:25 +00:00
|
|
|
path_flags = _make_flags(
|
|
|
|
override_paths + lib_path_hints + additional_paths,
|
|
|
|
"-L",
|
|
|
|
)
|
2020-09-21 17:47:08 +00:00
|
|
|
linker = _find_linker(repo_ctx)
|
|
|
|
for archive_name in archive_names:
|
|
|
|
cmd = """
|
|
|
|
{} -verbose -l:{} {} 2>/dev/null | \\
|
|
|
|
grep succeeded | \\
|
|
|
|
head -1 | \\
|
|
|
|
sed -e 's/^\\s*attempt to open //' -e 's/ succeeded\\s*$//'
|
|
|
|
""".format(
|
|
|
|
linker,
|
|
|
|
archive_name,
|
|
|
|
path_flags,
|
|
|
|
)
|
|
|
|
path = _execute_bash(repo_ctx, cmd)
|
|
|
|
if path:
|
|
|
|
return (archive_name, path)
|
|
|
|
return ("", "")
|
|
|
|
|
|
|
|
def _find_header_path(repo_ctx, lib_name, header_name, includes):
|
2020-09-22 08:18:25 +00:00
|
|
|
override_paths = _get_list_from_env_var(
|
|
|
|
repo_ctx,
|
|
|
|
BAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR,
|
|
|
|
lib_name,
|
|
|
|
)
|
|
|
|
additional_paths = _get_list_from_env_var(
|
|
|
|
repo_ctx,
|
|
|
|
BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR,
|
|
|
|
lib_name,
|
|
|
|
)
|
2020-09-21 17:47:08 +00:00
|
|
|
|
|
|
|
# See https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html
|
|
|
|
override_include_flags = _make_flags(override_paths, "-I")
|
|
|
|
standard_include_flags = _make_flags(includes, "-isystem")
|
|
|
|
additional_include_flags = _make_flags(additional_paths, "-idirafter")
|
|
|
|
|
|
|
|
compiler = _find_compiler(repo_ctx)
|
|
|
|
|
|
|
|
# Taken from https://stackoverflow.com/questions/63052707/which-header-exactly-will-c-preprocessor-include/63052918#63052918
|
|
|
|
cmd = """
|
|
|
|
f=\"{}\"; \\
|
|
|
|
echo | \\
|
|
|
|
{} -E {} {} {} -Wp,-v - 2>&1 | \\
|
|
|
|
sed '\\~^ /~!d; s/ //' | \\
|
|
|
|
while IFS= read -r path; \\
|
|
|
|
do if [[ -e \"$path/$f\" ]]; \\
|
|
|
|
then echo \"$path/$f\"; \\
|
|
|
|
break; \\
|
|
|
|
fi; \\
|
|
|
|
done
|
|
|
|
""".format(
|
|
|
|
header_name,
|
|
|
|
compiler,
|
|
|
|
override_include_flags,
|
|
|
|
standard_include_flags,
|
|
|
|
additional_include_flags,
|
|
|
|
)
|
|
|
|
return _execute_bash(repo_ctx, cmd)
|
|
|
|
|
|
|
|
def system_library_impl(repo_ctx):
|
|
|
|
repo_name = repo_ctx.attr.name
|
|
|
|
includes = repo_ctx.attr.includes
|
|
|
|
hdrs = repo_ctx.attr.hdrs
|
|
|
|
optional_hdrs = repo_ctx.attr.optional_hdrs
|
|
|
|
deps = repo_ctx.attr.deps
|
|
|
|
lib_path_hints = repo_ctx.attr.lib_path_hints
|
|
|
|
static_lib_names = repo_ctx.attr.static_lib_names
|
|
|
|
shared_lib_names = repo_ctx.attr.shared_lib_names
|
|
|
|
|
2020-09-22 08:18:25 +00:00
|
|
|
static_lib_name, static_lib_path = \
|
|
|
|
_find_lib_path(repo_ctx, repo_name, static_lib_names, lib_path_hints)
|
|
|
|
shared_lib_name, shared_lib_path = \
|
|
|
|
_find_lib_path(repo_ctx, repo_name, shared_lib_names, lib_path_hints)
|
2020-09-21 17:47:08 +00:00
|
|
|
|
|
|
|
if not static_lib_path and not shared_lib_path:
|
|
|
|
fail("Library {} could not be found".format(repo_name))
|
|
|
|
|
|
|
|
hdr_names = []
|
|
|
|
hdr_paths = []
|
|
|
|
for hdr in hdrs:
|
|
|
|
hdr_path = _find_header_path(repo_ctx, repo_name, hdr, includes)
|
|
|
|
if hdr_path:
|
|
|
|
repo_ctx.symlink(hdr_path, hdr)
|
|
|
|
hdr_names.append(hdr)
|
|
|
|
hdr_paths.append(hdr_path)
|
|
|
|
else:
|
|
|
|
fail("Could not find required header {}".format(hdr))
|
|
|
|
|
|
|
|
for hdr in optional_hdrs:
|
|
|
|
hdr_path = _find_header_path(repo_ctx, repo_name, hdr, includes)
|
|
|
|
if hdr_path:
|
|
|
|
repo_ctx.symlink(hdr_path, hdr)
|
|
|
|
hdr_names.append(hdr)
|
|
|
|
hdr_paths.append(hdr_path)
|
|
|
|
|
|
|
|
hdrs_param = "hdrs = {},".format(str(hdr_names))
|
|
|
|
|
2020-09-22 08:18:25 +00:00
|
|
|
# This is needed for the case when quote-includes and system-includes
|
|
|
|
# alternate in the include chain, i.e.
|
|
|
|
# #include <SDL2/SDL.h> -> #include "SDL_main.h"
|
|
|
|
# -> #include <SDL2/_real_SDL_config.h> -> #include "SDL_platform.h"
|
2020-09-21 17:47:08 +00:00
|
|
|
# The problem is that the quote-includes are assumed to be
|
2020-09-22 08:18:25 +00:00
|
|
|
# in the same directory as the header they are included from -
|
|
|
|
# they have no subdir prefix ("SDL2/") in their paths
|
2020-09-21 17:47:08 +00:00
|
|
|
include_subdirs = {}
|
|
|
|
for hdr in hdr_names:
|
|
|
|
path_segments = hdr.split("/")
|
|
|
|
path_segments.pop()
|
|
|
|
current_path_segments = ["external", repo_name]
|
|
|
|
for segment in path_segments:
|
|
|
|
current_path_segments.append(segment)
|
|
|
|
current_path = "/".join(current_path_segments)
|
|
|
|
include_subdirs.update({current_path: None})
|
|
|
|
|
|
|
|
includes_param = "includes = {},".format(str(include_subdirs.keys()))
|
|
|
|
|
|
|
|
deps_names = []
|
|
|
|
for dep in deps:
|
|
|
|
dep_name = repr("@" + dep)
|
|
|
|
deps_names.append(dep_name)
|
|
|
|
deps_param = "deps = [{}],".format(",".join(deps_names))
|
|
|
|
|
|
|
|
link_hdrs_command = "mkdir -p $(RULEDIR)/remote \n"
|
|
|
|
remote_hdrs = []
|
|
|
|
for path, hdr in zip(hdr_paths, hdr_names):
|
|
|
|
remote_hdr = "remote/" + hdr
|
|
|
|
remote_hdrs.append(remote_hdr)
|
|
|
|
link_hdrs_command += "cp {path} $(RULEDIR)/{hdr}\n ".format(
|
|
|
|
path = path,
|
|
|
|
hdr = remote_hdr,
|
|
|
|
)
|
|
|
|
|
2020-09-22 08:18:25 +00:00
|
|
|
link_remote_static_lib_genrule = ""
|
|
|
|
link_remote_shared_lib_genrule = ""
|
2020-09-21 17:47:08 +00:00
|
|
|
remote_static_library_param = ""
|
|
|
|
remote_shared_library_param = ""
|
|
|
|
static_library_param = ""
|
|
|
|
shared_library_param = ""
|
|
|
|
|
|
|
|
if static_lib_path:
|
|
|
|
repo_ctx.symlink(static_lib_path, static_lib_name)
|
2020-09-22 08:18:25 +00:00
|
|
|
static_library_param = "static_library = \"{}\",".format(
|
|
|
|
static_lib_name,
|
2020-09-21 17:47:08 +00:00
|
|
|
)
|
2020-09-22 08:18:25 +00:00
|
|
|
remote_static_library = "remote/" + static_lib_name
|
|
|
|
link_library_command = \
|
|
|
|
"mkdir -p $(RULEDIR)/remote && cp {path} $(RULEDIR)/{lib}".format(
|
|
|
|
path = static_lib_path,
|
|
|
|
lib = remote_static_library,
|
|
|
|
)
|
|
|
|
remote_static_library_param = \
|
|
|
|
"static_library = \"remote_link_static_library\","
|
|
|
|
link_remote_static_lib_genrule = \
|
2020-09-21 17:47:08 +00:00
|
|
|
"""
|
|
|
|
genrule(
|
|
|
|
name = "remote_link_static_library",
|
|
|
|
outs = ["{remote_static_library}"],
|
|
|
|
cmd = {link_library_command}
|
|
|
|
)
|
|
|
|
""".format(
|
|
|
|
link_library_command = repr(link_library_command),
|
|
|
|
remote_static_library = remote_static_library,
|
|
|
|
)
|
|
|
|
|
|
|
|
if shared_lib_path:
|
|
|
|
repo_ctx.symlink(shared_lib_path, shared_lib_name)
|
2020-09-22 08:18:25 +00:00
|
|
|
shared_library_param = \
|
|
|
|
"shared_library = \"{}\",".format(shared_lib_name)
|
2020-09-21 17:47:08 +00:00
|
|
|
remote_shared_library = "remote/" + shared_lib_name
|
2020-09-22 08:18:25 +00:00
|
|
|
link_library_command = \
|
|
|
|
"mkdir -p $(RULEDIR)/remote && cp {path} $(RULEDIR)/{lib}".format(
|
|
|
|
path = shared_lib_path,
|
|
|
|
lib = remote_shared_library,
|
|
|
|
)
|
|
|
|
remote_shared_library_param = \
|
|
|
|
"shared_library = \"remote_link_shared_library\","
|
|
|
|
link_remote_shared_lib_genrule = \
|
2020-09-21 17:47:08 +00:00
|
|
|
"""
|
|
|
|
genrule(
|
|
|
|
name = "remote_link_shared_library",
|
|
|
|
outs = ["{remote_shared_library}"],
|
|
|
|
cmd = {link_library_command}
|
|
|
|
)
|
|
|
|
""".format(
|
|
|
|
link_library_command = repr(link_library_command),
|
|
|
|
remote_shared_library = remote_shared_library,
|
|
|
|
)
|
|
|
|
|
|
|
|
repo_ctx.file(
|
|
|
|
"BUILD",
|
|
|
|
executable = False,
|
|
|
|
content =
|
|
|
|
"""
|
|
|
|
load("@bazel_tools//tools/build_defs/cc:cc_import.bzl", "cc_import")
|
|
|
|
cc_import(
|
|
|
|
name = "local_includes",
|
|
|
|
{static_library}
|
|
|
|
{shared_library}
|
|
|
|
{hdrs}
|
|
|
|
{deps}
|
|
|
|
{includes}
|
|
|
|
)
|
|
|
|
|
|
|
|
genrule(
|
|
|
|
name = "remote_link_headers",
|
|
|
|
outs = {remote_hdrs},
|
|
|
|
cmd = {link_hdrs_command}
|
|
|
|
)
|
|
|
|
|
2020-09-22 08:18:25 +00:00
|
|
|
{link_remote_static_lib_genrule}
|
2020-09-21 17:47:08 +00:00
|
|
|
|
2020-09-22 08:18:25 +00:00
|
|
|
{link_remote_shared_lib_genrule}
|
2020-09-21 17:47:08 +00:00
|
|
|
|
|
|
|
cc_import(
|
|
|
|
name = "remote_includes",
|
|
|
|
hdrs = [":remote_link_headers"],
|
|
|
|
{remote_static_library}
|
|
|
|
{remote_shared_library}
|
|
|
|
{deps}
|
|
|
|
{includes}
|
|
|
|
)
|
|
|
|
|
|
|
|
alias(
|
|
|
|
name = "{name}",
|
|
|
|
actual = select({{
|
|
|
|
"@bazel_tools//src/conditions:remote": "remote_includes",
|
|
|
|
"//conditions:default": "local_includes",
|
|
|
|
}}),
|
|
|
|
visibility = ["//visibility:public"],
|
|
|
|
)
|
|
|
|
""".format(
|
|
|
|
static_library = static_library_param,
|
|
|
|
shared_library = shared_library_param,
|
|
|
|
hdrs = hdrs_param,
|
|
|
|
deps = deps_param,
|
|
|
|
hdr_names = str(hdr_names),
|
|
|
|
link_hdrs_command = repr(link_hdrs_command),
|
|
|
|
name = repo_name,
|
|
|
|
includes = includes_param,
|
|
|
|
remote_hdrs = remote_hdrs,
|
2020-09-22 08:18:25 +00:00
|
|
|
link_remote_static_lib_genrule = link_remote_static_lib_genrule,
|
|
|
|
link_remote_shared_lib_genrule = link_remote_shared_lib_genrule,
|
2020-09-21 17:47:08 +00:00
|
|
|
remote_static_library = remote_static_library_param,
|
|
|
|
remote_shared_library = remote_shared_library_param,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
system_library = repository_rule(
|
|
|
|
implementation = system_library_impl,
|
|
|
|
local = True,
|
|
|
|
remotable = True,
|
|
|
|
environ = [
|
|
|
|
BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR,
|
|
|
|
BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR,
|
|
|
|
BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR,
|
|
|
|
BAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR,
|
|
|
|
],
|
|
|
|
attrs = {
|
|
|
|
"static_lib_names": attr.string_list(),
|
|
|
|
"shared_lib_names": attr.string_list(),
|
|
|
|
"lib_path_hints": attr.string_list(),
|
|
|
|
"includes": attr.string_list(),
|
|
|
|
"hdrs": attr.string_list(mandatory = True, allow_empty = False),
|
|
|
|
"optional_hdrs": attr.string_list(),
|
|
|
|
"deps": attr.string_list(),
|
|
|
|
},
|
|
|
|
)
|