nokogiri 1.11.0.rc2 → 1.11.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/LICENSE-DEPENDENCIES.md +1015 -947
  4. data/LICENSE.md +1 -1
  5. data/README.md +171 -94
  6. data/ext/nokogiri/depend +37 -358
  7. data/ext/nokogiri/extconf.rb +581 -374
  8. data/ext/nokogiri/html_document.c +78 -82
  9. data/ext/nokogiri/html_element_description.c +84 -71
  10. data/ext/nokogiri/html_entity_lookup.c +21 -16
  11. data/ext/nokogiri/html_sax_parser_context.c +69 -66
  12. data/ext/nokogiri/html_sax_push_parser.c +42 -34
  13. data/ext/nokogiri/libxml2_backwards_compat.c +121 -0
  14. data/ext/nokogiri/nokogiri.c +192 -93
  15. data/ext/nokogiri/nokogiri.h +177 -98
  16. data/ext/nokogiri/test_global_handlers.c +40 -0
  17. data/ext/nokogiri/xml_attr.c +15 -15
  18. data/ext/nokogiri/xml_attribute_decl.c +18 -18
  19. data/ext/nokogiri/xml_cdata.c +13 -18
  20. data/ext/nokogiri/xml_comment.c +19 -26
  21. data/ext/nokogiri/xml_document.c +225 -163
  22. data/ext/nokogiri/xml_document_fragment.c +13 -15
  23. data/ext/nokogiri/xml_dtd.c +54 -48
  24. data/ext/nokogiri/xml_element_content.c +30 -27
  25. data/ext/nokogiri/xml_element_decl.c +22 -22
  26. data/ext/nokogiri/xml_encoding_handler.c +17 -11
  27. data/ext/nokogiri/xml_entity_decl.c +32 -30
  28. data/ext/nokogiri/xml_entity_reference.c +16 -18
  29. data/ext/nokogiri/xml_namespace.c +56 -49
  30. data/ext/nokogiri/xml_node.c +338 -286
  31. data/ext/nokogiri/xml_node_set.c +168 -156
  32. data/ext/nokogiri/xml_processing_instruction.c +17 -19
  33. data/ext/nokogiri/xml_reader.c +191 -157
  34. data/ext/nokogiri/xml_relax_ng.c +52 -28
  35. data/ext/nokogiri/xml_sax_parser.c +118 -118
  36. data/ext/nokogiri/xml_sax_parser_context.c +103 -86
  37. data/ext/nokogiri/xml_sax_push_parser.c +36 -27
  38. data/ext/nokogiri/xml_schema.c +95 -47
  39. data/ext/nokogiri/xml_syntax_error.c +42 -21
  40. data/ext/nokogiri/xml_text.c +13 -17
  41. data/ext/nokogiri/xml_xpath_context.c +206 -123
  42. data/ext/nokogiri/xslt_stylesheet.c +158 -161
  43. data/lib/nokogiri.rb +4 -8
  44. data/lib/nokogiri/css/parser.rb +62 -62
  45. data/lib/nokogiri/css/parser.y +2 -2
  46. data/lib/nokogiri/css/xpath_visitor.rb +70 -42
  47. data/lib/nokogiri/extension.rb +26 -0
  48. data/lib/nokogiri/html/document.rb +12 -26
  49. data/lib/nokogiri/html/document_fragment.rb +15 -15
  50. data/lib/nokogiri/version.rb +2 -148
  51. data/lib/nokogiri/version/constant.rb +5 -0
  52. data/lib/nokogiri/version/info.rb +205 -0
  53. data/lib/nokogiri/xml/builder.rb +2 -2
  54. data/lib/nokogiri/xml/document.rb +48 -18
  55. data/lib/nokogiri/xml/document_fragment.rb +4 -6
  56. data/lib/nokogiri/xml/node.rb +88 -69
  57. data/lib/nokogiri/xml/parse_options.rb +6 -0
  58. data/lib/nokogiri/xml/reader.rb +2 -9
  59. data/lib/nokogiri/xml/relax_ng.rb +6 -2
  60. data/lib/nokogiri/xml/schema.rb +12 -4
  61. data/lib/nokogiri/xml/searchable.rb +3 -1
  62. data/lib/nokogiri/xml/xpath.rb +1 -3
  63. data/lib/nokogiri/xml/xpath/syntax_error.rb +1 -1
  64. data/patches/libxml2/0006-htmlParseComment-treat-as-if-it-closed-the-comment.patch +73 -0
  65. data/patches/libxml2/0007-use-new-htmlParseLookupCommentEnd-to-find-comment-en.patch +103 -0
  66. data/patches/libxml2/0008-use-glibc-strlen.patch +53 -0
  67. data/patches/libxml2/0009-avoid-isnan-isinf.patch +81 -0
  68. data/patches/libxml2/0010-parser.c-shrink-the-input-buffer-when-appropriate.patch +70 -0
  69. metadata +85 -155
  70. data/ext/nokogiri/html_document.h +0 -10
  71. data/ext/nokogiri/html_element_description.h +0 -10
  72. data/ext/nokogiri/html_entity_lookup.h +0 -8
  73. data/ext/nokogiri/html_sax_parser_context.h +0 -11
  74. data/ext/nokogiri/html_sax_push_parser.h +0 -9
  75. data/ext/nokogiri/xml_attr.h +0 -9
  76. data/ext/nokogiri/xml_attribute_decl.h +0 -9
  77. data/ext/nokogiri/xml_cdata.h +0 -9
  78. data/ext/nokogiri/xml_comment.h +0 -9
  79. data/ext/nokogiri/xml_document.h +0 -23
  80. data/ext/nokogiri/xml_document_fragment.h +0 -10
  81. data/ext/nokogiri/xml_dtd.h +0 -10
  82. data/ext/nokogiri/xml_element_content.h +0 -10
  83. data/ext/nokogiri/xml_element_decl.h +0 -9
  84. data/ext/nokogiri/xml_encoding_handler.h +0 -8
  85. data/ext/nokogiri/xml_entity_decl.h +0 -10
  86. data/ext/nokogiri/xml_entity_reference.h +0 -9
  87. data/ext/nokogiri/xml_io.c +0 -61
  88. data/ext/nokogiri/xml_io.h +0 -11
  89. data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
  90. data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
  91. data/ext/nokogiri/xml_namespace.h +0 -14
  92. data/ext/nokogiri/xml_node.h +0 -13
  93. data/ext/nokogiri/xml_node_set.h +0 -12
  94. data/ext/nokogiri/xml_processing_instruction.h +0 -9
  95. data/ext/nokogiri/xml_reader.h +0 -10
  96. data/ext/nokogiri/xml_relax_ng.h +0 -9
  97. data/ext/nokogiri/xml_sax_parser.h +0 -39
  98. data/ext/nokogiri/xml_sax_parser_context.h +0 -10
  99. data/ext/nokogiri/xml_sax_push_parser.h +0 -9
  100. data/ext/nokogiri/xml_schema.h +0 -9
  101. data/ext/nokogiri/xml_syntax_error.h +0 -13
  102. data/ext/nokogiri/xml_text.h +0 -9
  103. data/ext/nokogiri/xml_xpath_context.h +0 -10
  104. data/ext/nokogiri/xslt_stylesheet.h +0 -14
@@ -1,13 +1,173 @@
1
- # :stopdoc:
1
+ # frozen_string_literal: true
2
2
  ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
3
3
 
4
- require 'mkmf'
4
+ require "mkmf"
5
+ require "rbconfig"
6
+ require "fileutils"
7
+ require "shellwords"
8
+ require "pathname"
5
9
 
