Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix nokogumbo linking on windows #2202

Merged
merged 5 commits into from Mar 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@ Nokogiri follows [Semantic Versioning](https://semver.org/), please see the [REA
* [CRuby] `NodeSet` may now safely contain `Node` objects from multiple documents. Previously the GC lifecycle of the parent `Document` objects could lead to contained nodes being GCed while still in scope. [[#1952](https://github.com/sparklemotion/nokogiri/issues/1952)]
* [CRuby] Patch libxml2 to avoid "huge input lookup" errors on large CDATA elements. (See upstream [GNOME/libxml2#200](https://gitlab.gnome.org/GNOME/libxml2/-/issues/200) and [GNOME/libxml2!100](https://gitlab.gnome.org/GNOME/libxml2/-/merge_requests/100).) [[#2132](https://github.com/sparklemotion/nokogiri/issues/2132)].
* [CRuby] `{XML,HTML}::Document.parse` now invokes `#initialize` exactly once. Previously `#initialize` was invoked twice on each object.
* [CRuby+Windows] Enable Nokogumbo (and other downstream gems) to compile and link against `nokogiri.so` by including `LDFLAGS` in `Nokogiri::VERSION_INFO`. [[#2167](https://github.com/sparklemotion/nokogiri/issues/2167)]
* [JRuby] `{XML,HTML}::Document.parse` now invokes `#initialize` exactly once. Previously `#initialize` was not called, which was a problem for subclassing such as done by `Loofah`.


Expand Down
6 changes: 5 additions & 1 deletion ext/nokogiri/extconf.rb
Expand Up @@ -239,7 +239,7 @@ def ensure_package_configuration(opt: nil, pc: nil, lib:, func:, headers:)
end

def ensure_func(func, headers = nil)
have_func(func, headers) || abort_could_not_find_library(lib)
have_func(func, headers) || abort_could_not_find_library(func)
end

def preserving_globals
Expand Down Expand Up @@ -741,6 +741,10 @@ def compile
recipe.configure_options += ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"]
end

if windows?
cflags = concat_flags(cflags, "-ULIBXML_STATIC", "-DIN_LIBXML")
end

recipe.configure_options += [
"--without-python",
"--without-readline",
Expand Down
92 changes: 50 additions & 42 deletions ext/nokogiri/nokogiri.h
Expand Up @@ -15,6 +15,14 @@
# include <windows.h>
#endif

#if _WIN32
# define NOKOPUBFUN __declspec(dllexport)
# define NOKOPUBVAR __declspec(dllexport) extern
#else
# define NOKOPUBFUN
# define NOKOPUBVAR extern
#endif


#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -83,47 +91,47 @@ xmlNodePtr xmlLastElementChild(xmlNodePtr parent);
#endif


extern VALUE mNokogiri ;
extern VALUE mNokogiriHtml ;
extern VALUE mNokogiriHtmlSax ;
extern VALUE mNokogiriXml ;
extern VALUE mNokogiriXmlSax ;
extern VALUE mNokogiriXslt ;

extern VALUE cNokogiriSyntaxError;
extern VALUE cNokogiriXmlAttr;
extern VALUE cNokogiriXmlAttributeDecl;
extern VALUE cNokogiriXmlCData;
extern VALUE cNokogiriXmlCharacterData;
extern VALUE cNokogiriXmlComment;
extern VALUE cNokogiriXmlDocument ;
extern VALUE cNokogiriXmlDocumentFragment;
extern VALUE cNokogiriXmlDtd;
extern VALUE cNokogiriXmlElement ;
extern VALUE cNokogiriXmlElementContent;
extern VALUE cNokogiriXmlElementDecl;
extern VALUE cNokogiriXmlEntityDecl;
extern VALUE cNokogiriXmlEntityReference;
extern VALUE cNokogiriXmlNamespace ;
extern VALUE cNokogiriXmlNode ;
extern VALUE cNokogiriXmlNodeSet ;
extern VALUE cNokogiriXmlProcessingInstruction;
extern VALUE cNokogiriXmlReader;
extern VALUE cNokogiriXmlRelaxNG;
extern VALUE cNokogiriXmlSaxParser ;
extern VALUE cNokogiriXmlSaxParserContext;
extern VALUE cNokogiriXmlSaxPushParser ;
extern VALUE cNokogiriXmlSchema;
extern VALUE cNokogiriXmlSyntaxError;
extern VALUE cNokogiriXmlText ;
extern VALUE cNokogiriXmlXpathContext;
extern VALUE cNokogiriXmlXpathSyntaxError;
extern VALUE cNokogiriXsltStylesheet ;

extern VALUE cNokogiriHtmlDocument ;
extern VALUE cNokogiriHtmlSaxPushParser ;
extern VALUE cNokogiriHtmlElementDescription ;
extern VALUE cNokogiriHtmlSaxParserContext;
NOKOPUBVAR VALUE mNokogiri ;
NOKOPUBVAR VALUE mNokogiriHtml ;
NOKOPUBVAR VALUE mNokogiriHtmlSax ;
NOKOPUBVAR VALUE mNokogiriXml ;
NOKOPUBVAR VALUE mNokogiriXmlSax ;
NOKOPUBVAR VALUE mNokogiriXslt ;

NOKOPUBVAR VALUE cNokogiriSyntaxError;
NOKOPUBVAR VALUE cNokogiriXmlAttr;
NOKOPUBVAR VALUE cNokogiriXmlAttributeDecl;
NOKOPUBVAR VALUE cNokogiriXmlCData;
NOKOPUBVAR VALUE cNokogiriXmlCharacterData;
NOKOPUBVAR VALUE cNokogiriXmlComment;
NOKOPUBVAR VALUE cNokogiriXmlDocument ;
NOKOPUBVAR VALUE cNokogiriXmlDocumentFragment;
NOKOPUBVAR VALUE cNokogiriXmlDtd;
NOKOPUBVAR VALUE cNokogiriXmlElement ;
NOKOPUBVAR VALUE cNokogiriXmlElementContent;
NOKOPUBVAR VALUE cNokogiriXmlElementDecl;
NOKOPUBVAR VALUE cNokogiriXmlEntityDecl;
NOKOPUBVAR VALUE cNokogiriXmlEntityReference;
NOKOPUBVAR VALUE cNokogiriXmlNamespace ;
NOKOPUBVAR VALUE cNokogiriXmlNode ;
NOKOPUBVAR VALUE cNokogiriXmlNodeSet ;
NOKOPUBVAR VALUE cNokogiriXmlProcessingInstruction;
NOKOPUBVAR VALUE cNokogiriXmlReader;
NOKOPUBVAR VALUE cNokogiriXmlRelaxNG;
NOKOPUBVAR VALUE cNokogiriXmlSaxParser ;
NOKOPUBVAR VALUE cNokogiriXmlSaxParserContext;
NOKOPUBVAR VALUE cNokogiriXmlSaxPushParser ;
NOKOPUBVAR VALUE cNokogiriXmlSchema;
NOKOPUBVAR VALUE cNokogiriXmlSyntaxError;
NOKOPUBVAR VALUE cNokogiriXmlText ;
NOKOPUBVAR VALUE cNokogiriXmlXpathContext;
NOKOPUBVAR VALUE cNokogiriXmlXpathSyntaxError;
NOKOPUBVAR VALUE cNokogiriXsltStylesheet ;

NOKOPUBVAR VALUE cNokogiriHtmlDocument ;
NOKOPUBVAR VALUE cNokogiriHtmlSaxPushParser ;
NOKOPUBVAR VALUE cNokogiriHtmlElementDescription ;
NOKOPUBVAR VALUE cNokogiriHtmlSaxParserContext;

typedef struct _nokogiriTuple {
VALUE doc;
Expand Down Expand Up @@ -169,7 +177,7 @@ VALUE noko_xml_node_set_wrap(xmlNodeSetPtr node_set, VALUE document) ;

VALUE noko_xml_document_wrap_with_init_args(VALUE klass, xmlDocPtr doc, int argc, VALUE *argv);
VALUE noko_xml_document_wrap(VALUE klass, xmlDocPtr doc);
VALUE Nokogiri_wrap_xml_document(VALUE klass, xmlDocPtr doc); /* deprecated. use noko_xml_document_wrap() instead. */
NOKOPUBFUN VALUE Nokogiri_wrap_xml_document(VALUE klass, xmlDocPtr doc); /* deprecated. use noko_xml_document_wrap() instead. */

#define DOC_RUBY_OBJECT_TEST(x) ((nokogiriTuplePtr)(x->_private))
#define DOC_RUBY_OBJECT(x) (((nokogiriTuplePtr)(x->_private))->doc)
Expand Down
28 changes: 28 additions & 0 deletions lib/nokogiri/version/info.rb
Expand Up @@ -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
Expand Down Expand Up @@ -74,18 +82,38 @@ 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|
nokogiri["version"] = Nokogiri::VERSION

unless jruby?
# enable gems like nokogumbo to build with the following in their extconf.rb:
#
# append_cflags(Nokogiri::VERSION_INFO["nokogiri"]["cppflags"])
# append_ldflags(Nokogiri::VERSION_INFO["nokogiri"]["ldflags"])
#
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|
Expand Down
16 changes: 16 additions & 0 deletions scripts/test-gem-installation
Expand Up @@ -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") }

Expand Down Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions test/test_version.rb
Expand Up @@ -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"])
Expand Down