Skip to content

Commit

Permalink
C++: wrap generated DescriptorTable variable in extern "C" block
Browse files Browse the repository at this point in the history
To implement extensions in Rust, we are going to need a symbol we can depend on
to force-link the C++ extension registration code. The `descriptor_table_xxxxx`
variable seems ideal for this: it already exists and is not public-facing, so
we can reuse it without increasing code size. This CL marks it `extern "C"` to
ensure that we can safely access it from Rust.

PiperOrigin-RevId: 696239471
  • Loading branch information
acozzette authored and copybara-github committed Nov 14, 2024
1 parent e377706 commit d86e58b
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/google/protobuf/compiler/cpp/file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1769,9 +1769,14 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations(io::Printer* p) {
)cc");

if (HasDescriptorMethods(file_, options_)) {
// The DescriptorTable needs to be extern "C" so that we can access it from
// Rust. We do not attempt to read the contents of the table in Rust, but
// just use the symbol to force-link the C++ generated code when necessary.
p->Emit(R"cc(
extern "C" {
$dllexport_decl $extern const ::$proto_ns$::internal::DescriptorTable
$desc_table$;
} // extern "C"
)cc");
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/google/protobuf/compiler/java/java_features.pb.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/google/protobuf/compiler/plugin.pb.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/google/protobuf/cpp_features.pb.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/google/protobuf/descriptor.pb.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions src/google/protobuf/descriptor_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "absl/log/scoped_mock_log.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
Expand Down Expand Up @@ -14104,6 +14105,28 @@ TEST_F(LazilyBuildDependenciesTest, Dependency) {

// ===================================================================

// This is effectively a static_assert ensuring that the generated
// descriptor_table variable is marked extern "C". The compiler will give us an
// error if the generated declaration does not match this one. We need this
// variable to be extern "C" so that we can refer to it from Rust.
//
// If this causes a linker error, it is likely because the name mangling
// changed. That can be fixed by updating to the new name from the generated
// code for unittest.proto.

#define DESCRIPTOR_TABLE_NAME \
descriptor_table_google_2fprotobuf_2funittest_2eproto

extern "C" {
extern const ::google::protobuf::internal::DescriptorTable DESCRIPTOR_TABLE_NAME;
}

TEST(DescriptorTableExternLinkageTest, DescriptorTableExternLinkageTest) {
// The goal of this assertion is just to verify that the descriptor_table
// variable declaration above still refers to a real thing.
EXPECT_TRUE(absl::EndsWith(DESCRIPTOR_TABLE_NAME.filename, "unittest.proto"));
}


} // namespace descriptor_unittest
} // namespace protobuf
Expand Down

0 comments on commit d86e58b

Please sign in to comment.