nokogiri 1.10.9 → 1.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

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