6
- ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
10
+ # helpful constants
11
+ PACKAGE_ROOT_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
12
+ REQUIRED_LIBXML_VERSION = "2.6.21"
13
+ RECOMMENDED_LIBXML_VERSION = "2.9.3"
14
+
15
+ # The gem version constraint in the Rakefile is not respected at install time.
16
+ # Keep this version in sync with the one in the Rakefile !
17
+ REQUIRED_MINI_PORTILE_VERSION = "~> 2.5.0"
18
+ REQUIRED_PKG_CONFIG_VERSION = "~> 1.1"
19
+
20
+ # Keep track of what versions of what libraries we build against
21
+ OTHER_LIBRARY_VERSIONS = {}
22
+
23
+ NOKOGIRI_HELP_MESSAGE = <<~HELP
24
+ USAGE: ruby #{$0} [options]
25
+
26
+ Flags that are always valid:
27
+
28
+ --use-system-libraries
29
+ --enable-system-libraries
30
+ Use system libraries instead of building and using the packaged libraries.
31
+
32
+ --disable-system-libraries
33
+ Use the packaged libraries, and ignore the system libraries. This is the default on most
34
+ platforms, and overrides `--use-system-libraries` and the environment variable
35
+ `NOKOGIRI_USE_SYSTEM_LIBRARIES`.
36
+
37
+ --disable-clean
38
+ Do not clean out intermediate files after successful build.
39
+
40
+ --prevent-strip
41
+ Take steps to prevent stripping the symbol table and debugging info from the shared
42
+ library, potentially overriding RbConfig's CFLAGS/LDFLAGS/DLDFLAGS.
43
+
44
+
45
+ Flags only used when using system libraries:
46
+
47
+ General:
48
+
49
+ --with-opt-dir=DIRECTORY
50
+ Look for headers and libraries in DIRECTORY.
51
+
52
+ --with-opt-lib=DIRECTORY
53
+ Look for libraries in DIRECTORY.
54
+
55
+ --with-opt-include=DIRECTORY
56
+ Look for headers in DIRECTORY.
57
+
58
+
59
+ Related to zlib:
60
+
61
+ --with-zlib-dir=DIRECTORY
62
+ Look for zlib headers and library in DIRECTORY.
63
+
64
+ --with-zlib-lib=DIRECTORY
65
+ Look for zlib library in DIRECTORY.
66
+
67
+ --with-zlib-include=DIRECTORY
68
+ Look for zlib headers in DIRECTORY.
69
+
70
+
71
+ Related to iconv:
72
+
73
+ --with-iconv-dir=DIRECTORY
74
+ Look for iconv headers and library in DIRECTORY.
75
+
76
+ --with-iconv-lib=DIRECTORY
77
+ Look for iconv library in DIRECTORY.
78
+
79
+ --with-iconv-include=DIRECTORY
80
+ Look for iconv headers in DIRECTORY.
81
+
82
+
83
+ Related to libxml2:
84
+
85
+ --with-xml2-dir=DIRECTORY
86
+ Look for xml2 headers and library in DIRECTORY.
87
+
88
+ --with-xml2-lib=DIRECTORY
89
+ Look for xml2 library in DIRECTORY.
90
+
91
+ --with-xml2-include=DIRECTORY
92
+ Look for xml2 headers in DIRECTORY.
93
+
94
+
95
+ Related to libxslt:
96
+
97
+ --with-xslt-dir=DIRECTORY
98
+ Look for xslt headers and library in DIRECTORY.
99
+
100
+ --with-xslt-lib=DIRECTORY
101
+ Look for xslt library in DIRECTORY.
102
+
103
+ --with-xslt-include=DIRECTORY
104
+ Look for xslt headers in DIRECTORY.
105
+
106
+
107
+ Related to libexslt:
108
+
109
+ --with-exslt-dir=DIRECTORY
110
+ Look for exslt headers and library in DIRECTORY.
111
+
112
+ --with-exslt-lib=DIRECTORY
113
+ Look for exslt library in DIRECTORY.
114
+
115
+ --with-exslt-include=DIRECTORY
116
+ Look for exslt headers in DIRECTORY.
117
+
118
+
119
+ Flags only used when building and using the packaged libraries:
120
+
121
+ --disable-static
122
+ Do not statically link packaged libraries, instead use shared libraries.
123
+
124
+ --enable-cross-build
125
+ Enable cross-build mode. (You probably do not want to set this manually.)
126
+
127
+
128
+ Environment variables used:
129
+
130
+ NOKOGIRI_USE_SYSTEM_LIBRARIES
131
+ Equivalent to `--enable-system-libraries` when set, even if nil or blank.
132
+
133
+ CC
134
+ Use this path to invoke the compiler instead of `RbConfig::CONFIG['CC']`
135
+
136
+ CPPFLAGS
137
+ If this string is accepted by the C preprocessor, add it to the flags passed to the C preprocessor
138
+
139
+ CFLAGS
140
+ If this string is accepted by the compiler, add it to the flags passed to the compiler
141
+
142
+ LDFLAGS
143
+ If this string is accepted by the linker, add it to the flags passed to the linker
144
+
145
+ LIBS
146
+ Add this string to the flags passed to the linker
147
+ HELP
7
148
 
8
149
  #
9
- # functions
150
+ # utility functions
10
151
  #
152
+ def config_clean?
153
+ enable_config('clean', true)
154
+ end
155
+
156
+ def config_static?
157
+ default_static = !truffle?
158
+ enable_config("static", default_static)
159
+ end
160
+
161
+ def config_cross_build?
162
+ enable_config("cross-build")
163
+ end
164
+
165
+ def config_system_libraries?
166
+ enable_config("system-libraries", ENV.key?("NOKOGIRI_USE_SYSTEM_LIBRARIES")) do |_, default|
167
+ arg_config('--use-system-libraries', default)
168
+ end
169
+ end
170
+
11
171
  def windows?
12
172
  RbConfig::CONFIG['target_os'] =~ /mingw32|mswin/
13
173
  end
@@ -29,184 +189,170 @@ def aix?
29
189
  end
30
190
 
31
191
  def nix?
32
- ! (windows? || solaris? || darwin?)
192
+ !(windows? || solaris? || darwin?)
33
193
  end
34
194
 
35
- def sh_export_path path
36
- # because libxslt 1.1.29 configure.in uses AC_PATH_TOOL which treats ":"
37
- # as a $PATH separator, we need to convert windows paths from
38
- #
39
- # C:/path/to/foo
40
- #
41
- # to
42
- #
43
- # /C/path/to/foo
44
- #
45
- # which is sh-compatible, in order to find things properly during
46
- # configuration
47
- if windows?
48
- match = Regexp.new("^([A-Z]):(/.*)").match(path)
49
- if match && match.length == 3
50
- return File.join("/", match[1], match[2])
51
- end
52
- end
53
- path
195
+ def truffle?
196
+ ::RUBY_ENGINE == 'truffleruby'
54
197
  end
55
198
 
56
- def do_help
57
- print <<HELP
58
- usage: ruby #{$0} [options]
199
+ def concat_flags(*args)
200
+ args.compact.join(" ")
201
+ end
59
202
 
60
- --disable-clean
61
- Do not clean out intermediate files after successful build.
203
+ def local_have_library(lib, func = nil, headers = nil)
204
+ have_library(lib, func, headers) || have_library("lib#{lib}", func, headers)
205
+ end
62
206
 
63
- --disable-static
64
- Do not statically link bundled libraries.
207
+ LOCAL_PACKAGE_RESPONSE = Object.new
208
+ def LOCAL_PACKAGE_RESPONSE.%(package)
209
+ package ? "yes: #{package}" : "no"
210
+ end
65
211
 
66
- --with-iconv-dir=DIR
67
- Use the iconv library placed under DIR.
212
+ # wrapper around MakeMakefil#pkg_config and the PKGConfig gem
213
+ def try_package_configuration(pc)
214
+ unless ENV.key?("NOKOGIRI_TEST_PKG_CONFIG_GEM")
215
+ # try MakeMakefile#pkg_config, which uses the system utility `pkg-config`.
216
+ return if checking_for("#{pc} using `pkg_config`", LOCAL_PACKAGE_RESPONSE) do
217
+ pkg_config(pc)
218
+ end
219
+ end
68
220
 
