Skip to content

Commit 20ac142

Browse files
authored
Merge pull request #643 from larskanis/binary-macos
Add binary gem for Macos
2 parents e0ce86e + e04e5d0 commit 20ac142

5 files changed

Lines changed: 102 additions & 14 deletions

File tree

.github/workflows/binary-gems.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ jobs:
2828
- platform: "x64-mingw32"
2929
- platform: "x86-mingw32"
3030
- platform: "x86_64-linux"
31+
- platform: "x86_64-darwin"
32+
- platform: "arm64-darwin"
3133
steps:
3234
- uses: actions/checkout@v4
3335
- name: Set up Ruby
@@ -73,6 +75,12 @@ jobs:
7375
- os: ubuntu-latest
7476
ruby: "3.2"
7577
platform: "x86_64-linux"
78+
- os: macos-latest
79+
ruby: "3.4"
80+
platform: "arm64-darwin"
81+
- os: macos-13
82+
ruby: "3.4"
83+
platform: "x86_64-darwin"
7684

7785
runs-on: ${{ matrix.os }}
7886
env:

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ end
1313
group :test do
1414
gem "bundler", ">= 1.16", "< 3.0"
1515
gem "rake-compiler", "~> 1.0"
16-
gem "rake-compiler-dock", "~> 1.8.0"
16+
gem "rake-compiler-dock", "~> 1.9.1"
1717
gem "rspec", "~> 3.5"
1818
# "bigdecimal" is a gem on ruby-3.4+ and it's optional for ruby-pg.
1919
# Specs should succeed without it, but 4 examples are then excluded.

Rakefile

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ CLEAN.include "lib/*/libpq.dll"
3232
CLEAN.include "lib/pg_ext.*"
3333
CLEAN.include "lib/pg/postgresql_lib_path.rb"
3434
CLEAN.include "ports/*.installed"
35-
CLEAN.include "ports/*mingw*", "ports/*linux*"
35+
CLEAN.include "ports/*mingw*", "ports/*linux*", "ports/*darwin*"
3636

3737
Bundler::GemHelper.install_tasks
3838
$gem_spec = Bundler.load_gemspec(GEMSPEC)
@@ -49,6 +49,8 @@ CrossLibraries = [
4949
['x86-mingw32', 'mingw', 'i686-w64-mingw32'],
5050
['x64-mingw32', 'mingw64', 'x86_64-w64-mingw32'],
5151
['x86_64-linux', 'linux-x86_64', 'x86_64-linux-gnu'],
52+
['x86_64-darwin', 'darwin64-x86_64', 'x86_64-apple-darwin'],
53+
['arm64-darwin', 'darwin64-arm64', 'arm64-apple-darwin'],
5254
].map do |platform, openssl_config, toolchain|
5355
CrossLibrary.new platform, openssl_config, toolchain
5456
end
@@ -76,6 +78,7 @@ Rake::ExtensionTask.new do |ext|
7678
# Add libpq.dll/.so to fat binary gemspecs
7779
ext.cross_compiling do |spec|
7880
spec.files << "ports/#{spec.platform.to_s}/lib/libpq-ruby-pg.so.1" if spec.platform.to_s =~ /linux/
81+
spec.files << "ports/#{spec.platform.to_s}/lib/libpq-ruby-pg.1.dylib" if spec.platform.to_s =~ /darwin/
7982
spec.files << "ports/#{spec.platform.to_s}/lib/libpq.dll" if spec.platform.to_s =~ /mingw|mswin/
8083
end
8184
end
@@ -96,17 +99,33 @@ task 'gem:native:prepare' do
9699
end
97100
end
98101

