Skip to content

Commit a89fd5b

Browse files
sodabrewjunaruga
andauthored
Improve options for linking with OpenSSL especially on MacOS (#1303)
Starting a few MacOS majors ago, OpenSSL was no longer included in a way that applications could link against. Even the system Ruby at /usr/bin/ruby was modified to use a MacOS internal SSL implementation. The most common workaround is to use Homebrew to install OpenSSL. Using GitHub Actions as the project's CI tool, we found that both [email protected] and openssl@3 were installed in the default image, and that openssl@3 was returned by default but this mismatched the version the MySQL client libraries were compiled against. While the quick workaround might be to look for [email protected] instead of openssl, a more general improvement is to provide an option for users to specify where OpenSSL is installed. Indeed this issue has been the cause of many postings on GH issues and Stack Overflow over the years. Hopefully this PR improves the situation for a broad swath of users! Unlike the existing option `--with-opt-dir`, the new option `--with-openssl-dir` will fail if the argument is not a valid path rather than producing unexpected results at runtime. This is the default behavior on MacOS: --with-openssl-dir=$(brew --prefix openssl) If you have both [email protected] and openssl@3 installed, be explicit: --with-openssl-dir=$(brew --prefix [email protected]) The option is available on all platforms and may be helpful for non-default OpenSSL installations on Linux or FreeBSD as well. Co-authored-by: Jun Aruga <[email protected]>
1 parent c0410ab commit a89fd5b

File tree

2 files changed

+47
-17
lines changed

2 files changed

+47
-17
lines changed

.github/workflows/build.yml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,42 +26,41 @@ jobs:
2626
- '2.3'
2727
- '2.2'
2828
- '2.1'
29-
db: ['']
3029
include:
3130
# Comment out due to ci/setup.sh stucking.
3231
# - {os: ubuntu-18.04, ruby: 2.4, db: mariadb10.1}
3332
- {os: ubuntu-20.04, ruby: '2.4', db: mariadb10.3}
3433
- {os: ubuntu-18.04, ruby: '2.4', db: mysql57}
3534
- {os: ubuntu-20.04, ruby: '2.4', db: mysql80}
36-
- {os: ubuntu-18.04, ruby: 'head', db: ''}
35+
- {os: ubuntu-18.04, ruby: 'head'}
3736
# db: A DB's brew package name in macOS case.
3837
# Set a name "db: '[email protected]'" when using an old version.
3938
# MariaDB lastet version
4039
# Allow failure due to the following test failures that rarely happens.
4140
# https://github.com/brianmario/mysql2/issues/1194
42-
- {os: macos-latest, ruby: '2.6', db: mariadb, allow-failure: true}
41+
- {os: macos-latest, ruby: '2.6', db: mariadb, ssl: [email protected], allow-failure: true}
4342
# MySQL latest version
4443
# Allow failure due to the issue #1194.
45-
- {os: macos-latest, ruby: '2.6', db: mysql, allow-failure: true}
44+
- {os: macos-latest, ruby: '2.6', db: mysql, ssl: [email protected], allow-failure: true}
4645
# On the fail-fast: true, it cancels all in-progress jobs
4746
# if any matrix job fails unlike Travis fast_finish.
4847
fail-fast: false
4948
env:
5049
BUNDLE_WITHOUT: development
50+
# reduce MacOS CI time, don't need to clean a runtime that isn't saved
51+
HOMEBREW_NO_INSTALL_CLEANUP: 1
52+
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
5153
steps:
5254
- uses: actions/checkout@v3
53-
- name: Install openssl
54-
if: matrix.os == 'macos-latest'
55-
run: |
56-
brew update
57-
brew install openssl
5855
# https://github.com/ruby/setup-ruby
5956
- uses: ruby/setup-ruby@v1
6057
with:
6158
ruby-version: ${{ matrix.ruby }}
6259
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
63-
- if: matrix.db != ''
60+
- if: matrix.db
6461
run: echo 'DB=${{ matrix.db }}' >> $GITHUB_ENV
6562
- run: sudo echo "127.0.0.1 mysql2gem.example.com" | sudo tee -a /etc/hosts
6663
- run: bash ci/setup.sh
67-
- run: bundle exec rake spec
64+
- if: matrix.ssl
65+
run: echo "rake_spec_opts=--with-openssl-dir=$(brew --prefix ${{ matrix.ssl }})" >> $GITHUB_ENV
66+
- run: bundle exec rake spec -- $rake_spec_opts

ext/mysql2/extconf.rb

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
require 'mkmf'
22
require 'English'
33

4+
### Some helper functions
5+
46
def asplode(lib)
57
if RUBY_PLATFORM =~ /mingw|mswin/
68
abort "-----\n#{lib} is missing. Check your installation of MySQL or Connector/C, and try again.\n-----"
@@ -26,11 +28,7 @@ def add_ssl_defines(header)
2628
end
2729
end
2830

29-
# Homebrew openssl
30-
if RUBY_PLATFORM =~ /darwin/ && system("command -v brew")
31-
openssl_location = `brew --prefix openssl`.strip
32-
$LDFLAGS << " -L#{openssl_location}/lib" if openssl_location
33-
end
31+
### Check for Ruby C extention interfaces
3432

3533
# 2.1+
3634
have_func('rb_absint_size')
@@ -42,7 +40,33 @@ def add_ssl_defines(header)
4240
# Missing in RBX (https://github.com/rubinius/rubinius/issues/3771)
4341
have_func('rb_wait_for_single_fd')
4442

45-
have_func("rb_enc_interned_str", "ruby.h")
43+
# 3.0+
44+
have_func('rb_enc_interned_str', 'ruby.h')
45+
46+
### Find OpenSSL library
47+
48+
# User-specified OpenSSL if explicitly specified
49+
if with_config('openssl-dir')
50+
_, lib = dir_config('openssl')
51+
if lib
52+
# Ruby versions below 2.0 on Unix and below 2.1 on Windows
53+
# do not properly search for lib directories, and must be corrected:
54+
# https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39717
55+
unless lib && lib[-3, 3] == 'lib'
56+
@libdir_basename = 'lib'
57+
_, lib = dir_config('openssl')
58+
end
59+
abort "-----\nCannot find library dir(s) #{lib}\n-----" unless lib && lib.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) }
60+
warn "-----\nUsing --with-openssl-dir=#{File.dirname lib}\n-----"
61+
$LDFLAGS << " -L#{lib}"
62+
end
63+
# Homebrew OpenSSL on MacOS
64+
elsif RUBY_PLATFORM =~ /darwin/ && system('command -v brew')
65+
openssl_location = `brew --prefix openssl`.strip
66+
$LDFLAGS << " -L#{openssl_location}/lib" if openssl_location
67+
end
68+
69+
### Find MySQL client library
4670

4771
# borrowed from mysqlplus
4872
# http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb
@@ -140,10 +164,13 @@ def add_ssl_defines(header)
140164
# to retain compatibility with the typedef in earlier MySQLs.
141165
have_type('my_bool', mysql_h)
142166

167+
### Compiler flags to help catch errors
168+
143169
# This is our wishlist. We use whichever flags work on the host.
144170
# -Wall and -Wextra are included by default.
145171
wishlist = [
146172
'-Weverything',
173+
'-Wno-compound-token-split-by-macro', # Fixed in Ruby 2.7+ at https://bugs.ruby-lang.org/issues/17865
147174
'-Wno-bad-function-cast', # rb_thread_call_without_gvl returns void * that we cast to VALUE
148175
'-Wno-conditional-uninitialized', # false positive in client.c
149176
'-Wno-covered-switch-default', # result.c -- enum_field_types (when fully covered, e.g. mysql 5.5)
@@ -168,6 +195,8 @@ def add_ssl_defines(header)
168195

169196
$CFLAGS << ' ' << usable_flags.join(' ')
170197

198+
### Sanitizers to help with debugging -- many are available on both Clang/LLVM and GCC
199+
171200
enabled_sanitizers = disabled_sanitizers = []
172201
# Specify a comma-separated list of sanitizers, or try them all by default
173202
sanitizers = with_config('sanitize')
@@ -202,6 +231,8 @@ def add_ssl_defines(header)
202231
$CFLAGS << ' -g -fno-omit-frame-pointer'
203232
end
204233

234+
### Find MySQL Client on Windows, set RPATH to find the library at runtime
235+
205236
if RUBY_PLATFORM =~ /mswin|mingw/ && !defined?(RubyInstaller)
206237
# Build libmysql.a interface link library
207238
require 'rake'

0 commit comments

Comments
 (0)