69
- --with-zlib-dir=DIR
70
- Use the zlib library placed under DIR.
221
+ # `pkg-config` probably isn't installed, which appears to be the case for lots of freebsd systems.
222
+ # let's fall back to the pkg-config gem, which knows how to parse .pc files, and wrap it with the
223
+ # same logic as MakeMakefile#pkg_config
224
+ begin
225
+ require 'rubygems'
226
+ gem('pkg-config', REQUIRED_PKG_CONFIG_VERSION)
227
+ require 'pkg-config'
71
228
 
72
- --use-system-libraries
73
- Use system libraries instead of building and using the bundled
74
- libraries.
229
+ checking_for("#{pc} using pkg-config gem version #{PKGConfig::VERSION}", LOCAL_PACKAGE_RESPONSE) do
230
+ if PKGConfig.have_package(pc)
231
+ cflags = PKGConfig.cflags(pc)
232
+ ldflags = PKGConfig.libs_only_L(pc)
233
+ libs = PKGConfig.libs_only_l(pc)
75
234
 
76
- --with-xml2-dir=DIR / --with-xml2-config=CONFIG
77
- --with-xslt-dir=DIR / --with-xslt-config=CONFIG
78
- --with-exslt-dir=DIR / --with-exslt-config=CONFIG
79
- Use libxml2/libxslt/libexslt as specified.
235
+ Logging.message("pkg-config gem found package configuration for %s\n", pc)
236
+ Logging.message("cflags: %s\nldflags: %s\nlibs: %s\n\n", cflags, ldflags, libs)
80
237
 
81
- --enable-cross-build
82
- Do cross-build.
83
- HELP
84
- exit! 0
238
+ [cflags, ldflags, libs]
239
+ end
240
+ end
241
+ rescue LoadError
242
+ message("Please install either the `pkg-config` utility or the `pkg-config` rubygem.\n")
243
+ end
85
244
  end
86
245
 
87
- def do_clean
88
- require 'pathname'
89
- require 'fileutils'
90
-
91
- root = Pathname(ROOT)
92
- pwd = Pathname(Dir.pwd)
246
+ # set up mkmf to link against the library if we can find it
247
+ def have_package_configuration(opt: nil, pc: nil, lib:, func:, headers:)
248
+ if opt
249
+ dir_config(opt)
250
+ dir_config("opt")
251
+ end
93
252
 
94
- # Skip if this is a development work tree
95
- unless (root + '.git').exist?
96
- message "Cleaning files only used during build.\n"
253
+ # see if we have enough path info to do this without trying any harder
254
+ unless ENV.key?("NOKOGIRI_TEST_PKG_CONFIG")
255
+ return true if local_have_library(lib, func, headers)
256
+ end
97
257
 
98
- # (root + 'tmp') cannot be removed at this stage because
99
- # nokogiri.so is yet to be copied to lib.
258
+ try_package_configuration(pc) if pc
100
259
 
101
- # clean the ports build directory
102
- Pathname.glob(pwd.join('tmp', '*', 'ports')) do |dir|
103
- FileUtils.rm_rf(dir, verbose: true)
104
- end
260
+ # verify that we can compile and link against the library
261
+ local_have_library(lib, func, headers)
262
+ end
105
263
 
106
- if enable_config('static')
107
- # ports installation can be safely removed if statically linked.
108
- FileUtils.rm_rf(root + 'ports', verbose: true)
109
- else
110
- FileUtils.rm_rf(root + 'ports' + 'archives', verbose: true)
111
- end
112
- end
264
+ def ensure_package_configuration(opt: nil, pc: nil, lib:, func:, headers:)
265
+ have_package_configuration(opt: opt, pc: pc, lib: lib, func: func, headers: headers) ||
266
+ abort_could_not_find_library(lib)
267
+ end
113
268
 
114
- exit! 0
269
+ def ensure_func(func, headers = nil)
270
+ have_func(func, headers) || abort_could_not_find_library(func)
115
271
  end
116
272
 
117
- def package_config pkg, options={}
118
- package = pkg_config(pkg)
119
- return package if package
273
+ def preserving_globals
274
+ values = [$arg_config, $INCFLAGS, $CFLAGS, $CPPFLAGS, $LDFLAGS, $DLDFLAGS, $LIBPATH, $libs].map(&:dup)
275
+ yield
276
+ ensure
277
+ $arg_config, $INCFLAGS, $CFLAGS, $CPPFLAGS, $LDFLAGS, $DLDFLAGS, $LIBPATH, $libs = values
278
+ end
120
279
 
121
- begin
122
- require 'rubygems'
123
- gem 'pkg-config', (gem_ver='~> 1.1')
124
- require 'pkg-config' and message("Using pkg-config gem version #{PKGConfig::VERSION}\n")
125
- rescue LoadError
126
- message "pkg-config could not be used to find #{pkg}\nPlease install either `pkg-config` or the pkg-config gem per\n\n gem install pkg-config -v #{gem_ver.inspect}\n\n"
127
- else
128
- return nil unless PKGConfig.have_package(pkg)
280
+ def abort_could_not_find_library(lib)
281
+ abort("-----\n#{caller[0]}\n#{lib} is missing. Please locate mkmf.log to investigate how it is failing.\n-----")
282
+ end
129
283
 
130
- cflags = PKGConfig.cflags(pkg)
131
- ldflags = PKGConfig.libs_only_L(pkg)
132
- libs = PKGConfig.libs_only_l(pkg)
284
+ def chdir_for_build
285
+ # When using rake-compiler-dock on Windows, the underlying Virtualbox shared
286
+ # folders don't support symlinks, but libiconv expects it for a build on
287
+ # Linux. We work around this limitation by using the temp dir for cooking.
288
+ build_dir = ENV['RCD_HOST_RUBY_PLATFORM'].to_s =~ /mingw|mswin|cygwin/ ? '/tmp' : '.'
289
+ Dir.chdir(build_dir) do
290
+ yield
291
+ end
292
+ end
133
293
 
134
- Logging::message "PKGConfig package configuration for %s\n", pkg
135
- Logging::message "cflags: %s\nldflags: %s\nlibs: %s\n\n", cflags, ldflags, libs
294
+ def sh_export_path(path)
295
+ # because libxslt 1.1.29 configure.in uses AC_PATH_TOOL which treats ":"
296
+ # as a $PATH separator, we need to convert windows paths from
297
+ #
298
+ # C:/path/to/foo
299
+ #
300
+ # to
301
+ #
302
+ # /C/path/to/foo
303
+ #
304
+ # which is sh-compatible, in order to find things properly during
305
+ # configuration
306
+ return path unless windows?
136
307
 
137
- [cflags, ldflags, libs]
308
+ match = Regexp.new("^([A-Z]):(/.*)").match(path)
309
+ if match && match.length == 3
310
+ return File.join("/", match[1], match[2])
138
311
  end
139
- end
140
312
 
141
- def nokogiri_try_compile
142
- try_compile "int main() {return 0;}", "", {werror: true}
313
+ path
143
314
  end
144
315
 
145
- def check_libxml_version version=nil
146
- source = if version.nil?
147
- <<-SRC
148
- #include <libxml/xmlversion.h>
149
- SRC
150
- else
151
- version_int = sprintf "%d%2.2d%2.2d", *(version.split("."))
152
- <<-SRC
153
- #include <libxml/xmlversion.h>
154
- #if LIBXML_VERSION < #{version_int}
155
- #error libxml2 is older than #{version}
156
- #endif
157
- SRC
158
- end
159
-
160
- try_cpp source
161
- end
162
-
163
- def add_cflags(flags)
164
- print "checking if the C compiler accepts #{flags}... "
165
- with_cflags("#{$CFLAGS} #{flags}") do
166
- if nokogiri_try_compile
167
- puts 'yes'
168
- true
169
- else
170
- puts 'no'
171
- false
172
- end
316
+ def libflag_to_filename(ldflag)
317
+ case ldflag
318
+ when /\A-l(.+)/
319
+ "lib#{Regexp.last_match(1)}.#{$LIBEXT}"
173
320
  end
