bazel-contrib / bazel-contrib/rules_foreign_cc
Would it make sense to have a rule that exports a `cc_library()` into a UNIX-style lib/include directory?
- Dominant language
- Starlark
- Stars
- 737
- Forks
- 270
- PR merge metrics
- No merged PRs in 30d
Description
Hey! 👋
Last week I was working on setting up `rules_rust`'s `crate_repository()` in a project of mine. One of the crates, `openssl-sys`, has a dependency on OpenSSL. In my case my project already had a copy of OpenSSL laying around, which I'm `cc_import()`ing. I wanted to reuse that one for the Rust crate, but ran into a slight issue: I can set `build_script_env = {"OPENSSL_DIR": ...}`, but that expects the library to be placed in a UNIX-style directory layout. So header files in `include/`, and the libraries themselves in `lib/`. I ended up solving this by writing a rule like this:
```python
load("@bazel_skylib//lib:paths.bzl", "paths")
def _gather_library_impl(ctx):
cc_info = ctx.attr.lib[CcInfo]
files = []
# Copy over all header files.
for header in cc_info.compilation_context.headers.to_list():
for include in cc_info.compilation_context.includes.to_list():
if header.path.startswith(include + "/"):
header_symlink = ctx.actions.declare_file(paths.join(ctx.attr.name, "include", paths.relativize(header.path, include)))
ctx.actions.symlink(
output = header_symlink,
target_file = header,
)
files.append(header_symlink)
# Copy over all shared libraryes.
for linker_input in cc_info.linking_context.linker_inputs.to_list():
for library in linker_input.libraries:
# Remove version number from shared object filenames, as
# most compilers will only search for files whose names end
# with ".so".
name = paths.basename(library.dynamic_library.path)
if ".so." in name:
base_name = name.split(".so.")[0] + ".so"
library_symlink = ctx.actions.declare_file(paths.join(ctx.attr.name, "lib", base_name))
ctx.actions.symlink(
output = library_symlink,
target_file = library.dynamic_library,
)
files.append(library_symlink)
library_symlink = ctx.actions.declare_file(paths.join(ctx.attr.name, "lib", name))
ctx.actions.symlink(
output = library_symlink,
target_file = library.dynamic_library,
)
files.append(library_symlink)
return [DefaultInfo(files = depset(files))]
# Rule for turning a cc_library() into a UNIX-style directory layout.
# The "include" subdirectory contains all header files, while the "lib"
# subdirectory contains all shared objects.
gather_library = rule(
implementation = _gather_library_impl,
attrs = {
"lib": attr.label(mandatory = True),
},
)
```
Pretty slick, because now I can just write:
```python
cc_import(
name = "openssl",
...,
)
gather_library(
name = "openssl_gathered",
lib = "openssl",
)
```
Now I just need to turn it into a TreeArtifact:
```python
copy_to_directory(
name = "openssl_directory",
srcs = ["openssl_gathered"],
root_paths = ["openssl_gathered"],
)
```
And now I can build the `openssl-sys` crate by placing this in `WORKSPACE`:
```python
crates_repository(
name = "crates",
annotations = {
"openssl-sys": [crate.annotation(
build_script_data = ["@openssl//:openssl_directory"],
build_script_env = {
"OPENSSL_DIR": "$(execpath @openssl//:openssl_directory)",
"OPENSSL_LIBS": "",
},
deps = ["@openssl//:openssl"],
)],
},
)
```
Now I'm perfectly happy to hold on to that `gather_directory()` rule of mine. But at the same I was wondering whether it would make sense to add something like this to `rules_foreign_cc` as a utility function. Seems like a useful addition. Just let me know, and I'll send out a PR.
Contributor guide
Research direction
Start by reviewing the proposed gather_library rule and its cc_import, copy_to_directory, and crates_repository usage. Determine whether rules_foreign_cc should provide this UNIX-style include/lib layout utility and what its supported inputs and outputs should be. Done means the scope is agreed and the utility has coverage for the demonstrated OpenSSL-style use case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- build-system
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100