From 5d21dc9d5c7b742ebf21568e8b14e0b9da3eadb3 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Wed, 1 Apr 2015 18:23:27 +0800 Subject: [PATCH 01/14] Split the library path detection logic by platform. --- ext/mysql2/extconf.rb | 387 +++++++++++++++++++++++++----------------- 1 file changed, 228 insertions(+), 159 deletions(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index e38193d53..c03ce985b 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -1,17 +1,161 @@ # encoding: UTF-8 require 'mkmf' -require 'English' -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-----" - elsif RUBY_PLATFORM =~ /darwin/ - abort "-----\n#{lib} is missing. You may need to 'brew install mysql' or 'port install mysql', and try again.\n-----" - else - abort "-----\n#{lib} is missing. You may need to 'apt-get install libmysqlclient-dev' or 'yum install mysql-devel', and try again.\n-----" +class Platform + # Gets the proper platform object for the current platform. + def self.current + case RUBY_PLATFORM + when /mswin|mingw/ + Windows.new + when /darwin/ + MacOS.new + else + Linux.new + end + end + + # @return [(String, String)|nil] The include and library paths. + def detect_paths + detect_by_explicit_path || detect_by_mysql_config + end + + protected + + def detect_by_explicit_path + # If the user has provided a --with-mysql-dir argument, we must respect it or fail. + inc, lib = dir_config('mysql') + if inc && lib + # Ruby versions not incorporating the mkmf fix at + # https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39717 + # do not properly search for lib directories, and must be corrected + unless lib && lib[-3, 3] == 'lib' + @libdir_basename = 'lib' + inc, lib = dir_config('mysql') + end + + error "Cannot find include dir(s) #{inc}" unless inc && inc.split(File::PATH_SEPARATOR).any?{|dir| File.directory?(dir)} + error "Cannot find library dir(s) #{lib}" unless lib && lib.split(File::PATH_SEPARATOR).any?{|dir| File.directory?(dir)} + warn "Using --with-mysql-dir=#{File.dirname(inc)}" + [inc, lib] + else + nil + end + end + + def detect_by_mysql_config + if with_config('mysql-config') && !mysql_config_path + error 'Cannot find mysql_config' + end + warn "Using mysql_config at #{mysql_config_path}" + + ver = `#{mysql_config_path} --version`.chomp.to_f + includes = `#{mysql_config_path} --include`.chomp + exit 1 if $? != 0 + libs = `#{mysql_config_path} --libs_r`.chomp + + # MySQL 5.5 and above already have re-entrant code in libmysqlclient (no _r). + if ver >= 5.5 || libs.empty? + libs = `#{mysql_config_path} --libs`.chomp + end + exit 1 if $? != 0 + + $INCFLAGS += ' ' + includes + $libs = "#{libs} #{$libs}" + [includes, libs] + end + + def error(message) + abort("-----\n#{message}\n-----") + end + + def warn(message) + super("-----\n#{message}\n-----") + end + + def asplode(library) + complain("#{library} is missing. #{asplode_suggestion}") + end + + def asplode_suggestion + 'Please check your installation of MySQL and try again.' + end + + def mysql_config_path + nil end end +class Unix < Platform + # borrowed from mysqlplus + # http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb + DEFAULT_MYSQL_CONFIG_SEARCH_PATHS = %w[ + /opt + /opt/local + /opt/local/mysql + /opt/local/lib/mysql5* + /usr + /usr/mysql + /usr/local + /usr/local/mysql + /usr/local/mysql-* + /usr/local/lib/mysql5* + ].freeze + + def detect_paths + super || detect_by_known_paths + end + + protected + + def detect_by_known_paths + inc, lib = dir_config('mysql', '/usr/local') + libs = ['m', 'z', 'socket', 'nsl', 'mygcc'] + found = false + until find_library('mysqlclient', 'mysql_query', lib, "#{lib}/mysql") do + break if libs.empty? + found ||= have_library(libs.shift) + end + + asplode('mysql client') unless found + + [inc, lib] + end + + def default_mysql_config_search_path + ENV['PATH'].split(File::PATH_SEPARATOR) + + DEFAULT_MYSQL_CONFIG_SEARCH_PATHS.map{|dir| "#{dir}/bin" } + end + + def mysql_config_glob + "{#{default_mysql_config_search_path.join(',')}}/{mysql_config,mysql_config5}" + end + + def mysql_config_path + @mysql_config_path ||= Dir[mysql_config_glob].first + end +end + +class Linux < Unix + protected + + def asplode_suggestion + 'Try `apt-get install libmysqlclient-dev` or `yum install mysql-devel`, '\ + 'check your installation of MySQL and try again.' + end +end + +class MacOS < Unix + protected + + def asplode_suggestion + 'Try `brew install mysql`, check your installation of MySQL and try again.' + end +end + +class Windows < Platform + +end + # 2.0-only have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h') @@ -21,63 +165,7 @@ def asplode(lib) have_func('rb_hash_dup') have_func('rb_intern3') -# borrowed from mysqlplus -# http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb -dirs = ENV.fetch('PATH').split(File::PATH_SEPARATOR) + %w( - /opt - /opt/local - /opt/local/mysql - /opt/local/lib/mysql5* - /usr - /usr/mysql - /usr/local - /usr/local/mysql - /usr/local/mysql-* - /usr/local/lib/mysql5* - /usr/local/opt/mysql5* -).map { |dir| dir << '/bin' } - -GLOB = "{#{dirs.join(',')}}/{mysql_config,mysql_config5,mariadb_config}" - -# If the user has provided a --with-mysql-dir argument, we must respect it or fail. -inc, lib = dir_config('mysql') -if inc && lib - # TODO: Remove when 2.0.0 is the minimum supported version - # Ruby versions not incorporating the mkmf fix at - # https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39717 - # do not properly search for lib directories, and must be corrected - unless lib && lib[-3, 3] == 'lib' - @libdir_basename = 'lib' - inc, lib = dir_config('mysql') - end - abort "-----\nCannot find include dir(s) #{inc}\n-----" unless inc && inc.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) } - abort "-----\nCannot find library dir(s) #{lib}\n-----" unless lib && lib.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) } - warn "-----\nUsing --with-mysql-dir=#{File.dirname inc}\n-----" - rpath_dir = lib -elsif (mc = (with_config('mysql-config') || Dir[GLOB].first)) - # If the user has provided a --with-mysql-config argument, we must respect it or fail. - # If the user gave --with-mysql-config with no argument means we should try to find it. - mc = Dir[GLOB].first if mc == true - abort "-----\nCannot find mysql_config at #{mc}\n-----" unless mc && File.exist?(mc) - abort "-----\nCannot execute mysql_config at #{mc}\n-----" unless File.executable?(mc) - warn "-----\nUsing mysql_config at #{mc}\n-----" - ver = `#{mc} --version`.chomp.to_f - includes = `#{mc} --include`.chomp - abort unless $CHILD_STATUS.success? - libs = `#{mc} --libs_r`.chomp - # MySQL 5.5 and above already have re-entrant code in libmysqlclient (no _r). - libs = `#{mc} --libs`.chomp if ver >= 5.5 || libs.empty? - abort unless $CHILD_STATUS.success? - $INCFLAGS += ' ' + includes - $libs = libs + " " + $libs - rpath_dir = libs -else - _, usr_local_lib = dir_config('mysql', '/usr/local') - - asplode("mysql client") unless find_library('mysqlclient', 'mysql_query', usr_local_lib, "#{usr_local_lib}/mysql") - - rpath_dir = usr_local_lib -end +_, rpath_dir = Platform.current.detect_paths if have_header('mysql.h') prefix = nil @@ -87,111 +175,92 @@ def asplode(lib) asplode 'mysql.h' end -%w(errmsg.h mysqld_error.h).each do |h| - header = [prefix, h].compact.join '/' - asplode h unless have_header header -end + %w{ errmsg.h mysqld_error.h }.each do |h| + header = [prefix, h].compact.join '/' + asplode h unless have_header h + end -# This is our wishlist. We use whichever flags work on the host. -# -Wall and -Wextra are included by default. -wishlist = [ - '-Weverything', - '-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) - '-Wno-declaration-after-statement', # GET_CLIENT followed by GET_STATEMENT in statement.c - '-Wno-disabled-macro-expansion', # rubby :( - '-Wno-documentation-unknown-command', # rubby :( - '-Wno-missing-field-initializers', # gperf generates bad code - '-Wno-missing-variable-declarations', # missing symbols due to ruby native ext initialization - '-Wno-padded', # mysql :( - '-Wno-sign-conversion', # gperf generates bad code - '-Wno-static-in-inline', # gperf generates bad code - '-Wno-switch-enum', # result.c -- enum_field_types (when not fully covered, e.g. mysql 5.6+) - '-Wno-undef', # rubinius :( - '-Wno-used-but-marked-unused', # rubby :( -] - -if ENV['CI'] - wishlist += [ - '-Werror', - '-fsanitize=address', - '-fsanitize=cfi', - '-fsanitize=integer', - '-fsanitize=memory', - '-fsanitize=thread', - '-fsanitize=undefined', - ] -end + # This is our wishlist. We use whichever flags work on the host. + # -Wall and -Wextra are included by default. + # TODO: fix statement.c and remove -Wno-error=declaration-after-statement + %w( + -Werror + -Weverything + -fsanitize=address + -fsanitize=integer + -fsanitize=thread + -fsanitize=memory + -fsanitize=undefined + -fsanitize=cfi + -Wno-error=declaration-after-statement + ).each do |flag| + if try_link('int main() {return 0;}', flag) + $CFLAGS << ' ' << flag + end + end -usable_flags = wishlist.select do |flag| - try_link('int main() {return 0;}', flag) -end + if RUBY_PLATFORM =~ /mswin|mingw/ + # Build libmysql.a interface link library + require 'rake' -$CFLAGS << ' ' << usable_flags.join(' ') - -if RUBY_PLATFORM =~ /mswin|mingw/ - # Build libmysql.a interface link library - require 'rake' - - # Build libmysql.a interface link library - # Use rake to rebuild only if these files change - deffile = File.expand_path('../../../support/libmysql.def', __FILE__) - libfile = File.expand_path(File.join(rpath_dir, 'libmysql.lib')) - file 'libmysql.a' => [deffile, libfile] do - when_writing 'building libmysql.a' do - # Ruby kindly shows us where dllwrap is, but that tool does more than we want. - # Maybe in the future Ruby could provide RbConfig::CONFIG['DLLTOOL'] directly. - dlltool = RbConfig::CONFIG['DLLWRAP'].gsub('dllwrap', 'dlltool') - sh dlltool, '--kill-at', - '--dllname', 'libmysql.dll', - '--output-lib', 'libmysql.a', - '--input-def', deffile, libfile + # Build libmysql.a interface link library + # Use rake to rebuild only if these files change + deffile = File.expand_path('../../../support/libmysql.def', __FILE__) + libfile = File.expand_path(File.join(rpath_dir, 'libmysql.lib')) + file 'libmysql.a' => [deffile, libfile] do |t| + when_writing 'building libmysql.a' do + # Ruby kindly shows us where dllwrap is, but that tool does more than we want. + # Maybe in the future Ruby could provide RbConfig::CONFIG['DLLTOOL'] directly. + dlltool = RbConfig::CONFIG['DLLWRAP'].gsub('dllwrap', 'dlltool') + sh dlltool, '--kill-at', + '--dllname', 'libmysql.dll', + '--output-lib', 'libmysql.a', + '--input-def', deffile, libfile + end end - end - Rake::Task['libmysql.a'].invoke - $LOCAL_LIBS << ' ' << 'libmysql.a' + Rake::Task['libmysql.a'].invoke + $LOCAL_LIBS << ' ' << 'libmysql.a' - # Make sure the generated interface library works (if cross-compiling, trust without verifying) - unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ - abort "-----\nCannot find libmysql.a\n----" unless have_library('libmysql') - abort "-----\nCannot link to libmysql.a (my_init)\n----" unless have_func('my_init') - end + # Make sure the generated interface library works (if cross-compiling, trust without verifying) + unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + abort "-----\nCannot find libmysql.a\n----" unless have_library('libmysql') + abort "-----\nCannot link to libmysql.a (my_init)\n----" unless have_func('my_init') + end - # Vendor libmysql.dll - vendordir = File.expand_path('../../../vendor/', __FILE__) - directory vendordir + # Vendor libmysql.dll + vendordir = File.expand_path('../../../vendor/', __FILE__) + directory vendordir - vendordll = File.join(vendordir, 'libmysql.dll') - dllfile = File.expand_path(File.join(rpath_dir, 'libmysql.dll')) - file vendordll => [dllfile, vendordir] do - when_writing 'copying libmysql.dll' do - cp dllfile, vendordll + vendordll = File.join(vendordir, 'libmysql.dll') + dllfile = File.expand_path(File.join(rpath_dir, 'libmysql.dll')) + file vendordll => [dllfile, vendordir] do |t| + when_writing 'copying libmysql.dll' do + cp dllfile, vendordll + end end - end - # Copy libmysql.dll to the local vendor directory by default - if arg_config('--no-vendor-libmysql') - # Fine, don't. - puts "--no-vendor-libmysql" - else # Default: arg_config('--vendor-libmysql') - # Let's do it! - Rake::Task[vendordll].invoke - end -else - case explicit_rpath = with_config('mysql-rpath') - when true - abort "-----\nOption --with-mysql-rpath must have an argument\n-----" - when false - warn "-----\nOption --with-mysql-rpath has been disabled at your request\n-----" - when String - # The user gave us a value so use it - rpath_flags = " -Wl,-rpath,#{explicit_rpath}" - warn "-----\nSetting mysql rpath to #{explicit_rpath}\n-----" - $LDFLAGS << rpath_flags + # Copy libmysql.dll to the local vendor directory by default + if arg_config('--no-vendor-libmysql') + # Fine, don't. + puts "--no-vendor-libmysql" + else # Default: arg_config('--vendor-libmysql') + # Let's do it! + Rake::Task[vendordll].invoke + end else - if (libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2]) + case explicit_rpath = with_config('mysql-rpath') + when true + abort "-----\nOption --with-mysql-rpath must have an argument\n-----" + when false + warn "-----\nOption --with-mysql-rpath has been disabled at your request\n-----" + when String + # The user gave us a value so use it + rpath_flags = " -Wl,-rpath,#{explicit_rpath}" + warn "-----\nSetting mysql rpath to #{explicit_rpath}\n-----" + $LDFLAGS << rpath_flags + else + if libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2] rpath_flags = " -Wl,-rpath,#{libdir}" if RbConfig::CONFIG["RPATHFLAG"].to_s.empty? && try_link('int main() {return 0;}', rpath_flags) # Usually Ruby sets RPATHFLAG the right way for each system, but not on OS X. From 61bcc82ae843cd1338da340b3de061d520870aa9 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Wed, 1 Apr 2015 18:49:18 +0800 Subject: [PATCH 02/14] Move the header and library and compiler detection to the Platform class. --- ext/mysql2/extconf.rb | 71 ++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index c03ce985b..846fe88f6 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -14,11 +14,49 @@ def self.current end end + def configure + detect_paths + detect_headers + detect_libraries + + configure_compiler + end + # @return [(String, String)|nil] The include and library paths. def detect_paths detect_by_explicit_path || detect_by_mysql_config end + def detect_headers + headers = %w{ mysql.h errmsg.h mysqld_error.h } + prefix = ['', 'mysql/'].find do |prefix| + have_header("#{prefix}mysql.h") + end + + headers.each do |header| + header = [prefix, h].compact.join '/' + asplode(header) unless have_header(header) + end + end + + def detect_libraries + libraries = %w{ mysqlclient libmysql } + library = libraries.find do |library| + have_library(library, 'mysql_query') + end + + asplode 'mysqlclient or libmysql' unless library + end + + def configure_compiler + # These gcc style flags are also supported by clang and xcode compilers, + # so we'll use a does-it-work test instead of an is-it-gcc test. + gcc_flags = ' -Wall -funroll-loops' + if try_link('int main() {return 0;}', gcc_flags) + $CFLAGS << gcc_flags + end + end + protected def detect_by_explicit_path @@ -166,38 +204,7 @@ class Windows < Platform have_func('rb_intern3') _, rpath_dir = Platform.current.detect_paths - -if have_header('mysql.h') - prefix = nil -elsif have_header('mysql/mysql.h') - prefix = 'mysql' -else - asplode 'mysql.h' -end - - %w{ errmsg.h mysqld_error.h }.each do |h| - header = [prefix, h].compact.join '/' - asplode h unless have_header h - end - - # This is our wishlist. We use whichever flags work on the host. - # -Wall and -Wextra are included by default. - # TODO: fix statement.c and remove -Wno-error=declaration-after-statement - %w( - -Werror - -Weverything - -fsanitize=address - -fsanitize=integer - -fsanitize=thread - -fsanitize=memory - -fsanitize=undefined - -fsanitize=cfi - -Wno-error=declaration-after-statement - ).each do |flag| - if try_link('int main() {return 0;}', flag) - $CFLAGS << ' ' << flag - end - end +Platform.current.configure if RUBY_PLATFORM =~ /mswin|mingw/ # Build libmysql.a interface link library From ad1641c7b95ad47c57cef15fb65d6206fee7b245 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Wed, 1 Apr 2015 19:07:41 +0800 Subject: [PATCH 03/14] Split the logic for configuring the include and library paths by platform. --- ext/mysql2/extconf.rb | 155 +++++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 71 deletions(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index 846fe88f6..15212c685 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -5,8 +5,10 @@ class Platform # Gets the proper platform object for the current platform. def self.current case RUBY_PLATFORM - when /mswin|mingw/ + when /mswin/ Windows.new + when /mingw/ + WindowsMingw.new when /darwin/ MacOS.new else @@ -15,13 +17,19 @@ def self.current end def configure - detect_paths + _, @rpath_dir = detect_paths detect_headers detect_libraries configure_compiler end + protected + + def rpath_dir + @rpath_dir + end + # @return [(String, String)|nil] The include and library paths. def detect_paths detect_by_explicit_path || detect_by_mysql_config @@ -57,8 +65,6 @@ def configure_compiler end end - protected - def detect_by_explicit_path # If the user has provided a --with-mysql-dir argument, we must respect it or fail. inc, lib = dir_config('mysql') @@ -139,12 +145,46 @@ class Unix < Platform /usr/local/lib/mysql5* ].freeze - def detect_paths - super || detect_by_known_paths + def configure + super + + case explicit_rpath = with_config('mysql-rpath') + when true + error 'Option --with-mysql-rpath must have an argument' + when false + error 'Option --with-mysql-rpath has been disabled at your request' + when String + # The user gave us a value so use it + rpath_flags = " -Wl,-rpath,#{explicit_rpath}" + warn "Setting mysql rpath to #{explicit_rpath}" + $LDFLAGS << rpath_flags + else + if libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2] + rpath_flags = " -Wl,-rpath,#{libdir}" + if RbConfig::CONFIG['RPATHFLAG'].to_s.empty? && try_link('int main() {return 0;}', rpath_flags) + # Usually Ruby sets RPATHFLAG the right way for each system, but not on OS X. + warn "Setting rpath to #{libdir}" + $LDFLAGS << rpath_flags + else + if RbConfig::CONFIG['RPATHFLAG'].to_s.empty? + # If we got here because try_link failed, warn the user + warn 'Don\'t know how to set rpath on your system, if MySQL '\ + 'libraries are not in path mysql2 may not load' + end + # Make sure that LIBPATH gets set if we didn't explicitly set the rpath. + warn "Setting libpath to #{libdir}" + $LIBPATH << libdir unless $LIBPATH.include?(libdir) + end + end + end end protected + def detect_paths + super || detect_by_known_paths + end + def detect_by_known_paths inc, lib = dir_config('mysql', '/usr/local') libs = ['m', 'z', 'socket', 'nsl', 'mygcc'] @@ -191,27 +231,38 @@ def asplode_suggestion end class Windows < Platform + def configure + super -end + require 'rake' -# 2.0-only -have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h') + # Vendor libmysql.dll + vendordir = File.expand_path('../../../vendor/', __FILE__) + directory vendordir -# 1.9-only -have_func('rb_thread_blocking_region') -have_func('rb_wait_for_single_fd') -have_func('rb_hash_dup') -have_func('rb_intern3') + vendordll = File.join(vendordir, 'libmysql.dll') + dllfile = File.expand_path(File.join(rpath_dir, 'libmysql.dll')) + file vendordll => [dllfile, vendordir] do |t| + when_writing 'copying libmysql.dll' do + cp dllfile, vendordll + end + end -_, rpath_dir = Platform.current.detect_paths -Platform.current.configure + # Copy libmysql.dll to the local vendor directory by default + if arg_config('--no-vendor-libmysql') + # Fine, don't. + puts '--no-vendor-libmysql' + else # Default: arg_config('--vendor-libmysql') + # Let's do it! + Rake::Task[vendordll].invoke + end + end +end - if RUBY_PLATFORM =~ /mswin|mingw/ - # Build libmysql.a interface link library - require 'rake' +class WindowsMingw < Windows + def configure + super - # Build libmysql.a interface link library - # Use rake to rebuild only if these files change deffile = File.expand_path('../../../support/libmysql.def', __FILE__) libfile = File.expand_path(File.join(rpath_dir, 'libmysql.lib')) file 'libmysql.a' => [deffile, libfile] do |t| @@ -231,59 +282,21 @@ class Windows < Platform # Make sure the generated interface library works (if cross-compiling, trust without verifying) unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ - abort "-----\nCannot find libmysql.a\n----" unless have_library('libmysql') - abort "-----\nCannot link to libmysql.a (my_init)\n----" unless have_func('my_init') + error 'Cannot find libmysql.a' unless have_library('libmysql') + error 'Cannot link to libmysql.a (my_init)' unless have_func('my_init') end + end +end - # Vendor libmysql.dll - vendordir = File.expand_path('../../../vendor/', __FILE__) - directory vendordir +# 2.0-only +have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h') - vendordll = File.join(vendordir, 'libmysql.dll') - dllfile = File.expand_path(File.join(rpath_dir, 'libmysql.dll')) - file vendordll => [dllfile, vendordir] do |t| - when_writing 'copying libmysql.dll' do - cp dllfile, vendordll - end - end +# 1.9-only +have_func('rb_thread_blocking_region') +have_func('rb_wait_for_single_fd') +have_func('rb_hash_dup') +have_func('rb_intern3') - # Copy libmysql.dll to the local vendor directory by default - if arg_config('--no-vendor-libmysql') - # Fine, don't. - puts "--no-vendor-libmysql" - else # Default: arg_config('--vendor-libmysql') - # Let's do it! - Rake::Task[vendordll].invoke - end - else - case explicit_rpath = with_config('mysql-rpath') - when true - abort "-----\nOption --with-mysql-rpath must have an argument\n-----" - when false - warn "-----\nOption --with-mysql-rpath has been disabled at your request\n-----" - when String - # The user gave us a value so use it - rpath_flags = " -Wl,-rpath,#{explicit_rpath}" - warn "-----\nSetting mysql rpath to #{explicit_rpath}\n-----" - $LDFLAGS << rpath_flags - else - if libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2] - rpath_flags = " -Wl,-rpath,#{libdir}" - if RbConfig::CONFIG["RPATHFLAG"].to_s.empty? && try_link('int main() {return 0;}', rpath_flags) - # Usually Ruby sets RPATHFLAG the right way for each system, but not on OS X. - warn "-----\nSetting rpath to #{libdir}\n-----" - $LDFLAGS << rpath_flags - else - if RbConfig::CONFIG["RPATHFLAG"].to_s.empty? - # If we got here because try_link failed, warn the user - warn "-----\nDon't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load\n-----" - end - # Make sure that LIBPATH gets set if we didn't explicitly set the rpath. - warn "-----\nSetting libpath to #{libdir}\n-----" - $LIBPATH << libdir unless $LIBPATH.include?(libdir) - end - end - end -end +Platform.current.configure create_makefile('mysql2/mysql2') From a0cb29276069cdf68baee288c87043e7eb7ba79f Mon Sep 17 00:00:00 2001 From: Joel Low Date: Wed, 1 Apr 2015 19:11:26 +0800 Subject: [PATCH 04/14] Skip mysql-config if we cannot detect it. --- ext/mysql2/extconf.rb | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index 15212c685..aa68c7410 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -87,25 +87,27 @@ def detect_by_explicit_path end def detect_by_mysql_config - if with_config('mysql-config') && !mysql_config_path - error 'Cannot find mysql_config' - end - warn "Using mysql_config at #{mysql_config_path}" + if mysql_config_path + warn "Using mysql_config at #{mysql_config_path}" - ver = `#{mysql_config_path} --version`.chomp.to_f - includes = `#{mysql_config_path} --include`.chomp - exit 1 if $? != 0 - libs = `#{mysql_config_path} --libs_r`.chomp + ver = `#{mysql_config_path} --version`.chomp.to_f + includes = `#{mysql_config_path} --include`.chomp + exit 1 if $? != 0 + libs = `#{mysql_config_path} --libs_r`.chomp - # MySQL 5.5 and above already have re-entrant code in libmysqlclient (no _r). - if ver >= 5.5 || libs.empty? - libs = `#{mysql_config_path} --libs`.chomp - end - exit 1 if $? != 0 + # MySQL 5.5 and above already have re-entrant code in libmysqlclient (no _r). + if ver >= 5.5 || libs.empty? + libs = `#{mysql_config_path} --libs`.chomp + end + exit 1 if $? != 0 - $INCFLAGS += ' ' + includes - $libs = "#{libs} #{$libs}" - [includes, libs] + $INCFLAGS += ' ' + includes + $libs = "#{libs} #{$libs}" + [includes, libs] + else + error 'Cannot find mysql_config' if with_config('mysql-config') + nil + end end def error(message) From f93d3519eb5e2733b0b443124d8bb32113302f8e Mon Sep 17 00:00:00 2001 From: Joel Low Date: Wed, 1 Apr 2015 19:14:18 +0800 Subject: [PATCH 05/14] We provide the directory separator in our prefixes. --- ext/mysql2/extconf.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index aa68c7410..04b852257 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -42,7 +42,7 @@ def detect_headers end headers.each do |header| - header = [prefix, h].compact.join '/' + header = "#{prefix}#{header}" asplode(header) unless have_header(header) end end @@ -119,7 +119,7 @@ def warn(message) end def asplode(library) - complain("#{library} is missing. #{asplode_suggestion}") + error("#{library} is missing. #{asplode_suggestion}") end def asplode_suggestion From 6fdb088200dd8fa063e58738ae026b7589f7b93a Mon Sep 17 00:00:00 2001 From: Joel Low Date: Wed, 1 Apr 2015 19:36:52 +0800 Subject: [PATCH 06/14] Don't double check mysql.h --- ext/mysql2/extconf.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index 04b852257..ac04017ed 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -36,10 +36,11 @@ def detect_paths end def detect_headers - headers = %w{ mysql.h errmsg.h mysqld_error.h } + headers = %w{ errmsg.h mysqld_error.h } prefix = ['', 'mysql/'].find do |prefix| have_header("#{prefix}mysql.h") end + asplode('mysql.h') unless prefix headers.each do |header| header = "#{prefix}#{header}" From 13d8fbbea404589c92ea51e4503d58d48e95e326 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Wed, 1 Apr 2015 19:37:33 +0800 Subject: [PATCH 07/14] Allow users to succeed building the extension even when libmysql.dll cannot be found. --- ext/mysql2/extconf.rb | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index ac04017ed..f54fe99a9 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -1,6 +1,13 @@ # encoding: UTF-8 require 'mkmf' +# For compatibility with Ruby 1.8 and Ruby EE, whose Rake breaks Object#rm_f +class << self + alias_method :rm_f_original, :rm_f + require 'rake' + alias_method :rm_f, :rm_f_original +end + class Platform # Gets the proper platform object for the current platform. def self.current @@ -234,29 +241,30 @@ def asplode_suggestion end class Windows < Platform + include Rake::DSL + def configure super - require 'rake' - - # Vendor libmysql.dll - vendordir = File.expand_path('../../../vendor/', __FILE__) - directory vendordir - - vendordll = File.join(vendordir, 'libmysql.dll') - dllfile = File.expand_path(File.join(rpath_dir, 'libmysql.dll')) - file vendordll => [dllfile, vendordir] do |t| - when_writing 'copying libmysql.dll' do - cp dllfile, vendordll - end - end - # Copy libmysql.dll to the local vendor directory by default if arg_config('--no-vendor-libmysql') # Fine, don't. - puts '--no-vendor-libmysql' + warn 'Not including local libmysql.dll' + elsif !rpath_dir + error 'Cannot deduce path to libmysql.dll' else # Default: arg_config('--vendor-libmysql') - # Let's do it! + # Vendor libmysql.dll + vendordir = File.expand_path('../../../vendor/', __FILE__) + directory vendordir + + vendordll = File.join(vendordir, 'libmysql.dll') + dllfile = File.expand_path(File.join(rpath_dir, 'libmysql.dll')) + file vendordll => [dllfile, vendordir] do |t| + when_writing 'copying libmysql.dll' do + cp dllfile, vendordll + end + end + Rake::Task[vendordll].invoke end end From 078d93b854767c9d0d6ea2698ca0393e38776eeb Mon Sep 17 00:00:00 2001 From: Joel Low Date: Sat, 6 Jun 2015 11:46:20 +0800 Subject: [PATCH 08/14] Default to the mysql-config path specified on the command line. --- ext/mysql2/extconf.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index f54fe99a9..65b7fc254 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -135,7 +135,7 @@ def asplode_suggestion end def mysql_config_path - nil + @mysql_config_path ||= with_config('mysql-config') end end @@ -219,6 +219,7 @@ def mysql_config_glob end def mysql_config_path + super @mysql_config_path ||= Dir[mysql_config_glob].first end end From bcb46bf839ddb99535b4fc978aa17e4ac7825fd4 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Thu, 11 Jun 2015 07:50:28 +0800 Subject: [PATCH 09/14] Check for supported compiler flags. --- ext/mysql2/extconf.rb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index 65b7fc254..c08aa7d55 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -65,11 +65,20 @@ def detect_libraries end def configure_compiler - # These gcc style flags are also supported by clang and xcode compilers, - # so we'll use a does-it-work test instead of an is-it-gcc test. - gcc_flags = ' -Wall -funroll-loops' - if try_link('int main() {return 0;}', gcc_flags) - $CFLAGS << gcc_flags + # This is our wishlist. We use whichever flags work on the host. + # TODO: fix statement.c and remove -Wno-declaration-after-statement + # TODO: fix gperf mysql_enc_name_to_ruby.h and remove -Wno-missing-field-initializers + %w( + -Wall + -Wextra + -Werror + -Wno-unused-function + -Wno-declaration-after-statement + -Wno-missing-field-initializers + ).select do |flag| + try_link('int main() {return 0;}', flag) + end.each do |flag| + $CFLAGS << ' ' << flag end end From 4d67f57d1162da3eb2c9da4462281b9c312528b5 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Thu, 11 Jun 2015 07:50:56 +0800 Subject: [PATCH 10/14] Check for mariadb's configuration as well. --- ext/mysql2/extconf.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index c08aa7d55..415ce1be6 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -224,7 +224,7 @@ def default_mysql_config_search_path end def mysql_config_glob - "{#{default_mysql_config_search_path.join(',')}}/{mysql_config,mysql_config5}" + "{#{default_mysql_config_search_path.join(',')}}/{mysql_config,mysql_config5,mariadb_config}" end def mysql_config_path From f2fe877c47affebec73dc0682625491f3766ec88 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Thu, 11 Jun 2015 09:00:36 +0800 Subject: [PATCH 11/14] Support more paths where mysql might be installed. --- ext/mysql2/extconf.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index 415ce1be6..f31a3c55f 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -162,6 +162,7 @@ class Unix < Platform /usr/local/mysql /usr/local/mysql-* /usr/local/lib/mysql5* + /usr/local/opt/mysql5* ].freeze def configure From 46367f68a4f4ab2286cd0df22ed723267d2a0a7e Mon Sep 17 00:00:00 2001 From: Joel Low Date: Thu, 11 Jun 2015 09:05:34 +0800 Subject: [PATCH 12/14] Do not get into an infinite loop if all the extra libraries have been exhausted and a mysql library cannot be found. --- ext/mysql2/extconf.rb | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index f31a3c55f..eb60bd6b6 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -207,14 +207,7 @@ def detect_paths def detect_by_known_paths inc, lib = dir_config('mysql', '/usr/local') - libs = ['m', 'z', 'socket', 'nsl', 'mygcc'] - found = false - until find_library('mysqlclient', 'mysql_query', lib, "#{lib}/mysql") do - break if libs.empty? - found ||= have_library(libs.shift) - end - - asplode('mysql client') unless found + asplode('mysql client') unless has_mysql_client?(lib) [inc, lib] end @@ -232,6 +225,12 @@ def mysql_config_path super @mysql_config_path ||= Dir[mysql_config_glob].first end + + private + + def has_mysql_client?(lib) + find_library('mysqlclient', 'mysql_query', lib, "#{lib}/mysql") + end end class Linux < Unix From b5c1f9b99adc590c8f68b0fbafde16e6eb051a62 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Wed, 30 Sep 2015 14:49:56 +0800 Subject: [PATCH 13/14] Cherry-pick changes from new commits. - 83d36e24d260acd13f0071db9b0bef071ecb5684 - 110d05c706c28f4495716fda5e937d0a49d04b7d - 5b1d0952b5c42a320203961f9d76470415557cca - a253352b26f07d9926bfd35aada5e8cec73aeb33 - 0f56af3e619626716078a56e97479c383e47f3dd - 8f9eec4183d796246648c72f64578ae55829a409 - c5b8a1698d209982711e669a63ec3f833f73e58a - 6c64816c848a20026656e0e6b55defafa85fcb15 - a98b7bbfa594730e1c53c0a0591b0fada494fafa --- ext/mysql2/extconf.rb | 67 +++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index eb60bd6b6..6c7217f98 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -1,5 +1,6 @@ # encoding: UTF-8 require 'mkmf' +require 'English' # For compatibility with Ruby 1.8 and Ruby EE, whose Rake breaks Object#rm_f class << self @@ -68,24 +69,48 @@ def configure_compiler # This is our wishlist. We use whichever flags work on the host. # TODO: fix statement.c and remove -Wno-declaration-after-statement # TODO: fix gperf mysql_enc_name_to_ruby.h and remove -Wno-missing-field-initializers - %w( - -Wall - -Wextra - -Werror - -Wno-unused-function - -Wno-declaration-after-statement - -Wno-missing-field-initializers - ).select do |flag| + wishlist = [ + '-Weverything', + '-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) + '-Wno-declaration-after-statement', # GET_CLIENT followed by GET_STATEMENT in statement.c + '-Wno-disabled-macro-expansion', # rubby :( + '-Wno-documentation-unknown-command', # rubby :( + '-Wno-missing-field-initializers', # gperf generates bad code + '-Wno-missing-variable-declarations', # missing symbols due to ruby native ext initialization + '-Wno-padded', # mysql :( + '-Wno-sign-conversion', # gperf generates bad code + '-Wno-static-in-inline', # gperf generates bad code + '-Wno-switch-enum', # result.c -- enum_field_types (when not fully covered, e.g. mysql 5.6+) + '-Wno-undef', # rubinius :( + '-Wno-used-but-marked-unused', # rubby :( + ] + + if ENV['CI'] + wishlist += [ + '-Werror', + '-fsanitize=address', + '-fsanitize=cfi', + '-fsanitize=integer', + '-fsanitize=memory', + '-fsanitize=thread', + '-fsanitize=undefined', + ] + end + + usable_flags = wishlist.select do |flag| try_link('int main() {return 0;}', flag) - end.each do |flag| - $CFLAGS << ' ' << flag end + + $CFLAGS << ' ' << usable_flags.join(' ') end def detect_by_explicit_path # If the user has provided a --with-mysql-dir argument, we must respect it or fail. inc, lib = dir_config('mysql') if inc && lib + # TODO: Remove when 2.0.0 is the minimum supported version # Ruby versions not incorporating the mkmf fix at # https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39717 # do not properly search for lib directories, and must be corrected @@ -96,7 +121,7 @@ def detect_by_explicit_path error "Cannot find include dir(s) #{inc}" unless inc && inc.split(File::PATH_SEPARATOR).any?{|dir| File.directory?(dir)} error "Cannot find library dir(s) #{lib}" unless lib && lib.split(File::PATH_SEPARATOR).any?{|dir| File.directory?(dir)} - warn "Using --with-mysql-dir=#{File.dirname(inc)}" + warn "Using --with-mysql-dir=#{File.dirname(inc)}" [inc, lib] else nil @@ -109,14 +134,12 @@ def detect_by_mysql_config ver = `#{mysql_config_path} --version`.chomp.to_f includes = `#{mysql_config_path} --include`.chomp - exit 1 if $? != 0 + abort unless $CHILD_STATUS.success? libs = `#{mysql_config_path} --libs_r`.chomp # MySQL 5.5 and above already have re-entrant code in libmysqlclient (no _r). - if ver >= 5.5 || libs.empty? - libs = `#{mysql_config_path} --libs`.chomp - end - exit 1 if $? != 0 + libs = `#{mysql_config_path} --libs`.chomp if ver >= 5.5 || libs.empty? + abort unless $CHILD_STATUS.success? $INCFLAGS += ' ' + includes $libs = "#{libs} #{$libs}" @@ -140,7 +163,7 @@ def asplode(library) end def asplode_suggestion - 'Please check your installation of MySQL and try again.' + 'Check your installation of MySQL or Connector/C and try again.' end def mysql_config_path @@ -213,8 +236,8 @@ def detect_by_known_paths end def default_mysql_config_search_path - ENV['PATH'].split(File::PATH_SEPARATOR) + - DEFAULT_MYSQL_CONFIG_SEARCH_PATHS.map{|dir| "#{dir}/bin" } + ENV.fetch('PATH').split(File::PATH_SEPARATOR) + + DEFAULT_MYSQL_CONFIG_SEARCH_PATHS.map {|dir| "#{dir}/bin" } end def mysql_config_glob @@ -237,8 +260,8 @@ class Linux < Unix protected def asplode_suggestion - 'Try `apt-get install libmysqlclient-dev` or `yum install mysql-devel`, '\ - 'check your installation of MySQL and try again.' + "You may need to 'apt-get install libmysqlclient-dev' or 'yum install mysql-devel', and try "\ + "again." end end @@ -246,7 +269,7 @@ class MacOS < Unix protected def asplode_suggestion - 'Try `brew install mysql`, check your installation of MySQL and try again.' + "You may need to 'brew install mysql' or 'port install mysql', and try again." end end From 80c4eec832e8de242e41886214eef3da98dc6402 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Wed, 30 Sep 2015 14:54:32 +0800 Subject: [PATCH 14/14] Fix Rubocop warnings. --- ext/mysql2/extconf.rb | 73 +++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index 6c7217f98..0602171b1 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -2,6 +2,9 @@ require 'mkmf' require 'English' +# Disable these cops, because they make the build script _harder_ to read. +# rubocop:disable Metrics/ClassLength, Style/GuardClause + # For compatibility with Ruby 1.8 and Ruby EE, whose Rake breaks Object#rm_f class << self alias_method :rm_f_original, :rm_f @@ -9,18 +12,21 @@ class << self alias_method :rm_f, :rm_f_original end +# Represents the base configuration for all platforms. class Platform + attr_accessor :rpath_dir + # Gets the proper platform object for the current platform. def self.current case RUBY_PLATFORM - when /mswin/ - Windows.new - when /mingw/ - WindowsMingw.new - when /darwin/ - MacOS.new - else - Linux.new + when /mswin/ + Windows.new + when /mingw/ + WindowsMingw.new + when /darwin/ + MacOS.new + else + Linux.new end end @@ -34,19 +40,15 @@ def configure protected - def rpath_dir - @rpath_dir - end - # @return [(String, String)|nil] The include and library paths. def detect_paths detect_by_explicit_path || detect_by_mysql_config end def detect_headers - headers = %w{ errmsg.h mysqld_error.h } - prefix = ['', 'mysql/'].find do |prefix| - have_header("#{prefix}mysql.h") + headers = %w(errmsg.h mysqld_error.h) + prefix = ['', 'mysql/'].find do |candidate| + have_header("#{candidate}mysql.h") end asplode('mysql.h') unless prefix @@ -57,9 +59,9 @@ def detect_headers end def detect_libraries - libraries = %w{ mysqlclient libmysql } - library = libraries.find do |library| - have_library(library, 'mysql_query') + libraries = %w(mysqlclient libmysql) + library = libraries.find do |candidate| + have_library(candidate, 'mysql_query') end asplode 'mysqlclient or libmysql' unless library @@ -119,18 +121,16 @@ def detect_by_explicit_path inc, lib = dir_config('mysql') end - error "Cannot find include dir(s) #{inc}" unless inc && inc.split(File::PATH_SEPARATOR).any?{|dir| File.directory?(dir)} - error "Cannot find library dir(s) #{lib}" unless lib && lib.split(File::PATH_SEPARATOR).any?{|dir| File.directory?(dir)} + error "Cannot find include dir(s) #{inc}" unless inc && inc.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) } + error "Cannot find library dir(s) #{lib}" unless lib && lib.split(File::PATH_SEPARATOR).any? { |dir| File.directory?(dir) } warn "Using --with-mysql-dir=#{File.dirname(inc)}" [inc, lib] - else - nil end end def detect_by_mysql_config if mysql_config_path - warn "Using mysql_config at #{mysql_config_path}" + warn "Using mysql_config at #{mysql_config_path}" ver = `#{mysql_config_path} --version`.chomp.to_f includes = `#{mysql_config_path} --include`.chomp @@ -171,10 +171,11 @@ def mysql_config_path end end +# Configuration for generic Unix class Unix < Platform # borrowed from mysqlplus # http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb - DEFAULT_MYSQL_CONFIG_SEARCH_PATHS = %w[ + DEFAULT_MYSQL_CONFIG_SEARCH_PATHS = %w( /opt /opt/local /opt/local/mysql @@ -186,7 +187,7 @@ class Unix < Platform /usr/local/mysql-* /usr/local/lib/mysql5* /usr/local/opt/mysql5* - ].freeze + ).freeze def configure super @@ -202,7 +203,7 @@ def configure warn "Setting mysql rpath to #{explicit_rpath}" $LDFLAGS << rpath_flags else - if libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2] + if (libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2]) rpath_flags = " -Wl,-rpath,#{libdir}" if RbConfig::CONFIG['RPATHFLAG'].to_s.empty? && try_link('int main() {return 0;}', rpath_flags) # Usually Ruby sets RPATHFLAG the right way for each system, but not on OS X. @@ -230,14 +231,14 @@ def detect_paths def detect_by_known_paths inc, lib = dir_config('mysql', '/usr/local') - asplode('mysql client') unless has_mysql_client?(lib) + asplode('mysql client') unless mysql_client?(lib) [inc, lib] end def default_mysql_config_search_path ENV.fetch('PATH').split(File::PATH_SEPARATOR) + - DEFAULT_MYSQL_CONFIG_SEARCH_PATHS.map {|dir| "#{dir}/bin" } + DEFAULT_MYSQL_CONFIG_SEARCH_PATHS.map { |dir| "#{dir}/bin" } end def mysql_config_glob @@ -251,11 +252,12 @@ def mysql_config_path private - def has_mysql_client?(lib) + def mysql_client?(lib) find_library('mysqlclient', 'mysql_query', lib, "#{lib}/mysql") end end +# Configuration for Linux class Linux < Unix protected @@ -265,6 +267,7 @@ def asplode_suggestion end end +# Configuration for Mac OS class MacOS < Unix protected @@ -273,6 +276,7 @@ def asplode_suggestion end end +# Configuration for Windows class Windows < Platform include Rake::DSL @@ -292,7 +296,7 @@ def configure vendordll = File.join(vendordir, 'libmysql.dll') dllfile = File.expand_path(File.join(rpath_dir, 'libmysql.dll')) - file vendordll => [dllfile, vendordir] do |t| + file vendordll => [dllfile, vendordir] do when_writing 'copying libmysql.dll' do cp dllfile, vendordll end @@ -303,21 +307,22 @@ def configure end end +# Configuration for MingW builds on Windows class WindowsMingw < Windows def configure super deffile = File.expand_path('../../../support/libmysql.def', __FILE__) libfile = File.expand_path(File.join(rpath_dir, 'libmysql.lib')) - file 'libmysql.a' => [deffile, libfile] do |t| + file 'libmysql.a' => [deffile, libfile] do when_writing 'building libmysql.a' do # Ruby kindly shows us where dllwrap is, but that tool does more than we want. # Maybe in the future Ruby could provide RbConfig::CONFIG['DLLTOOL'] directly. dlltool = RbConfig::CONFIG['DLLWRAP'].gsub('dllwrap', 'dlltool') sh dlltool, '--kill-at', - '--dllname', 'libmysql.dll', - '--output-lib', 'libmysql.a', - '--input-def', deffile, libfile + '--dllname', 'libmysql.dll', + '--output-lib', 'libmysql.a', + '--input-def', deffile, libfile end end