diff --git a/.circleci/config.yml b/.circleci/config.yml index 66f8fab2..7fb3a4e6 100755 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,30 +39,47 @@ jobs: docker exec cimg_ruby bash -c './test/bin/setup_tinytds_db.sh' - run: - name: compile openssl library + name: bundle install gems command: | - docker exec cimg_ruby bash -c 'sudo -E ./test/bin/install-openssl.sh' + docker exec cimg_ruby bash -c 'bundle install' - run: - name: compile freetds library + name: Write used versions into file command: | - docker exec cimg_ruby bash -c 'sudo -E ./test/bin/install-freetds.sh' + docker exec cimg_ruby bash -c 'bundle exec rake ports:version_file' + + - restore_cache: + name: restore ports cache + keys: + - ports-<< parameters.ruby_version >>-{{ checksum ".ports_versions" }} + - ports-<< parameters.ruby_version >>- - run: - name: bundle install gems + name: compile ports command: | - docker exec cimg_ruby bash -c 'bundle install' + docker exec cimg_ruby bash -c 'bundle exec rake ports' - run: name: build gem command: | docker exec cimg_ruby bash -c 'bundle exec rake build' + - run: + name: Fix permissions on ports directory + command: | + docker exec cimg_ruby bash -c 'sudo chown -R $(id -u):$(id -g) ports' + - run: name: test gem command: | docker exec cimg_ruby bash -c 'bundle exec rake test' + - save_cache: + name: save ports cache + paths: + - ./ports + key: ports-<< parameters.ruby_version >>-{{ checksum ".ports_versions" }} + - store_test_results: path: test/reports @@ -197,53 +214,49 @@ jobs: path: test/reports cross_compile_gem: - machine: - image: ubuntu-2004:current + parameters: + platform: + description: "Platform to compile the gem resources" + type: string + + docker: + - image: "ghcr.io/rake-compiler/rake-compiler-dock-image:1.3.0-mri-<< parameters.platform >>" steps: - - ruby/install: - version: '2.7' - checkout - - restore_cache: - name: restore gem cache - keys: - - v1-bundle-{{ .Branch }}-{{ checksum "tiny_tds.gemspec" }} - - v1-bundle-{{ .Branch }}- - - v1-bundle- - run: name: bundle install gems command: | - bundle install --path vendor/bundle - - - save_cache: - name: save gem cache - paths: - - ./vendor/bundle - key: v1-bundle-{{ .Branch }}-{{ checksum "tiny_tds.gemspec" }} + bundle install - run: name: Write used versions for ports into file command: | - bundle exec rake ports:version_file + rake ports:version_file[<< parameters.platform >>] - restore_cache: name: restore ports cache keys: - - ports-{{ checksum ".ports_versions" }} - - ports- + - ports-win-{{ checksum ".ports_versions" }} + - ports-win- - run: - name: Build gems + name: Build gem command: | - bundle exec rake gem - bundle exec rake gem:native + rake gem:for_platform[<< parameters.platform >>] - run: name: Move gems into separate directory before caching command: | - mkdir -p artifacts/gems - mv pkg/*.gem artifacts/gems + mkdir -p artifacts-<< parameters.platform >>/gems + mv pkg/*.gem artifacts-<< parameters.platform >>/gems + + - run: + name: Remove non-native gem to avoid conflict in workspace + command: | + gemVersion=$(cat VERSION | tr -d "[:space:]") + rm -rf artifacts-<< parameters.platform >>/gems/tiny_tds-$gemVersion.gem - store_artifacts: path: artifacts/gems @@ -252,18 +265,24 @@ jobs: name: save ports cache paths: - ./ports - key: ports-{{ checksum ".ports_versions" }} + key: ports-win-{{ checksum ".ports_versions" }} - persist_to_workspace: name: save gems into workspace - root: artifacts + root: artifacts-<< parameters.platform >> paths: - gems workflows: test_supported_ruby_versions: jobs: - - cross_compile_gem + - cross_compile_gem: + matrix: + parameters: + platform: + - "x86-mingw32" + - "x64-mingw32" + - "x64-mingw-ucrt" - test_windows: requires: - cross_compile_gem @@ -275,5 +294,7 @@ workflows: - '2.6' - '2.7' - '3.0' + - '3.1' + - '3.2' - test_linux: matrix: *ruby_versions diff --git a/Rakefile b/Rakefile index 79fd07df..654dfa59 100644 --- a/Rakefile +++ b/Rakefile @@ -6,20 +6,33 @@ require 'rake/extensiontask' require_relative './ext/tiny_tds/extconsts' SPEC = Gem::Specification.load(File.expand_path('../tiny_tds.gemspec', __FILE__)) + +ruby_cc_ucrt_versions = "3.2.0:3.1.0".freeze +ruby_cc_mingw32_versions = "3.0.0:2.7.0:2.6.0:2.5.0:2.4.0".freeze + GEM_PLATFORM_HOSTS = { - 'x86-mingw32' => 'i686-w64-mingw32', - 'x64-mingw32' => 'x86_64-w64-mingw32' + 'x86-mingw32' => { + host: 'i686-w64-mingw32', + ruby_versions: ruby_cc_mingw32_versions + }, + 'x64-mingw32' => { + host: 'x86_64-w64-mingw32', + ruby_versions: ruby_cc_mingw32_versions + }, + 'x64-mingw-ucrt' => { + host: 'x86_64-w64-mingw32', + ruby_versions: ruby_cc_ucrt_versions + }, } -RUBY_CC_VERSION="3.0.0:2.7.0:2.6.0:2.5.0:2.4.0".freeze # Add our project specific files to clean for a rebuild CLEAN.include FileList["{ext,lib}/**/*.{so,#{RbConfig::CONFIG['DLEXT']},o}"], - FileList["exe/*"] + FileList["exe/*"] # Clobber all our temp files and ports files including .install files # and archives CLOBBER.include FileList["tmp/**/*"], - FileList["ports/**/*"].exclude(%r{^ports/archives}) + FileList["ports/**/*"].exclude(%r{^ports/archives}) Dir['tasks/*.rake'].sort.each { |f| load f } @@ -33,15 +46,11 @@ Rake::ExtensionTask.new('tiny_tds', SPEC) do |ext| # The fat binary gem doesn't depend on the freetds package, since it bundles the library. spec.metadata.delete('msys2_mingw_dependencies') - platform_host_map = GEM_PLATFORM_HOSTS - gemplat = spec.platform.to_s - host = platform_host_map[gemplat] - # We don't need the sources in a fat binary gem spec.files = spec.files.reject { |f| f =~ %r{^ports\/archives/} } # Make sure to include the ports binaries and libraries - spec.files += FileList["ports/#{host}/**/**/{bin,lib}/*"].exclude do |f| + spec.files += FileList["ports/#{spec.platform.to_s}/**/**/{bin,lib}/*"].exclude do |f| File.directory? f end diff --git a/ext/tiny_tds/extconf.rb b/ext/tiny_tds/extconf.rb index b05d4040..ad914d0f 100644 --- a/ext/tiny_tds/extconf.rb +++ b/ext/tiny_tds/extconf.rb @@ -21,9 +21,11 @@ def do_help do_help if arg_config('--help') # Make sure to check the ports path for the configured host -host = RbConfig::CONFIG['host'] +architecture = RbConfig::CONFIG['arch'] +architecture = "x86-mingw32" if architecture == "i386-mingw32" + project_dir = File.expand_path("../../..", __FILE__) -freetds_ports_dir = File.join(project_dir, 'ports', host, 'freetds', FREETDS_VERSION) +freetds_ports_dir = File.join(project_dir, 'ports', architecture, 'freetds', FREETDS_VERSION) freetds_ports_dir = File.expand_path(freetds_ports_dir) # Add all the special path searching from the original tiny_tds build diff --git a/lib/tiny_tds/gem.rb b/lib/tiny_tds/gem.rb index 49e6bf50..a52f047d 100644 --- a/lib/tiny_tds/gem.rb +++ b/lib/tiny_tds/gem.rb @@ -20,12 +20,7 @@ def ports_lib_paths end def ports_host - h = RbConfig::CONFIG['host'] - - # Our fat binary builds with a i686-w64-mingw32 toolchain - # but ruby for windows x32-mingw32 reports i686-pc-mingw32 - # so correct the host here - h.gsub('i686-pc-mingw32', 'i686-w64-mingw32') + RbConfig::CONFIG["arch"] end end end diff --git a/tasks/native_gem.rake b/tasks/native_gem.rake index 8dbe4768..355c1fb3 100644 --- a/tasks/native_gem.rake +++ b/tasks/native_gem.rake @@ -5,9 +5,19 @@ task 'gem:native' => ['ports:cross'] do require 'rake_compiler_dock' # make sure to install our bundle - sh "bundle package --all" # Avoid repeated downloads of gems by using gem files from the host. + sh "bundle package --all" # Avoid repeated downloads of gems by using gem files from the host. - GEM_PLATFORM_HOSTS.keys.each do |plat| - RakeCompilerDock.sh "bundle --local && RUBY_CC_VERSION=#{RUBY_CC_VERSION} rake native:#{plat} gem", platform: plat + GEM_PLATFORM_HOSTS.each do |plat, meta| + RakeCompilerDock.sh "bundle --local && RUBY_CC_VERSION=#{meta[:ruby_versions]} rake native:#{plat} gem", platform: plat end end + +# assumes you are in a container provided by Rake compiler +# if not, use the task above +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 diff --git a/tasks/ports.rake b/tasks/ports.rake index ca63e582..451267f7 100644 --- a/tasks/ports.rake +++ b/tasks/ports.rake @@ -14,32 +14,36 @@ namespace :ports do } directory "ports" - CLEAN.include "ports/*mingw32*" + CLEAN.include "ports/*mingw*" CLEAN.include "ports/*.installed" - task :openssl, [:host] do |task, args| - args.with_defaults(host: RbConfig::CONFIG['host']) + 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] do |task, args| - args.with_defaults(host: RbConfig::CONFIG['host']) + 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] do |task, args| - args.with_defaults(host: RbConfig::CONFIG['host']) + 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 @@ -59,13 +63,13 @@ namespace :ports do libraries_to_compile[:freetds].activate end - task :compile, [:host] do |task, args| - args.with_defaults(host: RbConfig::CONFIG['host']) + 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}..." + 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) + Rake::Task["ports:#{lib}"].invoke(args.host, args.gem_platform) end end @@ -74,22 +78,26 @@ namespace :ports do require 'rake_compiler_dock' # build the ports for all our cross compile hosts - GEM_PLATFORM_HOSTS.each do |gem_platform, host| + GEM_PLATFORM_HOSTS.each do |gem_platform, meta| # make sure to install our bundle build = ['bundle'] - build << "rake ports:compile[#{host}] MAKE='make -j`nproc`'" + 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" do + task "version_file", [:gem_platform] do |_task, args| + args.with_defaults(gem_platform: RbConfig::CONFIG["arch"]) + ports_version = {} libraries_to_compile.each do |library, library_recipe| ports_version[library] = library_recipe.version end + ports_version[:platform] = args.gem_platform + File.open(".ports_versions", "w") do |f| f.write ports_version end diff --git a/tasks/ports/recipe.rb b/tasks/ports/recipe.rb index 7fe89584..b3d4dd04 100644 --- a/tasks/ports/recipe.rb +++ b/tasks/ports/recipe.rb @@ -5,17 +5,30 @@ module Ports class Recipe < MiniPortile + attr_writer :gem_platform + def cook - checkpoint = "ports/#{name}-#{version}-#{host}.installed" + checkpoint = "ports/checkpoints/#{name}-#{version}-#{gem_platform}.installed" unless File.exist? checkpoint super + FileUtils.mkdir_p("ports/checkpoints") FileUtils.touch checkpoint end end private + attr_reader :gem_platform + + def port_path + "#{@target}/#{gem_platform}/#{@name}/#{@version}" + end + + def tmp_path + "tmp/#{gem_platform}/ports/#{@name}/#{@version}" + end + def configure_defaults [ "--host=#{@host}", @@ -38,9 +51,9 @@ def cross_build? def get_patches(libname, version) patches = [] - + patch_path = File.expand_path( - File.join('..','..','..','patches',libname,version), + File.join('..','..','..','patches',libname,version), __FILE__ ) @@ -49,4 +62,3 @@ def get_patches(libname, version) end end end - diff --git a/test/gem_test.rb b/test/gem_test.rb index 879988a1..48b7a631 100644 --- a/test/gem_test.rb +++ b/test/gem_test.rb @@ -9,11 +9,11 @@ class GemTest < MiniTest::Spec # We're going to muck with some system globals so lets make sure # they get set back later - original_host = RbConfig::CONFIG['host'] + original_platform = RbConfig::CONFIG['arch'] original_pwd = Dir.pwd after do - RbConfig::CONFIG['host'] = original_host + RbConfig::CONFIG['arch'] = original_platform Dir.chdir original_pwd end @@ -61,7 +61,7 @@ class GemTest < MiniTest::Spec end before do - RbConfig::CONFIG['host'] = 'fake-host-with-dirs' + RbConfig::CONFIG['arch'] = 'fake-host-with-dirs' fake_bin_paths.each do |path| FileUtils.mkdir_p(path) end @@ -85,7 +85,7 @@ class GemTest < MiniTest::Spec describe 'when the ports directories are missing' do before do - RbConfig::CONFIG['host'] = 'fake-host-without-dirs' + RbConfig::CONFIG['arch'] = 'fake-host-without-dirs' end it 'should return no directories' do @@ -115,7 +115,7 @@ class GemTest < MiniTest::Spec end before do - RbConfig::CONFIG['host'] = 'fake-host-with-dirs' + RbConfig::CONFIG['arch'] = 'fake-host-with-dirs' fake_lib_paths.each do |path| FileUtils.mkdir_p(path) end @@ -139,7 +139,7 @@ class GemTest < MiniTest::Spec describe 'when the ports directories are missing' do before do - RbConfig::CONFIG['host'] = 'fake-host-without-dirs' + RbConfig::CONFIG['arch'] = 'fake-host-without-dirs' end @@ -156,16 +156,14 @@ class GemTest < MiniTest::Spec describe '#ports_host' do { - 'i686-pc-linux-gnu' => 'i686-pc-linux-gnu', - 'x86_64-pc-linux-gnu' => 'x86_64-pc-linux-gnu', - 'i686-w64-mingw32' => 'i686-w64-mingw32', - 'x86_64-w64-mingw32' => 'x86_64-w64-mingw32', - # consolidate this host to our build w64-mingw32 arch - 'i686-pc-mingw32' => 'i686-w64-mingw32' + 'x64-mingw-ucrt' => 'x64-mingw-ucrt', + 'x64-mingw32' => 'x64-mingw32', + 'x86-mingw32' => 'x86-mingw32', + 'x86_64-linux' => 'x86_64-linux', }.each do |host,expected| describe "on a #{host} architecture" do before do - RbConfig::CONFIG['host'] = host + RbConfig::CONFIG['arch'] = host end it "should return a #{expected} ports host" do diff --git a/tiny_tds.gemspec b/tiny_tds.gemspec index e85ede2a..7afb4970 100644 --- a/tiny_tds.gemspec +++ b/tiny_tds.gemspec @@ -22,8 +22,8 @@ Gem::Specification.new do |s| s.metadata['msys2_mingw_dependencies'] = 'freetds' s.add_development_dependency 'mini_portile2', '~> 2.5.0' s.add_development_dependency 'rake', '~> 13.0.0' - s.add_development_dependency 'rake-compiler', '~> 1.1.0' - s.add_development_dependency 'rake-compiler-dock', '~> 1.1.0' + s.add_development_dependency 'rake-compiler', '~> 1.2' + s.add_development_dependency 'rake-compiler-dock', '~> 1.3.0' s.add_development_dependency 'minitest', '~> 5.14.0' s.add_development_dependency 'minitest-ci', '~> 3.4.0' s.add_development_dependency 'connection_pool', '~> 2.2.0'