174
321
  end
175
322
 
176
- def preserving_globals
177
- values = [
178
- $arg_config,
179
- $CFLAGS, $CPPFLAGS,
180
- $LDFLAGS, $LIBPATH, $libs
181
- ].map(&:dup)
182
- yield
183
- ensure
184
- $arg_config,
185
- $CFLAGS, $CPPFLAGS,
186
- $LDFLAGS, $LIBPATH, $libs =
187
- values
188
- end
323
+ def have_libxml_headers?(version = nil)
324
+ source = if version.nil?
325
+ <<~SRC
326
+ #include <libxml/xmlversion.h>
327
+ SRC
328
+ else
329
+ version_int = format("%d%2.2d%2.2d", *version.split("."))
330
+ <<~SRC
331
+ #include <libxml/xmlversion.h>
332
+ #if LIBXML_VERSION < #{version_int}
333
+ # error libxml2 is older than #{version}
334
+ #endif
335
+ SRC
336
+ end
189
337
 
190
- def asplode(lib)
191
- abort "-----\n#{lib} is missing. Please locate mkmf.log to investigate how it is failing.\n-----"
338
+ try_cpp(source)
192
339
  end
193
340
 
194
- def have_iconv?(using = nil)
341
+ def try_link_iconv(using = nil)
195
342
  checking_for(using ? "iconv using #{using}" : 'iconv') do
196
343
  ['', '-liconv'].any? do |opt|
197
344
  preserving_globals do
198
345
  yield if block_given?
199
346
 
200
- try_link(<<-'SRC', opt)
201
- #include <stdlib.h>
202
- #include <iconv.h>
203
-
204
- int main(void)
205
- {
206
- iconv_t cd = iconv_open("", "");
207
- iconv(cd, NULL, NULL, NULL, NULL);
208
- return EXIT_SUCCESS;
209
- }
347
+ try_link(<<~'SRC', opt)
348
+ #include <stdlib.h>
349
+ #include <iconv.h>
350
+ int main(void)
351
+ {
352
+ iconv_t cd = iconv_open("", "");
353
+ iconv(cd, NULL, NULL, NULL, NULL);
354
+ return EXIT_SUCCESS;
355
+ }
210
356
  SRC
211
357
  end
212
358
  end
@@ -214,31 +360,29 @@ int main(void)
214
360
  end
215
361
 
216
362
  def iconv_configure_flags
217
- # If --with-iconv-dir or --with-opt-dir is given, it should be
218
- # the first priority
219
- %w[iconv opt].each do |name|
220
- if (config = preserving_globals { dir_config(name) }).any? &&
221
- have_iconv?("--with-#{name}-* flags") { dir_config(name) }
222
- idirs, ldirs = config.map do |dirs|
223
- Array(dirs).flat_map do |dir|
224
- dir.split(File::PATH_SEPARATOR)
225
- end if dirs
226
- end
227
-
228
- return [
229
- '--with-iconv=yes',
230
- *("CPPFLAGS=#{idirs.map { |dir| '-I' + dir }.join(' ')}" if idirs),
231
- *("LDFLAGS=#{ldirs.map { |dir| '-L' + dir }.join(' ')}" if ldirs),
232
- ]
363
+ # give --with-iconv-dir and --with-opt-dir first priority
364
+ ["iconv", "opt"].each do |target|
365
+ config = preserving_globals { dir_config(target) }
366
+ next unless config.any? && try_link_iconv("--with-#{target}-* flags") { dir_config(target) }
367
+ idirs, ldirs = config.map do |dirs|
368
+ Array(dirs).flat_map do |dir|
369
+ dir.split(File::PATH_SEPARATOR)
370
+ end if dirs
233
371
  end
372
+
373
+ return [
374
+ '--with-iconv=yes',
375
+ *("CPPFLAGS=#{idirs.map { |dir| '-I' + dir }.join(' ')}" if idirs),
376
+ *("LDFLAGS=#{ldirs.map { |dir| '-L' + dir }.join(' ')}" if ldirs),
377
+ ]
234
378
  end
235
379
 
236
- if have_iconv?
380
+ if try_link_iconv
237
381
  return ['--with-iconv=yes']
238
382
  end
239
383
 
240
- if (config = preserving_globals { package_config('libiconv') }) &&
241
- have_iconv?('pkg-config libiconv') { package_config('libiconv') }
384
+ config = preserving_globals { have_package_configuration('libiconv') }
385
+ if config && try_link_iconv('pkg-config libiconv') { have_package_configuration('libiconv') }
242
386
  cflags, ldflags, libs = config
243
387
 
244
388
  return [
@@ -249,32 +393,31 @@ def iconv_configure_flags
249
393
  ]
250
394
  end
251
395
 
252
- asplode "libiconv"
396
+ abort_could_not_find_library("libiconv")
253
397
  end
254
398
 
255
- # When using rake-compiler-dock on Windows, the underlying Virtualbox shared
256
- # folders don't support symlinks, but libiconv expects it for a build on
257
- # Linux. We work around this limitation by using the temp dir for cooking.
258
- def chdir_for_build
259
- build_dir = ENV['RCD_HOST_RUBY_PLATFORM'].to_s =~ /mingw|mswin|cygwin/ ? '/tmp' : '.'
260
- Dir.chdir(build_dir) do
261
- yield
399
+ def process_recipe(name, version, static_p, cross_p)
400
+ require 'rubygems'
401
+ gem('mini_portile2', REQUIRED_MINI_PORTILE_VERSION)
402
+ require 'mini_portile2'
403
+ message("Using mini_portile version #{MiniPortile::VERSION}\n")
404
+
405
+ if name != "libxml2" && name != "libxslt"
406
+ OTHER_LIBRARY_VERSIONS[name] = version
262
407
  end
263
- end
264
408
 
265
- def process_recipe(name, version, static_p, cross_p)
266
409
  MiniPortile.new(name, version).tap do |recipe|
267
- recipe.target = File.join(ROOT, "ports")
410
+ recipe.target = File.join(PACKAGE_ROOT_DIR, "ports")
268
411
  # Prefer host_alias over host in order to use i586-mingw32msvc as
269
412
  # correct compiler prefix for cross build, but use host if not set.
270
413
  recipe.host = RbConfig::CONFIG["host_alias"].empty? ? RbConfig::CONFIG["host"] : RbConfig::CONFIG["host_alias"]
271
- recipe.patch_files = Dir[File.join(ROOT, "patches", name, "*.patch")].sort
272
- recipe.configure_options << "--libdir=#{File.join(recipe.path, "lib")}"
414
+ recipe.patch_files = Dir[File.join(PACKAGE_ROOT_DIR, "patches", name, "*.patch")].sort
415
+ recipe.configure_options << "--libdir=#{File.join(recipe.path, 'lib')}"
273
416
 
274
417
  yield recipe
275
418
 
276
419
  env = Hash.new do |hash, key|
277
- hash[key] = "#{ENV[key]}" # (ENV[key].dup rescue '')
420
+ hash[key] = (ENV[key]).to_s
278
421
  end
279
422
 
280
423
  recipe.configure_options.flatten!
@@ -282,7 +425,11 @@ def process_recipe(name, version, static_p, cross_p)
282
425
  recipe.configure_options.delete_if do |option|
283
426
  case option
284
427
  when /\A(\w+)=(.*)\z/
285
- env[$1] = $2
428
+ env[Regexp.last_match(1)] = if env.key?(Regexp.last_match(1))
429
+ concat_flags(env[Regexp.last_match(1)], Regexp.last_match(2))
430
+ else
431
+ Regexp.last_match(2)
432
+ end
286
433
  true
287
434
  else
288
435
  false
@@ -294,7 +441,7 @@ def process_recipe(name, version, static_p, cross_p)
294
441
  "--disable-shared",
295
442
  "--enable-static",
296
443
  ]
297
- env['CFLAGS'] = "-fPIC #{env['CFLAGS']}"
444
+ env["CFLAGS"] = concat_flags(env["CFLAGS"], "-fPIC")
298
445
  else
