Skip to content

Commit

Permalink
wip: restructure the entire thing
Browse files Browse the repository at this point in the history
  • Loading branch information
andyundso committed Jan 6, 2025
1 parent f5cd106 commit 65e5d49
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 346 deletions.
167 changes: 97 additions & 70 deletions ext/tiny_tds/extconf.rb
Original file line number Diff line number Diff line change
@@ -1,91 +1,118 @@
ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/

# :stopdoc:

require 'pp'
require 'mkmf'
require 'rbconfig'
require_relative './extconsts'

# Shamelessly copied from nokogiri
#

def do_help
print <<HELP
usage: ruby #{$0} [options]
--with-freetds-dir=DIR
Use the freetds library placed under DIR.
HELP
exit! 0
end

do_help if arg_config('--help')
if ENV['MAINTAINER_MODE']
$stderr.puts "Maintainer mode enabled."
$CFLAGS <<
' -Wall' <<
' -ggdb' <<
' -DDEBUG' <<
' -pedantic'
$LDFLAGS <<
' -ggdb'
end

# Make sure to check the ports path for the configured host
architecture = RbConfig::CONFIG['arch']
require 'mini_portile2'
require_relative 'extconsts'

project_dir = File.expand_path("../../..", __FILE__)
freetds_ports_dir = File.join(project_dir, 'ports', architecture, 'freetds', FREETDS_VERSION)
freetds_ports_dir = File.expand_path(freetds_ports_dir)
class BuildRecipe < MiniPortile
def initialize(name, version, files)
super(name, version)
self.files = files
rootdir = File.expand_path('../..', __FILE__)
self.target = File.join(rootdir, "ports")
self.patch_files = Dir[File.join(target, "patches", self.name, self.version, "*.patch")].sort
end

# Add all the special path searching from the original tiny_tds build
# order is important here! First in, first searched.
DIRS = %w(
/opt/local
/usr/local
)
def port_path
"../ports/#{RUBY_PLATFORM}/#{@name}/#{@version}"
end

if RbConfig::CONFIG['host_os'] =~ /darwin/i
# Ruby below 2.7 seems to label the host CPU on Apple Silicon as aarch64
# 2.7 and above print is as ARM64
target_host_cpu = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7') ? 'aarch64' : 'arm64'
def tmp_path
"../tmp/#{RUBY_PLATFORM}/ports/#{@name}/#{@version}"
end

if RbConfig::CONFIG['host_cpu'] == target_host_cpu
# Homebrew on Apple Silicon installs into /opt/hombrew
# https://docs.brew.sh/Installation
# On Intel Macs, it is /usr/local, so no changes necessary to DIRS
DIRS.unshift("/opt/homebrew")
def cook_and_activate
checkpoint = "../ports/checkpoints/#{name}-#{version}-#{RUBY_PLATFORM}.installed"

unless File.exist?(checkpoint)
self.cook
FileUtils.mkdir_p("../ports/checkpoints")
FileUtils.touch checkpoint
end

self.activate
self
end
end

if ENV["RI_DEVKIT"] && ENV["MINGW_PREFIX"] # RubyInstaller Support
DIRS.unshift(File.join(ENV["RI_DEVKIT"], ENV["MINGW_PREFIX"]))
openssl_recipe = BuildRecipe.new("openssl", OPENSSL_VERSION, [OPENSSL_SOURCE_URI]).tap do |recipe|
class << recipe
def configure
envs = []
envs << "CFLAGS=-DDSO_WIN32 -DOPENSSL_THREADS" if RUBY_PLATFORM =~ /mingw|mswin/
envs << "CFLAGS=-fPIC -DOPENSSL_THREADS" if RUBY_PLATFORM =~ /linux/
execute('configure', ['env', *envs, "./Configure", target_arch, "threads", "-static", "CROSS_COMPILE=#{host}-", configure_prefix], altlog: "config.log")
end

def compile
execute('compile', "#{make_cmd} build_libs")
end

def install
execute('install', "#{make_cmd} install_dev")
end

private

def target_arch
if RUBY_PLATFORM =~ /mingw|mswin/
arch = ''
arch = '64' if host=~ /x86_64/

"mingw#{arch}"
else
arch = 'x32'
arch = 'x86_64' if host=~ /x86_64/

"linux-#{arch}"
end
end
end

recipe.cook_and_activate
end

