rdkafka 0.21.0 → 0.22.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +3 -0
- data/.github/workflows/ci_linux_x86_64_gnu.yml +249 -0
- data/.github/workflows/ci_linux_x86_64_musl.yml +205 -0
- data/.github/workflows/ci_macos_arm64.yml +306 -0
- data/.github/workflows/push_linux_x86_64_gnu.yml +64 -0
- data/.github/workflows/push_linux_x86_64_musl.yml +77 -0
- data/.github/workflows/push_macos_arm64.yml +54 -0
- data/.github/workflows/push_ruby.yml +37 -0
- data/.github/workflows/verify-action-pins.yml +16 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +17 -0
- data/README.md +2 -1
- data/Rakefile +0 -2
- data/docker-compose.yml +1 -1
- data/ext/Rakefile +1 -1
- data/ext/build_common.sh +361 -0
- data/ext/build_linux_x86_64_gnu.sh +306 -0
- data/ext/build_linux_x86_64_musl.sh +763 -0
- data/ext/build_macos_arm64.sh +550 -0
- data/lib/rdkafka/bindings.rb +30 -3
- data/lib/rdkafka/config.rb +8 -4
- data/lib/rdkafka/consumer/headers.rb +14 -3
- data/lib/rdkafka/native_kafka.rb +8 -2
- data/lib/rdkafka/producer/partitions_count_cache.rb +216 -0
- data/lib/rdkafka/producer.rb +59 -35
- data/lib/rdkafka/version.rb +1 -1
- data/lib/rdkafka.rb +1 -0
- data/rdkafka.gemspec +27 -8
- data/renovate.json +87 -1
- data/spec/rdkafka/admin_spec.rb +27 -11
- data/spec/rdkafka/bindings_spec.rb +0 -9
- data/spec/rdkafka/config_spec.rb +17 -15
- data/spec/rdkafka/consumer/headers_spec.rb +26 -10
- data/spec/rdkafka/consumer_spec.rb +74 -15
- data/spec/rdkafka/metadata_spec.rb +2 -2
- data/spec/rdkafka/producer/partitions_count_cache_spec.rb +359 -0
- data/spec/rdkafka/producer_spec.rb +237 -7
- data/spec/spec_helper.rb +30 -7
- metadata +45 -87
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/ci.yml +0 -83
- data/Guardfile +0 -19
- data/certs/cert.pem +0 -26
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,550 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
#
|
3
|
+
# Simple librdkafka build script for macOS with Kerberos support
|
4
|
+
# Usage: ./build-librdkafka-macos.sh
|
5
|
+
#
|
6
|
+
# Expected directory structure:
|
7
|
+
# ext/build_macos.sh (this script)
|
8
|
+
# ext/build-common.sh (shared functions)
|
9
|
+
# dist/librdkafka-*.tar.gz (librdkafka source tarball)
|
10
|
+
# dist/patches/*.patch (optional Ruby-specific patches)
|
11
|
+
#
|
12
|
+
set -euo pipefail
|
13
|
+
|
14
|
+
# Source common functions and constants
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
16
|
+
source "$SCRIPT_DIR/build_common.sh"
|
17
|
+
|
18
|
+
# Platform-specific paths
|
19
|
+
DIST_DIR="$SCRIPT_DIR/../dist"
|
20
|
+
PATCHES_DIR="$DIST_DIR/patches"
|
21
|
+
BUILD_DIR="$(pwd)/build-tmp-macos"
|
22
|
+
DEPS_PREFIX="/tmp/macos-deps"
|
23
|
+
|
24
|
+
# macOS-specific dependency check
|
25
|
+
check_macos_dependencies() {
|
26
|
+
log "Checking macOS build dependencies..."
|
27
|
+
|
28
|
+
# Check for Xcode Command Line Tools
|
29
|
+
if ! xcode-select -p &> /dev/null; then
|
30
|
+
error "Xcode Command Line Tools not found. Install with: xcode-select --install"
|
31
|
+
fi
|
32
|
+
|
33
|
+
# Check for required tools (in addition to common ones)
|
34
|
+
local missing_tools=()
|
35
|
+
|
36
|
+
command -v gcc &> /dev/null || missing_tools+=("gcc")
|
37
|
+
command -v clang &> /dev/null || missing_tools+=("clang")
|
38
|
+
|
39
|
+
if [ ${#missing_tools[@]} -gt 0 ]; then
|
40
|
+
error "Missing required tools: ${missing_tools[*]}"
|
41
|
+
fi
|
42
|
+
|
43
|
+
log "✅ All required tools found"
|
44
|
+
|
45
|
+
# Show system info
|
46
|
+
log "Build environment:"
|
47
|
+
log " - macOS version: $(sw_vers -productVersion)"
|
48
|
+
log " - Architecture: $(uname -m)"
|
49
|
+
log " - Xcode tools: $(xcode-select -p)"
|
50
|
+
}
|
51
|
+
|
52
|
+
# macOS-specific compiler setup
|
53
|
+
setup_macos_compiler() {
|
54
|
+
local arch="$1"
|
55
|
+
|
56
|
+
# Get the proper macOS SDK path
|
57
|
+
MACOS_SDK_PATH=$(xcrun --show-sdk-path)
|
58
|
+
log "Using macOS SDK: $MACOS_SDK_PATH"
|
59
|
+
|
60
|
+
# Set macOS-specific flags
|
61
|
+
export CC="$(xcrun -find clang)"
|
62
|
+
export CFLAGS="-fPIC -O2 -arch $arch -isysroot $MACOS_SDK_PATH"
|
63
|
+
export CXXFLAGS="-fPIC -O2 -arch $arch -isysroot $MACOS_SDK_PATH"
|
64
|
+
export CPPFLAGS="-isysroot $MACOS_SDK_PATH"
|
65
|
+
|
66
|
+
log "Applied $arch specific flags"
|
67
|
+
}
|
68
|
+
|
69
|
+
# Build static OpenSSL for macOS
|
70
|
+
build_openssl_macos() {
|
71
|
+
local arch="$1"
|
72
|
+
local openssl_prefix="$2"
|
73
|
+
local openssl_dir="$3"
|
74
|
+
|
75
|
+
cd "$openssl_dir"
|
76
|
+
|
77
|
+
if [ ! -f "$openssl_prefix/lib/libssl.a" ]; then
|
78
|
+
log "Configuring and building static OpenSSL..."
|
79
|
+
make clean 2>/dev/null || true
|
80
|
+
|
81
|
+
setup_macos_compiler "$arch"
|
82
|
+
|
83
|
+
# Configure OpenSSL for macOS
|
84
|
+
if [ "$arch" = "arm64" ]; then
|
85
|
+
./Configure darwin64-arm64-cc \
|
86
|
+
no-shared \
|
87
|
+
no-dso \
|
88
|
+
--prefix="$openssl_prefix" \
|
89
|
+
--openssldir="$openssl_prefix/ssl"
|
90
|
+
else
|
91
|
+
./Configure darwin64-x86_64-cc \
|
92
|
+
no-shared \
|
93
|
+
no-dso \
|
94
|
+
--prefix="$openssl_prefix" \
|
95
|
+
--openssldir="$openssl_prefix/ssl"
|
96
|
+
fi
|
97
|
+
|
98
|
+
make -j$(get_cpu_count)
|
99
|
+
make install
|
100
|
+
|
101
|
+
# Verify the build
|
102
|
+
if [ ! -f "$openssl_prefix/lib/libssl.a" ] || [ ! -f "$openssl_prefix/lib/libcrypto.a" ]; then
|
103
|
+
error "Failed to build static OpenSSL"
|
104
|
+
fi
|
105
|
+
|
106
|
+
log "✅ Static OpenSSL built successfully at $openssl_prefix"
|
107
|
+
else
|
108
|
+
log "Static OpenSSL already built, skipping..."
|
109
|
+
fi
|
110
|
+
}
|
111
|
+
|
112
|
+
# Build static MIT Kerberos for macOS
|
113
|
+
build_krb5_macos() {
|
114
|
+
local arch="$1"
|
115
|
+
local krb5_prefix="$2"
|
116
|
+
local krb5_dir="$3"
|
117
|
+
|
118
|
+
cd "$krb5_dir/src"
|
119
|
+
|
120
|
+
if [ ! -f "$krb5_prefix/lib/libgssapi_krb5.a" ]; then
|
121
|
+
log "Configuring and building static MIT Kerberos..."
|
122
|
+
make clean 2>/dev/null || true
|
123
|
+
|
124
|
+
setup_macos_compiler "$arch"
|
125
|
+
|
126
|
+
# Configure MIT Kerberos for macOS
|
127
|
+
./configure \
|
128
|
+
--disable-shared \
|
129
|
+
--enable-static \
|
130
|
+
--prefix="$krb5_prefix" \
|
131
|
+
--without-ldap \
|
132
|
+
--without-tcl \
|
133
|
+
--without-keyutils \
|
134
|
+
--disable-rpath \
|
135
|
+
--without-system-verto \
|
136
|
+
--disable-thread-support \
|
137
|
+
--disable-aesni
|
138
|
+
|
139
|
+
# Build everything except the problematic kadmin tools (same as Linux)
|
140
|
+
log "Building Kerberos (will ignore kadmin build failures)..."
|
141
|
+
make -j$(get_cpu_count) || {
|
142
|
+
log "Full build failed (expected due to kadmin), continuing with libraries..."
|
143
|
+
# The libraries should be built even if kadmin fails
|
144
|
+
true
|
145
|
+
}
|
146
|
+
|
147
|
+
# Install what was successfully built
|
148
|
+
make install || {
|
149
|
+
log "Full install failed, installing individual components..."
|
150
|
+
# Try to install the core libraries manually
|
151
|
+
make install-mkdirs 2>/dev/null || true
|
152
|
+
make -C util install 2>/dev/null || true
|
153
|
+
make -C lib install 2>/dev/null || true
|
154
|
+
make -C plugins/kdb/db2 install 2>/dev/null || true
|
155
|
+
}
|
156
|
+
|
157
|
+
# Verify we got the essential libraries
|
158
|
+
if [ ! -f "$krb5_prefix/lib/libgssapi_krb5.a" ]; then
|
159
|
+
error "Failed to build essential Kerberos libraries"
|
160
|
+
fi
|
161
|
+
|
162
|
+
log "✅ Static MIT Kerberos built successfully at $krb5_prefix"
|
163
|
+
else
|
164
|
+
log "Static MIT Kerberos already built, skipping..."
|
165
|
+
fi
|
166
|
+
}
|
167
|
+
|
168
|
+
# Build static Cyrus SASL for macOS with Kerberos support
|
169
|
+
build_sasl_macos() {
|
170
|
+
local arch="$1"
|
171
|
+
local sasl_prefix="$2"
|
172
|
+
local sasl_dir="$3"
|
173
|
+
local openssl_prefix="$4"
|
174
|
+
local krb5_prefix="$5"
|
175
|
+
|
176
|
+
cd "$sasl_dir"
|
177
|
+
|
178
|
+
if [ ! -f "$sasl_prefix/lib/libsasl2.a" ]; then
|
179
|
+
log "Configuring and building static Cyrus SASL with Kerberos support..."
|
180
|
+
make clean 2>/dev/null || true
|
181
|
+
|
182
|
+
setup_macos_compiler "$arch"
|
183
|
+
export CPPFLAGS="$CPPFLAGS -I$openssl_prefix/include -I$krb5_prefix/include"
|
184
|
+
export LDFLAGS="-L$openssl_prefix/lib -L$krb5_prefix/lib"
|
185
|
+
|
186
|
+
# Configure SASL with Kerberos/GSSAPI support (now ENABLED)
|
187
|
+
./configure \
|
188
|
+
--disable-shared \
|
189
|
+
--enable-static \
|
190
|
+
--prefix="$sasl_prefix" \
|
191
|
+
--without-dblib \
|
192
|
+
--disable-gdbm \
|
193
|
+
--disable-macos-framework \
|
194
|
+
--disable-sample \
|
195
|
+
--disable-obsolete_cram_attr \
|
196
|
+
--disable-obsolete_digest_attr \
|
197
|
+
--enable-gssapi="$krb5_prefix" \
|
198
|
+
--disable-krb4 \
|
199
|
+
--with-openssl="$openssl_prefix"
|
200
|
+
|
201
|
+
make -j$(get_cpu_count)
|
202
|
+
make install
|
203
|
+
|
204
|
+
# Verify the build
|
205
|
+
if [ ! -f "$sasl_prefix/lib/libsasl2.a" ]; then
|
206
|
+
error "Failed to build static Cyrus SASL"
|
207
|
+
fi
|
208
|
+
|
209
|
+
log "✅ Static Cyrus SASL with Kerberos support built successfully at $sasl_prefix"
|
210
|
+
else
|
211
|
+
log "Static Cyrus SASL already built, skipping..."
|
212
|
+
fi
|
213
|
+
}
|
214
|
+
|
215
|
+
# Build generic static library for macOS
|
216
|
+
build_static_lib_macos() {
|
217
|
+
local lib_name="$1"
|
218
|
+
local arch="$2"
|
219
|
+
local prefix="$3"
|
220
|
+
local source_dir="$4"
|
221
|
+
local configure_args="$5"
|
222
|
+
|
223
|
+
cd "$source_dir"
|
224
|
+
|
225
|
+
local lib_file="$prefix/lib/lib${lib_name}.a"
|
226
|
+
if [ ! -f "$lib_file" ]; then
|
227
|
+
log "Configuring and building static $lib_name..."
|
228
|
+
make clean 2>/dev/null || true
|
229
|
+
|
230
|
+
setup_macos_compiler "$arch"
|
231
|
+
|
232
|
+
# Run configure with provided arguments
|
233
|
+
eval "./configure --prefix=\"$prefix\" $configure_args"
|
234
|
+
|
235
|
+
make -j$(get_cpu_count)
|
236
|
+
make install
|
237
|
+
|
238
|
+
# Verify the build
|
239
|
+
if [ ! -f "$lib_file" ]; then
|
240
|
+
error "Failed to build static $lib_name"
|
241
|
+
fi
|
242
|
+
|
243
|
+
log "✅ Static $lib_name built successfully at $prefix"
|
244
|
+
else
|
245
|
+
log "Static $lib_name already built, skipping..."
|
246
|
+
fi
|
247
|
+
}
|
248
|
+
|
249
|
+
# Check common and macOS-specific dependencies
|
250
|
+
check_common_dependencies
|
251
|
+
check_macos_dependencies
|
252
|
+
|
253
|
+
# Auto-detect librdkafka tarball
|
254
|
+
log "Looking for librdkafka tarball in $DIST_DIR..."
|
255
|
+
LIBRDKAFKA_TARBALL=$(find_librdkafka_tarball "$DIST_DIR")
|
256
|
+
log "Found librdkafka tarball: $LIBRDKAFKA_TARBALL"
|
257
|
+
|
258
|
+
# Verify librdkafka tarball checksum if available
|
259
|
+
verify_librdkafka_checksum "$LIBRDKAFKA_TARBALL"
|
260
|
+
|
261
|
+
# Find patches
|
262
|
+
PATCHES_FOUND=()
|
263
|
+
find_patches "$PATCHES_DIR" PATCHES_FOUND
|
264
|
+
|
265
|
+
# Detect architecture early since we need it for dependency building
|
266
|
+
ARCH=$(uname -m)
|
267
|
+
log "Detected architecture: $ARCH"
|
268
|
+
|
269
|
+
security_log "Starting secure build with checksum verification enabled"
|
270
|
+
log "Building self-contained librdkafka for macOS with Kerberos support"
|
271
|
+
log "Dependencies to build:"
|
272
|
+
log " - OpenSSL: $OPENSSL_VERSION"
|
273
|
+
log " - Cyrus SASL: $CYRUS_SASL_VERSION (with Kerberos support)"
|
274
|
+
log " - MIT Kerberos: $KRB5_VERSION"
|
275
|
+
log " - zlib: $ZLIB_VERSION"
|
276
|
+
log " - ZStd: $ZSTD_VERSION"
|
277
|
+
log "librdkafka source: $LIBRDKAFKA_TARBALL"
|
278
|
+
log "Build directory: $BUILD_DIR"
|
279
|
+
|
280
|
+
# Create build directory
|
281
|
+
mkdir -p "$BUILD_DIR"
|
282
|
+
cd "$BUILD_DIR"
|
283
|
+
|
284
|
+
# Build static OpenSSL first (other deps might need it)
|
285
|
+
log "Building static OpenSSL $OPENSSL_VERSION..."
|
286
|
+
OPENSSL_PREFIX="$DEPS_PREFIX/static-openssl-$OPENSSL_VERSION"
|
287
|
+
OPENSSL_TARBALL="openssl-$OPENSSL_VERSION.tar.gz"
|
288
|
+
OPENSSL_DIR="openssl-$OPENSSL_VERSION"
|
289
|
+
|
290
|
+
secure_download "$(get_openssl_url)" "$OPENSSL_TARBALL"
|
291
|
+
extract_if_needed "$OPENSSL_TARBALL" "$OPENSSL_DIR"
|
292
|
+
build_openssl_macos "$ARCH" "$OPENSSL_PREFIX" "$OPENSSL_DIR"
|
293
|
+
|
294
|
+
cd "$BUILD_DIR"
|
295
|
+
|
296
|
+
# Build static MIT Kerberos (before SASL since SASL needs it)
|
297
|
+
log "Building static MIT Kerberos $KRB5_VERSION..."
|
298
|
+
KRB5_PREFIX="$DEPS_PREFIX/static-krb5-$KRB5_VERSION"
|
299
|
+
KRB5_TARBALL="krb5-$KRB5_VERSION.tar.gz"
|
300
|
+
KRB5_DIR="krb5-$KRB5_VERSION"
|
301
|
+
|
302
|
+
secure_download "$(get_krb5_url)" "$KRB5_TARBALL"
|
303
|
+
extract_if_needed "$KRB5_TARBALL" "$KRB5_DIR"
|
304
|
+
build_krb5_macos "$ARCH" "$KRB5_PREFIX" "$KRB5_DIR"
|
305
|
+
|
306
|
+
cd "$BUILD_DIR"
|
307
|
+
|
308
|
+
# Build static Cyrus SASL (after OpenSSL and Kerberos since it needs both)
|
309
|
+
log "Building static Cyrus SASL $CYRUS_SASL_VERSION with Kerberos support..."
|
310
|
+
SASL_PREFIX="$DEPS_PREFIX/static-sasl-$CYRUS_SASL_VERSION"
|
311
|
+
SASL_TARBALL="cyrus-sasl-$CYRUS_SASL_VERSION.tar.gz"
|
312
|
+
SASL_DIR="cyrus-sasl-$CYRUS_SASL_VERSION"
|
313
|
+
|
314
|
+
secure_download "$(get_sasl_url)" "$SASL_TARBALL"
|
315
|
+
extract_if_needed "$SASL_TARBALL" "$SASL_DIR"
|
316
|
+
build_sasl_macos "$ARCH" "$SASL_PREFIX" "$SASL_DIR" "$OPENSSL_PREFIX" "$KRB5_PREFIX"
|
317
|
+
|
318
|
+
cd "$BUILD_DIR"
|
319
|
+
|
320
|
+
# Build static ZStd
|
321
|
+
log "Building static ZStd $ZSTD_VERSION..."
|
322
|
+
ZSTD_PREFIX="$DEPS_PREFIX/static-zstd-$ZSTD_VERSION"
|
323
|
+
ZSTD_TARBALL="zstd-$ZSTD_VERSION.tar.gz"
|
324
|
+
ZSTD_DIR="zstd-$ZSTD_VERSION"
|
325
|
+
|
326
|
+
secure_download "$(get_zstd_url)" "$ZSTD_TARBALL"
|
327
|
+
extract_if_needed "$ZSTD_TARBALL" "$ZSTD_DIR"
|
328
|
+
cd "$ZSTD_DIR"
|
329
|
+
|
330
|
+
if [ ! -f "$ZSTD_PREFIX/lib/libzstd.a" ]; then
|
331
|
+
log "Configuring and building static ZStd..."
|
332
|
+
make clean 2>/dev/null || true
|
333
|
+
|
334
|
+
setup_macos_compiler "$ARCH"
|
335
|
+
|
336
|
+
# Build static library using ZStd's Makefile
|
337
|
+
make lib-mt CFLAGS="$CFLAGS" PREFIX="$ZSTD_PREFIX" -j$(get_cpu_count)
|
338
|
+
make install PREFIX="$ZSTD_PREFIX"
|
339
|
+
|
340
|
+
# Verify the build
|
341
|
+
if [ ! -f "$ZSTD_PREFIX/lib/libzstd.a" ]; then
|
342
|
+
error "Failed to build static ZStd"
|
343
|
+
fi
|
344
|
+
|
345
|
+
log "✅ Static ZStd built successfully at $ZSTD_PREFIX"
|
346
|
+
else
|
347
|
+
log "Static ZStd already built, skipping..."
|
348
|
+
fi
|
349
|
+
|
350
|
+
cd "$BUILD_DIR"
|
351
|
+
|
352
|
+
# Build static zlib
|
353
|
+
log "Building static zlib $ZLIB_VERSION..."
|
354
|
+
ZLIB_PREFIX="$DEPS_PREFIX/static-zlib-$ZLIB_VERSION"
|
355
|
+
ZLIB_TARBALL="zlib-$ZLIB_VERSION.tar.gz"
|
356
|
+
ZLIB_DIR="zlib-$ZLIB_VERSION"
|
357
|
+
|
358
|
+
secure_download "$(get_zlib_url)" "$ZLIB_TARBALL"
|
359
|
+
extract_if_needed "$ZLIB_TARBALL" "$ZLIB_DIR"
|
360
|
+
build_static_lib_macos "z" "$ARCH" "$ZLIB_PREFIX" "$ZLIB_DIR" "--static"
|
361
|
+
|
362
|
+
cd "$BUILD_DIR"
|
363
|
+
|
364
|
+
# Completely disable pkg-config to prevent Homebrew library detection
|
365
|
+
log "Disabling pkg-config to prevent Homebrew interference..."
|
366
|
+
export PKG_CONFIG=""
|
367
|
+
export PKG_CONFIG_PATH=""
|
368
|
+
export PKG_CONFIG_LIBDIR=""
|
369
|
+
|
370
|
+
# Create a dummy pkg-config that always fails
|
371
|
+
mkdir -p "$BUILD_DIR/no-pkg-config"
|
372
|
+
cat > "$BUILD_DIR/no-pkg-config/pkg-config" << 'EOF'
|
373
|
+
#!/bin/sh
|
374
|
+
# Dummy pkg-config that always fails to prevent Homebrew detection
|
375
|
+
exit 1
|
376
|
+
EOF
|
377
|
+
chmod +x "$BUILD_DIR/no-pkg-config/pkg-config"
|
378
|
+
|
379
|
+
# Put our dummy pkg-config first in PATH
|
380
|
+
export PATH="$BUILD_DIR/no-pkg-config:$PATH"
|
381
|
+
|
382
|
+
log "pkg-config disabled - configure will use manual library detection only"
|
383
|
+
|
384
|
+
# Extract librdkafka
|
385
|
+
log "Extracting librdkafka..."
|
386
|
+
tar xzf "$LIBRDKAFKA_TARBALL"
|
387
|
+
cd "librdkafka-$LIBRDKAFKA_VERSION"
|
388
|
+
|
389
|
+
# Fix permissions and apply patches
|
390
|
+
fix_configure_permissions
|
391
|
+
apply_patches PATCHES_FOUND
|
392
|
+
|
393
|
+
# Set compiler flags for librdkafka
|
394
|
+
setup_macos_compiler "$ARCH"
|
395
|
+
|
396
|
+
# Configure librdkafka with static dependencies INCLUDING Kerberos
|
397
|
+
log "Configuring librdkafka with static dependencies including Kerberos..."
|
398
|
+
|
399
|
+
# Tell configure that math functions don't need -lm on macOS
|
400
|
+
export ac_cv_lib_m_floor=yes
|
401
|
+
export ac_cv_lib_m_ceil=yes
|
402
|
+
export ac_cv_lib_m_sqrt=yes
|
403
|
+
export ac_cv_lib_m_pow=yes
|
404
|
+
export LIBS="" # Clear any LIBS that might include -lm
|
405
|
+
|
406
|
+
# Use our static libraries instead of system versions (now including Kerberos)
|
407
|
+
export CPPFLAGS="$CPPFLAGS -I$OPENSSL_PREFIX/include -I$SASL_PREFIX/include -I$KRB5_PREFIX/include -I$ZLIB_PREFIX/include -I$ZSTD_PREFIX/include"
|
408
|
+
export LDFLAGS="-L$OPENSSL_PREFIX/lib -L$SASL_PREFIX/lib -L$KRB5_PREFIX/lib -L$ZLIB_PREFIX/lib -L$ZSTD_PREFIX/lib"
|
409
|
+
|
410
|
+
if [ -f configure ]; then
|
411
|
+
log "Using mklove configure script"
|
412
|
+
./configure \
|
413
|
+
--enable-static \
|
414
|
+
--disable-shared \
|
415
|
+
--disable-curl \
|
416
|
+
--enable-gssapi
|
417
|
+
else
|
418
|
+
error "No configure script found"
|
419
|
+
fi
|
420
|
+
|
421
|
+
# Fix system library path for linking
|
422
|
+
MACOS_SDK_PATH=$(xcrun --show-sdk-path)
|
423
|
+
export LDFLAGS="$LDFLAGS -L$MACOS_SDK_PATH/usr/lib"
|
424
|
+
|
425
|
+
# Build librdkafka
|
426
|
+
log "Compiling librdkafka..."
|
427
|
+
make clean || true
|
428
|
+
|
429
|
+
# Build with LIBS override, but ignore dylib build failures
|
430
|
+
make -j$(get_cpu_count) LIBS="" || {
|
431
|
+
log "Build failed (expected - dylib linking issue), checking if static library was created..."
|
432
|
+
}
|
433
|
+
|
434
|
+
# Verify static library exists (this is what we actually need)
|
435
|
+
if [ ! -f src/librdkafka.a ]; then
|
436
|
+
error "librdkafka.a not found after build"
|
437
|
+
fi
|
438
|
+
|
439
|
+
log "✅ Static librdkafka.a built successfully"
|
440
|
+
|
441
|
+
# Remove the dylib check since we're building our own
|
442
|
+
# Don't check for src/librdkafka.1.dylib
|
443
|
+
|
444
|
+
log "librdkafka built successfully - proceeding to create custom self-contained dylib"
|
445
|
+
|
446
|
+
# Create self-contained dylib with Kerberos libraries included
|
447
|
+
log "Creating self-contained librdkafka.dylib with Kerberos support..."
|
448
|
+
|
449
|
+
# Create self-contained shared library by linking all static dependencies (NOW INCLUDING KERBEROS)
|
450
|
+
# This is the macOS equivalent of your Linux gcc -shared command
|
451
|
+
clang -dynamiclib -fPIC \
|
452
|
+
-Wl,-force_load,src/librdkafka.a \
|
453
|
+
-Wl,-force_load,"$SASL_PREFIX/lib/libsasl2.a" \
|
454
|
+
-Wl,-force_load,"$KRB5_PREFIX/lib/libgssapi_krb5.a" \
|
455
|
+
-Wl,-force_load,"$KRB5_PREFIX/lib/libkrb5.a" \
|
456
|
+
-Wl,-force_load,"$KRB5_PREFIX/lib/libk5crypto.a" \
|
457
|
+
-Wl,-force_load,"$KRB5_PREFIX/lib/libcom_err.a" \
|
458
|
+
-Wl,-force_load,"$KRB5_PREFIX/lib/libkrb5support.a" \
|
459
|
+
-Wl,-force_load,"$OPENSSL_PREFIX/lib/libssl.a" \
|
460
|
+
-Wl,-force_load,"$OPENSSL_PREFIX/lib/libcrypto.a" \
|
461
|
+
-Wl,-force_load,"$ZLIB_PREFIX/lib/libz.a" \
|
462
|
+
-Wl,-force_load,"$ZSTD_PREFIX/lib/libzstd.a" \
|
463
|
+
-o librdkafka.dylib \
|
464
|
+
-lpthread -lc -arch $ARCH -lresolv \
|
465
|
+
-install_name @rpath/librdkafka.dylib \
|
466
|
+
-Wl,-undefined,dynamic_lookup
|
467
|
+
|
468
|
+
if [ ! -f librdkafka.dylib ]; then
|
469
|
+
error "Failed to create self-contained librdkafka.dylib"
|
470
|
+
fi
|
471
|
+
|
472
|
+
log "✅ Self-contained librdkafka.dylib with Kerberos support created successfully"
|
473
|
+
|
474
|
+
# Verify the self-contained build
|
475
|
+
log "Verifying self-contained build..."
|
476
|
+
file librdkafka.dylib
|
477
|
+
|
478
|
+
log "Checking dependencies with otool (should only show system libraries):"
|
479
|
+
otool -L librdkafka.dylib
|
480
|
+
|
481
|
+
# Check for external dependencies that shouldn't be there (strict like Linux version)
|
482
|
+
log "Checking for external dependencies (should only show system libraries):"
|
483
|
+
EXTERNAL_DEPS=$(otool -L librdkafka.dylib | grep -v "librdkafka.dylib" | grep -v "/usr/lib/" | grep -v "/System/Library/" | grep -v "@rpath" || true)
|
484
|
+
if [ -n "$EXTERNAL_DEPS" ]; then
|
485
|
+
error "Found external dependencies - library is not self-contained: $EXTERNAL_DEPS"
|
486
|
+
else
|
487
|
+
log "✅ No external dependencies found - library is self-contained!"
|
488
|
+
fi
|
489
|
+
|
490
|
+
log "Checking exported symbols:"
|
491
|
+
# Avoid SIGPIPE by not using head in a pipe
|
492
|
+
nm -gU librdkafka.dylib > /tmp/symbols.txt 2>/dev/null || true
|
493
|
+
if [ -f /tmp/symbols.txt ]; then
|
494
|
+
head -10 /tmp/symbols.txt
|
495
|
+
rm -f /tmp/symbols.txt
|
496
|
+
else
|
497
|
+
log "Could not extract symbols (this is normal)"
|
498
|
+
fi
|
499
|
+
|
500
|
+
# Force output flush and add small delay
|
501
|
+
sync
|
502
|
+
sleep 1
|
503
|
+
|
504
|
+
# Copy to output directory
|
505
|
+
OUTPUT_DIR="$SCRIPT_DIR"
|
506
|
+
cp librdkafka.dylib "$OUTPUT_DIR/"
|
507
|
+
cp src/librdkafka.a "$OUTPUT_DIR/"
|
508
|
+
|
509
|
+
log "Build artifacts copied to: $OUTPUT_DIR/"
|
510
|
+
log " - librdkafka.dylib (shared library)"
|
511
|
+
log " - librdkafka.a (static library)"
|
512
|
+
|
513
|
+
# Force another flush
|
514
|
+
sync
|
515
|
+
sleep 1
|
516
|
+
|
517
|
+
# Print summaries
|
518
|
+
print_security_summary
|
519
|
+
|
520
|
+
# Enhanced summary for macOS with Kerberos
|
521
|
+
sync
|
522
|
+
echo ""
|
523
|
+
echo "🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉"
|
524
|
+
log "Build completed successfully!"
|
525
|
+
log "📦 Self-contained librdkafka built for macOS $ARCH with Kerberos support:"
|
526
|
+
log " ✅ Static library: librdkafka.a"
|
527
|
+
log " ✅ Self-contained dylib: librdkafka.dylib (with bundled dependencies)"
|
528
|
+
log " ✅ Static OpenSSL: $OPENSSL_VERSION (SSL/TLS support) - bundled"
|
529
|
+
log " ✅ Static Cyrus SASL: $CYRUS_SASL_VERSION (authentication for AWS MSK) - bundled"
|
530
|
+
log " ✅ Static MIT Kerberos: $KRB5_VERSION (GSSAPI/Kerberos authentication) - bundled"
|
531
|
+
log " ✅ Static zlib: $ZLIB_VERSION (compression) - bundled"
|
532
|
+
log " ✅ Static ZStd: $ZSTD_VERSION (high-performance compression) - bundled"
|
533
|
+
log ""
|
534
|
+
log "🎯 Ready for deployment on macOS systems"
|
535
|
+
log "☁️ Compatible with AWS MSK and other secured Kafka clusters"
|
536
|
+
log "🔐 Supply chain security: All dependencies cryptographically verified"
|
537
|
+
log "📦 Self-contained: Ready for Ruby FFI distribution"
|
538
|
+
log "🔑 Kerberos/GSSAPI support: Full feature parity with Linux build"
|
539
|
+
log ""
|
540
|
+
log "Location: $OUTPUT_DIR/librdkafka.dylib"
|
541
|
+
echo "🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉"
|
542
|
+
|
543
|
+
# Force final flush
|
544
|
+
sync
|
545
|
+
|
546
|
+
# Cleanup
|
547
|
+
cleanup_build_dir "$BUILD_DIR"
|
548
|
+
|
549
|
+
# Reset environment variables
|
550
|
+
unset CFLAGS CXXFLAGS CPPFLAGS LDFLAGS
|
data/lib/rdkafka/bindings.rb
CHANGED
@@ -26,6 +26,8 @@ module Rdkafka
|
|
26
26
|
RD_KAFKA_OFFSET_STORED = -1000
|
27
27
|
RD_KAFKA_OFFSET_INVALID = -1001
|
28
28
|
|
29
|
+
EMPTY_HASH = {}.freeze
|
30
|
+
|
29
31
|
class SizePtr < FFI::Struct
|
30
32
|
layout :value, :size_t
|
31
33
|
end
|
@@ -201,9 +203,31 @@ module Rdkafka
|
|
201
203
|
StatsCallback = FFI::Function.new(
|
202
204
|
:int, [:pointer, :string, :int, :pointer]
|
203
205
|
) do |_client_ptr, json, _json_len, _opaque|
|
204
|
-
# Pass the stats hash to callback in config
|
205
206
|
if Rdkafka::Config.statistics_callback
|
206
207
|
stats = JSON.parse(json)
|
208
|
+
|
209
|
+
# If user requested statistics callbacks, we can use the statistics data to get the
|
210
|
+
# partitions count for each topic when this data is published. That way we do not have
|
211
|
+
# to query this information when user is using `partition_key`. This takes around 0.02ms
|
212
|
+
# every statistics interval period (most likely every 5 seconds) and saves us from making
|
213
|
+
# any queries to the cluster for the partition count.
|
214
|
+
#
|
215
|
+
# One edge case is if user would set the `statistics.interval.ms` much higher than the
|
216
|
+
# default current partition count refresh (30 seconds). This is taken care of as the lack
|
217
|
+
# of reporting to the partitions cache will cause cache expire and blocking refresh.
|
218
|
+
#
|
219
|
+
# If user sets `topic.metadata.refresh.interval.ms` too high this is on the user.
|
220
|
+
#
|
221
|
+
# Since this cache is shared, having few consumers and/or producers in one process will
|
222
|
+
# automatically improve the querying times even with low refresh times.
|
223
|
+
(stats['topics'] || EMPTY_HASH).each do |topic_name, details|
|
224
|
+
partitions_count = details['partitions'].keys.reject { |k| k == '-1' }.size
|
225
|
+
|
226
|
+
next unless partitions_count.positive?
|
227
|
+
|
228
|
+
Rdkafka::Producer.partitions_count_cache.set(topic_name, partitions_count)
|
229
|
+
end
|
230
|
+
|
207
231
|
Rdkafka::Config.statistics_callback.call(stats)
|
208
232
|
end
|
209
233
|
|
@@ -363,12 +387,15 @@ module Rdkafka
|
|
363
387
|
def self.partitioner(str, partition_count, partitioner_name = "consistent_random")
|
364
388
|
# Return RD_KAFKA_PARTITION_UA(unassigned partition) when partition count is nil/zero.
|
365
389
|
return -1 unless partition_count&.nonzero?
|
390
|
+
# musl architecture crashes with empty string
|
391
|
+
return 0 if str.empty?
|
366
392
|
|
367
|
-
str_ptr =
|
393
|
+
str_ptr = FFI::MemoryPointer.from_string(str)
|
368
394
|
method_name = PARTITIONERS.fetch(partitioner_name) do
|
369
395
|
raise Rdkafka::Config::ConfigError.new("Unknown partitioner: #{partitioner_name}")
|
370
396
|
end
|
371
|
-
|
397
|
+
|
398
|
+
public_send(method_name, nil, str_ptr, str.size, partition_count, nil, nil)
|
372
399
|
end
|
373
400
|
|
374
401
|
# Create Topics
|
data/lib/rdkafka/config.rb
CHANGED
@@ -233,11 +233,12 @@ module Rdkafka
|
|
233
233
|
#
|
234
234
|
# @param native_kafka_auto_start [Boolean] should the native kafka operations be started
|
235
235
|
# automatically. Defaults to true. Set to false only when doing complex initialization.
|
236
|
+
# @param native_kafka_poll_timeout_ms [Integer] ms poll time of the native Kafka
|
236
237
|
# @return [Producer] The created producer
|
237
238
|
#
|
238
239
|
# @raise [ConfigError] When the configuration contains invalid options
|
239
240
|
# @raise [ClientCreationError] When the native client cannot be created
|
240
|
-
def producer(native_kafka_auto_start: true)
|
241
|
+
def producer(native_kafka_auto_start: true, native_kafka_poll_timeout_ms: 100)
|
241
242
|
# Create opaque
|
242
243
|
opaque = Opaque.new
|
243
244
|
# Create Kafka config
|
@@ -254,7 +255,8 @@ module Rdkafka
|
|
254
255
|
kafka,
|
255
256
|
run_polling_thread: true,
|
256
257
|
opaque: opaque,
|
257
|
-
auto_start: native_kafka_auto_start
|
258
|
+
auto_start: native_kafka_auto_start,
|
259
|
+
timeout_ms: native_kafka_poll_timeout_ms
|
258
260
|
),
|
259
261
|
partitioner_name
|
260
262
|
).tap do |producer|
|
@@ -266,11 +268,12 @@ module Rdkafka
|
|
266
268
|
#
|
267
269
|
# @param native_kafka_auto_start [Boolean] should the native kafka operations be started
|
268
270
|
# automatically. Defaults to true. Set to false only when doing complex initialization.
|
271
|
+
# @param native_kafka_poll_timeout_ms [Integer] ms poll time of the native Kafka
|
269
272
|
# @return [Admin] The created admin instance
|
270
273
|
#
|
271
274
|
# @raise [ConfigError] When the configuration contains invalid options
|
272
275
|
# @raise [ClientCreationError] When the native client cannot be created
|
273
|
-
def admin(native_kafka_auto_start: true)
|
276
|
+
def admin(native_kafka_auto_start: true, native_kafka_poll_timeout_ms: 100)
|
274
277
|
opaque = Opaque.new
|
275
278
|
config = native_config(opaque)
|
276
279
|
Rdkafka::Bindings.rd_kafka_conf_set_background_event_cb(config, Rdkafka::Callbacks::BackgroundEventCallbackFunction)
|
@@ -282,7 +285,8 @@ module Rdkafka
|
|
282
285
|
kafka,
|
283
286
|
run_polling_thread: true,
|
284
287
|
opaque: opaque,
|
285
|
-
auto_start: native_kafka_auto_start
|
288
|
+
auto_start: native_kafka_auto_start,
|
289
|
+
timeout_ms: native_kafka_poll_timeout_ms
|
286
290
|
)
|
287
291
|
)
|
288
292
|
end
|
@@ -7,11 +7,13 @@ module Rdkafka
|
|
7
7
|
EMPTY_HEADERS = {}.freeze
|
8
8
|
|
9
9
|
# Reads a librdkafka native message's headers and returns them as a Ruby Hash
|
10
|
+
# where each key maps to either a String (single value) or Array<String> (multiple values)
|
11
|
+
# to support duplicate headers per KIP-82
|
10
12
|
#
|
11
13
|
# @private
|
12
14
|
#
|
13
15
|
# @param [Rdkafka::Bindings::Message] native_message
|
14
|
-
# @return [Hash<String, String
|
16
|
+
# @return [Hash<String, String|Array<String>>] headers Hash for the native_message
|
15
17
|
# @raise [Rdkafka::RdkafkaError] when fail to read headers
|
16
18
|
def self.from_native(native_message)
|
17
19
|
headers_ptrptr = FFI::MemoryPointer.new(:pointer)
|
@@ -53,10 +55,19 @@ module Rdkafka
|
|
53
55
|
size = size_ptr[:value]
|
54
56
|
|
55
57
|
value_ptr = value_ptrptr.read_pointer
|
56
|
-
|
57
58
|
value = value_ptr.read_string(size)
|
58
59
|
|
59
|
-
headers
|
60
|
+
if headers.key?(name)
|
61
|
+
# If we've seen this header before, convert to array if needed and append
|
62
|
+
if headers[name].is_a?(Array)
|
63
|
+
headers[name] << value
|
64
|
+
else
|
65
|
+
headers[name] = [headers[name], value]
|
66
|
+
end
|
67
|
+
else
|
68
|
+
# First occurrence - store as single value
|
69
|
+
headers[name] = value
|
70
|
+
end
|
60
71
|
|
61
72
|
idx += 1
|
62
73
|
end
|