diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index a4a680c..b737279 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -11,6 +11,11 @@ jobs: matrix: os: [macos] ruby: [ '3.2', '3.3' ] + compile_opt: [""] + include: + - os: "macos" + ruby: "3.3" + compile_opt: "ENABLE_STATIC=1" steps: - name: icu4c @@ -23,5 +28,5 @@ jobs: - name: Install dependencies run: bundle install - - name: Run tests ${{ matrix.rubyopt }} - run: bundle exec rake RUBYOPT="${{ matrix.rubyopt }}" + - name: "Run tests with compile_opt: ${{ matrix.compile_opt }}, rubyopt: ${{ matrix.rubyopt }}" + run: ${{ matrix.compile_opt }} bundle exec rake RUBYOPT="${{ matrix.rubyopt }}" diff --git a/Rakefile b/Rakefile index e943d79..7c16222 100644 --- a/Rakefile +++ b/Rakefile @@ -11,6 +11,7 @@ require "rake/extensiontask" Rake::ExtensionTask.new 'charlock_holmes' do |ext| ext.lib_dir = File.join 'lib', 'charlock_holmes' + ext.config_options << '--enable-static' if ENV['ENABLE_STATIC'] end -Rake::Task[:test].prerequisites << :compile \ No newline at end of file +Rake::Task[:test].prerequisites << :compile diff --git a/ext/charlock_holmes/extconf.rb b/ext/charlock_holmes/extconf.rb index 079224d..903c297 100644 --- a/ext/charlock_holmes/extconf.rb +++ b/ext/charlock_holmes/extconf.rb @@ -75,4 +75,67 @@ end end +def libflag_to_filename(ldflag) + case ldflag + when /\A-l(.+)/ + "lib#{Regexp.last_match(1)}.#{$LIBEXT}" + end +end + +def resolve_static_library(libflag, dirs) + filename = libflag_to_filename(libflag) + + dir = dirs.find { |path| File.exist?(File.join(path, filename)) } + + raise "Unable to find #{filename} in #{dirs}" unless dir + + File.join(dir, filename) +end + +def substitute_static_libs(packages) + packages.each do |pkg| + unless pkg_config(pkg) + message = <<~MSG + Unable to run `pkg-config #{pkg}`. + + Check that PKG_CONFIG_PATH includes #{pkg}.pc (or unset it if it's already set). + + Current environment: + PKG_CONFIG_PATH=#{ENV['PKG_CONFIG_PATH']} + MSG + + raise message + end + end + + # First, find all the -l flags added by pkg-config. We want to drop + # these dynamically linked libraries and substitute them with the static libraries. + libflags = packages.map do |pkg| + pkg_config(pkg, 'libs-only-l')&.strip&.split(' ') + end.flatten.uniq + + # To find where the static libraries live, we need to search the + # library paths given by the -L flag from pkg-config. + lib_paths = packages.map do |pkg| + include_path = pkg_config(pkg, 'libs-only-L')&.strip + include_path&.split(' ')&.map { |lib| lib.gsub(/^-L/, '') } + end.flatten.uniq + + # Drop the -l flags and add in the static libraries. + new_libs = $libs.shellsplit + new_libs.reject! { |arg| libflags.include?(arg) } + libflags.each { |flag| new_libs << resolve_static_library(flag, lib_paths) } + $libs = new_libs.uniq.shelljoin +end + +static_p = enable_config('static', false) +message "Static linking is #{static_p ? 'enabled' : 'disabled'}.\n" + +if static_p + $CXXFLAGS << ' -fPIC' + ENV['PKG_CONFIG_ALLOW_SYSTEM_LIBS'] = '1' + + substitute_static_libs(%w[icu-i18n icu-io icu-uc]) +end + create_makefile 'charlock_holmes/charlock_holmes'