nokogiri 1.8.5 → 1.15.3

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 (358) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +40 -18
  3. data/LICENSE-DEPENDENCIES.md +1636 -1024
  4. data/LICENSE.md +5 -28
  5. data/README.md +203 -90
  6. data/bin/nokogiri +63 -50
  7. data/dependencies.yml +33 -61
  8. data/ext/nokogiri/depend +38 -358
  9. data/ext/nokogiri/extconf.rb +867 -417
  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 +215 -90
  19. data/ext/nokogiri/test_global_handlers.c +40 -0
  20. data/ext/nokogiri/xml_attr.c +42 -37
  21. data/ext/nokogiri/xml_attribute_decl.c +22 -22
  22. data/ext/nokogiri/xml_cdata.c +40 -31
  23. data/ext/nokogiri/xml_comment.c +20 -27
  24. data/ext/nokogiri/xml_document.c +401 -237
  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 +136 -62
  33. data/ext/nokogiri/xml_node.c +1387 -678
  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 +347 -212
  37. data/ext/nokogiri/xml_relax_ng.c +86 -77
  38. data/ext/nokogiri/xml_sax_parser.c +149 -124
  39. data/ext/nokogiri/xml_sax_parser_context.c +145 -103
  40. data/ext/nokogiri/xml_sax_push_parser.c +64 -36
  41. data/ext/nokogiri/xml_schema.c +138 -81
  42. data/ext/nokogiri/xml_syntax_error.c +42 -21
  43. data/ext/nokogiri/xml_text.c +36 -26
  44. data/ext/nokogiri/xml_xpath_context.c +366 -178
  45. data/ext/nokogiri/xslt_stylesheet.c +335 -189
  46. data/gumbo-parser/CHANGES.md +63 -0
  47. data/gumbo-parser/Makefile +111 -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 +3463 -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 +107 -104
  98. data/lib/nokogiri/css/tokenizer.rex +3 -2
  99. data/lib/nokogiri/css/xpath_visitor.rb +224 -95
  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 +392 -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 +223 -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 +98 -54
  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 -126
  133. data/lib/nokogiri/xml/document_fragment.rb +104 -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 +45 -0
  140. data/lib/nokogiri/xml/node/save_options.rb +23 -8
  141. data/lib/nokogiri/xml/node.rb +1093 -411
  142. data/lib/nokogiri/xml/node_set.rb +173 -67
  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 +6 -4
  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 +38 -37
  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/0001-Remove-script-macro-support.patch +40 -0
  169. data/patches/libxml2/0002-Update-entities-to-remove-handling-of-ssi.patch +44 -0
  170. data/patches/libxml2/0003-libxml2.la-is-in-top_builddir.patch +25 -0
  171. data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
  172. data/patches/libxml2/0010-update-config.guess-and-config.sub-for-libxml2.patch +224 -0
  173. data/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch +30 -0
  174. data/patches/libxslt/0001-update-config.guess-and-config.sub-for-libxslt.patch +224 -0
  175. data/ports/archives/libxml2-2.11.4.tar.xz +0 -0
  176. data/ports/archives/libxslt-1.1.38.tar.xz +0 -0
  177. metadata +126 -399
  178. data/.autotest +0 -22
  179. data/.cross_rubies +0 -8
  180. data/.editorconfig +0 -17
  181. data/.gemtest +0 -0
  182. data/.travis.yml +0 -63
  183. data/CHANGELOG.md +0 -1368
  184. data/CONTRIBUTING.md +0 -42
  185. data/C_CODING_STYLE.rdoc +0 -33
  186. data/Gemfile-libxml-ruby +0 -3
  187. data/Manifest.txt +0 -370
  188. data/ROADMAP.md +0 -111
  189. data/Rakefile +0 -348
  190. data/SECURITY.md +0 -19
  191. data/STANDARD_RESPONSES.md +0 -47
  192. data/Y_U_NO_GEMSPEC.md +0 -155
  193. data/appveyor.yml +0 -29
  194. data/build_all +0 -44
  195. data/ext/nokogiri/html_document.c +0 -170
  196. data/ext/nokogiri/html_document.h +0 -10
  197. data/ext/nokogiri/html_element_description.c +0 -279
  198. data/ext/nokogiri/html_element_description.h +0 -10
  199. data/ext/nokogiri/html_entity_lookup.c +0 -32
  200. data/ext/nokogiri/html_entity_lookup.h +0 -8
  201. data/ext/nokogiri/html_sax_parser_context.c +0 -116
  202. data/ext/nokogiri/html_sax_parser_context.h +0 -11
  203. data/ext/nokogiri/html_sax_push_parser.c +0 -87
  204. data/ext/nokogiri/html_sax_push_parser.h +0 -9
  205. data/ext/nokogiri/xml_attr.h +0 -9
  206. data/ext/nokogiri/xml_attribute_decl.h +0 -9
  207. data/ext/nokogiri/xml_cdata.h +0 -9
  208. data/ext/nokogiri/xml_comment.h +0 -9
  209. data/ext/nokogiri/xml_document.h +0 -23
  210. data/ext/nokogiri/xml_document_fragment.h +0 -10
  211. data/ext/nokogiri/xml_dtd.h +0 -10
  212. data/ext/nokogiri/xml_element_content.h +0 -10
  213. data/ext/nokogiri/xml_element_decl.h +0 -9
  214. data/ext/nokogiri/xml_encoding_handler.h +0 -8
  215. data/ext/nokogiri/xml_entity_decl.h +0 -10
  216. data/ext/nokogiri/xml_entity_reference.h +0 -9
  217. data/ext/nokogiri/xml_io.c +0 -61
  218. data/ext/nokogiri/xml_io.h +0 -11
  219. data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
  220. data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
  221. data/ext/nokogiri/xml_namespace.h +0 -15
  222. data/ext/nokogiri/xml_node.h +0 -13
  223. data/ext/nokogiri/xml_node_set.h +0 -12
  224. data/ext/nokogiri/xml_processing_instruction.h +0 -9
  225. data/ext/nokogiri/xml_reader.h +0 -10
  226. data/ext/nokogiri/xml_relax_ng.h +0 -9
  227. data/ext/nokogiri/xml_sax_parser.h +0 -39
  228. data/ext/nokogiri/xml_sax_parser_context.h +0 -10
  229. data/ext/nokogiri/xml_sax_push_parser.h +0 -9
  230. data/ext/nokogiri/xml_schema.h +0 -9
  231. data/ext/nokogiri/xml_syntax_error.h +0 -13
  232. data/ext/nokogiri/xml_text.h +0 -9
  233. data/ext/nokogiri/xml_xpath_context.h +0 -10
  234. data/ext/nokogiri/xslt_stylesheet.h +0 -14
  235. data/lib/nokogiri/html/document.rb +0 -335
  236. data/lib/nokogiri/html/document_fragment.rb +0 -49
  237. data/lib/nokogiri/html/element_description_defaults.rb +0 -671
  238. data/lib/nokogiri/html/sax/parser_context.rb +0 -16
  239. data/patches/libxml2/0001-Revert-Do-not-URI-escape-in-server-side-includes.patch +0 -78
  240. data/patches/libxml2/0002-Fix-nullptr-deref-with-XPath-logic-ops.patch +0 -54
  241. data/patches/libxml2/0003-Fix-infinite-loop-in-LZMA-decompression.patch +0 -50
  242. data/patches/sort-patches-by-date +0 -25
  243. data/ports/archives/libxml2-2.9.8.tar.gz +0 -0
  244. data/ports/archives/libxslt-1.1.32.tar.gz +0 -0
  245. data/suppressions/README.txt +0 -1
  246. data/suppressions/nokogiri_ruby-2.supp +0 -10
  247. data/tasks/test.rb +0 -100
  248. data/test/css/test_nthiness.rb +0 -226
  249. data/test/css/test_parser.rb +0 -386
  250. data/test/css/test_tokenizer.rb +0 -215
  251. data/test/css/test_xpath_visitor.rb +0 -96
  252. data/test/decorators/test_slop.rb +0 -23
  253. data/test/files/2ch.html +0 -108
  254. data/test/files/GH_1042.html +0 -18
  255. data/test/files/address_book.rlx +0 -12
  256. data/test/files/address_book.xml +0 -10
  257. data/test/files/atom.xml +0 -344
  258. data/test/files/bar/bar.xsd +0 -4
  259. data/test/files/bogus.xml +0 -0
  260. data/test/files/dont_hurt_em_why.xml +0 -422
  261. data/test/files/encoding.html +0 -82
  262. data/test/files/encoding.xhtml +0 -84
  263. data/test/files/exslt.xml +0 -8
  264. data/test/files/exslt.xslt +0 -35
  265. data/test/files/foo/foo.xsd +0 -4
  266. data/test/files/metacharset.html +0 -10
  267. data/test/files/namespace_pressure_test.xml +0 -1684
  268. data/test/files/noencoding.html +0 -47
  269. data/test/files/po.xml +0 -32
  270. data/test/files/po.xsd +0 -66
  271. data/test/files/saml/saml20assertion_schema.xsd +0 -283
  272. data/test/files/saml/saml20protocol_schema.xsd +0 -302
  273. data/test/files/saml/xenc_schema.xsd +0 -146
  274. data/test/files/saml/xmldsig_schema.xsd +0 -318
  275. data/test/files/shift_jis.html +0 -10
  276. data/test/files/shift_jis.xml +0 -5
  277. data/test/files/shift_jis_no_charset.html +0 -9
  278. data/test/files/slow-xpath.xml +0 -25509
  279. data/test/files/snuggles.xml +0 -3
  280. data/test/files/staff.dtd +0 -10
  281. data/test/files/staff.xml +0 -59
  282. data/test/files/staff.xslt +0 -32
  283. data/test/files/test_document_url/bar.xml +0 -2
  284. data/test/files/test_document_url/document.dtd +0 -4
  285. data/test/files/test_document_url/document.xml +0 -6
  286. data/test/files/tlm.html +0 -851
  287. data/test/files/to_be_xincluded.xml +0 -2
  288. data/test/files/valid_bar.xml +0 -2
  289. data/test/files/xinclude.xml +0 -4
  290. data/test/helper.rb +0 -271
  291. data/test/html/sax/test_parser.rb +0 -168
  292. data/test/html/sax/test_parser_context.rb +0 -46
  293. data/test/html/sax/test_parser_text.rb +0 -163
  294. data/test/html/sax/test_push_parser.rb +0 -87
  295. data/test/html/test_attributes.rb +0 -85
  296. data/test/html/test_builder.rb +0 -164
  297. data/test/html/test_document.rb +0 -712
  298. data/test/html/test_document_encoding.rb +0 -143
  299. data/test/html/test_document_fragment.rb +0 -310
  300. data/test/html/test_element_description.rb +0 -105
  301. data/test/html/test_named_characters.rb +0 -14
  302. data/test/html/test_node.rb +0 -212
  303. data/test/html/test_node_encoding.rb +0 -91
  304. data/test/namespaces/test_additional_namespaces_in_builder_doc.rb +0 -14
  305. data/test/namespaces/test_namespaces_aliased_default.rb +0 -24
  306. data/test/namespaces/test_namespaces_in_builder_doc.rb +0 -75
  307. data/test/namespaces/test_namespaces_in_cloned_doc.rb +0 -31
  308. data/test/namespaces/test_namespaces_in_created_doc.rb +0 -75
  309. data/test/namespaces/test_namespaces_in_parsed_doc.rb +0 -80
  310. data/test/namespaces/test_namespaces_preservation.rb +0 -31
  311. data/test/test_convert_xpath.rb +0 -135
  312. data/test/test_css_cache.rb +0 -47
  313. data/test/test_encoding_handler.rb +0 -48
  314. data/test/test_memory_leak.rb +0 -156
  315. data/test/test_nokogiri.rb +0 -138
  316. data/test/test_soap4r_sax.rb +0 -52
  317. data/test/test_xslt_transforms.rb +0 -314
  318. data/test/xml/node/test_save_options.rb +0 -28
  319. data/test/xml/node/test_subclass.rb +0 -44
  320. data/test/xml/sax/test_parser.rb +0 -402
  321. data/test/xml/sax/test_parser_context.rb +0 -115
  322. data/test/xml/sax/test_parser_text.rb +0 -202
  323. data/test/xml/sax/test_push_parser.rb +0 -265
  324. data/test/xml/test_attr.rb +0 -74
  325. data/test/xml/test_attribute_decl.rb +0 -86
  326. data/test/xml/test_builder.rb +0 -341
  327. data/test/xml/test_c14n.rb +0 -180
  328. data/test/xml/test_cdata.rb +0 -54
  329. data/test/xml/test_comment.rb +0 -40
  330. data/test/xml/test_document.rb +0 -982
  331. data/test/xml/test_document_encoding.rb +0 -31
  332. data/test/xml/test_document_fragment.rb +0 -298
  333. data/test/xml/test_dtd.rb +0 -187
  334. data/test/xml/test_dtd_encoding.rb +0 -31
  335. data/test/xml/test_element_content.rb +0 -56
  336. data/test/xml/test_element_decl.rb +0 -73
  337. data/test/xml/test_entity_decl.rb +0 -122
  338. data/test/xml/test_entity_reference.rb +0 -262
  339. data/test/xml/test_namespace.rb +0 -96
  340. data/test/xml/test_node.rb +0 -1325
  341. data/test/xml/test_node_attributes.rb +0 -115
  342. data/test/xml/test_node_encoding.rb +0 -75
  343. data/test/xml/test_node_inheritance.rb +0 -32
  344. data/test/xml/test_node_reparenting.rb +0 -592
  345. data/test/xml/test_node_set.rb +0 -809
  346. data/test/xml/test_parse_options.rb +0 -64
  347. data/test/xml/test_processing_instruction.rb +0 -30
  348. data/test/xml/test_reader.rb +0 -620
  349. data/test/xml/test_reader_encoding.rb +0 -134
  350. data/test/xml/test_relax_ng.rb +0 -60
  351. data/test/xml/test_schema.rb +0 -142
  352. data/test/xml/test_syntax_error.rb +0 -36
  353. data/test/xml/test_text.rb +0 -60
  354. data/test/xml/test_unparented_node.rb +0 -483
  355. data/test/xml/test_xinclude.rb +0 -83
  356. data/test/xml/test_xpath.rb +0 -470
  357. data/test/xslt/test_custom_functions.rb +0 -133
  358. data/test/xslt/test_exception_handling.rb +0 -37
