From 1b448d7b9ae8b083b07d6cd2f67cf0fa875052f2 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Sun, 7 Mar 2021 15:44:00 -0500 Subject: [PATCH] fix(windows): version info contains ldflags on windows to allow downstream gems like nokogumbo to build correctly simply by requiring nokogiri in the extconf and running: append_cflags(Nokogiri::VERSION_INFO["nokogiri"]["cppflags"]) append_ldflags(Nokogiri::VERSION_INFO["nokogiri"]["ldflags"]) this is needed because unresolved symbols aren't allowed on windows. Related to #2167 --- lib/nokogiri/version/info.rb | 23 +++++++++++++++++++++++ scripts/test-gem-installation | 16 ++++++++++++++++ test/test_version.rb | 5 +++-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/nokogiri/version/info.rb b/lib/nokogiri/version/info.rb index 2cb8c23bbf..7a9787ac16 100644 --- a/lib/nokogiri/version/info.rb +++ b/lib/nokogiri/version/info.rb @@ -10,6 +10,14 @@ def jruby? ::JRUBY_VERSION if ::RUBY_PLATFORM == "java" end + def windows? + ::RUBY_PLATFORM =~ /mingw|mswin/ + end + + def ruby_minor + Gem::Version.new(::RUBY_VERSION).segments[0..1].join(".") + end + def engine defined?(::RUBY_ENGINE) ? ::RUBY_ENGINE : "mri" end @@ -74,6 +82,7 @@ def warnings def to_hash header_directory = File.expand_path(File.join(File.dirname(__FILE__), "../../../ext/nokogiri")) + {}.tap do |vi| vi["warnings"] = [] vi["nokogiri"] = {}.tap do |nokogiri| @@ -81,11 +90,25 @@ def to_hash unless jruby? cppflags = ["-I#{header_directory.shellescape}"] + ldflags = [] + if libxml2_using_packaged? cppflags << "-I#{File.join(header_directory, 'include').shellescape}" cppflags << "-I#{File.join(header_directory, 'include/libxml2').shellescape}" + + if windows? + # on windows, nokogumbo needs to link against nokogiri.so to resolve symbols. see #2167 + lib_directory = File.expand_path(File.join(File.dirname(__FILE__), "../#{ruby_minor}")) + unless File.exist?(lib_directory) + lib_directory = File.expand_path(File.join(File.dirname(__FILE__), "..")) + end + ldflags << "-L#{lib_directory.shellescape}" + ldflags << "-l:nokogiri.so" + end end + nokogiri["cppflags"] = cppflags + nokogiri["ldflags"] = ldflags end end vi["ruby"] = {}.tap do |ruby| diff --git a/scripts/test-gem-installation b/scripts/test-gem-installation index 8be0bb5a4a..d2b64bdcc5 100755 --- a/scripts/test-gem-installation +++ b/scripts/test-gem-installation @@ -43,6 +43,8 @@ Minitest::Reporters.use!([Minitest::Reporters::SpecReporter.new]) puts "Testing #{gemspec.full_name} installed in #{gemspec.base_dir}" describe gemspec.full_name do + let(:ruby_maj_min) { Gem::Version.new(::RUBY_VERSION).segments[0..1].join(".") } + let(:nokogiri_lib_dir) { File.join(gemspec.gem_dir, "lib/nokogiri") } let(:nokogiri_ext_dir) { File.join(gemspec.gem_dir, "ext/nokogiri") } let(:nokogiri_include_dir) { File.join(nokogiri_ext_dir, "include") } @@ -108,6 +110,20 @@ describe gemspec.full_name do assert(found, "expected to find #{header} in one of: #{headers_dirs.inspect}") end end + + it "has ldflags pointing to the shared object file" do + ldflags = Nokogiri::VERSION_INFO["nokogiri"]["ldflags"] + if ::RUBY_PLATFORM =~ /mingw|mswin/ + if gemspec.platform.cpu + assert_includes(ldflags, "-L#{File.join(nokogiri_lib_dir, ruby_maj_min)}") + else + assert_includes(ldflags, "-L#{nokogiri_lib_dir}") + end + assert_includes(ldflags, "-l:nokogiri.so") + else + assert_empty(ldflags) + end + end end if Nokogiri::VersionInfo.instance.libxml2_using_packaged? describe "using system libraries" do diff --git a/test/test_version.rb b/test/test_version.rb index dfef728b9c..e5d33d4936 100644 --- a/test/test_version.rb +++ b/test/test_version.rb @@ -18,8 +18,9 @@ def test_version_info_basics if jruby? refute(Nokogiri::VERSION_INFO["nokogiri"].has_key?("cppflags"), "did not expect cppflags") else - # cppflags are more fully tested in scripts/test-gem-installation - assert_kind_of(Array, Nokogiri::VERSION_INFO["nokogiri"]["cppflags"], "expected cppflags to be an array") + # cppflags/ldflags are more fully tested in scripts/test-gem-installation + assert_kind_of(Array, Nokogiri::VERSION_INFO["nokogiri"]["cppflags"], "cppflags should be an array") + assert_kind_of(Array, Nokogiri::VERSION_INFO["nokogiri"]["ldflags"], "ldflags should be an array") end assert_equal(::RUBY_VERSION, Nokogiri::VERSION_INFO["ruby"]["version"])