1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
# frozen_string_literal: true
require "bundler/gem_tasks"
require "rubygems/package_task"
require "rake/extensiontask"
require "rake_compiler_dock"
require "yaml"
cross_platforms = [
"aarch64-linux-gnu",
"aarch64-linux-musl",
"arm-linux-gnu",
"arm-linux-musl",
"x86-linux-gnu",
"x86-linux-musl",
"x86_64-linux-gnu",
"x86_64-linux-musl",
"arm64-darwin",
"x86_64-darwin",
"x64-mingw-ucrt"
]
RakeCompilerDock.set_ruby_cc_version(">= 3.2")
Gem::PackageTask.new(SQLITE3_SPEC).define # packaged_tarball version of the gem for platform=ruby
task "package" => cross_platforms.map { |p| "gem:#{p}" } # "package" task for all the native platforms
def gem_build_path
File.join("pkg", SQLITE3_SPEC.full_name)
end
def add_file_to_gem(relative_source_path)
if relative_source_path.nil? || !File.exist?(relative_source_path)
raise "Cannot find file '#{relative_source_path}'"
end
dest_path = File.join(gem_build_path, relative_source_path)
dest_dir = File.dirname(dest_path)
mkdir_p(dest_dir) unless Dir.exist?(dest_dir)
rm_f(dest_path) if File.exist?(dest_path)
safe_ln(relative_source_path, dest_path)
SQLITE3_SPEC.files << relative_source_path
end
task gem_build_path do
dependencies = YAML.load_file(File.join(__dir__, "..", "dependencies.yml"), symbolize_names: true)
sqlite_tarball = File.basename(dependencies[:sqlite3][:files].first[:url])
archive = Dir.glob(File.join("ports", "archives", sqlite_tarball)).first
add_file_to_gem(archive)
patches = `#{["git", "ls-files", "patches"].shelljoin}`.split("\n").grep(/\.patch\z/)
patches.each { |patch| add_file_to_gem patch }
end
Rake::ExtensionTask.new("sqlite3_native", SQLITE3_SPEC) do |ext|
ext.ext_dir = "ext/sqlite3"
ext.lib_dir = "lib/sqlite3"
ext.cross_compile = true
ext.cross_platform = cross_platforms
ext.cross_config_options << "--enable-cross-build" # so extconf.rb knows we're cross-compiling
ext.cross_compiling do |spec|
# remove things not needed for precompiled gems
spec.dependencies.reject! { |dep| dep.name == "mini_portile2" }
spec.metadata.delete("msys2_mingw_dependencies")
end
end
namespace "gem" do
cross_platforms.each do |platform|
desc "build native gem for #{platform}"
task platform do
RakeCompilerDock.sh(<<~EOF, platform: platform, verbose: true)
gem install bundler --no-document &&
bundle &&
bundle exec rake gem:#{platform}:buildit
EOF
end
namespace platform do
# this runs in the rake-compiler-dock docker container
task "buildit" do
# use Task#invoke because the pkg/*gem task is defined at runtime
Rake::Task["native:#{platform}"].invoke
Rake::Task["pkg/#{SQLITE3_SPEC.full_name}-#{Gem::Platform.new(platform)}.gem"].invoke
end
end
end
desc "build native gem for all platforms"
task "all" => [cross_platforms, "gem"].flatten
end
desc "Temporarily set VERSION to a unique timestamp"
task "set-version-to-timestamp" do
# this task is used by bin/test-gem-build
# to test building, packaging, and installing a precompiled gem
version_constant_re = /^\s*VERSION\s*=\s*["'](.*)["']$/
version_file_path = File.join(__dir__, "../lib/sqlite3/version.rb")
version_file_contents = File.read(version_file_path)
current_version_string = version_constant_re.match(version_file_contents)[1]
current_version = Gem::Version.new(current_version_string)
fake_version = Gem::Version.new(format("%s.test.%s", current_version.bump, Time.now.strftime("%Y.%m%d.%H%M")))
unless version_file_contents.gsub!(version_constant_re, " VERSION = \"#{fake_version}\"")
raise("Could not hack the VERSION constant")
end
File.write(version_file_path, version_file_contents)
puts "NOTE: wrote version as \"#{fake_version}\""
end
CLEAN.add("{ext,lib}/**/*.{o,so}", "pkg")
CLOBBER.add("ports/*").exclude(%r{ports/archives$})
# when packaging the gem, if the tarball isn't cached, we need to fetch it. the easiest thing to do
# is to run the compile phase to invoke the extconf and have mini_portile download the file for us.
# this is wasteful and in the future I would prefer to separate mini_portile from the extconf to
# allow us to download without compiling.
Rake::Task["package"].prerequisites.prepend("compile")
|