102+
task 'install_darwin_mig', [:arch] do |t, args|
103+
sh <<~EOT
104+
rm -rf bootstrap_cmds &&
105+
git clone --branch=cross_platform https://github.com/markmentovai/bootstrap_cmds &&
106+
cd bootstrap_cmds &&
107+
autoreconf --install &&
108+
sh configure &&
109+
make &&
110+
sed -E -i 's/^cppflags=(.*)/cppflags=(\\1 "-D#{args[:arch]}" "-I\\/opt\\/osxcross\\/target\\/SDK\\/MacOSX11.1.sdk\\/usr\\/include")/' migcom.tproj/mig.sh &&
111+
sudo make install
112+
EOT
113+
end
114+
99115
CrossLibraries.each do |xlib|
100116
platform = xlib.platform
101117
desc "Build fat binary gem for platform #{platform}"
102118
task "gem:native:#{platform}" => ['gem:native:prepare'] do
103119
RakeCompilerDock.sh <<-EOT, platform: platform
120+
#{ "sudo apt-get update && sudo apt-get install -y bison flex &&" if platform =~ /darwin/ }
104121
#{ # remove nm on Linux to suppress PostgreSQL's check for exit which raises thread_exit as a false positive:
105122
"sudo mv `which nm` `which nm`.bak &&" if platform =~ /linux/ }
106123
sudo apt-get update && sudo apt-get install -y bison flex &&
107124
(cp build/gem/gem-*.pem ~/.gem/ || true) &&
108125
bundle install --local &&
109-
rake native:#{platform} pkg/#{$gem_spec.full_name}-#{platform}.gem MAKEOPTS=-j`nproc` RUBY_CC_VERSION=3.4.1:3.3.5:3.2.6:3.1.6:3.0.7:2.7.8
126+
#{ "rake install_darwin_mig[__arm64__]" if platform =~ /arm64-darwin/ }
127+
#{ "rake install_darwin_mig[__x86_64__]" if platform =~ /x86_64-darwin/ }
128+
rake native:#{platform} pkg/#{$gem_spec.full_name}-#{platform}.gem MAKEOPTS=-j`nproc` RUBY_CC_VERSION=#{RakeCompilerDock.ruby_cc_version("~>2.7", "~>3.0")}
110129
EOT
111130
end
112131
desc "Build the native binary gems"

ext/extconf.rb

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class << recipe
6969
def configure
7070
envs = []
7171
envs << "CFLAGS=-DDSO_WIN32 -DOPENSSL_THREADS" if RUBY_PLATFORM =~ /mingw|mswin/
72-
envs << "CFLAGS=-fPIC -DOPENSSL_THREADS" if RUBY_PLATFORM =~ /linux/
72+
envs << "CFLAGS=-fPIC -DOPENSSL_THREADS" if RUBY_PLATFORM =~ /linux|darwin/
7373
execute('configure', ['env', *envs, "./Configure", openssl_platform, "threads", "-static", "CROSS_COMPILE=#{host}-", configure_prefix], altlog: "config.log")
7474
end
7575
def compile
@@ -85,17 +85,34 @@ def install
8585
recipe.cook_and_activate
8686
end
8787

88-
if RUBY_PLATFORM =~ /linux/
88+
if RUBY_PLATFORM =~ /linux|darwin/
8989
krb5_recipe = BuildRecipe.new("krb5", KRB5_VERSION, [KRB5_SOURCE_URI]).tap do |recipe|
9090
class << recipe
9191
def work_path
9292
File.join(super, "src")
9393
end
94+
def configure
95+
if RUBY_PLATFORM=~/darwin/
96+
ENV["CC"] = host[/^.*[^\.\d]/] + "-clang"
97+
ENV["CXX"] = host[/^.*[^\.\d]/] + "-c++"
98+
99+
# Manually set the correct values for configure checks that libkrb5 won't be
100+
# able to perform because we're cross-compiling.
101+
ENV["krb5_cv_attr_constructor_destructor"] = "yes"
102+
ENV["ac_cv_func_regcomp"] = "yes"
103+
ENV["ac_cv_printf_positional"] = "yes"
104+
end
105+
super
106+
end
94107
end
95108
# We specify -fcommon to get around duplicate definition errors in recent gcc.
96109
# See https://github.com/cockroachdb/cockroach/issues/49734
97110
recipe.configure_options << "CFLAGS=-fcommon#{" -fPIC" if RUBY_PLATFORM =~ /linux/}"
111+
recipe.configure_options << "LDFLAGS=-framework Kerberos" if RUBY_PLATFORM =~ /darwin/
98112
recipe.configure_options << "--without-keyutils"
113+
recipe.configure_options << "--disable-nls"
114+
recipe.configure_options << "--disable-silent-rules"
115+
recipe.configure_options << "--without-system-verto"
99116
recipe.configure_options << "krb5_cv_attr_constructor_destructor=yes"
100117
recipe.configure_options << "ac_cv_func_regcomp=yes"
101118
recipe.configure_options << "ac_cv_printf_positional=yes"
@@ -104,14 +121,28 @@ def work_path
104121
end
105122
end
106123