299
446
  recipe.configure_options += [
300
447
  "--enable-shared",
@@ -312,192 +459,207 @@ def process_recipe(name, version, static_p, cross_p)
312
459
  if RbConfig::CONFIG['target_cpu'] == 'universal'
313
460
  %w[CFLAGS LDFLAGS].each do |key|
314
461
  unless env[key].include?('-arch')
315
- env[key] += ' ' + RbConfig::CONFIG['ARCH_FLAG']
462
+ env[key] = concat_flags(env[key], RbConfig::CONFIG['ARCH_FLAG'])
316
463
  end
317
464
  end
318
465
  end
319
466
 
320
467
  recipe.configure_options += env.map do |key, value|
321
- "#{key}=#{value}"
468
+ "#{key}=#{value.strip}"
322
469
  end
323
470
 
324
- message <<-"EOS"
325
- ************************************************************************
326
- IMPORTANT NOTICE:
327
-
328
- Building Nokogiri with a packaged version of #{name}-#{version}#{'.' if recipe.patch_files.empty?}
329
- EOS
471
+ checkpoint = "#{recipe.target}/#{recipe.name}-#{recipe.version}-#{recipe.host}.installed"
472
+ if File.exist?(checkpoint)
473
+ message("Building Nokogiri with a packaged version of #{name}-#{version}.\n")
474
+ else
475
+ message(<<~EOM)
476
+ ---------- IMPORTANT NOTICE ----------
477
+ Building Nokogiri with a packaged version of #{name}-#{version}.
478
+ Configuration options: #{recipe.configure_options.shelljoin}
479
+ EOM
330
480
 
331
- unless recipe.patch_files.empty?
332
- message "with the following patches applied:\n"
481
+ unless recipe.patch_files.empty?
482
+ message("The following patches are being applied:\n")
333
483
 
334
- recipe.patch_files.each do |patch|
335
- message "\t- %s\n" % File.basename(patch)
484
+ recipe.patch_files.each do |patch|
485
+ message(" - %s\n" % File.basename(patch))
486
+ end
336
487
  end
337
- end
338
-
339
- message <<-"EOS"
340
488
 
341
- Team Nokogiri will keep on doing their best to provide security
342
- updates in a timely manner, but if this is a concern for you and want
343
- to use the system library instead; abort this installation process and
344
- reinstall nokogiri as follows:
489
+ message(<<~EOM)
345
490
 
346
- gem install nokogiri -- --use-system-libraries
347
- [--with-xml2-config=/path/to/xml2-config]
348
- [--with-xslt-config=/path/to/xslt-config]
491
+ The Nokogiri maintainers intend to provide timely security updates, but if
492
+ this is a concern for you and want to use your OS/distro system library
493
+ instead, then abort this installation process and install nokogiri as
494
+ instructed at:
349
495
 
350
- If you are using Bundler, tell it to use the option:
496
+ https://nokogiri.org/tutorials/installing_nokogiri.html#installing-using-standard-system-libraries
351
497
 
352
- bundle config build.nokogiri --use-system-libraries
353
- bundle install
354
- EOS
498
+ EOM
355
499
 
356
- message <<-"EOS" if name == 'libxml2'
500
+ message(<<~EOM) if name == 'libxml2'
501
+ Note, however, that nokogiri cannot guarantee compatiblity with every
502
+ version of libxml2 that may be provided by OS/package vendors.
357
503
 
358
- Note, however, that nokogiri is not fully compatible with arbitrary
359
- versions of libxml2 provided by OS/package vendors.
360
- EOS
504
+ EOM
361
505
 
362
- message <<-"EOS"
363
- ************************************************************************
364
- EOS
365
-
366
- checkpoint = "#{recipe.target}/#{recipe.name}-#{recipe.version}-#{recipe.host}.installed"
367
- unless File.exist?(checkpoint)
368
506
  chdir_for_build do
369
507
  recipe.cook
370
508
  end
371
- FileUtils.touch checkpoint
509
+ FileUtils.touch(checkpoint)
372
510
  end
373
511
  recipe.activate
374
512
  end
375
513
  end
376
514
 
377
- def lib_a(ldflag)
378
- case ldflag
379
- when /\A-l(.+)/
380
- "lib#{$1}.#{$LIBEXT}"
515
+ def copy_packaged_libraries_headers(to_path:, from_recipes:)
516
+ FileUtils.rm_rf(to_path, secure: true)
517
+ FileUtils.mkdir(to_path)
518
+ from_recipes.each do |recipe|
519
+ FileUtils.cp_r(Dir[File.join(recipe.path, 'include/*')], to_path)
381
520
  end
382
521
  end
383
522
 
384
- def using_system_libraries?
385
- arg_config('--use-system-libraries', !!ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'])
523
+ def do_help
524
+ print(NOKOGIRI_HELP_MESSAGE)
525
+ exit!(0)
386
526
  end
387
527
 
388
- #
389
- # main
390
- #
528
+ def do_clean
529
+ root = Pathname(PACKAGE_ROOT_DIR)
530
+ pwd = Pathname(Dir.pwd)
391
531
 
392
- case
393
- when arg_config('--help')
394
- do_help
395
- when arg_config('--clean')
396
- do_clean
397
- end
532
+ # Skip if this is a development work tree
533
+ unless (root + '.git').exist?
534
+ message("Cleaning files only used during build.\n")
535
+
536
+ # (root + 'tmp') cannot be removed at this stage because
537
+ # nokogiri.so is yet to be copied to lib.
538
+
539
+ # clean the ports build directory
540
+ Pathname.glob(pwd.join('tmp', '*', 'ports')) do |dir|
541
+ FileUtils.rm_rf(dir, verbose: true)
542
+ end
543
+
544
+ if config_static?
545
+ # ports installation can be safely removed if statically linked.
546
+ FileUtils.rm_rf(root + 'ports', verbose: true)
547
+ else
548
+ FileUtils.rm_rf(root + 'ports' + 'archives', verbose: true)
549
+ end
550
+ end
398
551
 
399
- if darwin?
400
- ENV['CFLAGS'] = "#{ENV['CFLAGS']} -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libxml2"
552
+ exit!(0)
401
553
  end
402
554
 
403
- if openbsd? && !using_system_libraries?
404
- if `#{ENV['CC'] || '/usr/bin/cc'} -v 2>&1` !~ /clang/
405
- ENV['CC'] ||= find_executable('egcc') or
406
- abort "Please install gcc 4.9+ from ports using `pkg_add -v gcc`"
555
+ #
556
+ # main
557
+ #
558
+ do_help if arg_config('--help')
559
+ do_clean if arg_config('--clean')
560
+
561
+ if openbsd? && !config_system_libraries?
562
+ if %x(#{ENV['CC'] || '/usr/bin/cc'} -v 2>&1) !~ /clang/
563
+ (ENV['CC'] ||= find_executable('egcc')) ||
564
+ abort("Please install gcc 4.9+ from ports using `pkg_add -v gcc`")
407
565
  end
408
- ENV['CFLAGS'] = "#{ENV['CFLAGS']} -I /usr/local/include"
566
+ append_cppflags "-I/usr/local/include"
409
567
  end
410
568
 
411
569
  if ENV['CC']
412
570
  RbConfig::CONFIG['CC'] = RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC']
413
571
  end
572
+
414
573
  # use same c compiler for libxml and libxslt
415
574
  ENV['CC'] = RbConfig::CONFIG['CC']
416
575
 
417
- $LIBS << " #{ENV["LIBS"]}"
418
-
419
- # Read CFLAGS from ENV and make sure compiling works.
420
- add_cflags(ENV["CFLAGS"])
421
-
422
- if windows?
423
- $CFLAGS << " -DXP_WIN -DXP_WIN32 -DUSE_INCLUDED_VASPRINTF"
576
+ if arg_config('--prevent-strip')
577
+ old_cflags = $CFLAGS.split.join(" ")
578
+ old_ldflags = $LDFLAGS.split.join(" ")
579
+ old_dldflags = $DLDFLAGS.split.join(" ")
580
+ $CFLAGS = $CFLAGS.split.reject { |flag| flag == "-s" }.join(" ")
581
+ $LDFLAGS = $LDFLAGS.split.reject { |flag| flag == "-s" }.join(" ")
582
+ $DLDFLAGS = $DLDFLAGS.split.reject { |flag| flag == "-s" }.join(" ")
583
+ puts "Prevent stripping by removing '-s' from $CFLAGS" if old_cflags != $CFLAGS
584
+ puts "Prevent stripping by removing '-s' from $LDFLAGS" if old_ldflags != $LDFLAGS
585
+ puts "Prevent stripping by removing '-s' from $DLDFLAGS" if old_dldflags != $DLDFLAGS
424
586
  end
425
587
 
426
- if solaris? || aix?
427
- $CFLAGS << " -DUSE_INCLUDED_VASPRINTF"
428
- end
588
+ # adopt environment config
589
+ append_cflags(ENV["CFLAGS"].split) unless ENV["CFLAGS"].nil?
590
+ append_cppflags(ENV["CPPFLAGS"].split) unless ENV["CPPFLAGS"].nil?
591
+ append_ldflags(ENV["LDFLAGS"].split) unless ENV["LDFLAGS"].nil?
592
+ $LIBS = concat_flags($LIBS, ENV["LIBS"])
429
593
 
430
- if darwin?
431
- # Let Apple LLVM/clang 5.1 ignore unknown compiler flags
432
- add_cflags("-Wno-error=unused-command-line-argument-hard-error-in-future")
433
- end
594
+ # always include debugging information
595
+ append_cflags("-g")
434
596
 
435
- if nix?
436
- $CFLAGS << " -g -DXP_UNIX"
437
- end
597
+ # we use at least one inline function in the C extension
598
+ append_cflags("-Winline")
438
599
 
439
- if RUBY_PLATFORM =~ /mingw/i
440
- # Work around a character escaping bug in MSYS by passing an arbitrary
441
- # double quoted parameter to gcc. See https://sourceforge.net/p/mingw/bugs/2142
442
- $CPPFLAGS << ' "-Idummypath"'
443
- end
600
+ # good to have no matter what Ruby was compiled with
601
+ append_cflags("-Wmissing-noreturn")
444
602
 
445
- if RbConfig::CONFIG['CC'] =~ /gcc/
446
- $CFLAGS << " -O3" unless $CFLAGS[/-O\d/]
447
- $CFLAGS << " -Wall -Wcast-qual -Wwrite-strings -Wmissing-noreturn -Winline"
448
- end
603
+ # handle clang variations, see #1101
604
+ append_cflags("-Wno-error=unused-command-line-argument-hard-error-in-future") if darwin?
449
605
 
450
- case
451
- when using_system_libraries?
452
- message "Building nokogiri using system libraries.\n"
606
+ # these tend to be noisy, but on occasion useful during development
607
+ # append_cflags(["-Wcast-qual", "-Wwrite-strings"])
453
608
 
454
- dir_config('zlib')
455
-
456
- # Using system libraries means we rely on the system libxml2 with
457
- # regard to the iconv support.
609
+ # Add SDK-specific include path for macOS and brew versions before v2.2.12 (2020-04-08) [#1851, #1801]
610
+ macos_mojave_sdk_include_path = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libxml2"
611
+ if config_system_libraries? && darwin? && Dir.exist?(macos_mojave_sdk_include_path)
612
+ append_cppflags("-I#{macos_mojave_sdk_include_path}")
613
+ end
458
614
 
459
- dir_config('xml2').any? or package_config('libxml-2.0')
460
- dir_config('xslt').any? or package_config('libxslt')
461
- dir_config('exslt').any? or package_config('libexslt')
615
+ # Work around a character escaping bug in MSYS by passing an arbitrary double-quoted parameter to gcc.
616
+ # See https://sourceforge.net/p/mingw/bugs/2142
617
+ append_cppflags(' "-Idummypath"') if windows?
462
618
 
463
- check_libxml_version or abort "ERROR: cannot discover where libxml2 is located on your system. please make sure `pkg-config` is installed."
464
- check_libxml_version("2.6.21") or abort "ERROR: libxml2 version 2.6.21 or later is required!"
465
- check_libxml_version("2.9.3") or warn "WARNING: libxml2 version 2.9.3 or later is highly recommended, but proceeding anyway."
619
+ if config_system_libraries?
620
+ message "Building nokogiri using system libraries.\n"
621
+ ensure_package_configuration(opt: "zlib", pc: "zlib", lib: "z",
622
+ headers: "zlib.h", func: "gzdopen")
623
+ ensure_package_configuration(opt: "xml2", pc: "libxml-2.0", lib: "xml2",
624
+ headers: "libxml/parser.h", func: "xmlParseDoc")
625
+ ensure_package_configuration(opt: "xslt", pc: "libxslt", lib: "xslt",
626
+ headers: "libxslt/xslt.h", func: "xsltParseStylesheetDoc")
627
+ ensure_package_configuration(opt: "exslt", pc: "libexslt", lib: "exslt",
628
+ headers: "libexslt/exslt.h", func: "exsltFuncRegister")
629
+
630
+ have_libxml_headers?(REQUIRED_LIBXML_VERSION) ||
631
+ abort("ERROR: libxml2 version #{REQUIRED_LIBXML_VERSION} or later is required!")
632
+ have_libxml_headers?(RECOMMENDED_LIBXML_VERSION) ||
633
+ warn("WARNING: libxml2 version #{RECOMMENDED_LIBXML_VERSION} or later is highly recommended, but proceeding anyway.")
466
634
 
467
635
  else
468
636
  message "Building nokogiri using packaged libraries.\n"
469
637
 
470
- # The gem version constraint in the Rakefile is not respected at install time.
471
- # Keep this version in sync with the one in the Rakefile !
472
- require 'rubygems'
473
- gem 'mini_portile2', '~> 2.5.0'
474
- require 'mini_portile2'
475
- message "Using mini_portile version #{MiniPortile::VERSION}\n"
638
+ static_p = config_static?
639
+ message "Static linking is #{static_p ? 'enabled' : 'disabled'}.\n"
476
640
 
477
- require 'yaml'
641
+ cross_build_p = config_cross_build?
642
+ message "Cross build is #{cross_build_p ? 'enabled' : 'disabled'}.\n"
478
643
 
479
- static_p = enable_config('static', true) or
480
- message "Static linking is disabled.\n"
644
+ require 'yaml'
645
+ dependencies = YAML.load_file(File.join(PACKAGE_ROOT_DIR, "dependencies.yml"))
481
646
 
482
647
  dir_config('zlib')
483
648
 
484
- dependencies = YAML.load_file(File.join(ROOT, "dependencies.yml"))
485
-
486
- cross_build_p = enable_config("cross-build")
487
649
  if cross_build_p || windows?
488
650
  zlib_recipe = process_recipe("zlib", dependencies["zlib"]["version"], static_p, cross_build_p) do |recipe|
489
651
  recipe.files = [{
490
- url: "http://zlib.net/fossils/#{recipe.name}-#{recipe.version}.tar.gz",
491
- sha256: dependencies["zlib"]["sha256"]
492
- }]
652
+ url: "http://zlib.net/fossils/#{recipe.name}-#{recipe.version}.tar.gz",
653
+ sha256: dependencies["zlib"]["sha256"],
654
+ }]
493
655
  if windows?
494
656
  class << recipe
495
657
  attr_accessor :cross_build_p
496
658
 
497
659
  def configure
498
- Dir.chdir work_path do
499
- mk = File.read 'win32/Makefile.gcc'
500
- File.open 'win32/Makefile.gcc', 'wb' do |f|
660
+ Dir.chdir(work_path) do
661
+ mk = File.read('win32/Makefile.gcc')
662
+ File.open('win32/Makefile.gcc', 'wb') do |f|
501
663
  f.puts "BINARY_PATH = #{path}/bin"
502
664
  f.puts "LIBRARY_PATH = #{path}/lib"
503
665
  f.puts "INCLUDE_PATH = #{path}/include"
@@ -508,119 +670,155 @@ else
508
670
  end
509
671
 
510
672
  def configured?
511
- Dir.chdir work_path do
512
- !! (File.read('win32/Makefile.gcc') =~ /^BINARY_PATH/)
673
+ Dir.chdir(work_path) do
674
+ !!(File.read('win32/Makefile.gcc') =~ /^BINARY_PATH/)
513
675
  end
514
676
  end
515
677
 
516
678
  def compile
517
- execute "compile", "make -f win32/Makefile.gcc"
679
+ execute("compile", "make -f win32/Makefile.gcc")
518
680
  end
519
681
 
520
682
  def install
521
- execute "install", "make -f win32/Makefile.gcc install"
683
+ execute("install", "make -f win32/Makefile.gcc install")
522
684
  end
523
685
  end
524
686
  recipe.cross_build_p = cross_build_p
525
687
  else
526
688
  class << recipe
527
689
  def configure
528
- execute "configure", ["env", "CHOST=#{host}", "CFLAGS=-fPIC #{ENV['CFLAGS']}", "./configure", "--static", configure_prefix]
690
+ cflags = concat_flags(ENV["CFLAGS"], "-fPIC", "-g")
691
+ execute("configure",
692
+ ["env", "CHOST=#{host}", "CFLAGS=#{cflags}", "./configure", "--static", configure_prefix])
693
+ end
694
+
695
+ def compile
696
+ if host =~ /darwin/
697
+ execute("compile", "make AR=#{host}-libtool")
698
+ else
699
+ super
700
+ end
529
701
  end
530
702
  end
531
703
  end
532
704
  end
533
705
 
534
706
  unless nix?
535
- libiconv_recipe = process_recipe("libiconv", dependencies["libiconv"]["version"], static_p, cross_build_p) do |recipe|
707
+ libiconv_recipe = process_recipe("libiconv", dependencies["libiconv"]["version"], static_p,
708
+ cross_build_p) do |recipe|
536
709
  recipe.files = [{
537
- url: "http://ftp.gnu.org/pub/gnu/libiconv/#{recipe.name}-#{recipe.version}.tar.gz",
538
- sha256: dependencies["libiconv"]["sha256"]
539
- }]
710
+ url: "http://ftp.gnu.org/pub/gnu/libiconv/#{recipe.name}-#{recipe.version}.tar.gz",
711
+ sha256: dependencies["libiconv"]["sha256"],
712
+ }]
713
+
714
+ cflags = concat_flags(ENV["CFLAGS"], "-O2", "-U_FORTIFY_SOURCE", "-g")
715
+
540
716
  recipe.configure_options += [
541
717
  "CPPFLAGS=-Wall",
542
- "CFLAGS=-O2 -g",
543
- "CXXFLAGS=-O2 -g",
544
- "LDFLAGS="
718
+ "CFLAGS=#{cflags}",
719
+ "CXXFLAGS=#{cflags}",
720
+ "LDFLAGS=",
545
721
  ]