# Add the ports directory if it exists for local developer builds
DIRS.unshift(freetds_ports_dir) if File.directory?(freetds_ports_dir)
libiconv_recipe = BuildRecipe.new("libiconv", ICONV_VERSION, [ICONV_SOURCE_URI]).tap do |recipe|
recipe.configure_options << "CFLAGS=-fPIC" if RUBY_PLATFORM =~ /linux/
recipe.cook_and_activate
end

# Grab freetds environment variable for use by people on services like
# Heroku who they can't easily use bundler config to set directories
DIRS.unshift(ENV['FREETDS_DIR']) if ENV.has_key?('FREETDS_DIR')
freetds_recipe = BuildRecipe.new("freetds", FREETDS_VERSION, [FREETDS_SOURCE_URI]).tap do |recipe|
recipe.configure_options << "CFLAGS=-fPIC" if RUBY_PLATFORM =~ /linux/
recipe.configure_options << "LDFLAGS=-L#{openssl_recipe.path}/lib -L#{openssl_recipe.path}/lib64 -L#{libiconv_recipe.path}/lib"
recipe.configure_options << "LIBS=-lssl -lcrypto -liconv"
recipe.configure_options << "CPPFLAGS=-I#{openssl_recipe.path}/include -I#{libiconv_recipe.path}/include"

# Add the search paths for freetds configured above
ldirs = DIRS.flat_map do |path|
ldir = "#{path}/lib"
[ldir, "#{ldir}/freetds"]
recipe.cook_and_activate
end

idirs = DIRS.flat_map do |path|
idir = "#{path}/include"
[idir, "#{idir}/freetds"]
end
# Avoid dependency to external libgcc.dll on x86-mingw32
$LDFLAGS << " -static-libgcc"

puts "looking for freetds headers in the following directories:\n#{idirs.map{|a| " - #{a}\n"}.join}"
puts "looking for freetds library in the following directories:\n#{ldirs.map{|a| " - #{a}\n"}.join}"
dir_config('freetds', idirs, ldirs)

have_dependencies = [
find_header('sybfront.h'),
find_header('sybdb.h'),
find_library('sybdb', 'tdsdbopen'),
find_library('sybdb', 'dbanydatecrack')
].inject(true) do |memo, current|
memo && current
end
dir_config('freetds', "#{freetds_recipe.path}/include", "#{freetds_recipe.path}/lib")

unless have_dependencies
abort 'Failed! Do you have FreeTDS 1.0.0 or higher installed?'
# $stderr.puts "Using freetds from #{dlldir}"

if /solaris/ =~ RUBY_PLATFORM
append_cppflags( '-D__EXTENSIONS__' )
end

create_makefile('tiny_tds/tiny_tds')
find_header('sybfront.h') or abort "Can't find the 'sybfront.h' header"
find_header('sybdb.h') or abort "Can't find the 'sybdb.h' header"

unless have_library('sybdb', 'dbanydatecrack')
abort "Failed! Do you have FreeTDS 1.0.0 or higher installed?"
end

# :startdoc:
create_makefile("tiny_tds/tiny_tds")
3 changes: 1 addition & 2 deletions tasks/native_gem.rake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# encoding: UTF-8

desc 'Build the native binary gems using rake-compiler-dock'
task 'gem:native' => ['ports:cross'] do
task 'gem:native' do
require 'rake_compiler_dock'

# make sure to install our bundle
Expand All @@ -18,6 +18,5 @@ task 'gem:for_platform', [:gem_platform] do |_task, args|
args.with_defaults(gem_platform: RbConfig::CONFIG["arch"])

sh "bundle install"
Rake::Task["ports:compile"].invoke(GEM_PLATFORM_HOSTS[args.gem_platform][:host], args.gem_platform)
sh "RUBY_CC_VERSION=#{GEM_PLATFORM_HOSTS[args.gem_platform][:ruby_versions]} rake native:#{args.gem_platform} gem"
end
90 changes: 0 additions & 90 deletions tasks/ports.rake
Original file line number Diff line number Diff line change
@@ -1,91 +1,4 @@
# encoding: UTF-8
require 'mini_portile2'
require 'fileutils'
require_relative 'ports/libiconv'
require_relative 'ports/openssl'
require_relative 'ports/freetds'
require_relative '../ext/tiny_tds/extconsts'