124+
# We build a libpq library file which static links OpenSSL and krb5.
125+
# Our builtin libpq is referenced in different ways depending on the OS:
126+
# - Window: Add the ports directory at runtime per RubyInstaller::Runtime.add_dll_directory
127+
# The file is called "libpq.dll"
128+
# - Linux: Add a rpath to pg_ext.so which references the ports directory.
129+
# The file is called "libpq-ruby-pg.so.1" to avoid loading of system libpq by accident.
130+
# - Macos: Add a reference with relative path in pg_ext.so to the ports directory.
131+
# The file is called "libpq-ruby-pg.1.dylib" to avoid loading of other libpq by accident.
132+
libpq_orig, libpq_rubypg = case RUBY_PLATFORM
133+
when /linux/ then ["libpq.so.5", "libpq-ruby-pg.so.1"]
134+
when /darwin/ then ["libpq.5.dylib", "libpq-ruby-pg.1.dylib"]
135+
# when /mingw/ then ["libpq.dll", "libpq.dll"] # renaming not needed
136+
end
137+
107138
postgresql_recipe = BuildRecipe.new("postgresql", POSTGRESQL_VERSION, [POSTGRESQL_SOURCE_URI]).tap do |recipe|
108139
class << recipe
109140
def configure_defaults
110141
[
111142
"--target=#{host}",
112143
"--host=#{host}",
113144
'--with-openssl',
114-
*(RUBY_PLATFORM=~/linux/ ? ['--with-gssapi'] : []),
145+
*(RUBY_PLATFORM=~/linux|darwin/ ? ['--with-gssapi'] : []),
115146
'--without-zlib',
116147
'--without-icu',
117148
'--without-readline',
@@ -127,24 +158,24 @@ def install
127158
end
128159

129160
recipe.host = toolchain
130-
recipe.configure_options << "CFLAGS=#{" -fPIC" if RUBY_PLATFORM =~ /linux/}"
131-
recipe.configure_options << "LDFLAGS=-L#{openssl_recipe.path}/lib -L#{openssl_recipe.path}/lib64 -L#{openssl_recipe.path}/lib-arm64 #{"-Wl,-soname,libpq-ruby-pg.so.1 -lgssapi_krb5 -lkrb5 -lk5crypto -lkrb5support" if RUBY_PLATFORM =~ /linux/}"
161+
recipe.configure_options << "CFLAGS=#{" -fPIC" if RUBY_PLATFORM =~ /linux|darwin/}"
162+
recipe.configure_options << "LDFLAGS=-L#{openssl_recipe.path}/lib -L#{openssl_recipe.path}/lib64 -L#{openssl_recipe.path}/lib-arm64 #{"-Wl,-soname,#{libpq_rubypg} -lgssapi_krb5 -lkrb5 -lk5crypto -lkrb5support" if RUBY_PLATFORM =~ /linux/} #{"-Wl,-install_name,@loader_path/../../ports/#{gem_platform}/lib/#{libpq_rubypg} -lgssapi_krb5 -lkrb5 -lk5crypto -lkrb5support -lresolv -framework Kerberos" if RUBY_PLATFORM =~ /darwin/}"
132163
recipe.configure_options << "LIBS=-lkrb5 -lcom_err -lk5crypto -lkrb5support -lresolv" if RUBY_PLATFORM =~ /linux/
133164
recipe.configure_options << "LIBS=-lssl -lwsock32 -lgdi32 -lws2_32 -lcrypt32" if RUBY_PLATFORM =~ /mingw|mswin/
134165
recipe.configure_options << "CPPFLAGS=-I#{openssl_recipe.path}/include"
135166
recipe.cook_and_activate
136167
end
137168

138169
# Use our own library name for libpq to avoid loading of system libpq by accident.
139-
FileUtils.ln_sf File.join(postgresql_recipe.port_path, "lib/libpq.so.5"),
140-
File.join(postgresql_recipe.port_path, "lib/libpq-ruby-pg.so.1")
170+
FileUtils.ln_sf File.join(postgresql_recipe.port_path, "lib/#{libpq_orig}"),
171+
File.join(postgresql_recipe.port_path, "lib/#{libpq_rubypg}")
141172
# Avoid dependency to external libgcc.dll on x86-mingw32
142-
$LDFLAGS << " -static-libgcc"
173+
$LDFLAGS << " -static-libgcc" if RUBY_PLATFORM =~ /mingw|mswin/
143174
# Avoid: "libpq.so: undefined reference to `dlopen'" in cross-ruby-2.7.8
144-
$LDFLAGS << " -Wl,--no-as-needed" if RUBY_PLATFORM !~ /aarch64/
145-
# Find libpq in the ports directory coming from lib/3.3
175+
$LDFLAGS << " -Wl,--no-as-needed" if RUBY_PLATFORM !~ /aarch64|arm64|darwin/
176+
# Find libpq in the ports directory coming from lib/3.x
146177
# It is shared between all compiled ruby versions.
147-
$LDFLAGS << " '-Wl,-rpath=$$ORIGIN/../../ports/#{gem_platform}/lib'"
178+
$LDFLAGS << " '-Wl,-rpath=$$ORIGIN/../../ports/#{gem_platform}/lib'" if RUBY_PLATFORM =~ /linux/
148179
# Don't use pg_config for cross build, but --with-pg-* path options
149180
dir_config('pg', "#{postgresql_recipe.path}/include", "#{postgresql_recipe.path}/lib")
150181

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
From e82c1b395162ea71279ea2170259383082e41ab0 Mon Sep 17 00:00:00 2001
2+
From: Lars Kanis <lars@greiz-reinsdorf.de>
3+
Date: Sat, 12 Jul 2025 10:55:17 +0200
4+
Subject: [PATCH] Allow static linking krb5 library
5+
6+
Otherwise it fails with:
7+
Undefined symbols for architecture arm64:
8+
"_krb5int_c_mit_des_zeroblock", referenced from:
9+
_krb5int_des3_cbc_encrypt in libk5crypto.a(d3_aead.o)
10+
_krb5int_des3_cbc_decrypt in libk5crypto.a(d3_aead.o)
11+
---
12+
src/lib/crypto/builtin/des/des_int.h | 2 +-
13+
1 file changed, 1 insertion(+), 1 deletion(-)
14+
15+
diff --git a/src/lib/crypto/builtin/des/des_int.h b/src/lib/crypto/builtin/des/des_int.h
16+
index 46fed7dbd..114e48ebd 100644
17+
--- a/lib/crypto/builtin/des/des_int.h
18+
+++ b/lib/crypto/builtin/des/des_int.h
19+
@@ -159,7 +159,7 @@ mit_des_cbc_encrypt(const mit_des_cblock *in, mit_des_cblock *out,
20+
const mit_des_cblock ivec, int enc);
21+
22+
#define mit_des_zeroblock krb5int_c_mit_des_zeroblock
23+
-extern const mit_des_cblock mit_des_zeroblock;
24+
+const mit_des_cblock mit_des_zeroblock;
25+
26+
/* fin_rndkey.c */
27+
krb5_error_code mit_des_finish_random_key(const krb5_encrypt_block *,
28+
--
29+
2.43.0
30+

0 commit comments

Comments
 (0)