@@ -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,374 +490,639 @@ 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)
552
+ end
553
+ end
554
+
555
+ def do_help
556
+ print(NOKOGIRI_HELP_MESSAGE)
557
+ exit!(0)
558
+ end
559
+
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.
570
+
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
377
582
  end
583
+
584
+ exit!(0)
378
585
  end
379
586
 
380
- def using_system_libraries?
381
- arg_config('--use-system-libraries', !!ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'])
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))
382
613
  end
383
614
 
384
615
  #
385
- # main
616
+ # main
386
617
  #
618
+ do_help if arg_config("--help")
619
+ do_clean if arg_config("--clean")
387
620
 
388
- case
389
- when arg_config('--help')
390
- do_help
391
- when arg_config('--clean')
392
- do_clean
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`")
625
+ end
626
+ append_cppflags "-I/usr/local/include"
393
627
  end
394
628
 
395
- if openbsd? && !using_system_libraries?
396
- if `#{ENV['CC'] || '/usr/bin/cc'} -v 2>&1` !~ /clang/
397
- ENV['CC'] ||= find_executable('egcc') or
398
- abort "Please install gcc 4.9+ from ports using `pkg_add -v gcc`"
399
- end
400
- ENV['CFLAGS'] = "#{ENV['CFLAGS']} -I /usr/local/include"
629
+ if ENV["CC"]
630
+ RbConfig::CONFIG["CC"] = RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"]
401
631
  end
