mirror of https://github.com/bazelbuild/rules_cc
Add a module description
This commit is contained in:
parent
d3808499d2
commit
c4886cbf16
|
@ -1,3 +1,108 @@
|
||||||
|
"""system_library is a repository rule for importing system libraries
|
||||||
|
|
||||||
|
`system_library` is a repository rule for safely depending on system-provided
|
||||||
|
libraries on Linux. It can be used with remote caching and remote execution.
|
||||||
|
Under the hood it uses gcc/clang for finding the library files and headers
|
||||||
|
and symlinks them into the build directory. Symlinking allows Bazel to take
|
||||||
|
these files into account when it calculates a checksum of the project.
|
||||||
|
This prevents cache poisoning from happening.
|
||||||
|
|
||||||
|
Currently `system_library` requires two exeperimental flags:
|
||||||
|
--experimental_starlark_cc_import
|
||||||
|
--experimental_repo_remote_exec
|
||||||
|
|
||||||
|
A typical usage looks like this:
|
||||||
|
WORKSPACE
|
||||||
|
```
|
||||||
|
system_library(
|
||||||
|
name = "jpeg",
|
||||||
|
hdrs = [
|
||||||
|
"jpeglib.h",
|
||||||
|
],
|
||||||
|
shared_lib_names = ["libjpeg.so, libjpeg.so.62"],
|
||||||
|
static_lib_names = ["libjpeg.a"],
|
||||||
|
includes = ["/usr/additional_includes"],
|
||||||
|
lib_path_hints = ["/usr/additional_libs", "/usr/some/other_path"]
|
||||||
|
optional_hdrs = [
|
||||||
|
"jconfig.h",
|
||||||
|
"jmorecfg.h",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
BUILD
|
||||||
|
```
|
||||||
|
cc_binary(
|
||||||
|
name = "foo",
|
||||||
|
srcs = ["foo.cc"],
|
||||||
|
deps = ["@jpeg"]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
foo.cc
|
||||||
|
```
|
||||||
|
#include "jpeglib.h"
|
||||||
|
|
||||||
|
[code using symbols from jpeglib]
|
||||||
|
```
|
||||||
|
|
||||||
|
`system_library` requires users to specify at least one header
|
||||||
|
(as it makes no sense to import a library without headers).
|
||||||
|
Public headers of a library (i.e. those included in the user-written code,
|
||||||
|
like `jpeglib.h` in the example above) should be put in `hdrs` param, as they
|
||||||
|
are required for the library to work. However, some libraries may use more
|
||||||
|
"private" headers. They should be imported as well, but their names may differ
|
||||||
|
from system to system. They should be specified in the `optional_hdrs` param.
|
||||||
|
The build will not fail if some of them are not found, so it's safe to put a
|
||||||
|
superset there, containing all possible combinations of names for different
|
||||||
|
versions/distributions. It's up to the user to determine which headers are
|
||||||
|
required for the library to work.
|
||||||
|
|
||||||
|
One `system_library` target always imports exactly one library.
|
||||||
|
Users can specify many potential names for the library file,
|
||||||
|
as these names can differ from system to system. The order of names establishes
|
||||||
|
the order of preference. As some libraries can be linked both statically
|
||||||
|
and dynamically, the names of files of each kind can be specified separately.
|
||||||
|
`system_library` rule will try to find library archives of both kinds, but it's
|
||||||
|
up to the top-level target (for example, `cc_binary`) to decide which kind of
|
||||||
|
linking will be used.
|
||||||
|
|
||||||
|
`system_library` rule depends on gcc/clang (whichever is installed) for
|
||||||
|
finding the actual locations of library archives and headers.
|
||||||
|
Libraries installed in a standard way by a package manager
|
||||||
|
(`sudo apt install libjpeg-dev`) are usually placed in one of directories
|
||||||
|
searched by the compiler/linker by default - on Ubuntu library most archives
|
||||||
|
are stored in `/usr/lib/x86_64-linux-gnu/` and their headers in
|
||||||
|
`/usr/include/`. If the maintainer of a project expects the files
|
||||||
|
to be installed in a non-standard location, they can use the `includes`
|
||||||
|
parameter to add directories to the search path for headers
|
||||||
|
and `lib_path_hints` to add directories to the search path for library
|
||||||
|
archives.
|
||||||
|
|
||||||
|
User building the project can override or extend these search paths by
|
||||||
|
providing these environment variables to the build:
|
||||||
|
BAZEL_INCLUDE_ADDITIONAL_PATHS, BAZEL_INCLUDE_OVERRIDE_PATHS,
|
||||||
|
BAZEL_LIB_ADDITIONAL_PATHS, BAZEL_LIB_OVERRIDE_PATHS.
|
||||||
|
The syntax for setting the env variables is:
|
||||||
|
`<library>=<path>,<library>=<path2>`.
|
||||||
|
Users can provide multiple paths for one library by repeating this segment:
|
||||||
|
`<library>=<path>`.
|
||||||
|
|
||||||
|
So in order to build the example presented above but with custom paths for the
|
||||||
|
jpeg lib, one would use the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
bazel build //:foo \
|
||||||
|
--experimental_starlark_cc_import \
|
||||||
|
--experimental_repo_remote_exec \
|
||||||
|
--action_env=BAZEL_LIB_OVERRIDE_PATHS=jpeg=/custom/libraries/path \
|
||||||
|
--action_env=BAZEL_INCLUDE_OVERRIDE_PATHS=jpeg=/custom/include/path,jpeg=/inc
|
||||||
|
```
|
||||||
|
|
||||||
|
Some libraries can depend on other libraries. `system_library` rule provides
|
||||||
|
a `deps` parameter for specifying such relationships.
|
||||||
|
"""
|
||||||
|
|
||||||
BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR = "BAZEL_LIB_ADDITIONAL_PATHS"
|
BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR = "BAZEL_LIB_ADDITIONAL_PATHS"
|
||||||
BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR = "BAZEL_LIB_OVERRIDE_PATHS"
|
BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR = "BAZEL_LIB_OVERRIDE_PATHS"
|
||||||
BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR = "BAZEL_INCLUDE_ADDITIONAL_PATHS"
|
BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR = "BAZEL_INCLUDE_ADDITIONAL_PATHS"
|
||||||
|
@ -112,7 +217,7 @@ def _find_header_path(repo_ctx, lib_name, header_name, includes):
|
||||||
|
|
||||||
compiler = _find_compiler(repo_ctx)
|
compiler = _find_compiler(repo_ctx)
|
||||||
|
|
||||||
# Taken from https://stackoverflow.com/questions/63052707/which-header-exactly-will-c-preprocessor-include/63052918#63052918
|
# Taken from https://stackoverflow.com/a/63052918/922404
|
||||||
cmd = """
|
cmd = """
|
||||||
f=\"{}\"; \\
|
f=\"{}\"; \\
|
||||||
echo | \\
|
echo | \\
|
||||||
|
@ -133,7 +238,7 @@ def _find_header_path(repo_ctx, lib_name, header_name, includes):
|
||||||
)
|
)
|
||||||
return _execute_bash(repo_ctx, cmd)
|
return _execute_bash(repo_ctx, cmd)
|
||||||
|
|
||||||
def system_library_impl(repo_ctx):
|
def _system_library_impl(repo_ctx):
|
||||||
repo_name = repo_ctx.attr.name
|
repo_name = repo_ctx.attr.name
|
||||||
includes = repo_ctx.attr.includes
|
includes = repo_ctx.attr.includes
|
||||||
hdrs = repo_ctx.attr.hdrs
|
hdrs = repo_ctx.attr.hdrs
|
||||||
|
@ -322,22 +427,22 @@ alias(
|
||||||
)
|
)
|
||||||
|
|
||||||
system_library = repository_rule(
|
system_library = repository_rule(
|
||||||
implementation = system_library_impl,
|
implementation = _system_library_impl,
|
||||||
local = True,
|
local = True,
|
||||||
remotable = True,
|
remotable = True,
|
||||||
environ = [
|
environ = [
|
||||||
BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR,
|
|
||||||
BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR,
|
|
||||||
BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR,
|
BAZEL_INCLUDE_ADDITIONAL_PATHS_ENV_VAR,
|
||||||
BAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR,
|
BAZEL_INCLUDE_OVERRIDE_PATHS_ENV_VAR,
|
||||||
|
BAZEL_LIB_ADDITIONAL_PATHS_ENV_VAR,
|
||||||
|
BAZEL_LIB_OVERRIDE_PATHS_ENV_VAR,
|
||||||
],
|
],
|
||||||
attrs = {
|
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(),
|
"deps": attr.string_list(),
|
||||||
|
"hdrs": attr.string_list(mandatory = True, allow_empty = False),
|
||||||
|
"includes": attr.string_list(),
|
||||||
|
"lib_path_hints": attr.string_list(),
|
||||||
|
"optional_hdrs": attr.string_list(),
|
||||||
|
"shared_lib_names": attr.string_list(),
|
||||||
|
"static_lib_names": attr.string_list(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -162,4 +162,32 @@ EOF
|
||||||
|| fail "Expected test_static_hardcoded_path to run successfully"
|
|| fail "Expected test_static_hardcoded_path to run successfully"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_system_library_no_lib_names() {
|
||||||
|
cat << EOF > WORKSPACE
|
||||||
|
load("//:cc/system_library.bzl", "system_library")
|
||||||
|
system_library(
|
||||||
|
name = "foo",
|
||||||
|
hdrs = [
|
||||||
|
"foo.h",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat << EOF > BUILD
|
||||||
|
cc_binary(
|
||||||
|
name = "test",
|
||||||
|
srcs = ["test.cc"],
|
||||||
|
deps = ["@foo"]
|
||||||
|
)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# It should fail when no static_lib_names and static_lib_names are given
|
||||||
|
bazel run //:test \
|
||||||
|
--experimental_starlark_cc_import \
|
||||||
|
--experimental_repo_remote_exec \
|
||||||
|
&> $TEST_log \
|
||||||
|
|| true
|
||||||
|
expect_log "Library foo could not be found"
|
||||||
|
}
|
||||||
|
|
||||||
run_suite "Integration tests for system_library."
|
run_suite "Integration tests for system_library."
|
Loading…
Reference in New Issue