Fix google-protobuf gem source build on the mswin platform (#28433)

`gem install google-protobuf --platform ruby` fails on Windows with the native mswin toolchain (`x64-mswin64_140`, `cl.exe` and `nmake`). `Init_protobuf_c` in `protobuf.c` is annotated with the GCC-style `__attribute__((visibility("default")))`, which `cl.exe` cannot parse and rejects with a cascade of C2143/C2091 syntax errors. In addition, `extconf.rb` passes GCC-only flags (`-std=gnu99`, `-O3`, `-fvisibility=hidden`) that `cl.exe` does not understand.

This change replaces the attribute with Ruby's portable `RUBY_FUNC_EXPORTED` macro, which expands to `extern __declspec(dllexport)` under MSVC and to `__attribute__((__visibility__("default"))) extern` under GCC/Clang, so the symbol stays exported when the extension is built with `-fvisibility=hidden`. It also gives mswin its own `$CFLAGS` branch. `-std:c11` is required there because the MSVC atomics fallback in upb only uses its `_Generic` based implementation when `__STDC_VERSION__` is at least 201112L. The pre-C11 fallback returns `void*` from `upb_Atomic_Load`, and mswin Ruby compiles extensions with `-we4047` by default, which turns those conversion warnings into hard errors.

Verified on Windows 11 with Ruby 4.0.5 (`x64-mswin64_140`) and Visual Studio 2022 Build Tools (MSVC 14.51). Building the extension in-tree succeeds, and a gem built from the released 4.35.1 sources with this patch applied installs successfully and passes a `Struct` and `Timestamp` encode/decode round-trip. Precompiled `x64-mingw-ucrt` gems are unaffected because MinGW keeps using the existing GCC branch.

Generated with [Claude Code](https://claude.com/claude-code)

Closes #28433

COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/28433 from hsbt:claude/elated-goldwasser-3862b4 7d533bab6c
PiperOrigin-RevId: 963158243
This commit is contained in:
Hiroshi SHIBATA 2026-08-11 20:01:27 -07:00 committed by Copybara-Service
parent e788b3ce3d
commit dce0d24702
2 changed files with 7 additions and 2 deletions

View file

@ -22,7 +22,12 @@ debug_enabled = ENV["PROTOBUF_CONFIG"] == "dbg"
additional_c_flags = debug_enabled ? "-O0 -fno-omit-frame-pointer -fvisibility=default -g" : "-O3 -DNDEBUG -fvisibility=hidden"
if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/ || RUBY_PLATFORM =~ /freebsd/
if RUBY_PLATFORM =~ /mswin/
# cl.exe does not understand GCC-style flags. C11 or later is required
# for _Generic, which the upb MSVC atomics fall back on. c17 is the
# highest C standard mode cl.exe supports.
$CFLAGS += debug_enabled ? " -std:c17 -Od" : " -std:c17 -DNDEBUG"
elsif RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/ || RUBY_PLATFORM =~ /freebsd/
$CFLAGS += " -std=gnu99 -Wall -Wsign-compare -Wno-declaration-after-statement #{additional_c_flags}"
else
$CFLAGS += " -std=gnu99 #{additional_c_flags}"

View file

@ -379,7 +379,7 @@ static VALUE Google_Protobuf_Internal_allocation_count_fail_on(VALUE self,
// This must be named "Init_protobuf_c" because the Ruby module is named
// "protobuf_c" -- the VM looks for this symbol in our .so.
__attribute__((visibility("default"))) void Init_protobuf_c() {
RUBY_FUNC_EXPORTED void Init_protobuf_c() {
VALUE google = rb_define_module("Google");
VALUE protobuf = rb_define_module_under(google, "Protobuf");