402
632
 
403
- RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
404
633
  # use same c compiler for libxml and libxslt
405
- ENV['CC'] = RbConfig::MAKEFILE_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
406
647
 
407
- $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"])
408
653
 
409
- # Read CFLAGS from ENV and make sure compiling works.
410
- add_cflags(ENV["CFLAGS"])
654
+ # nokogumbo code uses C90/C99 features, let's make sure older compilers won't give
655
+ # errors/warnings. see #2302
656
+ append_cflags(["-std=c99", "-Wno-declaration-after-statement"])
411
657
 
412
- if windows?
413
- $CFLAGS << " -DXP_WIN -DXP_WIN32 -DUSE_INCLUDED_VASPRINTF"
414
- end
658
+ # gumbo html5 serialization is slower with O3, let's make sure we use O2
659
+ append_cflags("-O2")
415
660
 
416
- if solaris?
417
- $CFLAGS << " -DUSE_INCLUDED_VASPRINTF"
418
- end
661
+ # always include debugging information
662
+ append_cflags("-g")
419
663
 
420
- if darwin?
421
- # Let Apple LLVM/clang 5.1 ignore unknown compiler flags
422
- add_cflags("-Wno-error=unused-command-line-argument-hard-error-in-future")
423
- end
664
+ # we use at least one inline function in the C extension
665
+ append_cflags("-Winline")
424
666
 
