Skip to content

Commit 72deddd

Browse files
committed
Merge pull request #473 from sodabrew/mingw64
Create libmysql.a using dlltool.exe on mingw64
2 parents 054b5f7 + f53219f commit 72deddd

File tree

10 files changed

+457
-99
lines changed

10 files changed

+457
-99
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ end
1313

1414
group :development do
1515
gem 'pry'
16+
gem 'eventmachine' unless RUBY_PLATFORM =~ /mswin|mingw/
1617
end
1718

1819
platforms :rbx do

README.md

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Mysql2 - A modern, simple and very fast MySQL library for Ruby - binding to libmysql
22

3-
[![Build Status](https://travis-ci.org/brianmario/mysql2.png)](https://travis-ci.org/brianmario/mysql2)
3+
Travis CI [![Travis CI Status](https://travis-ci.org/brianmario/mysql2.png)](https://travis-ci.org/brianmario/mysql2)
4+
Appveyor CI [![Appveyor CI Status](https://ci.appveyor.com/api/projects/status/github/sodabrew/mysql2)](https://ci.appveyor.com/project/sodabrew/mysql2)
45

56
The Mysql2 gem is meant to serve the extremely common use-case of connecting, querying and iterating on results.
67
Some database libraries out there serve as direct 1:1 mappings of the already complex C APIs available.
@@ -52,24 +53,21 @@ are located somewhere different than on your build system.
5253
This overrides any rpath calculated by default or by the options above.
5354

5455
### Windows
55-
First, make sure you have the DevKit installed (http://rubyinstaller.org/downloads/) and its variables
56-
are loaded by running devkit\devktvars.bat .
56+
Make sure that you have Ruby and the DevKit compilers installed. We recommend
57+
the [Ruby Installer](http://rubyinstaller.org) distribution.
5758

58-
Next, you need a MySQL library to link against. If you have MySQL loaded on your development machine,
59-
you can use that. If not, you will need to either copy the MySQL directory from your server, or else
60-
obtain a copy of the MySQL C connector: http://dev.mysql.com/downloads/connector/c/
59+
By default, the mysql2 gem will download and use MySQL Connector/C from
60+
mysql.com. If you prefer to use a local installation of Connector/C, add the
61+
flag `--with-mysql-dir=c:/mysql-connector-c-x-y-z` (_this path may use forward slashes_).
6162

62-
If you're using the connector, I recommend just getting the .zip file and unzipping it someplace convenient.
63+
By default, the `libmysql.dll` library will be copied into the mysql2 gem
64+
directory. To prevent this, add the flag `--no-vendor-libmysql`. The mysql2 gem
65+
will search for `libmysql.dll` in the following paths, in order:
6366

64-
Now you can install mysql2. You must use the `--with-mysql-dir` option to tell gem where your MySQL library
65-
files are. For example, if you unzipped the connector to c:\mysql-connector-c-6.1.1-win32 you would install
66-
the gem like this:
67-
68-
gem install mysql2 -- --with-mysql-dir=c:\mysql-connector-c-6.1.1-win32
69-
70-
Finally, you must copy libmysql.dll from the lib subdirectory of your MySQL or MySQL connector directory into
71-
your ruby\bin directory. In the above example, libmysql.dll would be located at
72-
c:\mysql-connector-c-6.1.1-win32\lib .
67+
* Environment variable `RUBY_MYSQL2_LIBMYSQL_DLL=C:\path\to\libmysql.dll`
68+
(_note the Windows-style backslashes_).
69+
* In the mysql2 gem's own directory `vendor/libmysql.dll`
70+
* In the system's default library search paths.
7371

7472
## Usage
7573

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
require 'rake'
33

44
# Load custom tasks (careful attention to define tasks before prerequisites)
5+
load 'tasks/vendor_mysql.rake'
56
load 'tasks/rspec.rake'
67
load 'tasks/compile.rake'
78
load 'tasks/generate.rake'
89
load 'tasks/benchmarks.rake'
9-
load 'tasks/vendor_mysql.rake'
1010

1111
task :default => :spec

appveyor.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
version: "{build}"
3+
clone_depth: 10
4+
install:
5+
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
6+
- ruby --version
7+
- gem --version
8+
- gem install bundler --quiet --no-ri --no-rdoc
9+
- bundler --version
10+
- bundle install --without benchmarks
11+
build_script:
12+
- bundle exec rake compile
13+
test_script:
14+
- '"C:\Program Files\MySQL\MySQL Server 5.6\bin\mysql" --version'
15+
- >
16+
"C:\Program Files\MySQL\MySQL Server 5.6\bin\mysql" -u root -p"Password12!" -e "
17+
CREATE DATABASE IF NOT EXISTS test;
18+
CREATE USER '%USERNAME%'@'localhost';
19+
SET PASSWORD = PASSWORD('');
20+
FLUSH PRIVILEGES;
21+
"
22+
- bundle exec rake spec
23+
# Where do I get Unix find?
24+
#on_failure:
25+
# - find tmp -name "*.log" -exec cat {};
26+
environment:
27+
matrix:
28+
- ruby_version: "200"
29+
- ruby_version: "200-x64"
30+
- ruby_version: "21"
31+
- ruby_version: "21-x64"
32+
cache:
33+
- vendor
34+
- C:\Ruby200\lib\ruby\gems\2.0.0
35+
- C:\Ruby200\bin
36+
- C:\Ruby200-x64\lib\ruby\gems\2.0.0
37+
- C:\Ruby200-x64\bin
38+
- C:\Ruby21\lib\ruby\gems\2.1.0
39+
- C:\Ruby21\bin
40+
- C:\Ruby21-x64\lib\ruby\gems\2.1.0
41+
- C:\Ruby21-x64\bin
42+
services:
43+
- mysql

ext/mysql2/extconf.rb

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,6 @@ def asplode lib
7474
rpath_dir = lib
7575
end
7676

77-
if RUBY_PLATFORM =~ /mswin|mingw/
78-
exit 1 unless have_library('libmysql')
79-
end
80-
8177
if have_header('mysql.h')
8278
prefix = nil
8379
elsif have_header('mysql/mysql.h')
@@ -98,31 +94,82 @@ def asplode lib
9894
$CFLAGS << gcc_flags
9995
end
10096

101-
case explicit_rpath = with_config('mysql-rpath')
102-
when true
103-
abort "-----\nOption --with-mysql-rpath must have an argument\n-----"
104-
when false
105-
warn "-----\nOption --with-mysql-rpath has been disabled at your request\n-----"
106-
when String
107-
# The user gave us a value so use it
108-
rpath_flags = " -Wl,-rpath,#{explicit_rpath}"
109-
warn "-----\nSetting mysql rpath to #{explicit_rpath}\n-----"
110-
$LDFLAGS << rpath_flags
97+
if RUBY_PLATFORM =~ /mswin|mingw/
98+
# Build libmysql.a interface link library
99+
require 'rake'
100+
101+
# Build libmysql.a interface link library
102+
# Use rake to rebuild only if these files change
103+
deffile = File.expand_path('../../../support/libmysql.def', __FILE__)
104+
libfile = File.expand_path(File.join(rpath_dir, 'libmysql.lib'))
105+
file 'libmysql.a' => [deffile, libfile] do |t|
106+
when_writing 'building libmysql.a' do
107+
# Ruby kindly shows us where dllwrap is, but that tool does more than we want.
108+
# Maybe in the future Ruby could provide RbConfig::CONFIG['DLLTOOL'] directly.
109+
dlltool = RbConfig::CONFIG['DLLWRAP'].gsub('dllwrap', 'dlltool')
110+
sh dlltool, '--kill-at',
111+
'--dllname', 'libmysql.dll',
112+
'--output-lib', 'libmysql.a',
113+
'--input-def', deffile, libfile
114+
end
115+
end
116+
117+
Rake::Task['libmysql.a'].invoke
118+
$LOCAL_LIBS << ' ' << 'libmysql.a'
119+
120+
# Make sure the generated interface library works (if cross-compiling, trust without verifying)
121+
unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
122+
abort "-----\nCannot find libmysql.a\n----" unless have_library('libmysql')
123+
abort "-----\nCannot link to libmysql.a (my_init)\n----" unless have_func('my_init')
124+
end
125+
126+
# Vendor libmysql.dll
127+
vendordir = File.expand_path('../../../vendor/', __FILE__)
128+
directory vendordir
129+
130+
vendordll = File.join(vendordir, 'libmysql.dll')
131+
dllfile = File.expand_path(File.join(rpath_dir, 'libmysql.dll'))
132+
file vendordll => [dllfile, vendordir] do |t|
133+
when_writing 'copying libmysql.dll' do
134+
cp dllfile, vendordll
135+
end
136+
end
137+
138+
# Copy libmysql.dll to the local vendor directory by default
139+
if arg_config('--no-vendor-libmysql')
140+
# Fine, don't.
141+
puts "--no-vendor-libmysql"
142+
else # Default: arg_config('--vendor-libmysql')
143+
# Let's do it!
144+
Rake::Task[vendordll].invoke
145+
end
111146
else
112-
if libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2]
113-
rpath_flags = " -Wl,-rpath,#{libdir}"
114-
if RbConfig::CONFIG["RPATHFLAG"].to_s.empty? && try_link('int main() {return 0;}', rpath_flags)
115-
# Usually Ruby sets RPATHFLAG the right way for each system, but not on OS X.
116-
warn "-----\nSetting rpath to #{libdir}\n-----"
117-
$LDFLAGS << rpath_flags
118-
else
119-
if RbConfig::CONFIG["RPATHFLAG"].to_s.empty?
120-
# If we got here because try_link failed, warn the user
121-
warn "-----\nDon't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load\n-----"
147+
case explicit_rpath = with_config('mysql-rpath')
148+
when true
149+
abort "-----\nOption --with-mysql-rpath must have an argument\n-----"
150+
when false
151+
warn "-----\nOption --with-mysql-rpath has been disabled at your request\n-----"
152+
when String
153+
# The user gave us a value so use it
154+
rpath_flags = " -Wl,-rpath,#{explicit_rpath}"
155+
warn "-----\nSetting mysql rpath to #{explicit_rpath}\n-----"
156+
$LDFLAGS << rpath_flags
157+
else
158+
if libdir = rpath_dir[%r{(-L)?(/[^ ]+)}, 2]
159+
rpath_flags = " -Wl,-rpath,#{libdir}"
160+
if RbConfig::CONFIG["RPATHFLAG"].to_s.empty? && try_link('int main() {return 0;}', rpath_flags)
161+
# Usually Ruby sets RPATHFLAG the right way for each system, but not on OS X.
162+
warn "-----\nSetting rpath to #{libdir}\n-----"
163+
$LDFLAGS << rpath_flags
164+
else
165+
if RbConfig::CONFIG["RPATHFLAG"].to_s.empty?
166+
# If we got here because try_link failed, warn the user
167+
warn "-----\nDon't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load\n-----"
168+
end
169+
# Make sure that LIBPATH gets set if we didn't explicitly set the rpath.
170+
warn "-----\nSetting libpath to #{libdir}\n-----"
171+
$LIBPATH << libdir unless $LIBPATH.include?(libdir)
122172
end
123-
# Make sure that LIBPATH gets set if we didn't explicitly set the rpath.
124-
warn "-----\nSetting libpath to #{libdir}\n-----"
125-
$LIBPATH << libdir unless $LIBPATH.include?(libdir)
126173
end
127174
end
128175
end

lib/mysql2.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@
33
require 'bigdecimal'
44
require 'rational' unless RUBY_VERSION >= '1.9.2'
55

6+
# Load libmysql.dll before requiring mysql2/mysql2.so
7+
# This gives a chance to be flexible about the load path
8+
# Or to bomb out with a clear error message instead of a linker crash
9+
if RUBY_PLATFORM =~ /mswin|mingw/
10+
dll_path = if ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
11+
# If this environment variable is set, it overrides any other paths
12+
# The user is advised to use backslashes not forward slashes
13+
ENV['RUBY_MYSQL2_LIBMYSQL_DLL'].dup
14+
elsif File.exist?(File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)))
15+
# Use vendor/libmysql.dll if it exists, convert slashes for Win32 LoadLibrary
16+
File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)).gsub('/', '\\')
17+
else
18+
# This will use default / system library paths
19+
'libmysql.dll'
20+
end
21+
22+
require 'Win32API'
23+
LoadLibrary = Win32API.new('Kernel32', 'LoadLibrary', ['P'], 'I')
24+
if 0 == LoadLibrary.call(dll_path)
25+
abort "Failed to load libmysql.dll from #{dll_path}"
26+
end
27+
end
28+
629
require 'mysql2/version' unless defined? Mysql2::VERSION
730
require 'mysql2/error'
831
require 'mysql2/mysql2'

mysql2.gemspec

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ Gem::Specification.new do |s|
1515
s.test_files = `git ls-files spec examples`.split
1616

1717
# tests
18-
s.add_development_dependency 'eventmachine'
19-
s.add_development_dependency 'rake-compiler', '~> 0.8.1'
18+
s.add_development_dependency 'rake-compiler', '~> 0.9.5'
2019
s.add_development_dependency 'rake', '~> 0.9.3'
2120
s.add_development_dependency 'rspec', '~> 2.8.0'
2221
end

0 commit comments

Comments
 (0)