546
722
  end
547
723
  end
548
- else
549
- if darwin? && !have_header('iconv.h')
550
- abort <<'EOM'.chomp
551
- -----
552
- The file "iconv.h" is missing in your build environment,
553
- which means you haven't installed Xcode Command Line Tools properly.
554
-
555
- To install Command Line Tools, try running `xcode-select --install` on
556
- terminal and follow the instructions. If it fails, open Xcode.app,
557
- select from the menu "Xcode" - "Open Developer Tool" - "More Developer
558
- Tools" to open the developer site, download the installer for your OS
559
- version and run it.
560
- -----
561
- EOM
562
- end
724
+ elsif darwin? && !have_header('iconv.h')
725
+ abort(<<~EOM.chomp)
726
+ -----
727
+ The file "iconv.h" is missing in your build environment,
728
+ which means you haven't installed Xcode Command Line Tools properly.
729
+
730
+ To install Command Line Tools, try running `xcode-select --install` on
731
+ terminal and follow the instructions. If it fails, open Xcode.app,
732
+ select from the menu "Xcode" - "Open Developer Tool" - "More Developer
733
+ Tools" to open the developer site, download the installer for your OS
734
+ version and run it.
735
+ -----
736
+ EOM
563
737
  end
564
738
 
565
739
  unless windows?