425
- if nix?
426
- $CFLAGS << " -g -DXP_UNIX"
427
- end
667
+ # good to have no matter what Ruby was compiled with
668
+ append_cflags("-Wmissing-noreturn")
428
669
 
429
- if RUBY_PLATFORM =~ /mingw/i
430
- # Work around a character escaping bug in MSYS by passing an arbitrary
431
- # double quoted parameter to gcc. See https://sourceforge.net/p/mingw/bugs/2142
432
- $CPPFLAGS << ' "-Idummypath"'
670
+ # check integer loss of precision
671
+ if darwin?
672
+ append_cflags("-Wshorten-64-to-32")
673
+ else
674
+ append_cflags("-Wconversion -Wno-sign-conversion")
433
675
  end
434
676
 
435
- if RbConfig::MAKEFILE_CONFIG['CC'] =~ /gcc/
436
- $CFLAGS << " -O3" unless $CFLAGS[/-O\d/]
437
- $CFLAGS << " -Wall -Wcast-qual -Wwrite-strings -Wmissing-noreturn -Winline"
677
+ # handle clang variations, see #1101
678
+ if darwin?
679
+ append_cflags("-Wno-error=unused-command-line-argument-hard-error-in-future")
680
+ append_cflags("-Wno-unknown-warning-option")
438
681
  end
439
682
 
440
- case
441
- when using_system_libraries?
442
- message "Building nokogiri using system libraries.\n"
443
-
444
- dir_config('zlib')
683
+ # these tend to be noisy, but on occasion useful during development
684
+ # append_cflags(["-Wcast-qual", "-Wwrite-strings"])
445
685
 
446
- # Using system libraries means we rely on the system libxml2 with
447
- # regard to the iconv support.
686
+ # Add SDK-specific include path for macOS and brew versions before v2.2.12 (2020-04-08) [#1851, #1801]
687
+ macos_mojave_sdk_include_path = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libxml2"
688
+ if config_system_libraries? && darwin? && Dir.exist?(macos_mojave_sdk_include_path)
689
+ append_cppflags("-I#{macos_mojave_sdk_include_path}")
690
+ end
448
691
 
449
- dir_config('xml2').any? or package_config('libxml-2.0')
450
- dir_config('xslt').any? or package_config('libxslt')
451
- dir_config('exslt').any? or package_config('libexslt')
692
+ # Work around a character escaping bug in MSYS by passing an arbitrary double-quoted parameter to gcc.
693
+ # See https://sourceforge.net/p/mingw/bugs/2142
694
+ append_cppflags(' "-Idummypath"') if windows?
452
695
 
453
- check_libxml_version or abort "ERROR: cannot discover where libxml2 is located on your system. please make sure `pkg-config` is installed."
454
- check_libxml_version("2.6.21") or abort "ERROR: libxml2 version 2.6.21 or later is required!"
455
- check_libxml_version("2.9.3") or warn "WARNING: libxml2 version 2.9.3 or later is highly recommended, but proceeding anyway."
696
+ if config_system_libraries?
697
+ message "Building nokogiri using system libraries.\n"
698
+ ensure_package_configuration(
699
+ opt: "zlib",
700
+ pc: "zlib",
701
+ lib: "z",
702
+ headers: "zlib.h",
703
+ func: "gzdopen",
704
+ )
705
+ ensure_package_configuration(
706
+ opt: "xml2",
707
+ pc: "libxml-2.0",
708
+ lib: "xml2",
709
+ headers: "libxml/parser.h",
710
+ func: "xmlParseDoc",
711
+ )
712
+ ensure_package_configuration(
713
+ opt: "xslt",
714
+ pc: "libxslt",
715
+ lib: "xslt",
716
+ headers: "libxslt/xslt.h",
717
+ func: "xsltParseStylesheetDoc",
718
+ )
719
+ ensure_package_configuration(
720
+ opt: "exslt",
721
+ pc: "libexslt",
722
+ lib: "exslt",
723
+ headers: "libexslt/exslt.h",
724
+ func: "exsltFuncRegister",
725
+ )
726
+
727
+ have_libxml_headers?(REQUIRED_LIBXML_VERSION) ||
728
+ abort("ERROR: libxml2 version #{REQUIRED_LIBXML_VERSION} or later is required!")
729
+ have_libxml_headers?(RECOMMENDED_LIBXML_VERSION) ||
730
+ warn("WARNING: libxml2 version #{RECOMMENDED_LIBXML_VERSION} or later is highly recommended, but proceeding anyway.")
456
731
 
457
732
  else
458
733
  message "Building nokogiri using packaged libraries.\n"
459
734
 
460
- # The gem version constraint in the Rakefile is not respected at install time.
461
- # Keep this version in sync with the one in the Rakefile !
462
- require 'rubygems'
463
- gem 'mini_portile2', '~> 2.3.0'
464
- require 'mini_portile2'
465
- message "Using mini_portile version #{MiniPortile::VERSION}\n"
735
+ static_p = config_static?
736
+ message "Static linking is #{static_p ? "enabled" : "disabled"}.\n"
466
737
 
467
- require 'yaml'
738
+ cross_build_p = config_cross_build?
739
+ message "Cross build is #{cross_build_p ? "enabled" : "disabled"}.\n"
468
740
 
469
- static_p = enable_config('static', true) or
470
- message "Static linking is disabled.\n"
741
+ if needs_darwin_linker_hack
742
+ append_ldflags("-Wl,-flat_namespace")
743
+ end
471
744
 
472
- dir_config('zlib')
745
+ require "yaml"
746
+ dependencies = YAML.load_file(File.join(PACKAGE_ROOT_DIR, "dependencies.yml"))
473
747
 
474
- dependencies = YAML.load_file(File.join(ROOT, "dependencies.yml"))
748
+ dir_config("zlib")
475
749
 
476
- cross_build_p = enable_config("cross-build")
477
750
  if cross_build_p || windows?
478
751
  zlib_recipe = process_recipe("zlib", dependencies["zlib"]["version"], static_p, cross_build_p) do |recipe|
479
752
  recipe.files = [{
480
- url: "http://zlib.net/fossils/#{recipe.name}-#{recipe.version}.tar.gz",
481
- sha256: dependencies["zlib"]["sha256"]
482
- }]
483
- class << recipe
484
- attr_accessor :cross_build_p
485
-
486
- def configure
487
- Dir.chdir work_path do
488
- mk = File.read 'win32/Makefile.gcc'
489
- File.open 'win32/Makefile.gcc', 'wb' do |f|
490
- f.puts "BINARY_PATH = #{path}/bin"
491
- f.puts "LIBRARY_PATH = #{path}/lib"
492
- f.puts "INCLUDE_PATH = #{path}/include"
493
- mk.sub!(/^PREFIX\s*=\s*$/, "PREFIX = #{host}-") if cross_build_p
494
- f.puts mk
753
+ url: zlib_source(recipe.version),
754
+ sha256: dependencies["zlib"]["sha256"],
755
+ }]
756
+ if windows?
757
+ class << recipe
758
+ attr_accessor :cross_build_p
759
+
760
+ def configure
761
+ Dir.chdir(work_path) do
762
+ mk = File.read("win32/Makefile.gcc")
763
+ File.open("win32/Makefile.gcc", "wb") do |f|
764
+ f.puts "BINARY_PATH = #{path}/bin"
765
+ f.puts "LIBRARY_PATH = #{path}/lib"
766
+ f.puts "INCLUDE_PATH = #{path}/include"
767
+ mk.sub!(/^PREFIX\s*=\s*$/, "PREFIX = #{host}-") if cross_build_p
768
+ f.puts mk
769
+ end
770
+ end
771
+ end
772
+
773
+ def configured?
774
+ Dir.chdir(work_path) do
775
+ !!(File.read("win32/Makefile.gcc") =~ /^BINARY_PATH/)
495
776
  end
496
777
  end
497
- end
498
778
 
499
- def configured?
500
- Dir.chdir work_path do
501
- !! (File.read('win32/Makefile.gcc') =~ /^BINARY_PATH/)
779
+ def compile
780
+ execute("compile", "make -f win32/Makefile.gcc")
502
781
  end
503
- end
504
782
 
505
- def compile
506
- execute "compile", "make -f win32/Makefile.gcc"
783
+ def install
784
+ execute("install", "make -f win32/Makefile.gcc install")
785
+ end
507
786
  end
508
-
509
- def install
510
- execute "install", "make -f win32/Makefile.gcc install"
787
+ recipe.cross_build_p = cross_build_p
788
+ else
789
+ class << recipe
790
+ def configure
791
+ env = {}
792
+ env["CFLAGS"] = concat_flags(ENV["CFLAGS"], "-fPIC", "-g")
793
+ env["CHOST"] = host
794
+ execute("configure", ["./configure", "--static", configure_prefix], { env: env })
795
+ if darwin?
796
+ # needed as of zlib 1.2.13
797
+ Dir.chdir(work_path) do
798
+ makefile = File.read("Makefile").gsub(/^AR=.*$/, "AR=#{host}-libtool")
799
+ File.open("Makefile", "w") { |m| m.write(makefile) }
800
+ end
801
+ end
802
+ end
511
803
  end
512
804
  end
513
- recipe.cross_build_p = cross_build_p
514
805
  end
515
806
 
516
- libiconv_recipe = process_recipe("libiconv", dependencies["libiconv"]["version"], static_p, cross_build_p) do |recipe|
517
- recipe.files = [{
518
- url: "http://ftp.gnu.org/pub/gnu/libiconv/#{recipe.name}-#{recipe.version}.tar.gz",
519
- sha256: dependencies["libiconv"]["sha256"]
807
+ unless nix?
808
+ libiconv_recipe = process_recipe(
809
+ "libiconv",
810
+ dependencies["libiconv"]["version"],
811
+ static_p,
812
+ cross_build_p,
813
+ ) do |recipe|
814
+ recipe.files = [{
815
+ url: "https://ftp.gnu.org/pub/gnu/libiconv/#{recipe.name}-#{recipe.version}.tar.gz",
816
+ sha256: dependencies["libiconv"]["sha256"],
520
817
  }]
521
- recipe.configure_options += [
522
- "CPPFLAGS=-Wall",
523
- "CFLAGS=-O2 -g",
524
- "CXXFLAGS=-O2 -g",
525
- "LDFLAGS="
526
- ]
527
- end
528
- else
529
- if darwin? && !have_header('iconv.h')
530
- abort <<'EOM'.chomp
531
- -----
532
- The file "iconv.h" is missing in your build environment,
533
- which means you haven't installed Xcode Command Line Tools properly.
534
-
535
- To install Command Line Tools, try running `xcode-select --install` on
536
- terminal and follow the instructions. If it fails, open Xcode.app,
537
- select from the menu "Xcode" - "Open Developer Tool" - "More Developer
538
- Tools" to open the developer site, download the installer for your OS
539
- version and run it.
540
- -----
541
- EOM
818
+
819
+ # The libiconv configure script doesn't accept "arm64" host string but "aarch64"
820
+ recipe.host = recipe.host.gsub("arm64-apple-darwin", "aarch64-apple-darwin")
821
+
822
+ cflags = concat_flags(ENV["CFLAGS"], "-O2", "-U_FORTIFY_SOURCE", "-g")
823
+
824
+ recipe.configure_options += [
825
+ "--disable-dependency-tracking",
826
+ "CPPFLAGS=-Wall",
827
+ "CFLAGS=#{cflags}",
828
+ "CXXFLAGS=#{cflags}",
829
+ "LDFLAGS=",
830
+ ]
831
+ end
542
832
  end
833
+ elsif darwin? && !have_header("iconv.h")
834
+ abort(<<~EOM.chomp)
835
+ -----
836
+ The file "iconv.h" is missing in your build environment,
837
+ which means you haven't installed Xcode Command Line Tools properly.
838
+
839
+ To install Command Line Tools, try running `xcode-select --install` on
840
+ terminal and follow the instructions. If it fails, open Xcode.app,
841
+ select from the menu "Xcode" - "Open Developer Tool" - "More Developer
842
+ Tools" to open the developer site, download the installer for your OS
843
+ version and run it.
844
+ -----
845
+ EOM
846
+ end
847
+
848
+ if zlib_recipe
849
+ append_cppflags("-I#{zlib_recipe.path}/include")
850
+ $LIBPATH = ["#{zlib_recipe.path}/lib"] | $LIBPATH
851
+ ensure_package_configuration(
852
+ opt: "zlib",
853
+ pc: "zlib",
854
+ lib: "z",
855
+ headers: "zlib.h",
856
+ func: "gzdopen",
857
+ )
543
858
  end
544
859
 
545
- unless windows?
546
- preserving_globals {
547
- have_library('z', 'gzdopen', 'zlib.h')
548
- } or abort 'zlib is missing; necessary for building libxml2'
860
+ if libiconv_recipe
861
+ append_cppflags("-I#{libiconv_recipe.path}/include")
862
+ $LIBPATH = ["#{libiconv_recipe.path}/lib"] | $LIBPATH
863
+ ensure_package_configuration(
864
+ opt: "iconv",
865
+ pc: "iconv",
866
+ lib: "iconv",
867
+ headers: "iconv.h",
868
+ func: "iconv_open",
869
+ )
549
870
  end
550
871
 
551
872
  libxml2_recipe = process_recipe("libxml2", dependencies["libxml2"]["version"], static_p, cross_build_p) do |recipe|
552
- recipe.files = [{
553
- url: "http://xmlsoft.org/sources/#{recipe.name}-#{recipe.version}.tar.gz",
554
- sha256: dependencies["libxml2"]["sha256"]
873
+ source_dir = arg_config("--with-xml2-source-dir")
874
+ if source_dir
875
+ recipe.source_directory = source_dir
876
+ else
877
+ minor_version = Gem::Version.new(recipe.version).segments.take(2).join(".")
878
+ recipe.files = [{
879
+ url: "#{gnome_source}/sources/libxml2/#{minor_version}/#{recipe.name}-#{recipe.version}.tar.xz",
880
+ sha256: dependencies["libxml2"]["sha256"],
555
881
  }]
882
+ recipe.patch_files = Dir[File.join(PACKAGE_ROOT_DIR, "patches", "libxml2", "*.patch")].sort
883
+ end
884
+
885
+ cppflags = concat_flags(ENV["CPPFLAGS"])
886
+ cflags = concat_flags(ENV["CFLAGS"], "-O2", "-U_FORTIFY_SOURCE", "-g")
887
+
888
+ if cross_build_p
889
+ cppflags = concat_flags(cppflags, "-DNOKOGIRI_PRECOMPILED_LIBRARIES")
890
+ end
891
+
892
+ if zlib_recipe
893
+ recipe.configure_options << "--with-zlib=#{zlib_recipe.path}"
894
+ end
895
+
896
+ if libiconv_recipe
897
+ recipe.configure_options << "--with-iconv=#{libiconv_recipe.path}"
898
+ else
899
+ recipe.configure_options += iconv_configure_flags
900
+ end
901
+
902
+ if darwin? && !cross_build_p
903
+ recipe.configure_options += ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"]
904
+ end
905
+
906
+ if windows?
907
+ cflags = concat_flags(cflags, "-ULIBXML_STATIC", "-DIN_LIBXML")
908
+ end
909
+
910
+ recipe.configure_options << if source_dir
911
+ "--config-cache"
912
+ else
913
+ "--disable-dependency-tracking"
914
+ end
915
+
556
916
  recipe.configure_options += [
557
917
  "--without-python",
558
918
  "--without-readline",
559
- *(zlib_recipe ? ["--with-zlib=#{zlib_recipe.path}", "CFLAGS=-I#{zlib_recipe.path}/include"] : []),
560
- *(libiconv_recipe ? "--with-iconv=#{libiconv_recipe.path}" : iconv_configure_flags),
561
919
  "--with-c14n",
562
920
  "--with-debug",
563
- "--with-threads"
921
+ "--with-threads",
922
+ "CPPFLAGS=#{cppflags}",
923
+ "CFLAGS=#{cflags}",
564
924
  ]
565
925
  end
566
926
 
567
927
  libxslt_recipe = process_recipe("libxslt", dependencies["libxslt"]["version"], static_p, cross_build_p) do |recipe|
568
- recipe.files = [{
569
- url: "http://xmlsoft.org/sources/#{recipe.name}-#{recipe.version}.tar.gz",
570
- 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"],
571
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
+
572
957
  recipe.configure_options += [
573
958
  "--without-python",
574
959
  "--without-crypto",
575
960
  "--with-debug",
576
- "--with-libxml-prefix=#{sh_export_path(libxml2_recipe.path)}"
961
+ "--with-libxml-prefix=#{sh_export_path(libxml2_recipe.path)}",
962
+ "CFLAGS=#{cflags}",
577
963
  ]
578
964
  end
579
965
 
580
- $CFLAGS << ' ' << '-DNOKOGIRI_USE_PACKAGED_LIBRARIES'
581
- $LIBPATH = ["#{zlib_recipe.path}/lib"] | $LIBPATH if zlib_recipe
582
- $LIBPATH = ["#{libiconv_recipe.path}/lib"] | $LIBPATH if libiconv_recipe
583
-
584
- have_lzma = preserving_globals {
585
- have_library('lzma')
586
- }
966
+ append_cppflags("-DNOKOGIRI_PACKAGED_LIBRARIES")
967
+ append_cppflags("-DNOKOGIRI_PRECOMPILED_LIBRARIES") if cross_build_p
587
968
 
588
969
  $libs = $libs.shellsplit.tap do |libs|
589
970
  [libxml2_recipe, libxslt_recipe].each do |recipe|
590
971
  libname = recipe.name[/\Alib(.+)\z/, 1]
591
- 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|
592
974
  # call config scripts explicit with 'sh' for compat with Windows
593
- $CPPFLAGS = `sh #{config} --cflags`.strip << ' ' << $CPPFLAGS
594
- `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|
595
980
  case arg
596
981
  when /\A-L(.+)\z/
597
982
  # Prioritize ports' directories
598
- if $1.start_with?(ROOT + '/')
599
- $LIBPATH = [$1] | $LIBPATH
983
+ $LIBPATH = if Regexp.last_match(1).start_with?(PACKAGE_ROOT_DIR + "/")
984
+ [Regexp.last_match(1)] | $LIBPATH
600
985
  else
601
- $LIBPATH = $LIBPATH | [$1]
986
+ $LIBPATH | [Regexp.last_match(1)]
602
987
  end
603
988
  when /\A-l./
604
989
  libs.unshift(arg)
605
990
  else
606
- $LDFLAGS << ' ' << arg.shellescape
991
+ $LDFLAGS << " " << arg.shellescape
607
992
  end
608
993
  end
609
994
  end
610
995
 
611
- # Defining a macro that expands to a C string; double quotes are significant.
612
- $CPPFLAGS << ' ' << "-DNOKOGIRI_#{recipe.name.upcase}_PATH=\"#{recipe.path}\"".inspect
613
- $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}\\""])
614
998
 
615
999
  case libname
616
- when 'xml2'
1000
+ when "xml2"
617
1001
  # xslt-config --libs or pkg-config libxslt --libs does not include
618
1002
  # -llzma, so we need to add it manually when linking statically.
619
- if static_p && have_lzma
1003
+ if static_p && preserving_globals { local_have_library("lzma") }
620
1004
  # Add it at the end; GH #988
621
- libs << '-llzma'
1005
+ libs << "-llzma"
622
1006
  end
623
- when 'xslt'
1007
+ when "xslt"
624
1008
  # xslt-config does not have a flag to emit options including
625
1009
  # -lexslt, so add it manually.
626
- libs.unshift('-lexslt')
1010
+ libs.unshift("-lexslt")
627
1011
  end
628
1012
  end
629
1013
  end.shelljoin
630
1014
 
631
1015
  if static_p
1016
+ static_archive_ld_flag = needs_darwin_linker_hack ? ["-load_hidden"] : []
632
1017
  $libs = $libs.shellsplit.map do |arg|
633
1018
  case arg
634
- when '-lxml2'
635
- File.join(libxml2_recipe.path, 'lib', lib_a(arg))
636
- when '-lxslt', '-lexslt'
637
- 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))]
638
1023
  else
639
1024
  arg
640
1025
  end
641
- end.shelljoin
1026
+ end.flatten.shelljoin
642
1027
  end
643
- end
644
1028
 
645
- {
646
- "xml2" => ['xmlParseDoc', 'libxml/parser.h'],
647
- "xslt" => ['xsltParseStylesheetDoc', 'libxslt/xslt.h'],
648
- "exslt" => ['exsltFuncRegister', 'libexslt/exslt.h'],
649
- }.each do |lib, (func, header)|
650
- have_func(func, header) ||
651
- have_library(lib, func, header) ||
652
- have_library("lib#{lib}", func, header) or
653
- asplode("lib#{lib}")
1029
+ ensure_func("xmlParseDoc", "libxml/parser.h")
1030
+ ensure_func("xsltParseStylesheetDoc", "libxslt/xslt.h")
1031
+ ensure_func("exsltFuncRegister", "libexslt/exslt.h")
654
1032
  end
655
1033
 
656
- have_func('xmlHasFeature') or abort "xmlHasFeature() is missing."
657
- have_func('xmlFirstElementChild')
658
- have_func('xmlRelaxNGSetParserStructuredErrors')
659
- have_func('xmlRelaxNGSetParserStructuredErrors')
660
- have_func('xmlRelaxNGSetValidStructuredErrors')
661
- have_func('xmlSchemaSetValidStructuredErrors')
662
- 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_gc_location") # introduced in Ruby 2.7
1091
+ have_func("rb_category_warning") # introduced in Ruby 3.0
1092
+
1093
+ other_library_versions_string = OTHER_LIBRARY_VERSIONS.map { |k, v| [k, v].join(":") }.join(",")
1094
+ append_cppflags(%[-DNOKOGIRI_OTHER_LIBRARY_VERSIONS="\\"#{other_library_versions_string}\\""])
1095
+
1096
+ unless config_system_libraries?
1097
+ if cross_build_p
1098
+ # When precompiling native gems, copy packaged libraries' headers to ext/nokogiri/include
1099
+ # These are packaged up by the cross-compiling callback in the ExtensionTask
1100
+ copy_packaged_libraries_headers(
1101
+ to_path: File.join(PACKAGE_ROOT_DIR, "ext/nokogiri/include"),
1102
+ from_recipes: [libxml2_recipe, libxslt_recipe],
1103
+ )
1104
+ else
1105
+ # When compiling during installation, install packaged libraries' header files into ext/nokogiri/include
1106
+ copy_packaged_libraries_headers(
1107
+ to_path: "include",
1108
+ from_recipes: [libxml2_recipe, libxslt_recipe],
1109
+ )
1110
+ $INSTALLFILES << ["include/**/*.h", "$(rubylibdir)"]
1111
+ end
1112
+ end
663
1113
 
664
- create_makefile('nokogiri/nokogiri')
1114
+ create_makefile("nokogiri/nokogiri")
665
1115
 
666
- if enable_config('clean', true)
1116
+ if config_clean?
667
1117
  # Do not clean if run in a development work tree.
668
- File.open('Makefile', 'at') do |mk|
669
- mk.print <<EOF
670
- all: clean-ports
1118
+ File.open("Makefile", "at") do |mk|
1119
+ mk.print(<<~EOF)
671
1120
 
672
- clean-ports: $(DLLIB)
673
- -$(Q)$(RUBY) $(srcdir)/extconf.rb --clean --#{static_p ? 'enable' : 'disable'}-static
674
- EOF
1121
+ all: clean-ports
1122
+ clean-ports: $(DLLIB)
1123
+ \t-$(Q)$(RUBY) $(srcdir)/extconf.rb --clean --#{static_p ? "enable" : "disable"}-static
1124
+ EOF
675
1125
  end
676
1126
  end
677
1127
 
678
- # :startdoc:
1128
+ # rubocop:enable Style/GlobalVars