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?

Open
#1,206 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.