566
- preserving_globals {
567
- have_library('z', 'gzdopen', 'zlib.h')
568
- } or abort 'zlib is missing; necessary for building libxml2'
740
+ preserving_globals { local_have_library('z', 'gzdopen', 'zlib.h') } ||
741
+ abort('zlib is missing; necessary for building libxml2')
569
742
  end
570
743
 
571
744
  libxml2_recipe = process_recipe("libxml2", dependencies["libxml2"]["version"], static_p, cross_build_p) do |recipe|
572
745
  recipe.files = [{
573
- url: "http://xmlsoft.org/sources/#{recipe.name}-#{recipe.version}.tar.gz",
574
- sha256: dependencies["libxml2"]["sha256"]
575
- }]
746
+ url: "http://xmlsoft.org/sources/#{recipe.name}-#{recipe.version}.tar.gz",
747
+ sha256: dependencies["libxml2"]["sha256"],
748
+ }]
749
+
750
+ cflags = concat_flags(ENV["CFLAGS"], "-O2", "-U_FORTIFY_SOURCE", "-g")
751
+
752
+ if zlib_recipe
753
+ recipe.configure_options << "--with-zlib=#{zlib_recipe.path}"
754
+ cflags = concat_flags(cflags, "-I#{zlib_recipe.path}/include")
755
+ end
756
+
757
+ if libiconv_recipe
758
+ recipe.configure_options << "--with-iconv=#{libiconv_recipe.path}"
759
+ else
760
+ recipe.configure_options += iconv_configure_flags
761
+ end
762
+
763
+ if darwin? && !cross_build_p
764
+ recipe.configure_options += ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"]
765
+ end
766
+
767
+ if windows?
768
+ cflags = concat_flags(cflags, "-ULIBXML_STATIC", "-DIN_LIBXML")
769
+ end
770
+
576
771
  recipe.configure_options += [
577
772
  "--without-python",
578
773
  "--without-readline",
579
- *(zlib_recipe ? ["--with-zlib=#{zlib_recipe.path}", "CFLAGS=-I#{zlib_recipe.path}/include"] : []),
580
- *(libiconv_recipe ? "--with-iconv=#{libiconv_recipe.path}" : iconv_configure_flags),
581
774
  "--with-c14n",
582
775
  "--with-debug",
583
776
  "--with-threads",
584
- *(darwin? ? ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"] : "")
777
+ "CFLAGS=#{cflags}",
585
778
  ]
586
779
  end
587
780
 
588
781
  libxslt_recipe = process_recipe("libxslt", dependencies["libxslt"]["version"], static_p, cross_build_p) do |recipe|
589
782
  recipe.files = [{
590
- url: "http://xmlsoft.org/sources/#{recipe.name}-#{recipe.version}.tar.gz",
591
- sha256: dependencies["libxslt"]["sha256"]
592
- }]
783
+ url: "http://xmlsoft.org/sources/#{recipe.name}-#{recipe.version}.tar.gz",
784
+ sha256: dependencies["libxslt"]["sha256"],
785
+ }]
786
+
787
+ cflags = concat_flags(ENV["CFLAGS"], "-O2", "-U_FORTIFY_SOURCE", "-g")
788
+
789
+ if darwin? && !cross_build_p
790
+ recipe.configure_options += ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"]
791
+ end
792
+
593
793
  recipe.configure_options += [
594
794
  "--without-python",
595
795
  "--without-crypto",
596
796
  "--with-debug",
597
797
  "--with-libxml-prefix=#{sh_export_path(libxml2_recipe.path)}",
598
- *(darwin? ? ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"] : "")
798
+ "CFLAGS=#{cflags}",
599
799
  ]
600
800
  end
601
801
 
602
- $CFLAGS << ' ' << '-DNOKOGIRI_USE_PACKAGED_LIBRARIES'
802
+ append_cppflags("-DNOKOGIRI_PACKAGED_LIBRARIES")
803
+ append_cppflags("-DNOKOGIRI_PRECOMPILED_LIBRARIES") if cross_build_p
804
+
603
805
  $LIBPATH = ["#{zlib_recipe.path}/lib"] | $LIBPATH if zlib_recipe
604
806
  $LIBPATH = ["#{libiconv_recipe.path}/lib"] | $LIBPATH if libiconv_recipe
605
807
 
606
- have_lzma = preserving_globals {
607
- have_library('lzma')
608
- }
609
-
610
808
  $libs = $libs.shellsplit.tap do |libs|
611
809
  [libxml2_recipe, libxslt_recipe].each do |recipe|
612
810
  libname = recipe.name[/\Alib(.+)\z/, 1]
613
811
  File.join(recipe.path, "bin", "#{libname}-config").tap do |config|
614
812
  # call config scripts explicit with 'sh' for compat with Windows
615
- $CPPFLAGS = `sh #{config} --cflags`.strip << ' ' << $CPPFLAGS
616
- `sh #{config} --libs`.strip.shellsplit.each do |arg|
813
+ $CPPFLAGS = %x(sh #{config} --cflags).strip << ' ' << $CPPFLAGS
814
+ %x(sh #{config} --libs).strip.shellsplit.each do |arg|
617
815
  case arg
618
816
  when /\A-L(.+)\z/
619
817
  # Prioritize ports' directories
620
- if $1.start_with?(ROOT + '/')
621
- $LIBPATH = [$1] | $LIBPATH
818
+ $LIBPATH = if Regexp.last_match(1).start_with?(PACKAGE_ROOT_DIR + '/')
819
+ [Regexp.last_match(1)] | $LIBPATH
622
820
  else
623
- $LIBPATH = $LIBPATH | [$1]
821
+ $LIBPATH | [Regexp.last_match(1)]
624
822
  end
625
823
  when /\A-l./
626
824
  libs.unshift(arg)
@@ -630,14 +828,14 @@ EOM
630
828
  end
631
829
  end
632
830
 
633
- # Defining a macro that expands to a C string; double quotes are significant.
634
- $CPPFLAGS << ' ' << "-DNOKOGIRI_#{recipe.name.upcase}_PATCHES=\"#{recipe.patch_files.map { |path| File.basename(path) }.join(' ')}\"".inspect
831
+ patches_string = recipe.patch_files.map { |path| File.basename(path) }.join(' ')
832
+ append_cppflags(%[-DNOKOGIRI_#{recipe.name.upcase}_PATCHES="\\\"#{patches_string}\\\""])
635
833
 
636
834
  case libname
637
835
  when 'xml2'
638
836
  # xslt-config --libs or pkg-config libxslt --libs does not include
639
837
  # -llzma, so we need to add it manually when linking statically.
640
- if static_p && have_lzma
838
+ if static_p && preserving_globals { local_have_library('lzma') }
641
839
  # Add it at the end; GH #988
642
840
  libs << '-llzma'
643
841
  end
@@ -653,47 +851,56 @@ EOM
653
851
  $libs = $libs.shellsplit.map do |arg|
654
852
  case arg
655
853
  when '-lxml2'
656
- File.join(libxml2_recipe.path, 'lib', lib_a(arg))
854
+ File.join(libxml2_recipe.path, 'lib', libflag_to_filename(arg))
657
855
  when '-lxslt', '-lexslt'
658
- File.join(libxslt_recipe.path, 'lib', lib_a(arg))
856
+ File.join(libxslt_recipe.path, 'lib', libflag_to_filename(arg))
659
857
  else
660
858
  arg
661
859
  end
662
860
  end.shelljoin
663
861
  end
664
- end
665
862
 
666
- {
667
- "xml2" => ['xmlParseDoc', 'libxml/parser.h'],
668
- "xslt" => ['xsltParseStylesheetDoc', 'libxslt/xslt.h'],
669
- "exslt" => ['exsltFuncRegister', 'libexslt/exslt.h'],
670
- }.each do |lib, (func, header)|
671
- have_func(func, header) ||
672
- have_library(lib, func, header) ||
673
- have_library("lib#{lib}", func, header) or
674
- asplode("lib#{lib}")
863
+ ensure_func("xmlParseDoc", "libxml/parser.h")
864
+ ensure_func("xsltParseStylesheetDoc", "libxslt/xslt.h")
865
+ ensure_func("exsltFuncRegister", "libexslt/exslt.h")
675
866
  end
676
867
 
677
- have_func('xmlHasFeature') or abort "xmlHasFeature() is missing."
678
- have_func('xmlFirstElementChild')
679
- have_func('xmlRelaxNGSetParserStructuredErrors')
680
- have_func('xmlRelaxNGSetParserStructuredErrors')
681
- have_func('xmlRelaxNGSetValidStructuredErrors')
682
- have_func('xmlSchemaSetValidStructuredErrors')
683
- have_func('xmlSchemaSetParserStructuredErrors')
868
+ have_func('xmlHasFeature') || abort("xmlHasFeature() is missing.") # introduced in libxml 2.6.21
869
+ have_func('xmlFirstElementChild') # introduced in libxml 2.7.3
870
+ have_func('xmlRelaxNGSetParserStructuredErrors') # introduced in libxml 2.6.24
871
+ have_func('xmlRelaxNGSetValidStructuredErrors') # introduced in libxml 2.6.21
872
+ have_func('xmlSchemaSetValidStructuredErrors') # introduced in libxml 2.6.23
873
+ have_func('xmlSchemaSetParserStructuredErrors') # introduced in libxml 2.6.23
874
+
875
+ have_func('vasprintf')
876
+
877
+ other_library_versions_string = OTHER_LIBRARY_VERSIONS.map { |k, v| [k, v].join(":") }.join(",")
878
+ append_cppflags(%[-DNOKOGIRI_OTHER_LIBRARY_VERSIONS="\\\"#{other_library_versions_string}\\\""])
879
+
880
+ unless config_system_libraries?
881
+ if cross_build_p
882
+ # When precompiling native gems, copy packaged libraries' headers to ext/nokogiri/include
883
+ # These are packaged up by the cross-compiling callback in the ExtensionTask
884
+ copy_packaged_libraries_headers(to_path: File.join(PACKAGE_ROOT_DIR, "ext/nokogiri/include"),
885
+ from_recipes: [libxml2_recipe, libxslt_recipe])
886
+ else
887
+ # When compiling during installation, install packaged libraries' header files into ext/nokogiri/include
888
+ copy_packaged_libraries_headers(to_path: "include",
889
+ from_recipes: [libxml2_recipe, libxslt_recipe])
890
+ $INSTALLFILES << ["include/**/*.h", "$(rubylibdir)"]
891
+ end
892
+ end
684
893
 
685
894
  create_makefile('nokogiri/nokogiri')
686
895
 
687
- if enable_config('clean', true)
896
+ if config_clean?
688
897
  # Do not clean if run in a development work tree.
689
898
  File.open('Makefile', 'at') do |mk|
690
- mk.print <<EOF
691
- all: clean-ports
899
+ mk.print(<<~EOF)
692
900
 
693
- clean-ports: $(DLLIB)
694
- -$(Q)$(RUBY) $(srcdir)/extconf.rb --clean --#{static_p ? 'enable' : 'disable'}-static
695
- EOF
901
+ all: clean-ports
902
+ clean-ports: $(DLLIB)
903
+ \t-$(Q)$(RUBY) $(srcdir)/extconf.rb --clean --#{static_p ? 'enable' : 'disable'}-static
904
+ EOF
696
905
  end
697
906
  end
698
-
699
- # :startdoc: