Top Level Namespace

Defined Under Namespace

Modules: TinyTds Classes: BuildRecipe

Constant Summary collapse

ICONV_VERSION =
ENV['TINYTDS_ICONV_VERSION'] || "1.14"
ICONV_SOURCE_URI =
"http://ftp.gnu.org/pub/gnu/libiconv/libiconv-#{ICONV_VERSION}.tar.gz"
OPENSSL_VERSION =
ENV['TINYTDS_OPENSSL_VERSION'] || '1.0.2j'
OPENSSL_SOURCE_URI =
"https://www.openssl.org/source/openssl-#{OPENSSL_VERSION}.tar.gz"
FREETDS_VERSION =
ENV['TINYTDS_FREETDS_VERSION'] || "1.00.21"
FREETDS_VERSION_INFO =
Hash.new { |h,k|
  h[k] = {files: "ftp://ftp.freetds.org/pub/freetds/stable/freetds-#{k}.tar.bz2"}
}
FREETDS_SOURCE_URI =
FREETDS_VERSION_INFO[FREETDS_VERSION][:files]
FREETDSDIR =
ENV['FREETDS_DIR']
LIBDIR =
"#{FREETDSDIR}/lib"
INCLUDEDIR =
"#{FREETDSDIR}/include"
SEARCHABLE_PATHS =
begin
  eop_regexp = /#{File::SEPARATOR}bin$/
  paths = ENV['PATH']
  paths = paths.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
  paths = paths.split(File::PATH_SEPARATOR)
  bin_paths = paths.select{ |p| p =~ eop_regexp }
  bin_paths.map{ |p| p.sub(eop_regexp,'') }.compact.reject{ |p| p.empty? }.uniq
end
HEADER_DIRS =

There's no default include/lib dir on Windows. Let's just add the Ruby ones and resort on the search path specified by INCLUDE and LIB environment variables

[
  # First search /opt/local for macports
  '/opt/local/include',
  # Then search /usr/local for people that installed from source
  '/usr/local/include',
  # Check the ruby install locations
  INCLUDEDIR,
  # Finally fall back to /usr
  '/usr/include'
].reject{ |dir| !File.directory?(dir) }
LIB_DIRS =
[
  # First search /opt/local for macports
  '/opt/local/lib',
  # Then search /usr/local for people that installed from source
  '/usr/local/lib',
  # Check the ruby install locations
  LIBDIR,
  # Finally fall back to /usr
  '/usr/lib',
].reject{ |dir| !File.directory?(dir) }
FREETDS_HEADER_DIRS =
(searchable_paths_with_directories(['include'],['include','freetds']) + HEADER_DIRS).uniq
FREETDS_LIB_DIRS =
(searchable_paths_with_directories(['lib'],['lib','freetds']) + LIB_DIRS).uniq

Instance Method Summary collapse

Instance Method Details

#asplode(lib) ⇒ Object


308
309
310
311
312
313
314
# File 'ext/tiny_tds/extconf.rb', line 308

def asplode(lib)
  msg = "-----\n"
  msg << "#{lib} is missing.\n"
  msg << "Do you have FreeTDS 0.95.80 or higher installed?\n" if lib == 'freetds'
  msg << "-----"
  abort(msg)
end

#define_freetds_recipe(host, libiconv, libssl, gnutls) ⇒ Object


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'ext/tiny_tds/extconf.rb', line 214

def define_freetds_recipe(host, libiconv, libssl, gnutls)
  BuildRecipe.new("freetds", FREETDS_VERSION, [FREETDS_SOURCE_URI]).tap do |recipe|
    with_tdsver = FREETDS_VERSION =~ /0\.91/ ? "--with-tdsver=7.1" : "--with-tdsver=7.3"
    for_windows = recipe.host =~ /mswin|mingw/i
    recipe.configure_options << '--with-pic'
    recipe.configure_options << "--with-libiconv-prefix=#{libiconv.path}" if libiconv
    if true == libssl
      recipe.configure_options << "--with-openssl"
    elsif libssl
      recipe.configure_options << "--with-openssl=#{libssl.path}"
    end
    recipe.configure_options << "--with-gnutls" if gnutls
    recipe.configure_options << '--sysconfdir=C:\Sites' if for_windows
    recipe.configure_options << '--enable-sspi' if for_windows
    recipe.configure_options << "--disable-odbc"
    recipe.configure_options << with_tdsver
    if libiconv
      # For some reason freetds doesn't honor --with-libiconv-prefix
      # so we have do add it by hand:
      recipe.configure_options << "CFLAGS=-I#{libiconv.path}/include"
      recipe.configure_options << "LDFLAGS=-L#{libiconv.path}/lib -liconv"
    end

    class << recipe

      def install
        super_value = super
        # Install binstub target binaries.
        if super_value
          bin_path = File.expand_path File.join(path, 'bin')
          exe_path = File.expand_path File.join(target, '..', 'exe')
          return unless File.directory?(bin_path)
          ['tsql', 'defncopy'].each do |bin|
            ['.exe', ''].each do |ext|
              exe = File.join bin_path, "#{bin}#{ext}"
              next unless File.exists?(exe)
              next unless File.executable?(exe)
              FileUtils.cp exe, exe_path
            end
          end
        end
        super_value
      end

    end

  end
end

#define_libiconv_recipe(host) ⇒ Object


205
206
207
208
209
210
211
212
# File 'ext/tiny_tds/extconf.rb', line 205

def define_libiconv_recipe(host)
  BuildRecipe.new("libiconv", ICONV_VERSION, [ICONV_SOURCE_URI]).tap do |recipe|
    # always produce position independent code
    # and set an explicit optimization to avoid inline functions being optimized
    # out of libiconv
    recipe.configure_options << "CFLAGS=-fPIC -O2"
  end
end

#define_libssl_recipe(host) ⇒ Object


137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'ext/tiny_tds/extconf.rb', line 137

def define_libssl_recipe(host)
  BuildRecipe.new("openssl", OPENSSL_VERSION, [OPENSSL_SOURCE_URI]).tap do |recipe|
    class << recipe
      def extract_file(file, target)
        filename = File.basename(file)
        FileUtils.mkdir_p target

        message "Extracting #{filename} into #{target}... "
        result = `#{tar_exe} #{tar_compression_switch(filename)}xf "#{file}" -C "#{target}" 2>&1`
        if $?.success?
          output "OK"
        else
          # tar on windows returns error exit code, because it can not extract symlinks
          output "ERROR (ignored)"
        end
      end

      def configure
        config = if host=~/mingw/
          host=~/x86_64/ ? 'mingw64' : 'mingw'
        end
        args = [ "CFLAGS=-DDSO_WIN32",
            "./Configure",
            "no-shared",
            configure_prefix,
            config,
          ]
        args.unshift("CROSS_COMPILE=#{host}-") if enable_config("cross-build")

        execute "configure", "sh -c \"#{args.join(" ")}\""
      end

      def dllwrap(dllname, outputlib, deffile, linkto)
        gcc = consolidated_host(RbConfig::CONFIG["CC"])

        #RbConfig does not provide dlltool, but it should exist where dllwrap lives
        dlltool = consolidated_host(RbConfig::CONFIG["DLLWRAP"]).sub('dllwrap','dlltool')

        execute "gcc-#{dllname}-compile", "#{gcc} -Wl,--base-file,#{dllname}.base -mdll -o #{dllname}.dll --leading-underscore #{linkto}"
        execute "dlltool-#{dllname}-exp", "#{dlltool} --base-file #{dllname}.base --output-exp #{dllname}.exp --dllname #{dllname}.dll --def #{deffile}"
        execute "gcc-#{dllname}-dll", "#{gcc} -Wl,--base-file,#{dllname}.base #{dllname}.exp -mdll -o #{dllname}.dll --leading-underscore #{linkto}"
        execute "dlltool-#{dllname}-outputlib", "#{dlltool} --base-file #{dllname}.base --output-exp #{dllname}.exp --dllname #{dllname}.dll --def #{deffile} --output-lib #{outputlib}"
        execute "gcc-#{dllname}-link", "#{gcc} #{dllname}.exp -mdll -o #{dllname}.dll --leading-underscore #{linkto}"
      end

      def compile
        super
        # OpenSSL DLLs are called "libeay32.dll" and "ssleay32.dll" per default,
        # regardless to the version. This is best suited to meet the Windows DLL hell.
        # To avoid any conflicts we do a static build and build DLLs afterwards,
        # with our own naming scheme.
        execute "mkdef-libeay32", "(perl util/mkdef.pl 32 libeay >libeay32.def)"
        execute "mkdef-ssleay32", "(perl util/mkdef.pl 32 ssleay >ssleay32.def)"
        dllwrap("libeay32-#{version}-#{host}", "libcrypto.dll.a", "libeay32.def", "libcrypto.a -lws2_32 -lgdi32 -lcrypt32")
        dllwrap("ssleay32-#{version}-#{host}", "libssl.dll.a", "ssleay32.def", "libssl.a libcrypto.dll.a")
      end

      def install
        super
        FileUtils.cp "#{work_path}/libeay32-#{version}-#{host}.dll", "#{path}/bin/"
        FileUtils.cp "#{work_path}/ssleay32-#{version}-#{host}.dll", "#{path}/bin/"
        FileUtils.cp "#{work_path}/libcrypto.dll.a", "#{path}/lib/"
        FileUtils.cp "#{work_path}/libssl.dll.a", "#{path}/lib/"
      end
    end
  end
end

#do_helpObject

Shamelessly copied from nokogiri


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'ext/tiny_tds/extconf.rb', line 19

def do_help
  print <<HELP
usage: ruby #{$0} [options]

    --enable-system-freetds / --disable-system-freetds
    --enable-system-iconv   / --disable-system-iconv
    --enable-system-openssl / --disable-system-openssl
      Force use of system or builtin freetds/iconv/openssl library.
      Default is to prefer system libraries and fallback to builtin.

    --with-freetds-dir=DIR
      Use the freetds library placed under DIR.

    --enable-lookup
      Search for freetds through all paths in the PATH environment variable.

    --disable-openssl
      Disable OpenSSL for freetds build. No effect on system-freetds.

    --enable-gnutls
      Use GnuTLS instead of OpenSSL for freetds build.

    --enable-cross-build
      Do cross-build.
HELP
  exit! 0
end

#freetds_usable?(lib_prefix) ⇒ Boolean

Returns:

  • (Boolean)

316
317
318
319
320
# File 'ext/tiny_tds/extconf.rb', line 316

def freetds_usable?(lib_prefix)
  have_header('sybfront.h') && have_header('sybdb.h') &&
    find_library("#{lib_prefix}sybdb", 'tdsdbopen') &&
    find_library("#{lib_prefix}sybdb", 'dbanydatecrack')
end

#searchable_paths_with_directories(*directories) ⇒ Object


73
74
75
76
77
78
79
80
# File 'ext/tiny_tds/extconf.rb', line 73

def searchable_paths_with_directories(*directories)
  SEARCHABLE_PATHS.map do |path|
    directories.map do |paths|
      dir = File.join path, *paths
      File.directory?(dir) ? dir : nil
    end.flatten.compact
  end.flatten.compact
end