namespace :ports do
libraries_to_compile = {
openssl: Ports::Openssl.new(OPENSSL_VERSION),
libiconv: Ports::Libiconv.new(ICONV_VERSION),
freetds: Ports::Freetds.new(FREETDS_VERSION)
}

directory "ports"
CLEAN.include "ports/*mingw*"
CLEAN.include "ports/*.installed"

task :openssl, [:host, :gem_platform] do |_task, args|
args.with_defaults(host: RbConfig::CONFIG['host'], gem_platform: RbConfig::CONFIG["arch"])

libraries_to_compile[:openssl].files = [OPENSSL_SOURCE_URI]
libraries_to_compile[:openssl].host = args.host
libraries_to_compile[:openssl].gem_platform = args.gem_platform

libraries_to_compile[:openssl].cook
libraries_to_compile[:openssl].activate
end

task :libiconv, [:host, :gem_platform] do |_task, args|
args.with_defaults(host: RbConfig::CONFIG['host'], gem_platform: RbConfig::CONFIG["arch"])

libraries_to_compile[:libiconv].files = [ICONV_SOURCE_URI]
libraries_to_compile[:libiconv].host = args.host
libraries_to_compile[:libiconv].gem_platform = args.gem_platform
libraries_to_compile[:libiconv].cook
libraries_to_compile[:libiconv].activate
end

task :freetds, [:host, :gem_platform] do |_task, args|
args.with_defaults(host: RbConfig::CONFIG['host'], gem_platform: RbConfig::CONFIG["arch"])

libraries_to_compile[:freetds].files = [FREETDS_SOURCE_URI]
libraries_to_compile[:freetds].host = args.host
libraries_to_compile[:freetds].gem_platform = args.gem_platform

if libraries_to_compile[:openssl]
# freetds doesn't have an option that will provide an rpath
# so we do it manually
ENV['OPENSSL_CFLAGS'] = "-Wl,-rpath -Wl,#{libraries_to_compile[:openssl].path}/lib64"
# Add the pkgconfig file with MSYS2'ish path, to prefer our ports build
# over MSYS2 system OpenSSL.
ENV['PKG_CONFIG_PATH'] = "#{libraries_to_compile[:openssl].path.gsub(/^(\w):/i) { "/" + $1.downcase }}/lib64/pkgconfig:#{ENV['PKG_CONFIG_PATH']}"
libraries_to_compile[:freetds].configure_options << "--with-openssl=#{libraries_to_compile[:openssl].path}"
end

if libraries_to_compile[:libiconv]
libraries_to_compile[:freetds].configure_options << "--with-libiconv-prefix=#{libraries_to_compile[:libiconv].path}"
end

libraries_to_compile[:freetds].cook
libraries_to_compile[:freetds].activate
end

task :compile, [:host, :gem_platform] do |_task, args|
args.with_defaults(host: RbConfig::CONFIG['host'], gem_platform: RbConfig::CONFIG["arch"])

puts "Compiling ports for #{args.host} (Ruby platform #{args.gem_platform}) ..."

libraries_to_compile.keys.each do |lib|
Rake::Task["ports:#{lib}"].invoke(args.host, args.gem_platform)
end
end

desc 'Build the ports windows binaries via rake-compiler-dock'
task 'cross' do
require 'rake_compiler_dock'

# build the ports for all our cross compile hosts
GEM_PLATFORM_HOSTS.each do |gem_platform, meta|
# make sure to install our bundle
build = ['bundle']
build << "RUBY_CC_VERSION=#{meta[:ruby_versions]} rake ports:compile[#{meta[:host]},#{gem_platform}] MAKE='make -j`nproc`'"
RakeCompilerDock.sh build.join(' && '), platform: gem_platform
end
end

desc "Notes the actual versions for the compiled ports into a file"
task "version_file", [:gem_platform] do |_task, args|
args.with_defaults(gem_platform: RbConfig::CONFIG["arch"])
Expand All @@ -103,6 +16,3 @@ namespace :ports do
end
end
end

desc 'Build ports and activate libraries for the current architecture.'
task :ports => ['ports:compile']
32 changes: 0 additions & 32 deletions tasks/ports/freetds.rb

This file was deleted.

26 changes: 0 additions & 26 deletions tasks/ports/libiconv.rb

This file was deleted.

Loading

0 comments on commit 65e5d49

Please sign in to comment.