Skip to content

Instantly share code, notes, and snippets.

@shannonwells
Last active August 29, 2015 14:10
Show Gist options
  • Save shannonwells/70f50b2df94dd0cbb319 to your computer and use it in GitHub Desktop.
Save shannonwells/70f50b2df94dd0cbb319 to your computer and use it in GitHub Desktop.
This is an edited and annotated tiny_tds extconf.rb with changes needed to get tiny_tds to build as a platform-specific linux gem, statically linked with a custom build of freetds with openssl. It is intended to allow encrypted connections with MS SQL Server. Please use the tiny_tds_ports.rake Gist or else this code will not work.
ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
# :stopdoc:
require 'mkmf'
# Shamelessly copied from nokogiri
#
# All my notes are tagged with --shannonwells.
# I was able to compile platform-specfic gems on OS X Mavericks, AWS-linux AMI and AWS ubuntu AMI.
# Please feel free to pm me here or on Twitter (@shannonewells) if you want help. --shannonwells
# Commented this line out --shannonwells
#FREETDSDIR = ENV['FREETDS_DIR']
# I needed to create a platform-specific gem for heroku, which uses openssl. That means freetds has to be built
# and statically linked, so here I just force tiny_tds to use the one it downloads. --shannonwells
MYDIR = File.dirname(__FILE__)
FREETDSDIR = "#{MYDIR}/../../ports/x86_64-unknown-linux-gnu/freetds/0.91/"
if FREETDSDIR.nil? || FREETDSDIR.empty?
LIBDIR = RbConfig::CONFIG['libdir']
INCLUDEDIR = RbConfig::CONFIG['includedir']
else
puts "Will use #{FREETDSDIR}"
LIBDIR = "#{FREETDSDIR}/lib"
INCLUDEDIR = "#{FREETDSDIR}/include"
end
$CFLAGS << " #{ENV["CFLAGS"]}"
$LDFLAGS << " #{ENV["LDFLAGS"]}"
$LIBS << " #{ENV["LIBS"]}"
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
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
# TRAP: lib_prefix is DEFINITELY NOT 'lib' on UNIXes. Setting it to such will mess up your compiler options. --shannonwells
if RbConfig::CONFIG['target_os'] =~ /mswin32|mingw32/
lib_prefix = 'lib' unless RbConfig::CONFIG['target_os'] =~ /mingw32/
# 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
HEADER_DIRS = [INCLUDEDIR]
LIB_DIRS = [LIBDIR]
else
lib_prefix = ''
HEADER_DIRS = [
# 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) }
end
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
# lookup over searchable paths is great for native compilation, however, when
# cross compiling we need to specify our own paths.
if enable_config("lookup", true)
dir_config('iconv', FREETDS_HEADER_DIRS, FREETDS_LIB_DIRS)
dir_config('freetds', FREETDS_HEADER_DIRS, FREETDS_LIB_DIRS)
# I had to add these two lines to get the find_library/find_header tests to pass.
dir_config('sybdb', FREETDS_HEADER_DIRS, FREETDS_LIB_DIRS)
dir_config('ct', FREETDS_HEADER_DIRS, FREETDS_LIB_DIRS)
else
dir_config('iconv')
dir_config('freetds')
# remove LDFLAGS
$LDFLAGS = ENV.fetch("LDFLAGS", "")
end
def asplode(lib)
abort "-----\n#{lib} is missing.\n-----"
end
asplode 'libiconv' unless have_func('iconv_open', 'iconv.h') || have_library('iconv', 'iconv_open', 'iconv.h')
asplode 'freetds' unless have_header('sybfront.h') && have_header('sybdb.h')
# I ran some test code to figure out why the original lines of this were failing. Once I got that code working, I
# used it here. You must comment out the line in the ports.rake file that says "--without-odbc", because otherwise
# these entry points are not found. Also watch out for tdsdbopen to be defined as dbopen instead (this is a configure
# option). I saw this on OS X. You can test this by just changing tdsdbopen to dbopen, below. --shannonwells
asplode 'freetds' unless find_library("#{lib_prefix}ct", 'ct_bind', FREETDS_LIB_DIRS.join(File::PATH_SEPARATOR) )
asplode 'freetds' unless find_library("#{lib_prefix}sybdb", 'tdsdbopen', FREETDS_LIB_DIRS.join(File::PATH_SEPARATOR) )
create_makefile('tiny_tds/tiny_tds')
# :startdoc:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment