nokogiri 1.10.7 → 1.16.0

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 (224) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +42 -0
  3. data/LICENSE-DEPENDENCIES.md +1632 -1022
  4. data/LICENSE.md +1 -1
  5. data/README.md +188 -96
  6. data/bin/nokogiri +63 -50
  7. data/dependencies.yml +34 -66
  8. data/ext/nokogiri/depend +38 -358
  9. data/ext/nokogiri/extconf.rb +862 -421
  10. data/ext/nokogiri/gumbo.c +594 -0
  11. data/ext/nokogiri/html4_document.c +165 -0
  12. data/ext/nokogiri/html4_element_description.c +299 -0
  13. data/ext/nokogiri/html4_entity_lookup.c +37 -0
  14. data/ext/nokogiri/html4_sax_parser_context.c +108 -0
  15. data/ext/nokogiri/html4_sax_push_parser.c +95 -0
  16. data/ext/nokogiri/libxml2_backwards_compat.c +121 -0
  17. data/ext/nokogiri/nokogiri.c +251 -105
  18. data/ext/nokogiri/nokogiri.h +222 -90
  19. data/ext/nokogiri/test_global_handlers.c +40 -0
  20. data/ext/nokogiri/xml_attr.c +17 -17
  21. data/ext/nokogiri/xml_attribute_decl.c +22 -22
  22. data/ext/nokogiri/xml_cdata.c +39 -31
  23. data/ext/nokogiri/xml_comment.c +20 -27
  24. data/ext/nokogiri/xml_document.c +408 -243
  25. data/ext/nokogiri/xml_document_fragment.c +13 -17
  26. data/ext/nokogiri/xml_dtd.c +64 -58
  27. data/ext/nokogiri/xml_element_content.c +63 -55
  28. data/ext/nokogiri/xml_element_decl.c +31 -31
  29. data/ext/nokogiri/xml_encoding_handler.c +54 -21
  30. data/ext/nokogiri/xml_entity_decl.c +37 -35
  31. data/ext/nokogiri/xml_entity_reference.c +17 -19
  32. data/ext/nokogiri/xml_namespace.c +131 -61
  33. data/ext/nokogiri/xml_node.c +1343 -674
  34. data/ext/nokogiri/xml_node_set.c +246 -216
  35. data/ext/nokogiri/xml_processing_instruction.c +18 -20
  36. data/ext/nokogiri/xml_reader.c +305 -213
  37. data/ext/nokogiri/xml_relax_ng.c +87 -78
  38. data/ext/nokogiri/xml_sax_parser.c +149 -124
  39. data/ext/nokogiri/xml_sax_parser_context.c +149 -103
  40. data/ext/nokogiri/xml_sax_push_parser.c +65 -37
  41. data/ext/nokogiri/xml_schema.c +138 -82
  42. data/ext/nokogiri/xml_syntax_error.c +42 -21
  43. data/ext/nokogiri/xml_text.c +35 -26
  44. data/ext/nokogiri/xml_xpath_context.c +363 -178
  45. data/ext/nokogiri/xslt_stylesheet.c +335 -189
  46. data/gumbo-parser/CHANGES.md +63 -0
  47. data/gumbo-parser/Makefile +126 -0
  48. data/gumbo-parser/THANKS +27 -0
  49. data/gumbo-parser/src/Makefile +34 -0
  50. data/gumbo-parser/src/README.md +41 -0
  51. data/gumbo-parser/src/ascii.c +75 -0
  52. data/gumbo-parser/src/ascii.h +115 -0
  53. data/gumbo-parser/src/attribute.c +42 -0
  54. data/gumbo-parser/src/attribute.h +17 -0
  55. data/gumbo-parser/src/char_ref.c +22225 -0
  56. data/gumbo-parser/src/char_ref.h +29 -0
  57. data/gumbo-parser/src/char_ref.rl +2154 -0
  58. data/gumbo-parser/src/error.c +630 -0
  59. data/gumbo-parser/src/error.h +148 -0
  60. data/gumbo-parser/src/foreign_attrs.c +103 -0
  61. data/gumbo-parser/src/foreign_attrs.gperf +27 -0
  62. data/gumbo-parser/src/insertion_mode.h +33 -0
  63. data/gumbo-parser/src/macros.h +91 -0
  64. data/gumbo-parser/src/nokogiri_gumbo.h +944 -0
  65. data/gumbo-parser/src/parser.c +4891 -0
  66. data/gumbo-parser/src/parser.h +41 -0
  67. data/gumbo-parser/src/replacement.h +33 -0
  68. data/gumbo-parser/src/string_buffer.c +103 -0
  69. data/gumbo-parser/src/string_buffer.h +68 -0
  70. data/gumbo-parser/src/string_piece.c +48 -0
  71. data/gumbo-parser/src/svg_attrs.c +174 -0
  72. data/gumbo-parser/src/svg_attrs.gperf +77 -0
  73. data/gumbo-parser/src/svg_tags.c +137 -0
  74. data/gumbo-parser/src/svg_tags.gperf +55 -0
  75. data/gumbo-parser/src/tag.c +223 -0
  76. data/gumbo-parser/src/tag_lookup.c +382 -0
  77. data/gumbo-parser/src/tag_lookup.gperf +170 -0
  78. data/gumbo-parser/src/tag_lookup.h +13 -0
  79. data/gumbo-parser/src/token_buffer.c +79 -0
  80. data/gumbo-parser/src/token_buffer.h +71 -0
  81. data/gumbo-parser/src/token_type.h +17 -0
  82. data/gumbo-parser/src/tokenizer.c +3464 -0
  83. data/gumbo-parser/src/tokenizer.h +112 -0
  84. data/gumbo-parser/src/tokenizer_states.h +339 -0
  85. data/gumbo-parser/src/utf8.c +245 -0
  86. data/gumbo-parser/src/utf8.h +164 -0
  87. data/gumbo-parser/src/util.c +66 -0
  88. data/gumbo-parser/src/util.h +34 -0
  89. data/gumbo-parser/src/vector.c +111 -0
  90. data/gumbo-parser/src/vector.h +45 -0
  91. data/lib/nokogiri/class_resolver.rb +67 -0
  92. data/lib/nokogiri/css/node.rb +10 -8
  93. data/lib/nokogiri/css/parser.rb +397 -377
  94. data/lib/nokogiri/css/parser.y +250 -245
  95. data/lib/nokogiri/css/parser_extras.rb +54 -49
  96. data/lib/nokogiri/css/syntax_error.rb +3 -1
  97. data/lib/nokogiri/css/tokenizer.rb +5 -3
  98. data/lib/nokogiri/css/tokenizer.rex +3 -2
  99. data/lib/nokogiri/css/xpath_visitor.rb +205 -96
  100. data/lib/nokogiri/css.rb +56 -17
  101. data/lib/nokogiri/decorators/slop.rb +9 -7
  102. data/lib/nokogiri/encoding_handler.rb +57 -0
  103. data/lib/nokogiri/extension.rb +32 -0
  104. data/lib/nokogiri/gumbo.rb +15 -0
  105. data/lib/nokogiri/html.rb +38 -27
  106. data/lib/nokogiri/{html → html4}/builder.rb +4 -2
  107. data/lib/nokogiri/html4/document.rb +214 -0
  108. data/lib/nokogiri/html4/document_fragment.rb +54 -0
  109. data/lib/nokogiri/{html → html4}/element_description.rb +3 -1
  110. data/lib/nokogiri/html4/element_description_defaults.rb +2040 -0
  111. data/lib/nokogiri/html4/encoding_reader.rb +121 -0
  112. data/lib/nokogiri/{html → html4}/entity_lookup.rb +4 -2
  113. data/lib/nokogiri/{html → html4}/sax/parser.rb +17 -16
  114. data/lib/nokogiri/html4/sax/parser_context.rb +20 -0
  115. data/lib/nokogiri/{html → html4}/sax/push_parser.rb +12 -11
  116. data/lib/nokogiri/html4.rb +47 -0
  117. data/lib/nokogiri/html5/document.rb +168 -0
  118. data/lib/nokogiri/html5/document_fragment.rb +90 -0
  119. data/lib/nokogiri/html5/node.rb +103 -0
  120. data/lib/nokogiri/html5.rb +326 -0
  121. data/lib/nokogiri/jruby/dependencies.rb +3 -0
  122. data/lib/nokogiri/jruby/nokogiri_jars.rb +43 -0
  123. data/lib/nokogiri/syntax_error.rb +2 -0
  124. data/lib/nokogiri/version/constant.rb +6 -0
  125. data/lib/nokogiri/version/info.rb +224 -0
  126. data/lib/nokogiri/version.rb +3 -108
  127. data/lib/nokogiri/xml/attr.rb +55 -3
  128. data/lib/nokogiri/xml/attribute_decl.rb +6 -2
  129. data/lib/nokogiri/xml/builder.rb +75 -34
  130. data/lib/nokogiri/xml/cdata.rb +3 -1
  131. data/lib/nokogiri/xml/character_data.rb +2 -0
  132. data/lib/nokogiri/xml/document.rb +312 -127
  133. data/lib/nokogiri/xml/document_fragment.rb +93 -48
  134. data/lib/nokogiri/xml/dtd.rb +4 -2
  135. data/lib/nokogiri/xml/element_content.rb +12 -2
  136. data/lib/nokogiri/xml/element_decl.rb +6 -2
  137. data/lib/nokogiri/xml/entity_decl.rb +7 -3
  138. data/lib/nokogiri/xml/entity_reference.rb +2 -0
  139. data/lib/nokogiri/xml/namespace.rb +44 -0
  140. data/lib/nokogiri/xml/node/save_options.rb +23 -8
  141. data/lib/nokogiri/xml/node.rb +1096 -419
  142. data/lib/nokogiri/xml/node_set.rb +137 -61
  143. data/lib/nokogiri/xml/notation.rb +13 -0
  144. data/lib/nokogiri/xml/parse_options.rb +145 -52
  145. data/lib/nokogiri/xml/pp/character_data.rb +9 -6
  146. data/lib/nokogiri/xml/pp/node.rb +42 -30
  147. data/lib/nokogiri/xml/pp.rb +4 -2
  148. data/lib/nokogiri/xml/processing_instruction.rb +4 -1
  149. data/lib/nokogiri/xml/reader.rb +21 -28
  150. data/lib/nokogiri/xml/relax_ng.rb +8 -2
  151. data/lib/nokogiri/xml/sax/document.rb +45 -49
  152. data/lib/nokogiri/xml/sax/parser.rb +39 -36
  153. data/lib/nokogiri/xml/sax/parser_context.rb +8 -3
  154. data/lib/nokogiri/xml/sax/push_parser.rb +6 -5
  155. data/lib/nokogiri/xml/sax.rb +6 -4
  156. data/lib/nokogiri/xml/schema.rb +19 -9
  157. data/lib/nokogiri/xml/searchable.rb +120 -72
  158. data/lib/nokogiri/xml/syntax_error.rb +7 -5
  159. data/lib/nokogiri/xml/text.rb +2 -0
  160. data/lib/nokogiri/xml/xpath/syntax_error.rb +4 -2
  161. data/lib/nokogiri/xml/xpath.rb +15 -4
  162. data/lib/nokogiri/xml/xpath_context.rb +3 -3
  163. data/lib/nokogiri/xml.rb +39 -38
  164. data/lib/nokogiri/xslt/stylesheet.rb +3 -1
  165. data/lib/nokogiri/xslt.rb +101 -22
  166. data/lib/nokogiri.rb +59 -75
  167. data/lib/xsd/xmlparser/nokogiri.rb +29 -25
  168. data/patches/libxml2/{0004-libxml2.la-is-in-top_builddir.patch → 0003-libxml2.la-is-in-top_builddir.patch} +1 -1
  169. data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
  170. data/patches/libxml2/0010-update-config.guess-and-config.sub-for-libxml2.patch +224 -0
  171. data/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch +30 -0
  172. data/patches/libxslt/0001-update-config.guess-and-config.sub-for-libxslt.patch +224 -0
  173. data/ports/archives/libxml2-2.12.3.tar.xz +0 -0
  174. data/ports/archives/libxslt-1.1.39.tar.xz +0 -0
  175. metadata +121 -291
  176. data/ext/nokogiri/html_document.c +0 -170
  177. data/ext/nokogiri/html_document.h +0 -10
  178. data/ext/nokogiri/html_element_description.c +0 -279
  179. data/ext/nokogiri/html_element_description.h +0 -10
  180. data/ext/nokogiri/html_entity_lookup.c +0 -32
  181. data/ext/nokogiri/html_entity_lookup.h +0 -8
  182. data/ext/nokogiri/html_sax_parser_context.c +0 -116
  183. data/ext/nokogiri/html_sax_parser_context.h +0 -11
  184. data/ext/nokogiri/html_sax_push_parser.c +0 -87
  185. data/ext/nokogiri/html_sax_push_parser.h +0 -9
  186. data/ext/nokogiri/xml_attr.h +0 -9
  187. data/ext/nokogiri/xml_attribute_decl.h +0 -9
  188. data/ext/nokogiri/xml_cdata.h +0 -9
  189. data/ext/nokogiri/xml_comment.h +0 -9
  190. data/ext/nokogiri/xml_document.h +0 -23
  191. data/ext/nokogiri/xml_document_fragment.h +0 -10
  192. data/ext/nokogiri/xml_dtd.h +0 -10
  193. data/ext/nokogiri/xml_element_content.h +0 -10
  194. data/ext/nokogiri/xml_element_decl.h +0 -9
  195. data/ext/nokogiri/xml_encoding_handler.h +0 -8
  196. data/ext/nokogiri/xml_entity_decl.h +0 -10
  197. data/ext/nokogiri/xml_entity_reference.h +0 -9
  198. data/ext/nokogiri/xml_io.c +0 -61
  199. data/ext/nokogiri/xml_io.h +0 -11
  200. data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
  201. data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
  202. data/ext/nokogiri/xml_namespace.h +0 -14
  203. data/ext/nokogiri/xml_node.h +0 -13
  204. data/ext/nokogiri/xml_node_set.h +0 -12
  205. data/ext/nokogiri/xml_processing_instruction.h +0 -9
  206. data/ext/nokogiri/xml_reader.h +0 -10
  207. data/ext/nokogiri/xml_relax_ng.h +0 -9
  208. data/ext/nokogiri/xml_sax_parser.h +0 -39
  209. data/ext/nokogiri/xml_sax_parser_context.h +0 -10
  210. data/ext/nokogiri/xml_sax_push_parser.h +0 -9
  211. data/ext/nokogiri/xml_schema.h +0 -9
  212. data/ext/nokogiri/xml_syntax_error.h +0 -13
  213. data/ext/nokogiri/xml_text.h +0 -9
  214. data/ext/nokogiri/xml_xpath_context.h +0 -10
  215. data/ext/nokogiri/xslt_stylesheet.h +0 -14
  216. data/lib/nokogiri/html/document.rb +0 -335
  217. data/lib/nokogiri/html/document_fragment.rb +0 -49
  218. data/lib/nokogiri/html/element_description_defaults.rb +0 -671
  219. data/lib/nokogiri/html/sax/parser_context.rb +0 -16
  220. data/patches/libxml2/0001-Revert-Do-not-URI-escape-in-server-side-includes.patch +0 -78
  221. data/ports/archives/libxml2-2.9.10.tar.gz +0 -0
  222. data/ports/archives/libxslt-1.1.34.tar.gz +0 -0
  223. /data/patches/libxml2/{0002-Remove-script-macro-support.patch → 0001-Remove-script-macro-support.patch} +0 -0
  224. /data/patches/libxml2/{0003-Update-entities-to-remove-handling-of-ssi.patch → 0002-Update-entities-to-remove-handling-of-ssi.patch} +0 -0
@@ -1,208 +1,386 @@
1
- # :stopdoc:
2
- ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
1
+ # frozen_string_literal: true
3
2
 
4
- require 'mkmf'
3
+ # rubocop:disable Style/GlobalVars
5
4
 
6
- ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
5
+ ENV["RC_ARCHS"] = "" if RUBY_PLATFORM.include?("darwin")
6
+
7
+ require "mkmf"
8
+ require "rbconfig"
9
+ require "fileutils"
10
+ require "shellwords"
11
+ require "pathname"
12
+
13
+ # helpful constants
14
+ PACKAGE_ROOT_DIR = File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
15
+ REQUIRED_LIBXML_VERSION = "2.6.21"
16
+ RECOMMENDED_LIBXML_VERSION = "2.9.3"
17
+
18
+ REQUIRED_MINI_PORTILE_VERSION = "~> 2.8.2" # keep this version in sync with the one in the gemspec
19
+ REQUIRED_PKG_CONFIG_VERSION = "~> 1.1"
20
+
21
+ # Keep track of what versions of what libraries we build against
22
+ OTHER_LIBRARY_VERSIONS = {}
23
+
24
+ NOKOGIRI_HELP_MESSAGE = <<~HELP
25
+ USAGE: ruby #{$PROGRAM_NAME} [options]
26
+
27
+ Flags that are always valid:
28
+
29
+ --use-system-libraries
30
+ --enable-system-libraries
31
+ Use system libraries instead of building and using the packaged libraries.
32
+
33
+ --disable-system-libraries
34
+ Use the packaged libraries, and ignore the system libraries. This is the default on most
35
+ platforms, and overrides `--use-system-libraries` and the environment variable
36
+ `NOKOGIRI_USE_SYSTEM_LIBRARIES`.
37
+
38
+ --disable-clean
39
+ Do not clean out intermediate files after successful build.
40
+
41
+ --prevent-strip
42
+ Take steps to prevent stripping the symbol table and debugging info from the shared
43
+ library, potentially overriding RbConfig's CFLAGS/LDFLAGS/DLDFLAGS.
44
+
45
+
46
+ Flags only used when using system libraries:
47
+
48
+ General:
49
+
50
+ --with-opt-dir=DIRECTORY
51
+ Look for headers and libraries in DIRECTORY.
52
+
53
+ --with-opt-lib=DIRECTORY
54
+ Look for libraries in DIRECTORY.
55
+
56
+ --with-opt-include=DIRECTORY
57
+ Look for headers in DIRECTORY.
58
+
59
+
60
+ Related to zlib:
61
+
62
+ --with-zlib-dir=DIRECTORY
63
+ Look for zlib headers and library in DIRECTORY.
64
+
65
+ --with-zlib-lib=DIRECTORY
66
+ Look for zlib library in DIRECTORY.
67
+
68
+ --with-zlib-include=DIRECTORY
69
+ Look for zlib headers in DIRECTORY.
70
+
71
+
72
+ Related to iconv:
73
+
74
+ --with-iconv-dir=DIRECTORY
75
+ Look for iconv headers and library in DIRECTORY.
76
+
77
+ --with-iconv-lib=DIRECTORY
78
+ Look for iconv library in DIRECTORY.
79
+
80
+ --with-iconv-include=DIRECTORY
81
+ Look for iconv headers in DIRECTORY.
82
+
83
+
84
+ Related to libxml2:
85
+
86
+ --with-xml2-dir=DIRECTORY
87
+ Look for xml2 headers and library in DIRECTORY.
88
+
89
+ --with-xml2-lib=DIRECTORY
90
+ Look for xml2 library in DIRECTORY.
91
+
92
+ --with-xml2-include=DIRECTORY
93
+ Look for xml2 headers in DIRECTORY.
94
+
95
+ --with-xml2-source-dir=DIRECTORY
96
+ (dev only) Build libxml2 from the source code in DIRECTORY
97
+
98
+
99
+ Related to libxslt:
100
+
101
+ --with-xslt-dir=DIRECTORY
102
+ Look for xslt headers and library in DIRECTORY.
103
+
104
+ --with-xslt-lib=DIRECTORY
105
+ Look for xslt library in DIRECTORY.
106
+
107
+ --with-xslt-include=DIRECTORY
108
+ Look for xslt headers in DIRECTORY.
109
+
110
+ --with-xslt-source-dir=DIRECTORY
111
+ (dev only) Build libxslt from the source code in DIRECTORY
112
+
113
+
114
+ Related to libexslt:
115
+
116
+ --with-exslt-dir=DIRECTORY
117
+ Look for exslt headers and library in DIRECTORY.
118
+
119
+ --with-exslt-lib=DIRECTORY
120
+ Look for exslt library in DIRECTORY.
121
+
122
+ --with-exslt-include=DIRECTORY
123
+ Look for exslt headers in DIRECTORY.
124
+
125
+
126
+ Flags only used when building and using the packaged libraries:
127
+
128
+ --disable-static
129
+ Do not statically link packaged libraries, instead use shared libraries.
130
+
131
+ --enable-cross-build
132
+ Enable cross-build mode. (You probably do not want to set this manually.)
133
+
134
+
135
+ Environment variables used:
136
+
137
+ NOKOGIRI_USE_SYSTEM_LIBRARIES
138
+ Equivalent to `--enable-system-libraries` when set, even if nil or blank.
139
+
140
+ CC
141
+ Use this path to invoke the compiler instead of `RbConfig::CONFIG['CC']`
142
+
143
+ CPPFLAGS
144
+ If this string is accepted by the C preprocessor, add it to the flags passed to the C preprocessor
145
+
146
+ CFLAGS
147
+ If this string is accepted by the compiler, add it to the flags passed to the compiler
148
+
149
+ LDFLAGS
150
+ If this string is accepted by the linker, add it to the flags passed to the linker
151
+
152
+ LIBS
153
+ Add this string to the flags passed to the linker
154
+ HELP
7
155
 
8
156
  #
9
- # functions
157
+ # utility functions
10
158
  #
159
+ def config_clean?
160
+ enable_config("clean", true)
161
+ end
162
+
163
+ def config_static?
164
+ default_static = !truffle?
165
+ enable_config("static", default_static)
166
+ end
167
+
168
+ def config_cross_build?
169
+ enable_config("cross-build")
170
+ end
171
+
172
+ def config_system_libraries?
173
+ enable_config("system-libraries", ENV.key?("NOKOGIRI_USE_SYSTEM_LIBRARIES")) do |_, default|
174
+ arg_config("--use-system-libraries", default)
175
+ end
176
+ end
177
+
11
178
  def windows?
12
- RbConfig::CONFIG['target_os'] =~ /mingw32|mswin/
179
+ RbConfig::CONFIG["target_os"].match?(/mingw|mswin/)
13
180
  end
14
181
 
15
182
  def solaris?
16
- RbConfig::CONFIG['target_os'] =~ /solaris/
183
+ RbConfig::CONFIG["target_os"].include?("solaris")
17
184
  end
18
185
 
19
186
  def darwin?
20
- RbConfig::CONFIG['target_os'] =~ /darwin/
187
+ RbConfig::CONFIG["target_os"].include?("darwin")
21
188
  end
22
189
 
23
190
  def openbsd?
24
- RbConfig::CONFIG['target_os'] =~ /openbsd/
191
+ RbConfig::CONFIG["target_os"].include?("openbsd")
25
192
  end
26
193
 
27
- def nix?
28
- ! (windows? || solaris? || darwin?)
194
+ def aix?
195
+ RbConfig::CONFIG["target_os"].include?("aix")
29
196
  end
30
197
 
31
- def sh_export_path path
32
- # because libxslt 1.1.29 configure.in uses AC_PATH_TOOL which treats ":"
33
- # as a $PATH separator, we need to convert windows paths from
34
- #
35
- # C:/path/to/foo
36
- #
37
- # to
38
- #
39
- # /C/path/to/foo
40
- #
41
- # which is sh-compatible, in order to find things properly during
42
- # configuration
43
- if windows?
44
- match = Regexp.new("^([A-Z]):(/.*)").match(path)
45
- if match && match.length == 3
46
- return File.join("/", match[1], match[2])
47
- end
48
- end
49
- path
198
+ def nix?
199
+ !(windows? || solaris? || darwin?)
50
200
  end
51
201
 
52
- def do_help
53
- print <<HELP
54
- usage: ruby #{$0} [options]
55
-
56
- --disable-clean
57
- Do not clean out intermediate files after successful build.
58
-
59
- --disable-static
60
- Do not statically link bundled libraries.
61
-
62
- --with-iconv-dir=DIR
63
- Use the iconv library placed under DIR.
202
+ def truffle?
203
+ RUBY_ENGINE == "truffleruby"
204
+ end
64
205
 
65
- --with-zlib-dir=DIR
66
- Use the zlib library placed under DIR.
206
+ def concat_flags(*args)
207
+ args.compact.join(" ")
208
+ end
67
209
 
68
- --use-system-libraries
69
- Use system libraries instead of building and using the bundled
70
- libraries.
210
+ def local_have_library(lib, func = nil, headers = nil)
211
+ have_library(lib, func, headers) || have_library("lib#{lib}", func, headers)
212
+ end
71
213
 
72
- --with-xml2-dir=DIR / --with-xml2-config=CONFIG
73
- --with-xslt-dir=DIR / --with-xslt-config=CONFIG
74
- --with-exslt-dir=DIR / --with-exslt-config=CONFIG
75
- Use libxml2/libxslt/libexslt as specified.
214
+ def zlib_source(version_string)
215
+ # As of 2022-12, I'm starting to see failed downloads often enough from zlib.net that I want to
216
+ # change the default to github.
217
+ if ENV["NOKOGIRI_USE_CANONICAL_ZLIB_SOURCE"]
218
+ "https://zlib.net/fossils/zlib-#{version_string}.tar.gz"
219
+ else
220
+ "https://github.com/madler/zlib/releases/download/v#{version_string}/zlib-#{version_string}.tar.gz"
221
+ end
222
+ end
76
223
 
77
- --enable-cross-build
78
- Do cross-build.
79
- HELP
80
- exit! 0
224
+ def gnome_source
225
+ # As of 2022-02-20, some mirrors have expired SSL certificates. I'm able to retrieve from my home,
226
+ # but whatever host is resolved on the github actions workers see an expired cert.
227
+ #
228
+ # See https://github.com/sparklemotion/nokogiri/runs/5266206403?check_suite_focus=true
229
+ if ENV["NOKOGIRI_USE_CANONICAL_GNOME_SOURCE"]
230
+ "https://download.gnome.org"
231
+ else
232
+ "https://muug.ca/mirror/gnome" # old reliable
233
+ end
81
234
  end
82
235
 
83
- def do_clean
84
- require 'pathname'
85
- require 'fileutils'
236
+ LOCAL_PACKAGE_RESPONSE = Object.new
237
+ def LOCAL_PACKAGE_RESPONSE.%(package)
238
+ package ? "yes: #{package}" : "no"
239
+ end
86
240
 
87
- root = Pathname(ROOT)
88
- pwd = Pathname(Dir.pwd)
241
+ # wrapper around MakeMakefil#pkg_config and the PKGConfig gem
242
+ def try_package_configuration(pc)
243
+ unless ENV.key?("NOKOGIRI_TEST_PKG_CONFIG_GEM")
244
+ # try MakeMakefile#pkg_config, which uses the system utility `pkg-config`.
245
+ return if checking_for("#{pc} using `pkg_config`", LOCAL_PACKAGE_RESPONSE) do
246
+ pkg_config(pc)
247
+ end
248
+ end
89
249
 
90
- # Skip if this is a development work tree
91
- unless (root + '.git').exist?
92
- message "Cleaning files only used during build.\n"
250
+ # `pkg-config` probably isn't installed, which appears to be the case for lots of freebsd systems.
251
+ # let's fall back to the pkg-config gem, which knows how to parse .pc files, and wrap it with the
252
+ # same logic as MakeMakefile#pkg_config
253
+ begin
254
+ require "rubygems"
255
+ gem("pkg-config", REQUIRED_PKG_CONFIG_VERSION)
256
+ require "pkg-config"
93
257
 
94
- # (root + 'tmp') cannot be removed at this stage because
95
- # nokogiri.so is yet to be copied to lib.
258
+ checking_for("#{pc} using pkg-config gem version #{PKGConfig::VERSION}", LOCAL_PACKAGE_RESPONSE) do
259
+ if PKGConfig.have_package(pc)
260
+ cflags = PKGConfig.cflags(pc)
261
+ ldflags = PKGConfig.libs_only_L(pc)
262
+ libs = PKGConfig.libs_only_l(pc)
96
263
 
97
- # clean the ports build directory
98
- Pathname.glob(pwd.join('tmp', '*', 'ports')) do |dir|
99
- FileUtils.rm_rf(dir, verbose: true)
100
- end
264
+ Logging.message("pkg-config gem found package configuration for %s\n", pc)
265
+ Logging.message("cflags: %s\nldflags: %s\nlibs: %s\n\n", cflags, ldflags, libs)
101
266
 
102
- if enable_config('static')
103
- # ports installation can be safely removed if statically linked.
104
- FileUtils.rm_rf(root + 'ports', verbose: true)
105
- else
106
- FileUtils.rm_rf(root + 'ports' + 'archives', verbose: true)
267
+ [cflags, ldflags, libs]
268
+ end
107
269
  end
270
+ rescue LoadError
271
+ message("Please install either the `pkg-config` utility or the `pkg-config` rubygem.\n")
108
272
  end
109
-
110
- exit! 0
111
273
  end
112
274
 
113
- def package_config pkg, options={}
114
- package = pkg_config(pkg)
115
- return package if package
116
-
117
- begin
118
- require 'rubygems'
119
- gem 'pkg-config', (gem_ver='~> 1.1')
120
- require 'pkg-config' and message("Using pkg-config gem version #{PKGConfig::VERSION}\n")
121
- rescue LoadError
122
- 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"
123
- else
124
- return nil unless PKGConfig.have_package(pkg)
275
+ # set up mkmf to link against the library if we can find it
276
+ def have_package_configuration(opt: nil, pc: nil, lib:, func:, headers:)
277
+ if opt
278
+ dir_config(opt)
279
+ dir_config("opt")
280
+ end
125
281
 
126
- cflags = PKGConfig.cflags(pkg)
127
- ldflags = PKGConfig.libs_only_L(pkg)
128
- libs = PKGConfig.libs_only_l(pkg)
282
+ # see if we have enough path info to do this without trying any harder
283
+ unless ENV.key?("NOKOGIRI_TEST_PKG_CONFIG")
284
+ return true if local_have_library(lib, func, headers)
285
+ end
129
286
 
130
- Logging::message "PKGConfig package configuration for %s\n", pkg
131
- Logging::message "cflags: %s\nldflags: %s\nlibs: %s\n\n", cflags, ldflags, libs
287
+ try_package_configuration(pc) if pc
132
288
 
133
- [cflags, ldflags, libs]
134
- end
289
+ # verify that we can compile and link against the library
290
+ local_have_library(lib, func, headers)
135
291
  end
136
292
 
137
- def nokogiri_try_compile
138
- try_compile "int main() {return 0;}", "", {werror: true}
293
+ def ensure_package_configuration(opt: nil, pc: nil, lib:, func:, headers:)
294
+ have_package_configuration(opt: opt, pc: pc, lib: lib, func: func, headers: headers) ||
295
+ abort_could_not_find_library(lib)
139
296
  end
140
297
 
141
- def check_libxml_version version=nil
142
- source = if version.nil?
143
- <<-SRC
144
- #include <libxml/xmlversion.h>
145
- SRC
146
- else
147
- version_int = sprintf "%d%2.2d%2.2d", *(version.split("."))
148
- <<-SRC
149
- #include <libxml/xmlversion.h>
150
- #if LIBXML_VERSION < #{version_int}
151
- #error libxml2 is older than #{version}
152
- #endif
153
- SRC
154
- end
155
-
156
- try_cpp source
157
- end
158
-
159
- def add_cflags(flags)
160
- print "checking if the C compiler accepts #{flags}... "
161
- with_cflags("#{$CFLAGS} #{flags}") do
162
- if nokogiri_try_compile
163
- puts 'yes'
164
- true
165
- else
166
- puts 'no'
167
- false
168
- end
169
- end
298
+ def ensure_func(func, headers = nil)
299
+ have_func(func, headers) || abort_could_not_find_library(func)
170
300
  end
171
301
 
172
302
  def preserving_globals
173
- values = [
174
- $arg_config,
175
- $CFLAGS, $CPPFLAGS,
176
- $LDFLAGS, $LIBPATH, $libs
177
- ].map(&:dup)
303
+ values = [$arg_config, $INCFLAGS, $CFLAGS, $CPPFLAGS, $LDFLAGS, $DLDFLAGS, $LIBPATH, $libs].map(&:dup)
178
304
  yield
179
305
  ensure
180
- $arg_config,
181
- $CFLAGS, $CPPFLAGS,
182
- $LDFLAGS, $LIBPATH, $libs =
183
- values
306
+ $arg_config, $INCFLAGS, $CFLAGS, $CPPFLAGS, $LDFLAGS, $DLDFLAGS, $LIBPATH, $libs = values
184
307
  end
185
308
 
186
- def asplode(lib)
187
- abort "-----\n#{lib} is missing. Please locate mkmf.log to investigate how it is failing.\n-----"
309
+ def abort_could_not_find_library(lib)
310
+ callers = caller(1..2).join("\n")
311
+ abort("-----\n#{callers}\n#{lib} is missing. Please locate mkmf.log to investigate how it is failing.\n-----")
188
312
  end
189
313
 
190
- def have_iconv?(using = nil)
191
- checking_for(using ? "iconv using #{using}" : 'iconv') do
192
- ['', '-liconv'].any? do |opt|
314
+ def chdir_for_build(&block)
315
+ # When using rake-compiler-dock on Windows, the underlying Virtualbox shared
316
+ # folders don't support symlinks, but libiconv expects it for a build on
317
+ # Linux. We work around this limitation by using the temp dir for cooking.
318
+ build_dir = /mingw|mswin|cygwin/.match?(ENV["RCD_HOST_RUBY_PLATFORM"].to_s) ? "/tmp" : "."
319
+ Dir.chdir(build_dir, &block)
320
+ end
321
+
322
+ def sh_export_path(path)
323
+ # because libxslt 1.1.29 configure.in uses AC_PATH_TOOL which treats ":"
324
+ # as a $PATH separator, we need to convert windows paths from
325
+ #
326
+ # C:/path/to/foo
327
+ #
328
+ # to
329
+ #
330
+ # /C/path/to/foo
331
+ #
332
+ # which is sh-compatible, in order to find things properly during
333
+ # configuration
334
+ return path unless windows?
335
+
336
+ match = Regexp.new("^([A-Z]):(/.*)").match(path)
337
+ if match && match.length == 3
338
+ return File.join("/", match[1], match[2])
339
+ end
340
+
341
+ path
342
+ end
343
+
344
+ def libflag_to_filename(ldflag)
345
+ case ldflag
346
+ when /\A-l(.+)/
347
+ "lib#{Regexp.last_match(1)}.#{$LIBEXT}"
348
+ end
349
+ end
350
+
351
+ def have_libxml_headers?(version = nil)
352
+ source = if version.nil?
353
+ <<~SRC
354
+ #include <libxml/xmlversion.h>
355
+ SRC
356
+ else
357
+ version_int = format("%d%2.2d%2.2d", *version.split("."))
358
+ <<~SRC
359
+ #include <libxml/xmlversion.h>
360
+ #if LIBXML_VERSION < #{version_int}
361
+ # error libxml2 is older than #{version}
362
+ #endif
363
+ SRC
364
+ end
365
+
366
+ try_cpp(source)
367
+ end
368
+
369
+ def try_link_iconv(using = nil)
370
+ checking_for(using ? "iconv using #{using}" : "iconv") do
371
+ ["", "-liconv"].any? do |opt|
193
372
  preserving_globals do
194
373
  yield if block_given?
195
374
 
196
- try_link(<<-'SRC', opt)
197
- #include <stdlib.h>
198
- #include <iconv.h>
199
-
200
- int main(void)
201
- {
202
- iconv_t cd = iconv_open("", "");
203
- iconv(cd, NULL, NULL, NULL, NULL);
204
- return EXIT_SUCCESS;
205
- }
375
+ try_link(<<~SRC, opt)
376
+ #include <stdlib.h>
377
+ #include <iconv.h>
378
+ int main(void)
379
+ {
380
+ iconv_t cd = iconv_open("", "");
381
+ iconv(cd, NULL, NULL, NULL, NULL);
382
+ return EXIT_SUCCESS;
383
+ }
206
384
  SRC
207
385
  end
208
386
  end
@@ -210,67 +388,70 @@ int main(void)
210
388
  end
211
389
 
212
390
  def iconv_configure_flags
213
- # If --with-iconv-dir or --with-opt-dir is given, it should be
214
- # the first priority
215
- %w[iconv opt].each do |name|
216
- if (config = preserving_globals { dir_config(name) }).any? &&
217
- have_iconv?("--with-#{name}-* flags") { dir_config(name) }
218
- idirs, ldirs = config.map do |dirs|
219
- Array(dirs).flat_map do |dir|
220
- dir.split(File::PATH_SEPARATOR)
221
- end if dirs
222
- end
223
-
224
- return [
225
- '--with-iconv=yes',
226
- *("CPPFLAGS=#{idirs.map { |dir| '-I' + dir }.join(' ')}" if idirs),
227
- *("LDFLAGS=#{ldirs.map { |dir| '-L' + dir }.join(' ')}" if ldirs),
228
- ]
391
+ # give --with-iconv-dir and --with-opt-dir first priority
392
+ ["iconv", "opt"].each do |target|
393
+ config = preserving_globals { dir_config(target) }
394
+ next unless config.any? && try_link_iconv("--with-#{target}-* flags") { dir_config(target) }
395
+
396
+ idirs, ldirs = config.map do |dirs|
397
+ Array(dirs).flat_map do |dir|
398
+ dir.split(File::PATH_SEPARATOR)
399
+ end if dirs
229
400
  end
401
+
402
+ return [
403
+ "--with-iconv=yes",
404
+ *("CPPFLAGS=#{idirs.map { |dir| "-I" + dir }.join(" ")}" if idirs),
405
+ *("LDFLAGS=#{ldirs.map { |dir| "-L" + dir }.join(" ")}" if ldirs),
406
+ ]
230
407
  end
231
408
 
232
- if have_iconv?
233
- return ['--with-iconv=yes']
409
+ if try_link_iconv
410
+ return ["--with-iconv=yes"]
234
411
  end
235
412
 
236
- if (config = preserving_globals { package_config('libiconv') }) &&
237
- have_iconv?('pkg-config libiconv') { package_config('libiconv') }
413
+ config = preserving_globals { pkg_config("libiconv") }
414
+ if config && try_link_iconv("pkg-config libiconv") { pkg_config("libiconv") }
238
415
  cflags, ldflags, libs = config
239
416
 
240
417
  return [
241
- '--with-iconv=yes',
418
+ "--with-iconv=yes",
242
419
  "CPPFLAGS=#{cflags}",
243
420
  "LDFLAGS=#{ldflags}",
244
421
  "LIBS=#{libs}",
245
422
  ]
246
423
  end
247
424
 
248
- asplode "libiconv"
425
+ abort_could_not_find_library("libiconv")
249
426
  end
250
427
 
251
- # When using rake-compiler-dock on Windows, the underlying Virtualbox shared
252
- # folders don't support symlinks, but libiconv expects it for a build on
253
- # Linux. We work around this limitation by using the temp dir for cooking.
254
- def chdir_for_build
255
- build_dir = ENV['RCD_HOST_RUBY_PLATFORM'].to_s =~ /mingw|mswin|cygwin/ ? '/tmp' : '.'
256
- Dir.chdir(build_dir) do
257
- yield
428
+ def process_recipe(name, version, static_p, cross_p, cacheable_p = true)
429
+ require "rubygems"
430
+ gem("mini_portile2", REQUIRED_MINI_PORTILE_VERSION) # gemspec is not respected at install time
431
+ require "mini_portile2"
432
+ message("Using mini_portile version #{MiniPortile::VERSION}\n")
433
+
434
+ unless ["libxml2", "libxslt"].include?(name)
435
+ OTHER_LIBRARY_VERSIONS[name] = version
258
436
  end
259
- end
260
437
 
261
- def process_recipe(name, version, static_p, cross_p)
262
438
  MiniPortile.new(name, version).tap do |recipe|
263
- recipe.target = File.join(ROOT, "ports")
264
- # Prefer host_alias over host in order to use i586-mingw32msvc as
265
- # correct compiler prefix for cross build, but use host if not set.
439
+ def recipe.port_path
440
+ "#{@target}/#{RUBY_PLATFORM}/#{@name}/#{@version}"
441
+ end
442
+
443
+ # We use 'host' to set compiler prefix for cross-compiling. Prefer host_alias over host. And
444
+ # prefer i686 (what external dev tools use) to i386 (what ruby's configure.ac emits).
266
445
  recipe.host = RbConfig::CONFIG["host_alias"].empty? ? RbConfig::CONFIG["host"] : RbConfig::CONFIG["host_alias"]
267
- recipe.patch_files = Dir[File.join(ROOT, "patches", name, "*.patch")].sort
446
+ recipe.host = recipe.host.gsub("i386", "i686")
447
+
448
+ recipe.target = File.join(PACKAGE_ROOT_DIR, "ports") if cacheable_p
268
449
  recipe.configure_options << "--libdir=#{File.join(recipe.path, "lib")}"
269
450
 
270
451
  yield recipe
271
452
 
272
453
  env = Hash.new do |hash, key|
273
- hash[key] = "#{ENV[key]}" # (ENV[key].dup rescue '')
454
+ hash[key] = (ENV[key]).to_s
274
455
  end
275
456
 
276
457
  recipe.configure_options.flatten!
@@ -278,7 +459,11 @@ def process_recipe(name, version, static_p, cross_p)
278
459
  recipe.configure_options.delete_if do |option|
279
460
  case option
280
461
  when /\A(\w+)=(.*)\z/
281
- env[$1] = $2
462
+ env[Regexp.last_match(1)] = if env.key?(Regexp.last_match(1))
463
+ concat_flags(env[Regexp.last_match(1)], Regexp.last_match(2))
464
+ else
465
+ Regexp.last_match(2)
466
+ end
282
467
  true
283
468
  else
284
469
  false
@@ -290,7 +475,7 @@ def process_recipe(name, version, static_p, cross_p)
290
475
  "--disable-shared",
291
476
  "--enable-static",
292
477
  ]
293
- env['CFLAGS'] = "-fPIC #{env['CFLAGS']}"
478
+ env["CFLAGS"] = concat_flags(env["CFLAGS"], "-fPIC")
294
479
  else
295
480
  recipe.configure_options += [
296
481
  "--enable-shared",
@@ -305,382 +490,638 @@ def process_recipe(name, version, static_p, cross_p)
305
490
  ]
306
491
  end
307
492
 
308
- if RbConfig::CONFIG['target_cpu'] == 'universal'
309
- %w[CFLAGS LDFLAGS].each do |key|
310
- unless env[key].include?('-arch')
311
- env[key] += ' ' + RbConfig::CONFIG['ARCH_FLAG']
493
+ if RbConfig::CONFIG["target_cpu"] == "universal"
494
+ ["CFLAGS", "LDFLAGS"].each do |key|
495
+ unless env[key].include?("-arch")
496
+ env[key] = concat_flags(env[key], RbConfig::CONFIG["ARCH_FLAG"])
312
497
  end
313
498
  end
314
499
  end
315
500
 
316
501
  recipe.configure_options += env.map do |key, value|
317
- "#{key}=#{value}"
502
+ "#{key}=#{value.strip}"
318
503
  end
319
504
 
320
- message <<-"EOS"
321
- ************************************************************************
322
- IMPORTANT NOTICE:
323
-
324
- Building Nokogiri with a packaged version of #{name}-#{version}#{'.' if recipe.patch_files.empty?}
325
- EOS
505
+ checkpoint = "#{recipe.target}/#{recipe.name}-#{recipe.version}-#{RUBY_PLATFORM}.installed"
506
+ if File.exist?(checkpoint) && !recipe.source_directory
507
+ message("Building Nokogiri with a packaged version of #{name}-#{version}.\n")
508
+ else
509
+ message(<<~EOM)
510
+ ---------- IMPORTANT NOTICE ----------
511
+ Building Nokogiri with a packaged version of #{name}-#{version}.
512
+ Configuration options: #{recipe.configure_options.shelljoin}
513
+ EOM
326
514
 
327
- unless recipe.patch_files.empty?
328
- message "with the following patches applied:\n"
515
+ unless recipe.patch_files.empty?
516
+ message("The following patches are being applied:\n")
329
517
 
330
- recipe.patch_files.each do |patch|
331
- message "\t- %s\n" % File.basename(patch)
518
+ recipe.patch_files.each do |patch|
519
+ message(format(" - %s\n", File.basename(patch)))
520
+ end
332
521
  end
333
- end
334
-
335
- message <<-"EOS"
336
-
337
- Team Nokogiri will keep on doing their best to provide security
338
- updates in a timely manner, but if this is a concern for you and want
339
- to use the system library instead; abort this installation process and
340
- reinstall nokogiri as follows:
341
522
 
342
- gem install nokogiri -- --use-system-libraries
343
- [--with-xml2-config=/path/to/xml2-config]
344
- [--with-xslt-config=/path/to/xslt-config]
523
+ message(<<~EOM) if name != "libgumbo"
345
524
 
346
- If you are using Bundler, tell it to use the option:
525
+ The Nokogiri maintainers intend to provide timely security updates, but if
526
+ this is a concern for you and want to use your OS/distro system library
527
+ instead, then abort this installation process and install nokogiri as
528
+ instructed at:
347
529
 
348
- bundle config build.nokogiri --use-system-libraries
349
- bundle install
350
- EOS
530
+ https://nokogiri.org/tutorials/installing_nokogiri.html#installing-using-standard-system-libraries
351
531
 
352
- message <<-"EOS" if name == 'libxml2'
532
+ EOM
353
533
 
354
- Note, however, that nokogiri is not fully compatible with arbitrary
355
- versions of libxml2 provided by OS/package vendors.
356
- EOS
534
+ message(<<~EOM) if name == "libxml2"
535
+ Note, however, that nokogiri cannot guarantee compatibility with every
536
+ version of libxml2 that may be provided by OS/package vendors.
357
537
 
358
- message <<-"EOS"
359
- ************************************************************************
360
- EOS
538
+ EOM
361
539
 
362
- checkpoint = "#{recipe.target}/#{recipe.name}-#{recipe.version}-#{recipe.host}.installed"
363
- unless File.exist?(checkpoint)
364
- chdir_for_build do
365
- recipe.cook
366
- end
367
- FileUtils.touch checkpoint
540
+ chdir_for_build { recipe.cook }
541
+ FileUtils.touch(checkpoint)
368
542
  end
369
543
  recipe.activate
370
544
  end
371
545
  end
372
546
 
373
- def lib_a(ldflag)
374
- case ldflag
375
- when /\A-l(.+)/
376
- "lib#{$1}.#{$LIBEXT}"
547
+ def copy_packaged_libraries_headers(to_path:, from_recipes:)
548
+ FileUtils.rm_rf(to_path, secure: true)
549
+ FileUtils.mkdir(to_path)
550
+ from_recipes.each do |recipe|
551
+ FileUtils.cp_r(Dir[File.join(recipe.path, "include/*")], to_path)
377
552
  end
378
553
  end
379
554
 
380
- def using_system_libraries?
381
- arg_config('--use-system-libraries', !!ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'])
555
+ def do_help
556
+ print(NOKOGIRI_HELP_MESSAGE)
557
+ exit!(0)
382
558
  end
383
559
 
384
- #
385
- # main
386
- #
560
+ def do_clean
561
+ root = Pathname(PACKAGE_ROOT_DIR)
562
+ pwd = Pathname(Dir.pwd)
563
+
564
+ # Skip if this is a development work tree
565
+ unless (root + ".git").exist?
566
+ message("Cleaning files only used during build.\n")
567
+
568
+ # (root + 'tmp') cannot be removed at this stage because
569
+ # nokogiri.so is yet to be copied to lib.
387
570
 
388
- case
389
- when arg_config('--help')
390
- do_help
391
- when arg_config('--clean')
392
- do_clean
571
+ # clean the ports build directory
572
+ Pathname.glob(pwd.join("tmp", "*", "ports")) do |dir|
573
+ FileUtils.rm_rf(dir, verbose: true)
574
+ end
575
+
576
+ if config_static?
577
+ # ports installation can be safely removed if statically linked.
578
+ FileUtils.rm_rf(root + "ports", verbose: true)
579
+ else
580
+ FileUtils.rm_rf(root + "ports" + "archives", verbose: true)
581
+ end
582
+ end
583
+
584
+ exit!(0)
393
585
  end
394
586
 
395
- if darwin?
396
- ENV['CFLAGS'] = "#{ENV['CFLAGS']} -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libxml2"
587
+ # In ruby 3.2, symbol resolution changed on Darwin, to introduce the `-bundle_loader` flag to
588
+ # resolve symbols against the ruby binary.
589
+ #
590
+ # This makes it challenging to build a single extension that works with both a ruby with
591
+ # `--enable-shared` and one with `--disable-shared. To work around that, we choose to add
592
+ # `-flat_namespace` to the link line (later in this file).
593
+ #
594
+ # The `-flat_namespace` line introduces its own behavior change, which is that (similar to on
595
+ # Linux), any symbols in the extension that are exported may now be resolved by shared libraries
596
+ # loaded by the Ruby process. Specifically, that means that libxml2 and libxslt, which are
597
+ # statically linked into the nokogiri bundle, will resolve (at runtime) to a system libxml2 loaded
598
+ # by Ruby on Darwin. And it appears that often Ruby on Darwin does indeed load the system libxml2,
599
+ # and that messes with our assumptions about whether we're running with a patched libxml2 or a
600
+ # vanilla libxml2.
601
+ #
602
+ # We choose to use `-load_hidden` in this case to prevent exporting those symbols from libxml2 and
603
+ # libxslt, which ensures that they will be resolved to the static libraries in the bundle. In other
604
+ # words, when we use `load_hidden`, what happens in the extension stays in the extension.
605
+ #
606
+ # See https://github.com/rake-compiler/rake-compiler-dock/issues/87 for more info.
607
+ #
608
+ # Anyway, this method is the logical bit to tell us when to turn on these workarounds.
609
+ def needs_darwin_linker_hack
610
+ config_cross_build? &&
611
+ darwin? &&
612
+ Gem::Requirement.new("~> 3.2").satisfied_by?(Gem::Version.new(RbConfig::CONFIG["ruby_version"].split("+").first))
397
613
  end
398
614
 
399
- if openbsd? && !using_system_libraries?
400
- if `#{ENV['CC'] || '/usr/bin/cc'} -v 2>&1` !~ /clang/
401
- ENV['CC'] ||= find_executable('egcc') or
402
- abort "Please install gcc 4.9+ from ports using `pkg_add -v gcc`"
615
+ #
616
+ # main
617
+ #
618
+ do_help if arg_config("--help")
619
+ do_clean if arg_config("--clean")
620
+
621
+ if openbsd? && !config_system_libraries?
622
+ unless %x(#{ENV["CC"] || "/usr/bin/cc"} -v 2>&1).include?("clang")
623
+ (ENV["CC"] ||= find_executable("egcc")) ||
624
+ abort("Please install gcc 4.9+ from ports using `pkg_add -v gcc`")
403
625
  end
404
- ENV['CFLAGS'] = "#{ENV['CFLAGS']} -I /usr/local/include"
626
+ append_cppflags "-I/usr/local/include"
405
627
  end
406
628
 
407
- if ENV['CC']
408
- RbConfig::CONFIG['CC'] = RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC']
629
+ if ENV["CC"]
630
+ RbConfig::CONFIG["CC"] = RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"]
409
631
  end
632
+
410
633
  # use same c compiler for libxml and libxslt
411
- ENV['CC'] = RbConfig::CONFIG['CC']
634
+ ENV["CC"] = RbConfig::CONFIG["CC"]
635
+
636
+ if arg_config("--prevent-strip")
637
+ old_cflags = $CFLAGS.split.join(" ")
638
+ old_ldflags = $LDFLAGS.split.join(" ")
639
+ old_dldflags = $DLDFLAGS.split.join(" ")
640
+ $CFLAGS = $CFLAGS.split.reject { |flag| flag == "-s" }.join(" ")
641
+ $LDFLAGS = $LDFLAGS.split.reject { |flag| flag == "-s" }.join(" ")
642
+ $DLDFLAGS = $DLDFLAGS.split.reject { |flag| flag == "-s" }.join(" ")
643
+ puts "Prevent stripping by removing '-s' from $CFLAGS" if old_cflags != $CFLAGS
644
+ puts "Prevent stripping by removing '-s' from $LDFLAGS" if old_ldflags != $LDFLAGS
645
+ puts "Prevent stripping by removing '-s' from $DLDFLAGS" if old_dldflags != $DLDFLAGS
646
+ end
412
647
 
413
- $LIBS << " #{ENV["LIBS"]}"
648
+ # adopt environment config
649
+ append_cflags(ENV["CFLAGS"].split) unless ENV["CFLAGS"].nil?
650
+ append_cppflags(ENV["CPPFLAGS"].split) unless ENV["CPPFLAGS"].nil?
651
+ append_ldflags(ENV["LDFLAGS"].split) unless ENV["LDFLAGS"].nil?
652
+ $LIBS = concat_flags($LIBS, ENV["LIBS"])
414
653
 
415
- # Read CFLAGS from ENV and make sure compiling works.
416
- add_cflags(ENV["CFLAGS"])
654
+ # libgumbo uses C90/C99 features, see #2302
655
+ append_cflags(["-std=c99", "-Wno-declaration-after-statement"])
417
656
 
418
- if windows?
419
- $CFLAGS << " -DXP_WIN -DXP_WIN32 -DUSE_INCLUDED_VASPRINTF"
420
- end
657
+ # gumbo html5 serialization is slower with O3, let's make sure we use O2
658
+ append_cflags("-O2")
421
659
 
422
- if solaris?
423
- $CFLAGS << " -DUSE_INCLUDED_VASPRINTF"
424
- end
660
+ # always include debugging information
661
+ append_cflags("-g")
425
662
 
426
- if darwin?
427
- # Let Apple LLVM/clang 5.1 ignore unknown compiler flags
428
- add_cflags("-Wno-error=unused-command-line-argument-hard-error-in-future")
429
- end
663
+ # we use at least one inline function in the C extension
664
+ append_cflags("-Winline")
430
665
 
431
- if nix?
432
- $CFLAGS << " -g -DXP_UNIX"
433
- end
666
+ # good to have no matter what Ruby was compiled with
667
+ append_cflags("-Wmissing-noreturn")
434
668
 
435
- if RUBY_PLATFORM =~ /mingw/i
436
- # Work around a character escaping bug in MSYS by passing an arbitrary
437
- # double quoted parameter to gcc. See https://sourceforge.net/p/mingw/bugs/2142
438
- $CPPFLAGS << ' "-Idummypath"'
669
+ # check integer loss of precision
670
+ if darwin?
671
+ append_cflags("-Wshorten-64-to-32")
672
+ else
673
+ append_cflags("-Wconversion -Wno-sign-conversion")
439
674
  end
440
675
 
441
- if RbConfig::CONFIG['CC'] =~ /gcc/
442
- $CFLAGS << " -O3" unless $CFLAGS[/-O\d/]
443
- $CFLAGS << " -Wall -Wcast-qual -Wwrite-strings -Wmissing-noreturn -Winline"
676
+ # handle clang variations, see #1101
677
+ if darwin?
678
+ append_cflags("-Wno-error=unused-command-line-argument-hard-error-in-future")
679
+ append_cflags("-Wno-unknown-warning-option")
444
680
  end
445
681
 
446
- case
447
- when using_system_libraries?
448
- message "Building nokogiri using system libraries.\n"
449
-
450
- dir_config('zlib')
682
+ # these tend to be noisy, but on occasion useful during development
683
+ # append_cflags(["-Wcast-qual", "-Wwrite-strings"])
451
684
 
452
- # Using system libraries means we rely on the system libxml2 with
453
- # regard to the iconv support.
685
+ # Add SDK-specific include path for macOS and brew versions before v2.2.12 (2020-04-08) [#1851, #1801]
686
+ macos_mojave_sdk_include_path = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libxml2"
687
+ if config_system_libraries? && darwin? && Dir.exist?(macos_mojave_sdk_include_path)
688
+ append_cppflags("-I#{macos_mojave_sdk_include_path}")
689
+ end
454
690
 
455
- dir_config('xml2').any? or package_config('libxml-2.0')
456
- dir_config('xslt').any? or package_config('libxslt')
457
- dir_config('exslt').any? or package_config('libexslt')
691
+ # Work around a character escaping bug in MSYS by passing an arbitrary double-quoted parameter to gcc.
692
+ # See https://sourceforge.net/p/mingw/bugs/2142
693
+ append_cppflags(' "-Idummypath"') if windows?
458
694
 
459
- check_libxml_version or abort "ERROR: cannot discover where libxml2 is located on your system. please make sure `pkg-config` is installed."
460
- check_libxml_version("2.6.21") or abort "ERROR: libxml2 version 2.6.21 or later is required!"
461
- check_libxml_version("2.9.3") or warn "WARNING: libxml2 version 2.9.3 or later is highly recommended, but proceeding anyway."
695
+ if config_system_libraries?
696
+ message "Building nokogiri using system libraries.\n"
697
+ ensure_package_configuration(
698
+ opt: "zlib",
699
+ pc: "zlib",
700
+ lib: "z",
701
+ headers: "zlib.h",
702
+ func: "gzdopen",
703
+ )
704
+ ensure_package_configuration(
705
+ opt: "xml2",
706
+ pc: "libxml-2.0",
707
+ lib: "xml2",
708
+ headers: "libxml/parser.h",
709
+ func: "xmlParseDoc",
710
+ )
711
+ ensure_package_configuration(
712
+ opt: "xslt",
713
+ pc: "libxslt",
714
+ lib: "xslt",
715
+ headers: "libxslt/xslt.h",
716
+ func: "xsltParseStylesheetDoc",
717
+ )
718
+ ensure_package_configuration(
719
+ opt: "exslt",
720
+ pc: "libexslt",
721
+ lib: "exslt",
722
+ headers: "libexslt/exslt.h",
723
+ func: "exsltFuncRegister",
724
+ )
725
+
726
+ have_libxml_headers?(REQUIRED_LIBXML_VERSION) ||
727
+ abort("ERROR: libxml2 version #{REQUIRED_LIBXML_VERSION} or later is required!")
728
+ have_libxml_headers?(RECOMMENDED_LIBXML_VERSION) ||
729
+ warn("WARNING: libxml2 version #{RECOMMENDED_LIBXML_VERSION} or later is highly recommended, but proceeding anyway.")
462
730
 
463
731
  else
464
732
  message "Building nokogiri using packaged libraries.\n"
465
733
 
466
- # The gem version constraint in the Rakefile is not respected at install time.
467
- # Keep this version in sync with the one in the Rakefile !
468
- require 'rubygems'
469
- gem 'mini_portile2', '~> 2.4.0'
470
- require 'mini_portile2'
471
- message "Using mini_portile version #{MiniPortile::VERSION}\n"
734
+ static_p = config_static?
735
+ message "Static linking is #{static_p ? "enabled" : "disabled"}.\n"
472
736
 
473
- require 'yaml'
737
+ cross_build_p = config_cross_build?
738
+ message "Cross build is #{cross_build_p ? "enabled" : "disabled"}.\n"
474
739
 
475
- static_p = enable_config('static', true) or
476
- message "Static linking is disabled.\n"
740
+ if needs_darwin_linker_hack
741
+ append_ldflags("-Wl,-flat_namespace")
742
+ end
477
743
 
478
- dir_config('zlib')
744
+ require "yaml"
745
+ dependencies = YAML.load_file(File.join(PACKAGE_ROOT_DIR, "dependencies.yml"))
479
746
 
480
- dependencies = YAML.load_file(File.join(ROOT, "dependencies.yml"))
747
+ dir_config("zlib")
481
748
 
482
- cross_build_p = enable_config("cross-build")
483
749
  if cross_build_p || windows?
484
750
  zlib_recipe = process_recipe("zlib", dependencies["zlib"]["version"], static_p, cross_build_p) do |recipe|
485
751
  recipe.files = [{
486
- url: "http://zlib.net/fossils/#{recipe.name}-#{recipe.version}.tar.gz",
487
- sha256: dependencies["zlib"]["sha256"]
488
- }]
489
- class << recipe
490
- attr_accessor :cross_build_p
491
-
492
- def configure
493
- Dir.chdir work_path do
494
- mk = File.read 'win32/Makefile.gcc'
495
- File.open 'win32/Makefile.gcc', 'wb' do |f|
496
- f.puts "BINARY_PATH = #{path}/bin"
497
- f.puts "LIBRARY_PATH = #{path}/lib"
498
- f.puts "INCLUDE_PATH = #{path}/include"
499
- mk.sub!(/^PREFIX\s*=\s*$/, "PREFIX = #{host}-") if cross_build_p
500
- f.puts mk
752
+ url: zlib_source(recipe.version),
753
+ sha256: dependencies["zlib"]["sha256"],
754
+ }]
755
+ if windows?
756
+ class << recipe
757
+ attr_accessor :cross_build_p
758
+
759
+ def configure
760
+ Dir.chdir(work_path) do
761
+ mk = File.read("win32/Makefile.gcc")
762
+ File.open("win32/Makefile.gcc", "wb") do |f|
763
+ f.puts "BINARY_PATH = #{path}/bin"
764
+ f.puts "LIBRARY_PATH = #{path}/lib"
765
+ f.puts "INCLUDE_PATH = #{path}/include"
766
+ mk.sub!(/^PREFIX\s*=\s*$/, "PREFIX = #{host}-") if cross_build_p
767
+ f.puts mk
768
+ end
769
+ end
770
+ end
771
+
772
+ def configured?
773
+ Dir.chdir(work_path) do
774
+ !!(File.read("win32/Makefile.gcc") =~ /^BINARY_PATH/)
501
775
  end
502
776
  end
503
- end
504
777
 
505
- def configured?
506
- Dir.chdir work_path do
507
- !! (File.read('win32/Makefile.gcc') =~ /^BINARY_PATH/)
778
+ def compile
779
+ execute("compile", "make -f win32/Makefile.gcc")
508
780
  end
509
- end
510
781
 
511
- def compile
512
- execute "compile", "make -f win32/Makefile.gcc"
782
+ def install
783
+ execute("install", "make -f win32/Makefile.gcc install")
784
+ end
513
785
  end
514
-
515
- def install
516
- execute "install", "make -f win32/Makefile.gcc install"
786
+ recipe.cross_build_p = cross_build_p
787
+ else
788
+ class << recipe
789
+ def configure
790
+ env = {}
791
+ env["CFLAGS"] = concat_flags(ENV["CFLAGS"], "-fPIC", "-g")
792
+ env["CHOST"] = host
793
+ execute("configure", ["./configure", "--static", configure_prefix], { env: env })
794
+ if darwin?
795
+ # needed as of zlib 1.2.13
796
+ Dir.chdir(work_path) do
797
+ makefile = File.read("Makefile").gsub(/^AR=.*$/, "AR=#{host}-libtool")
798
+ File.open("Makefile", "w") { |m| m.write(makefile) }
799
+ end
800
+ end
801
+ end
517
802
  end
518
803
  end
519
- recipe.cross_build_p = cross_build_p
520
804
  end
521
805
 
522
- libiconv_recipe = process_recipe("libiconv", dependencies["libiconv"]["version"], static_p, cross_build_p) do |recipe|
523
- recipe.files = [{
524
- url: "http://ftp.gnu.org/pub/gnu/libiconv/#{recipe.name}-#{recipe.version}.tar.gz",
525
- sha256: dependencies["libiconv"]["sha256"]
806
+ unless nix?
807
+ libiconv_recipe = process_recipe(
808
+ "libiconv",
809
+ dependencies["libiconv"]["version"],
810
+ static_p,
811
+ cross_build_p,
812
+ ) do |recipe|
813
+ recipe.files = [{
814
+ url: "https://ftp.gnu.org/pub/gnu/libiconv/#{recipe.name}-#{recipe.version}.tar.gz",
815
+ sha256: dependencies["libiconv"]["sha256"],
526
816
  }]
527
- recipe.configure_options += [
528
- "CPPFLAGS=-Wall",
529
- "CFLAGS=-O2 -g",
530
- "CXXFLAGS=-O2 -g",
531
- "LDFLAGS="
532
- ]
533
- end
534
- else
535
- if darwin? && !have_header('iconv.h')
536
- abort <<'EOM'.chomp
537
- -----
538
- The file "iconv.h" is missing in your build environment,
539
- which means you haven't installed Xcode Command Line Tools properly.
540
-
541
- To install Command Line Tools, try running `xcode-select --install` on
542
- terminal and follow the instructions. If it fails, open Xcode.app,
543
- select from the menu "Xcode" - "Open Developer Tool" - "More Developer
544
- Tools" to open the developer site, download the installer for your OS
545
- version and run it.
546
- -----
547
- EOM
817
+
818
+ # The libiconv configure script doesn't accept "arm64" host string but "aarch64"
819
+ recipe.host = recipe.host.gsub("arm64-apple-darwin", "aarch64-apple-darwin")
820
+
821
+ cflags = concat_flags(ENV["CFLAGS"], "-O2", "-U_FORTIFY_SOURCE", "-g")
822
+
823
+ recipe.configure_options += [
824
+ "--disable-dependency-tracking",
825
+ "CPPFLAGS=-Wall",
826
+ "CFLAGS=#{cflags}",
827
+ "CXXFLAGS=#{cflags}",
828
+ "LDFLAGS=",
829
+ ]
830
+ end
548
831
  end
832
+ elsif darwin? && !have_header("iconv.h")
833
+ abort(<<~EOM.chomp)
834
+ -----
835
+ The file "iconv.h" is missing in your build environment,
836
+ which means you haven't installed Xcode Command Line Tools properly.
837
+
838
+ To install Command Line Tools, try running `xcode-select --install` on
839
+ terminal and follow the instructions. If it fails, open Xcode.app,
840
+ select from the menu "Xcode" - "Open Developer Tool" - "More Developer
841
+ Tools" to open the developer site, download the installer for your OS
842
+ version and run it.
843
+ -----
844
+ EOM
845
+ end
846
+
847
+ if zlib_recipe
848
+ append_cppflags("-I#{zlib_recipe.path}/include")
849
+ $LIBPATH = ["#{zlib_recipe.path}/lib"] | $LIBPATH
850
+ ensure_package_configuration(
851
+ opt: "zlib",
852
+ pc: "zlib",
853
+ lib: "z",
854
+ headers: "zlib.h",
855
+ func: "gzdopen",
856
+ )
549
857
  end
550
858
 
551
- unless windows?
552
- preserving_globals {
553
- have_library('z', 'gzdopen', 'zlib.h')
554
- } or abort 'zlib is missing; necessary for building libxml2'
859
+ if libiconv_recipe
860
+ append_cppflags("-I#{libiconv_recipe.path}/include")
861
+ $LIBPATH = ["#{libiconv_recipe.path}/lib"] | $LIBPATH
862
+ ensure_package_configuration(
863
+ opt: "iconv",
864
+ pc: "iconv",
865
+ lib: "iconv",
866
+ headers: "iconv.h",
867
+ func: "iconv_open",
868
+ )
555
869
  end
556
870
 
557
871
  libxml2_recipe = process_recipe("libxml2", dependencies["libxml2"]["version"], static_p, cross_build_p) do |recipe|
558
- recipe.files = [{
559
- url: "http://xmlsoft.org/sources/#{recipe.name}-#{recipe.version}.tar.gz",
560
- sha256: dependencies["libxml2"]["sha256"]
872
+ source_dir = arg_config("--with-xml2-source-dir")
873
+ if source_dir
874
+ recipe.source_directory = source_dir
875
+ else
876
+ minor_version = Gem::Version.new(recipe.version).segments.take(2).join(".")
877
+ recipe.files = [{
878
+ url: "#{gnome_source}/sources/libxml2/#{minor_version}/#{recipe.name}-#{recipe.version}.tar.xz",
879
+ sha256: dependencies["libxml2"]["sha256"],
561
880
  }]
881
+ recipe.patch_files = Dir[File.join(PACKAGE_ROOT_DIR, "patches", "libxml2", "*.patch")].sort
882
+ end
883
+
884
+ cppflags = concat_flags(ENV["CPPFLAGS"])
885
+ cflags = concat_flags(ENV["CFLAGS"], "-O2", "-U_FORTIFY_SOURCE", "-g")
886
+
887
+ if cross_build_p
888
+ cppflags = concat_flags(cppflags, "-DNOKOGIRI_PRECOMPILED_LIBRARIES")
889
+ end
890
+
891
+ if zlib_recipe
892
+ recipe.configure_options << "--with-zlib=#{zlib_recipe.path}"
893
+ end
894
+
895
+ if libiconv_recipe
896
+ recipe.configure_options << "--with-iconv=#{libiconv_recipe.path}"
897
+ else
898
+ recipe.configure_options += iconv_configure_flags
899
+ end
900
+
901
+ if darwin? && !cross_build_p
902
+ recipe.configure_options += ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"]
903
+ end
904
+
905
+ if windows?
906
+ cflags = concat_flags(cflags, "-ULIBXML_STATIC", "-DIN_LIBXML")
907
+ end
908
+
909
+ recipe.configure_options << if source_dir
910
+ "--config-cache"
911
+ else
912
+ "--disable-dependency-tracking"
913
+ end
914
+
562
915
  recipe.configure_options += [
563
916
  "--without-python",
564
917
  "--without-readline",
565
- *(zlib_recipe ? ["--with-zlib=#{zlib_recipe.path}", "CFLAGS=-I#{zlib_recipe.path}/include"] : []),
566
- *(libiconv_recipe ? "--with-iconv=#{libiconv_recipe.path}" : iconv_configure_flags),
567
918
  "--with-c14n",
568
919
  "--with-debug",
569
920
  "--with-threads",
570
- *(darwin? ? ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"] : "")
921
+ "--without-tls", # see https://github.com/sparklemotion/nokogiri/issues/3031
922
+ "CPPFLAGS=#{cppflags}",
923
+ "CFLAGS=#{cflags}",
571
924
  ]
572
925
  end
573
926
 
574
927
  libxslt_recipe = process_recipe("libxslt", dependencies["libxslt"]["version"], static_p, cross_build_p) do |recipe|
575
- recipe.files = [{
576
- url: "http://xmlsoft.org/sources/#{recipe.name}-#{recipe.version}.tar.gz",
577
- sha256: dependencies["libxslt"]["sha256"]
928
+ source_dir = arg_config("--with-xslt-source-dir")
929
+ if source_dir
930
+ recipe.source_directory = source_dir
931
+ else
932
+ minor_version = Gem::Version.new(recipe.version).segments.take(2).join(".")
933
+ recipe.files = [{
934
+ url: "#{gnome_source}/sources/libxslt/#{minor_version}/#{recipe.name}-#{recipe.version}.tar.xz",
935
+ sha256: dependencies["libxslt"]["sha256"],
578
936
  }]
937
+ recipe.patch_files = Dir[File.join(PACKAGE_ROOT_DIR, "patches", "libxslt", "*.patch")].sort
938
+ end
939
+
940
+ cflags = concat_flags(ENV["CFLAGS"], "-O2", "-U_FORTIFY_SOURCE", "-g")
941
+
942
+ if darwin? && !cross_build_p
943
+ recipe.configure_options += ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"]
944
+ end
945
+
946
+ if windows?
947
+ cflags = concat_flags(cflags, "-ULIBXSLT_STATIC", "-DIN_LIBXSLT")
948
+ cflags = concat_flags(cflags, "-ULIBEXSLT_STATIC", "-DIN_LIBEXSLT")
949
+ end
950
+
951
+ recipe.configure_options << if source_dir
952
+ "--config-cache"
953
+ else
954
+ "--disable-dependency-tracking"
955
+ end
956
+
579
957
  recipe.configure_options += [
580
958
  "--without-python",
581
959
  "--without-crypto",
582
960
  "--with-debug",
583
961
  "--with-libxml-prefix=#{sh_export_path(libxml2_recipe.path)}",
584
- *(darwin? ? ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"] : "")
962
+ "CFLAGS=#{cflags}",
585
963
  ]
586
964
  end
587
965
 
588
- $CFLAGS << ' ' << '-DNOKOGIRI_USE_PACKAGED_LIBRARIES'
589
- $LIBPATH = ["#{zlib_recipe.path}/lib"] | $LIBPATH if zlib_recipe
590
- $LIBPATH = ["#{libiconv_recipe.path}/lib"] | $LIBPATH if libiconv_recipe
591
-
592
- have_lzma = preserving_globals {
593
- have_library('lzma')
594
- }
966
+ append_cppflags("-DNOKOGIRI_PACKAGED_LIBRARIES")
967
+ append_cppflags("-DNOKOGIRI_PRECOMPILED_LIBRARIES") if cross_build_p
595
968
 
596
969
  $libs = $libs.shellsplit.tap do |libs|
597
970
  [libxml2_recipe, libxslt_recipe].each do |recipe|
598
971
  libname = recipe.name[/\Alib(.+)\z/, 1]
599
- File.join(recipe.path, "bin", "#{libname}-config").tap do |config|
972
+ config_basename = "#{libname}-config"
973
+ File.join(recipe.path, "bin", config_basename).tap do |config|
600
974
  # call config scripts explicit with 'sh' for compat with Windows
601
- $CPPFLAGS = `sh #{config} --cflags`.strip << ' ' << $CPPFLAGS
602
- `sh #{config} --libs`.strip.shellsplit.each do |arg|
975
+ cflags = %x(sh #{config} --cflags).strip
976
+ message("#{config_basename} cflags: #{cflags}\n")
977
+ $CPPFLAGS = concat_flags(cflags, $CPPFLAGS) # prepend
978
+
979
+ %x(sh #{config} --libs).strip.shellsplit.each do |arg|
603
980
  case arg
604
981
  when /\A-L(.+)\z/
605
982
  # Prioritize ports' directories
606
- if $1.start_with?(ROOT + '/')
607
- $LIBPATH = [$1] | $LIBPATH
983
+ $LIBPATH = if Regexp.last_match(1).start_with?(PACKAGE_ROOT_DIR + "/")
984
+ [Regexp.last_match(1)] | $LIBPATH
608
985
  else
609
- $LIBPATH = $LIBPATH | [$1]
986
+ $LIBPATH | [Regexp.last_match(1)]
610
987
  end
611
988
  when /\A-l./
612
989
  libs.unshift(arg)
613
990
  else
614
- $LDFLAGS << ' ' << arg.shellescape
991
+ $LDFLAGS << " " << arg.shellescape
615
992
  end
616
993
  end
617
994
  end
618
995
 
619
- # Defining a macro that expands to a C string; double quotes are significant.
620
- $CPPFLAGS << ' ' << "-DNOKOGIRI_#{recipe.name.upcase}_PATH=\"#{recipe.path}\"".inspect
621
- $CPPFLAGS << ' ' << "-DNOKOGIRI_#{recipe.name.upcase}_PATCHES=\"#{recipe.patch_files.map { |path| File.basename(path) }.join(' ')}\"".inspect
996
+ patches_string = recipe.patch_files.map { |path| File.basename(path) }.join(" ")
997
+ append_cppflags(%[-DNOKOGIRI_#{recipe.name.upcase}_PATCHES="\\"#{patches_string}\\""])
622
998
 
623
999
  case libname
624
- when 'xml2'
1000
+ when "xml2"
625
1001
  # xslt-config --libs or pkg-config libxslt --libs does not include
626
1002
  # -llzma, so we need to add it manually when linking statically.
627
- if static_p && have_lzma
1003
+ if static_p && preserving_globals { local_have_library("lzma") }
628
1004
  # Add it at the end; GH #988
629
- libs << '-llzma'
1005
+ libs << "-llzma"
630
1006
  end
631
- when 'xslt'
1007
+ when "xslt"
632
1008
  # xslt-config does not have a flag to emit options including
633
1009
  # -lexslt, so add it manually.
634
- libs.unshift('-lexslt')
1010
+ libs.unshift("-lexslt")
635
1011
  end
636
1012
  end
637
1013
  end.shelljoin
638
1014
 
639
1015
  if static_p
1016
+ static_archive_ld_flag = needs_darwin_linker_hack ? ["-load_hidden"] : []
640
1017
  $libs = $libs.shellsplit.map do |arg|
641
1018
  case arg
642
- when '-lxml2'
643
- File.join(libxml2_recipe.path, 'lib', lib_a(arg))
644
- when '-lxslt', '-lexslt'
645
- File.join(libxslt_recipe.path, 'lib', lib_a(arg))
1019
+ when "-lxml2"
1020
+ static_archive_ld_flag + [File.join(libxml2_recipe.path, "lib", libflag_to_filename(arg))]
1021
+ when "-lxslt", "-lexslt"
1022
+ static_archive_ld_flag + [File.join(libxslt_recipe.path, "lib", libflag_to_filename(arg))]
646
1023
  else
647
1024
  arg
648
1025
  end
649
- end.shelljoin
1026
+ end.flatten.shelljoin
650
1027
  end
651
- end
652
1028
 
653
- {
654
- "xml2" => ['xmlParseDoc', 'libxml/parser.h'],
655
- "xslt" => ['xsltParseStylesheetDoc', 'libxslt/xslt.h'],
656
- "exslt" => ['exsltFuncRegister', 'libexslt/exslt.h'],
657
- }.each do |lib, (func, header)|
658
- have_func(func, header) ||
659
- have_library(lib, func, header) ||
660
- have_library("lib#{lib}", func, header) or
661
- asplode("lib#{lib}")
1029
+ ensure_func("xmlParseDoc", "libxml/parser.h")
1030
+ ensure_func("xsltParseStylesheetDoc", "libxslt/xslt.h")
1031
+ ensure_func("exsltFuncRegister", "libexslt/exslt.h")
662
1032
  end
663
1033
 
664
- have_func('xmlHasFeature') or abort "xmlHasFeature() is missing."
665
- have_func('xmlFirstElementChild')
666
- have_func('xmlRelaxNGSetParserStructuredErrors')
667
- have_func('xmlRelaxNGSetParserStructuredErrors')
668
- have_func('xmlRelaxNGSetValidStructuredErrors')
669
- have_func('xmlSchemaSetValidStructuredErrors')
670
- have_func('xmlSchemaSetParserStructuredErrors')
1034
+ libgumbo_recipe = process_recipe("libgumbo", "1.0.0-nokogiri", static_p, cross_build_p, false) do |recipe|
1035
+ recipe.configure_options = []
1036
+
1037
+ class << recipe
1038
+ def downloaded?
1039
+ true
1040
+ end
1041
+
1042
+ def extract
1043
+ target = File.join(tmp_path, "gumbo-parser")
1044
+ output("Copying gumbo-parser files into #{target}...")
1045
+ FileUtils.mkdir_p(target)
1046
+ FileUtils.cp(Dir.glob(File.join(PACKAGE_ROOT_DIR, "gumbo-parser/src/*")), target)
1047
+ end
1048
+
1049
+ def configured?
1050
+ true
1051
+ end
1052
+
1053
+ def install
1054
+ lib_dir = File.join(port_path, "lib")
1055
+ inc_dir = File.join(port_path, "include")
1056
+ FileUtils.mkdir_p([lib_dir, inc_dir])
1057
+ FileUtils.cp(File.join(work_path, "libgumbo.a"), lib_dir)
1058
+ FileUtils.cp(Dir.glob(File.join(work_path, "*.h")), inc_dir)
1059
+ end
1060
+
1061
+ def compile
1062
+ cflags = concat_flags(ENV["CFLAGS"], "-fPIC", "-O2", "-g")
1063
+
1064
+ env = { "CC" => gcc_cmd, "CFLAGS" => cflags }
1065
+ if config_cross_build?
1066
+ if host.include?("darwin")
1067
+ env["AR"] = "#{host}-libtool"
1068
+ env["ARFLAGS"] = "-o"
1069
+ else
1070
+ env["AR"] = "#{host}-ar"
1071
+ end
1072
+ env["RANLIB"] = "#{host}-ranlib"
1073
+ end
1074
+
1075
+ execute("compile", make_cmd, { env: env })
1076
+ end
1077
+ end
1078
+ end
1079
+ append_cppflags("-I#{File.join(libgumbo_recipe.path, "include")}")
1080
+ $libs = $libs + " " + File.join(libgumbo_recipe.path, "lib", "libgumbo.a")
1081
+ $LIBPATH = $LIBPATH | [File.join(libgumbo_recipe.path, "lib")]
1082
+ ensure_func("gumbo_parse_with_options", "nokogiri_gumbo.h")
1083
+
1084
+ have_func("xmlHasFeature") || abort("xmlHasFeature() is missing.") # introduced in libxml 2.6.21
1085
+ have_func("xmlFirstElementChild") # introduced in libxml 2.7.3
1086
+ have_func("xmlRelaxNGSetParserStructuredErrors") # introduced in libxml 2.6.24
1087
+ have_func("xmlRelaxNGSetValidStructuredErrors") # introduced in libxml 2.6.21
1088
+ have_func("xmlSchemaSetValidStructuredErrors") # introduced in libxml 2.6.23
1089
+ have_func("xmlSchemaSetParserStructuredErrors") # introduced in libxml 2.6.23
1090
+ have_func("rb_category_warning") # introduced in Ruby 3.0
1091
+
1092
+ other_library_versions_string = OTHER_LIBRARY_VERSIONS.map { |k, v| [k, v].join(":") }.join(",")
1093
+ append_cppflags(%[-DNOKOGIRI_OTHER_LIBRARY_VERSIONS="\\"#{other_library_versions_string}\\""])
1094
+
1095
+ unless config_system_libraries?
1096
+ if cross_build_p
1097
+ # When precompiling native gems, copy packaged libraries' headers to ext/nokogiri/include
1098
+ # These are packaged up by the cross-compiling callback in the ExtensionTask
1099
+ copy_packaged_libraries_headers(
1100
+ to_path: File.join(PACKAGE_ROOT_DIR, "ext/nokogiri/include"),
1101
+ from_recipes: [libxml2_recipe, libxslt_recipe],
1102
+ )
1103
+ else
1104
+ # When compiling during installation, install packaged libraries' header files into ext/nokogiri/include
1105
+ copy_packaged_libraries_headers(
1106
+ to_path: "include",
1107
+ from_recipes: [libxml2_recipe, libxslt_recipe],
1108
+ )
1109
+ $INSTALLFILES << ["include/**/*.h", "$(rubylibdir)"]
1110
+ end
1111
+ end
671
1112
 
672
- create_makefile('nokogiri/nokogiri')
1113
+ create_makefile("nokogiri/nokogiri")
673
1114
 
674
- if enable_config('clean', true)
1115
+ if config_clean?
675
1116
  # Do not clean if run in a development work tree.
676
- File.open('Makefile', 'at') do |mk|
677
- mk.print <<EOF
678
- all: clean-ports
1117
+ File.open("Makefile", "at") do |mk|
1118
+ mk.print(<<~EOF)
679
1119
 
680
- clean-ports: $(DLLIB)
681
- -$(Q)$(RUBY) $(srcdir)/extconf.rb --clean --#{static_p ? 'enable' : 'disable'}-static
682
- EOF
1120
+ all: clean-ports
1121
+ clean-ports: $(DLLIB)
1122
+ \t-$(Q)$(RUBY) $(srcdir)/extconf.rb --clean --#{static_p ? "enable" : "disable"}-static
1123
+ EOF
683
1124
  end
684
1125
  end
685
1126
 
686
- # :startdoc:
1127
+ # rubocop:enable Style/GlobalVars