Skip to content

Instantly share code, notes, and snippets.

@rrbutani
Last active July 12, 2024 11:03
Show Gist options
  • Save rrbutani/7defe71c2195762da406d8c351f7dcbc to your computer and use it in GitHub Desktop.
Save rrbutani/7defe71c2195762da406d8c351f7dcbc to your computer and use it in GitHub Desktop.
# https://github.com/bazelbuild/bazel/commit/f417aa985790a36c56a7da82ef46f76aba4c984e
common --experimental_rule_extension_api=true
8.0.0-pre.20240618.2
d73e9bf9be20cdaefd5c1b265999af1ed9d0c6df34c7eae6135d377fe51e2433
# ^ sha256 for `.dist.zip`
# https://releases.bazel.build/8.0.0/rolling/8.0.0-pre.20240618.2/index.html
# rev: 0c2ed165335327a2c5b534312324baa9ae6b6ebd
use flake
/bazel-*
/.direnv
result*
#include <dlfcn.h>
#include "common.h"
#include "a.h"
using Func = void(void);
void A::run() noexcept(true) {
auto lib = CHECK(dlopen, ("libruntime-a.so", RTLD_NOW | RTLD_DEEPBIND));
auto func = reinterpret_cast<Func*>(CHECK(dlsym, (lib, "print_a")));
func();
}
#pragma once
struct A {
static void run() noexcept(true);
};
#include <dlfcn.h>
#include "common.h"
#include "b.h"
#include "a.h"
void B::run() noexcept(true) {
A::run();
auto lib = CHECK(dlopen, ("libruntime-b.so", RTLD_NOW | RTLD_DEEPBIND));
auto func = reinterpret_cast<Func*>(CHECK(dlsym, (lib, "print_b")));
func();
}
#pragma once
struct B {
static void run() noexcept(true);
};
load(":defs.bzl", "cc_library", "cc_binary")
cc_binary(
name = "libruntime-a.so",
srcs = [":runtime-lib-a.cc"],
linkstatic = True,
linkshared = True,
)
cc_binary(
name = "libruntime-b.so",
srcs = [":runtime-lib-b.cc"],
linkstatic = True,
linkshared = True,
)
#-------------------------------------------------------------------------------
cc_library(
name = "a",
deps = [":libruntime-a.so"],
srcs = [":a.cc", "common.h"],
hdrs = [":a.h"],
data = [":libruntime-a.so"],
# copts = ["-Wl,-rpath='$ORIGIN/liba.so.runfiles/_main'"],
# TODO: this is propagated to rdeps; we don't want this to be
#
# NOTE: in rdeps, $ORIGIN is a symlink path; `./<name>.runfiles` is not
# available in these contexts..
#
# the symlink path is something like
# `<rdep's name>.runfiles/<repo>/_solib_k8/<package path?>/liblib<lib name>.so`
#
# since data deps *are* hoisted to the top-level target's runfiles tree, we
# should be able to access our data deps at
# `$ORIGIN/<.. for pkg path>/../../<repo>/`..
#
# EDIT: nevermind; see below
linkopts = [
# For direct usages of this library:
#
# (TODO: ideally we'd have top-level rdeps not use this flag...)
"-Wl,-rpath='$ORIGIN/liba.so.runfiles/_main'",
# For indirect usages of this library (refers to the top-level runfiles
# tree):
#
# this is necessary because:
# - `dlopen` only consults this library's runpath
# - binaries that link dynamically to this library will find this
# library via a symlink in their runfiles trees' solib dir; this
# path is different than the `bazel-out/...` path at which this
# library actually resides
# + for the purpose of resolving `$ORIGIN` relative paths, the
# symlink path is what the runtime loader will use
# + additionally, while we can rely on the top-level target's
# runfiles tree containing our data deps, we cannot rely on *our*
# runfiles tree being present (this is usually not the case)
#
# so, we include an rpath entry that maps from the top-level target's
# runfiles tree solib symlink of this library to the directory in the
# top-level target's runfiles tree where we can expect to find our data
# deps:
#
# NOTE: EDIT: this actually doesn't work because shared object deps in
# final binaries are actually (sometimes) via the top-level target's
# `$ORIGIN/_solib.../` runpath entry rather than via the
# `$ORIGIN/<name>.runfiles/_main/_solib.../` entry; when this happens
# the relative path specified here doesn't work. We once again have to
# name the top-level target in order to construct a working relative
# path which, as explained below, we cannot do.
#
# (TODO: ideally we'd have top-level rdeps not use this flag...)
"-Wl,-rpath='$ORIGIN/../../_main'",
# TODO: for usages where this library is linked directly (statically)
# into a top-level shared-object, we need to add an rpath entry for
# `$ORIGIN/<top-level name>.runfiles/<repo>`
#
# Unfortunately we cannot do that here — we do not know the top-level
# target's name and there may very well be many top-level rdeps for this
# library.
],
# linkstatic = True,
)
cc_library(
name = "b",
deps = [":a"],
srcs = [":b.cc", "common.h"],
hdrs = [":b.h"],
data = [":libruntime-b.so"],
# linkstatic = False,
)
#-------------------------------------------------------------------------------
cc_binary(
name = "main-shared",
deps = [":b"],
srcs = [":main.cc"],
# shared binary but with `a.cc` and `b.cc` linked in via shared objects
linkstatic = False,
# FIXME: doesn't work because the `dlopen` calls in `liba.so`, `libb.so`
# will not use the parent executable's runpath (or rpath) entries...
# linkopts = ["-Wl,-rpath='$ORIGIN/main-shared.runfiles/_main/'"],
# Forcing `--runpath` does not help:
# linkopts = ["-Wl,--disable-new-dtags", "-Wl,-rpath='$ORIGIN/main-shared.runfiles/_main/'"],
)
cc_binary(
name = "main-static",
deps = [":b"],
srcs = [":main.cc"],
# shared binary but with `a.cc` and `b.cc` linked in directly
linkstatic = True,
# This works because the `dlopen` callsite is now part of the final binary.
#
# NOTE that this is *necessary*: see the comment on `:a`; because the
# libraries using `dlopen` have been linked into `main-static` statically,
# it's this target's RUNPATH that will be consulted when those `dlopen`s
# are resolved.
linkopts = ["-Wl,-rpath='$ORIGIN/main-static.runfiles/_main/'"],
)
#pragma once
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <dlfcn.h>
using Func = void(void);
#define CHECK(func_name, args) [&]{ \
if (auto var = func_name args) { return var; } \
else { \
std::perror("Error in " # func_name); \
std::cerr << "dlerror: " << dlerror() << std::endl; \
std::exit(1); \
} \
}()
# See:
# - subrule design doc: https://docs.google.com/document/d/1RbNC88QieKvBEwir7iV5zZU08AaMlOzxhVkPnmKDedQ/edit#heading=h.1rg4gw6b0c54
# - extending rules design doc: https://docs.google.com/document/d/1p6z-shWf9sdqo_ep7dcjZCGvqN5r2jsPkJCqHHgfRp4/edit#heading=h.5mcn15i0e1ch
def _patchelf_add_rpath_impl(sctx, output_file, input_file, shared_objects):
pass
patchelf_add_rpath = subrule(
implementation = _patchelf_add_rpath_impl,
attrs = dict(
_patchelf_binary = attr.label(
executable = True,
default = Label("@patchelf"),
cfg = "exec",
),
),
)
EXTRA_ATTRS = dict(
runtime_shared_objects = attr.label_list(
allow_empty = True,
doc = "TODO",
allow_files = [".so"],
cfg = "target",
),
)
def _cc_child_impl(ctx):
return ctx.super(
# NOTE: we'd like to just pass in a computed `linkopts` flag that has
# all the appropriate `rpaths` but unfortunately overriding parent rule
# attributes during child rule analysis isn't (yet?) supported:
# https://docs.google.com/document/d/1p6z-shWf9sdqo_ep7dcjZCGvqN5r2jsPkJCqHHgfRp4/edit?disco=AAAA3pixqsA
)
cc_binary = rule(
implementation = _cc_child_impl,
attrs = EXTRA_ATTRS,
parent = native.cc_binary,
subrules = [patchelf_add_rpath],
)
cc_library = rule(
implementation = _cc_child_impl,
attrs = EXTRA_ATTRS,
parent = native.cc_library,
subrules = [patchelf_add_rpath],
)
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1720542800,
"narHash": "sha256-ZgnNHuKV6h2+fQ5LuqnUaqZey1Lqqt5dTUAiAnqH0QQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "feb2849fdeb70028c70d73b848214b00d324a497",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
{
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
inputs.flake-utils.url = github:numtide/flake-utils;
outputs = { nixpkgs, flake-utils, self }: flake-utils.lib.eachDefaultSystem (sys: let
np = nixpkgs.legacyPackages.${sys};
inherit (np) lib;
in {
# We want to use a pre-release Bazel.
packages.bazel = let
# get the version and `dist.zip` SHA256 from `.bazelversion`:
versionInfo = let
lines = lib.splitString "\n" (builtins.readFile ./.bazelversion);
in rec {
version = builtins.head lines;
sha256 = builtins.elemAt lines 1;
majorVersion = builtins.head (lib.splitString "-" version);
};
# override the source, lockfile:
src = with versionInfo; np.fetchurl {
url = "https://releases.bazel.build/${majorVersion}/rolling/${version}/bazel-${version}-dist.zip";
inherit sha256;
};
# the actual bazel nixpkg vendors this file to avoid IFD; we're okay with
# IFD:
lockfile = np.stdenvNoCC.mkDerivation {
name = "bazel-${versionInfo.version}-MODULE.bazel.lock";
inherit src;
sourceRoot = ".";
nativeBuildInputs = [ np.unzip ];
buildPhase = "cp MODULE.bazel.lock $out";
};
# apply the overrides:
base = np.bazel_7;
in lib.pipe base [
# bazel 8 wants JDK 21:
(pkg: pkg.override rec {
buildJdk = np.jdk21_headless;
runJdk = buildJdk;
})
(pkg: pkg.overrideAttrs (old: {
postPatch = builtins.replaceStrings
["java_runtime_version=local_jdk_17" "java_language_version=17" "--extra_toolchains=@bazel_tools//tools/jdk:all"]
["java_runtime_version=local_jdk_21" "java_language_version=21" ""]
old.postPatch
;
}))
# version gets used in many places and is overrideable at the
# `callPackage` level:
(pkg: pkg.override { inherit (versionInfo) version; })
# `src` and `lockfile` must be overriden at the `mkDerivation` level:
(pkg: pkg.overrideAttrs (old: let
# `lockfile` gets used in a couple of places:
distDir = repoCache;
repoCache = old.passthru.repoCache.override { inherit lockfile; };
in {
inherit src;
postPatch = builtins.replaceStrings
["${old.passthru.repoCache}"]
["${repoCache}"]
old.postPatch
;
passthru = old.passthru // {
tests = old.passthru.tests.override { inherit lockfile repoCache; };
inherit lockfile distDir repoCache;
};
}))
];
devShells.default = np.mkShell {
nativeBuildInputs = with np; [
self.packages.${sys}.bazel
buildifier
];
};
});
}
#include "a.h"
// #include "b.h"
auto main() -> int {
A::run();
// B::run();
return 1;
}
module(name = "rules_cc_subrule_playground")
bazel_dep(name = "patchelf", version = "0.18.0")
{
"lockFileVersion": 11,
"registryFileHashes": {
"https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497",
"https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2",
"https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589",
"https://bcr.bazel.build/modules/abseil-cpp/20211102.0/source.json": "7e3a9adf473e9af076ae485ed649d5641ad50ec5c11718103f34de03170d94ad",
"https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8",
"https://bcr.bazel.build/modules/bazel_features/1.11.0/source.json": "c9320aa53cd1c441d24bd6b716da087ad7e4ff0d9742a9884587596edfe53015",
"https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
"https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a",
"https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5",
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/source.json": "082ed5f9837901fada8c68c2f3ddc958bb22b6d654f71dd73f3df30d45d4b749",
"https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
"https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
"https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4",
"https://bcr.bazel.build/modules/googletest/1.11.0/source.json": "c73d9ef4268c91bd0c1cd88f1f9dfa08e814b1dbe89b5f594a9f08ba0244d206",
"https://bcr.bazel.build/modules/patchelf/0.18.0/MODULE.bazel": "15a6beff7e828d585c5bd0f9f93589df117b5594e9d19e43096c77de58b9ae5f",
"https://bcr.bazel.build/modules/patchelf/0.18.0/source.json": "57caf6bcaa5ba515c6fb1c2eacee00735afbeb1ffacb34a57553fb139c8e4333",
"https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee",
"https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37",
"https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615",
"https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814",
"https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc",
"https://bcr.bazel.build/modules/platforms/0.0.9/source.json": "cd74d854bf16a9e002fb2ca7b1a421f4403cda29f824a765acd3a8c56f8d43e6",
"https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7",
"https://bcr.bazel.build/modules/protobuf/21.7/source.json": "bbe500720421e582ff2d18b0802464205138c06056f443184de39fbb8187b09b",
"https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0",
"https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858",
"https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647",
"https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c",
"https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e",
"https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
"https://bcr.bazel.build/modules/rules_cc/0.0.9/source.json": "1f1ba6fea244b616de4a554a0f4983c91a9301640c8fe0dd1d410254115c8430",
"https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74",
"https://bcr.bazel.build/modules/rules_java/7.6.3/MODULE.bazel": "c2b6ace50614007f95d788a50f9fc7bb35ba535deebf90b60acc2a60c01e0b1b",
"https://bcr.bazel.build/modules/rules_java/7.6.3/source.json": "a32ddce6b75dbe8aa73e790b11182bd23abba80012bb1390cce3f4c8e8888f6c",
"https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7",
"https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/source.json": "a075731e1b46bc8425098512d038d416e966ab19684a10a34f4741295642fc35",
"https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0",
"https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d",
"https://bcr.bazel.build/modules/rules_license/0.0.7/source.json": "355cc5737a0f294e560d52b1b7a6492d4fff2caf0bef1a315df5a298fca2d34a",
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc",
"https://bcr.bazel.build/modules/rules_pkg/0.7.0/source.json": "c2557066e0c0342223ba592510ad3d812d4963b9024831f7f66fd0584dd8c66c",
"https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06",
"https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7",
"https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/source.json": "d57902c052424dfda0e71646cb12668d39c4620ee0544294d9d941e7d12bc3a9",
"https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f",
"https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7",
"https://bcr.bazel.build/modules/rules_python/0.22.1/source.json": "57226905e783bae7c37c2dd662be078728e48fa28ee4324a7eabcafb5a43d014",
"https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
"https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8",
"https://bcr.bazel.build/modules/stardoc/0.5.1/source.json": "a96f95e02123320aa015b956f29c00cb818fa891ef823d55148e1a362caacf29",
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/source.json": "f1ef7d3f9e0e26d4b23d1c39b5f5de71f584dd7d1b4ef83d9bbba6ec7a6a6459",
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
"https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27",
"https://bcr.bazel.build/modules/zlib/1.3/MODULE.bazel": "6a9c02f19a24dcedb05572b2381446e27c272cd383aed11d41d99da9e3167a72",
"https://bcr.bazel.build/modules/zlib/1.3/source.json": "b6b43d0737af846022636e6e255fd4a96fee0d34f08f3830e6e0bac51465c37c"
},
"selectedYankedVersions": {},
"moduleExtensions": {
"@@platforms//host:extension.bzl%host_platform": {
"general": {
"bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=",
"usagesDigest": "meSzxn3DUCcYEhq4HQwExWkWtU4EjriRBQLsZN+Q0SU=",
"recordedFileInputs": {},
"recordedDirentsInputs": {},
"envVariables": {},
"generatedRepoSpecs": {
"host_platform": {
"bzlFile": "@@platforms//host:extension.bzl",
"ruleClassName": "host_platform_repo",
"attributes": {}
}
},
"recordedRepoMappingEntries": []
}
}
}
}
#include <iostream>
extern "C" void print_a(void) {
std::cout << "hello from a" << std::endl;
}
#include <iostream>
extern "C" void print_b(void) {
std::cout << "hello from b" << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment