Skip to content

Commit

Permalink
Improve options for linking with OpenSSL especially on MacOS (brianma…
Browse files Browse the repository at this point in the history
…rio#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]>
(cherry picked from commit a89fd5b)
  • Loading branch information
sodabrew authored and philr committed May 21, 2023
1 parent 59e446d commit 4ac618d
Showing 1 changed file with 36 additions and 0 deletions.
36 changes: 36 additions & 0 deletions ext/mysql2/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
require 'mkmf'
require 'English'

### Some helper functions

def asplode(lib)
if RUBY_PLATFORM =~ /mingw|mswin/
abort "-----\n#{lib} is missing. Check your installation of MySQL or Connector/C, and try again.\n-----"
Expand All @@ -22,6 +24,8 @@ def add_ssl_defines(header)
$CFLAGS << ' -DNO_SSL_MODE_SUPPORT' if has_no_support
end

### Check for Ruby C extention interfaces

# 2.1+
have_func('rb_absint_size')
have_func('rb_absint_singlebit_p')
Expand All @@ -36,6 +40,31 @@ def add_ssl_defines(header)
have_func('rb_intern3')
have_func('rb_big_cmp')

### Find OpenSSL library

# User-specified OpenSSL if explicitly specified
if with_config('openssl-dir')
_, lib = dir_config('openssl')
if lib
# Ruby versions below 2.0 on Unix and below 2.1 on Windows
# do not properly search for lib directories, and must be corrected:
# https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39717
unless lib && lib[-3, 3] == 'lib'
@libdir_basename = 'lib'
_, lib = dir_config('openssl')
end
abort "-----\nCannot find library dir(s) #{lib}\n-----" unless lib && lib.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) }
warn "-----\nUsing --with-openssl-dir=#{File.dirname lib}\n-----"
$LDFLAGS << " -L#{lib}"
end
# Homebrew OpenSSL on MacOS
elsif RUBY_PLATFORM =~ /darwin/ && system('command -v brew')
openssl_location = `brew --prefix openssl`.strip
$LDFLAGS << " -L#{openssl_location}/lib" if openssl_location
end

### Find MySQL client library

# borrowed from mysqlplus
# http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb
dirs = ENV.fetch('PATH').split(File::PATH_SEPARATOR) + %w(
Expand Down Expand Up @@ -116,10 +145,13 @@ def add_ssl_defines(header)
have_struct_member('MYSQL', 'net.pvio', mysql_h)
have_const('MYSQL_ENABLE_CLEARTEXT_PLUGIN', mysql_h)

### Compiler flags to help catch errors

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

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

### Sanitizers to help with debugging -- many are available on both Clang/LLVM and GCC

enabled_sanitizers = disabled_sanitizers = []
# Specify a commna-separated list of sanitizers, or try them all by default
sanitizers = with_config('sanitize')
Expand Down Expand Up @@ -178,6 +212,8 @@ def add_ssl_defines(header)
$CFLAGS << ' -g -fno-omit-frame-pointer'
end

### Find MySQL Client on Windows, set RPATH to find the library at runtime

if RUBY_PLATFORM =~ /mswin|mingw/
# Build libmysql.a interface link library
require 'rake'
Expand Down

0 comments on commit 4ac618d

Please sign in to comment.