Skip to content

Add cc_static_library for non-bazel projects #281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ common --incompatible_config_setting_private_default_visibility
# Link Google Test against Abseil and RE2.
build --define='absl=1'

# https://github.com/bazelbuild/bazel/pull/26294
build --experimental_cc_static_library

# AllocationGuard.CooperativeDeathTest checks for "SIGABRT received"
# message printed by this signal handler.
test --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1"
Expand Down
20 changes: 20 additions & 0 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,26 @@ build --cxxopt='-std=c++17'

Congratulations! You've created your first binary using TCMalloc.

### Using TCMalloc in non-Bazel Projects

If you are not using Bazel, you can instead build a standalone version
of TCMalloc that you can vendor in your project. Before doing so you
should still run the tests, as described above, to make sure the
vendored library will work in your environment. Then build the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppose I also link against Abseil, but I build it with CMake, in addition to the TCMalloc library provided by this target.

  1. I assume I absolutely, positively have to use the same version of Abseil?
  2. What symbols end up exported from the cc_static_library?
  3. Anything else someone should be aware of?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great callouts 🙏🏻

  1. added a note about this
  2. a whole lot more than is considered public API but I believe to fix that we'd have to flip the fvisibility default, or potentially produce a relocatable object via an allowlist of symbols. I don't think there's a difference between the public symbols included in this archive vs the combined public symbols in all the static libs that would make up tcmalloc in a normal bazel build
  3. i didn't do anything with headers in this case, so i guess if users actually wanted to access some public API, we'd have to handle that separately, but I figured that shouldn't be an issue for most cases

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a convenient way of hermetically testing this? I poked Bazel briefly by adding this to variants.bzl's list, but it didn't like being specified as the malloc attribute, nor does it really know what to do with it as a dep.

I'm trying to figure out which is the lesser evil of symbol visibility versus potential ODR issues.

  • Symbol visibility probably means making MallocExtension & friends not work, because quite a few of those contain Abseil types. In practice, those ABIs don't change much; but this isn't guaranteed by Abseil either.
  • No symbol visibility means exporting a lot of other stuff, and potentially running afoul of ODR issues in subtle ways if/when it does happen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed a test skeleton pulling the example from the quickstart, they have to be manual unless you're ok with us flipping --experimental_cc_static_library in the .bazelrc.

What do you think we should throw in there instead of those default contents?

standalone bazel target:

```
tcmalloc$ bazel build tcmalloc:tcmalloc_standalone
```

Once this builds you can copy the resulting static library from
`bazel-bin/tcmalloc/libtcmalloc_standalone.a` into your project!

Note that if you have dependencies in your project that are also
included in TCMalloc, it is up to you to ensure the versions are
compatible in order to avoid symbol conflicts (which may or may not be
hard errors at link time).

## What's Next

* Read our [overview](overview.md), if you haven't already. The overview
Expand Down
7 changes: 7 additions & 0 deletions tcmalloc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ cc_library(
alwayslink = 1,
)

cc_static_library(
name = "tcmalloc_standalone",
tags = ["manual"],
visibility = [":__subpackages__"],
deps = [":tcmalloc"],
)

cc_library(
name = "tcmalloc_internal_methods_only",
srcs = [
Expand Down
19 changes: 19 additions & 0 deletions tcmalloc/testing/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -1028,3 +1028,22 @@ create_tcmalloc_testsuite(
"@com_google_googletest//:gtest_main",
],
)

cc_import(
name = "standalone_import",
static_library = "//tcmalloc:tcmalloc_standalone",
alwayslink = True,
)

cc_test(
name = "standalone_test",
srcs = ["standalone_test.cc"],
tags = [
"noasan",
"nomsan",
"notsan",
],
deps = [
":standalone_import",
],
)
17 changes: 17 additions & 0 deletions tcmalloc/testing/standalone_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <iostream>
#include <cstddef>

int main() {
std::cout << "Standard Alignment: " << alignof(std::max_align_t) << '\n';

double *ptr = (double*) malloc(sizeof(double));
std::cout << "Double Alignment: " << alignof(*ptr) << '\n';

char *ptr2 = (char*) malloc(1);
std::cout << "Char Alignment: " << alignof(*ptr2) << '\n';

void *ptr3;
std::cout << "Sizeof void*: " << sizeof(ptr3) << '\n';

return 0;
}