nokogiri 1.9.1 → 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 (226) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +45 -0
  3. data/LICENSE-DEPENDENCIES.md +1636 -1024
  4. data/LICENSE.md +5 -28
  5. data/README.md +203 -89
  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 +864 -418
  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 +17 -17
  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 -240
  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 +135 -61
  33. data/ext/nokogiri/xml_node.c +1346 -677
  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 +93 -48
  134. data/lib/nokogiri/xml/dtd.rb +4 -2
  135. data/lib/nokogiri/xml/element_content.rb +12 -2
  136. data/lib/nokogiri/xml/element_decl.rb +6 -2
  137. data/lib/nokogiri/xml/entity_decl.rb +7 -3
  138. data/lib/nokogiri/xml/entity_reference.rb +2 -0
  139. data/lib/nokogiri/xml/namespace.rb +45 -0
  140. data/lib/nokogiri/xml/node/save_options.rb +23 -8
  141. data/lib/nokogiri/xml/node.rb +1088 -418
  142. data/lib/nokogiri/xml/node_set.rb +173 -63
  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 +128 -265
  178. data/ext/nokogiri/html_document.c +0 -170
  179. data/ext/nokogiri/html_document.h +0 -10
  180. data/ext/nokogiri/html_element_description.c +0 -279
  181. data/ext/nokogiri/html_element_description.h +0 -10
  182. data/ext/nokogiri/html_entity_lookup.c +0 -32
  183. data/ext/nokogiri/html_entity_lookup.h +0 -8
  184. data/ext/nokogiri/html_sax_parser_context.c +0 -116
  185. data/ext/nokogiri/html_sax_parser_context.h +0 -11
  186. data/ext/nokogiri/html_sax_push_parser.c +0 -87
  187. data/ext/nokogiri/html_sax_push_parser.h +0 -9
  188. data/ext/nokogiri/xml_attr.h +0 -9
  189. data/ext/nokogiri/xml_attribute_decl.h +0 -9
  190. data/ext/nokogiri/xml_cdata.h +0 -9
  191. data/ext/nokogiri/xml_comment.h +0 -9
  192. data/ext/nokogiri/xml_document.h +0 -23
  193. data/ext/nokogiri/xml_document_fragment.h +0 -10
  194. data/ext/nokogiri/xml_dtd.h +0 -10
  195. data/ext/nokogiri/xml_element_content.h +0 -10
  196. data/ext/nokogiri/xml_element_decl.h +0 -9
  197. data/ext/nokogiri/xml_encoding_handler.h +0 -8
  198. data/ext/nokogiri/xml_entity_decl.h +0 -10
  199. data/ext/nokogiri/xml_entity_reference.h +0 -9
  200. data/ext/nokogiri/xml_io.c +0 -61
  201. data/ext/nokogiri/xml_io.h +0 -11
  202. data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
  203. data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
  204. data/ext/nokogiri/xml_namespace.h +0 -14
  205. data/ext/nokogiri/xml_node.h +0 -13
  206. data/ext/nokogiri/xml_node_set.h +0 -12
  207. data/ext/nokogiri/xml_processing_instruction.h +0 -9
  208. data/ext/nokogiri/xml_reader.h +0 -10
  209. data/ext/nokogiri/xml_relax_ng.h +0 -9
  210. data/ext/nokogiri/xml_sax_parser.h +0 -39
  211. data/ext/nokogiri/xml_sax_parser_context.h +0 -10
  212. data/ext/nokogiri/xml_sax_push_parser.h +0 -9
  213. data/ext/nokogiri/xml_schema.h +0 -9
  214. data/ext/nokogiri/xml_syntax_error.h +0 -13
  215. data/ext/nokogiri/xml_text.h +0 -9
  216. data/ext/nokogiri/xml_xpath_context.h +0 -10
  217. data/ext/nokogiri/xslt_stylesheet.h +0 -14
  218. data/lib/nokogiri/html/document.rb +0 -335
  219. data/lib/nokogiri/html/document_fragment.rb +0 -49
  220. data/lib/nokogiri/html/element_description_defaults.rb +0 -671
  221. data/lib/nokogiri/html/sax/parser_context.rb +0 -16
  222. data/patches/libxml2/0001-Revert-Do-not-URI-escape-in-server-side-includes.patch +0 -78
  223. data/patches/libxml2/0002-Fix-nullptr-deref-with-XPath-logic-ops.patch +0 -54
  224. data/patches/libxml2/0003-Fix-infinite-loop-in-LZMA-decompression.patch +0 -50
  225. data/ports/archives/libxml2-2.9.8.tar.gz +0 -0
  226. data/ports/archives/libxslt-1.1.32.tar.gz +0 -0
@@ -1,208 +1,386 @@
1
- # :stopdoc:
2
- ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
1
+ # frozen_string_literal: true
3
2
 
4
- require 'mkmf'
3
+ # rubocop:disable Style/GlobalVars
5
4
 
6
- ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
5
+ ENV["RC_ARCHS"] = "" if RUBY_PLATFORM.include?("darwin")
6
+
7
+ require "mkmf"
8
+ require "rbconfig"
9
+ require "fileutils"
10
+ require "shellwords"
11
+ require "pathname"
12
+
13
+ # helpful constants
14
+ PACKAGE_ROOT_DIR = File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
15
+ REQUIRED_LIBXML_VERSION = "2.6.21"
16
+ RECOMMENDED_LIBXML_VERSION = "2.9.3"
17
+
18
+ REQUIRED_MINI_PORTILE_VERSION = "~> 2.8.2" # keep this version in sync with the one in the gemspec
19
+ REQUIRED_PKG_CONFIG_VERSION = "~> 1.1"
20
+
21
+ # Keep track of what versions of what libraries we build against
22
+ OTHER_LIBRARY_VERSIONS = {}
23
+
24
+ NOKOGIRI_HELP_MESSAGE = <<~HELP
25
+ USAGE: ruby #{$PROGRAM_NAME} [options]
26
+
27
+ Flags that are always valid:
28
+
29
+ --use-system-libraries
30
+ --enable-system-libraries
31
+ Use system libraries instead of building and using the packaged libraries.
32
+
33
+ --disable-system-libraries
34
+ Use the packaged libraries, and ignore the system libraries. This is the default on most
35
+ platforms, and overrides `--use-system-libraries` and the environment variable
36
+ `NOKOGIRI_USE_SYSTEM_LIBRARIES`.
37
+
38
+ --disable-clean
39
+ Do not clean out intermediate files after successful build.
40
+
41
+ --prevent-strip
42
+ Take steps to prevent stripping the symbol table and debugging info from the shared
43
+ library, potentially overriding RbConfig's CFLAGS/LDFLAGS/DLDFLAGS.
44
+
45
+
46
+ Flags only used when using system libraries:
47
+
48
+ General:
49
+
50
+ --with-opt-dir=DIRECTORY
51
+ Look for headers and libraries in DIRECTORY.
52
+
53
+ --with-opt-lib=DIRECTORY
54
+ Look for libraries in DIRECTORY.
55
+
56
+ --with-opt-include=DIRECTORY
57
+ Look for headers in DIRECTORY.
58
+
59
+
60
+ Related to zlib:
61
+
62
+ --with-zlib-dir=DIRECTORY
63
+ Look for zlib headers and library in DIRECTORY.
64
+
65
+ --with-zlib-lib=DIRECTORY
66
+ Look for zlib library in DIRECTORY.
67
+
68
+ --with-zlib-include=DIRECTORY
69
+ Look for zlib headers in DIRECTORY.
70
+
71
+
72
+ Related to iconv:
73
+
74
+ --with-iconv-dir=DIRECTORY
75
+ Look for iconv headers and library in DIRECTORY.
76
+
77
+ --with-iconv-lib=DIRECTORY
78
+ Look for iconv library in DIRECTORY.
79
+
80
+ --with-iconv-include=DIRECTORY
81
+ Look for iconv headers in DIRECTORY.
82
+
83
+
84
+ Related to libxml2:
85
+
86
+ --with-xml2-dir=DIRECTORY
87
+ Look for xml2 headers and library in DIRECTORY.
88
+
89
+ --with-xml2-lib=DIRECTORY
90
+ Look for xml2 library in DIRECTORY.
91
+
92
+ --with-xml2-include=DIRECTORY
93
+ Look for xml2 headers in DIRECTORY.
94
+
95
+ --with-xml2-source-dir=DIRECTORY
96
+ (dev only) Build libxml2 from the source code in DIRECTORY
97
+
98
+
99
+ Related to libxslt:
100
+
101
+ --with-xslt-dir=DIRECTORY
102
+ Look for xslt headers and library in DIRECTORY.
103
+
104
+ --with-xslt-lib=DIRECTORY
105
+ Look for xslt library in DIRECTORY.
106
+
107
+ --with-xslt-include=DIRECTORY
108
+ Look for xslt headers in DIRECTORY.
109
+
110
+ --with-xslt-source-dir=DIRECTORY
111
+ (dev only) Build libxslt from the source code in DIRECTORY
112
+
113
+
114
+ Related to libexslt:
115
+
116
+ --with-exslt-dir=DIRECTORY
117
+ Look for exslt headers and library in DIRECTORY.
118
+
119
+ --with-exslt-lib=DIRECTORY
120
+ Look for exslt library in DIRECTORY.
121
+
122
+ --with-exslt-include=DIRECTORY
123
+ Look for exslt headers in DIRECTORY.
124
+
125
+
126
+ Flags only used when building and using the packaged libraries:
127
+
128
+ --disable-static
129
+ Do not statically link packaged libraries, instead use shared libraries.
130
+
131
+ --enable-cross-build
132
+ Enable cross-build mode. (You probably do not want to set this manually.)
133
+
134
+
135
+ Environment variables used:
136
+
137
+ NOKOGIRI_USE_SYSTEM_LIBRARIES
138
+ Equivalent to `--enable-system-libraries` when set, even if nil or blank.
139
+
140
+ CC
141
+ Use this path to invoke the compiler instead of `RbConfig::CONFIG['CC']`
142
+
143
+ CPPFLAGS
144
+ If this string is accepted by the C preprocessor, add it to the flags passed to the C preprocessor
145
+
146
+ CFLAGS
147
+ If this string is accepted by the compiler, add it to the flags passed to the compiler
148
+
149
+ LDFLAGS
150
+ If this string is accepted by the linker, add it to the flags passed to the linker
151
+
152
+ LIBS
153
+ Add this string to the flags passed to the linker
154
+ HELP
7
155
 
8
156
  #
9
- # functions
157
+ # utility functions
10
158
  #
159
+ def config_clean?
160
+ enable_config("clean", true)
161
+ end
162
+
163
+ def config_static?
164
+ default_static = !truffle?
165
+ enable_config("static", default_static)
166
+ end
167
+
168
+ def config_cross_build?
169
+ enable_config("cross-build")
170
+ end
171
+
172
+ def config_system_libraries?
173
+ enable_config("system-libraries", ENV.key?("NOKOGIRI_USE_SYSTEM_LIBRARIES")) do |_, default|
174
+ arg_config("--use-system-libraries", default)
175
+ end
176
+ end
177
+
11
178
  def windows?
12
- RbConfig::CONFIG['target_os'] =~ /mingw32|mswin/
179
+ RbConfig::CONFIG["target_os"].match?(/mingw|mswin/)
13
180
  end
14
181
 
15
182
  def solaris?
16
- RbConfig::CONFIG['target_os'] =~ /solaris/
183
+ RbConfig::CONFIG["target_os"].include?("solaris")
17
184
  end
18
185
 
19
186
  def darwin?
20
- RbConfig::CONFIG['target_os'] =~ /darwin/
187
+ RbConfig::CONFIG["target_os"].include?("darwin")
21
188
  end
22
189
 
23
190
  def openbsd?
24
- RbConfig::CONFIG['target_os'] =~ /openbsd/
191
+ RbConfig::CONFIG["target_os"].include?("openbsd")
25
192
  end
26
193
 
27
- def nix?
28
- ! (windows? || solaris? || darwin?)
194
+ def aix?
195
+ RbConfig::CONFIG["target_os"].include?("aix")
29
196
  end
30
197
 
31
- def sh_export_path path
32
- # because libxslt 1.1.29 configure.in uses AC_PATH_TOOL which treats ":"
33
- # as a $PATH separator, we need to convert windows paths from
34
- #
35
- # C:/path/to/foo
36
- #
37
- # to
38
- #
39
- # /C/path/to/foo
40
- #
41
- # which is sh-compatible, in order to find things properly during
42
- # configuration
43
- if windows?
44
- match = Regexp.new("^([A-Z]):(/.*)").match(path)
45
- if match && match.length == 3
46
- return File.join("/", match[1], match[2])
47
- end
48
- end
49
- path
198
+ def nix?
199
+ !(windows? || solaris? || darwin?)
50
200
  end
51
201
 
52
- def do_help
53
- print <<HELP
54
- usage: ruby #{$0} [options]
55
-
56
- --disable-clean
57
- Do not clean out intermediate files after successful build.
58
-
59
- --disable-static
60
- Do not statically link bundled libraries.
61
-
62
- --with-iconv-dir=DIR
63
- Use the iconv library placed under DIR.
202
+ def truffle?
203
+ RUBY_ENGINE == "truffleruby"
204
+ end
64
205
 
65
- --with-zlib-dir=DIR
66
- Use the zlib library placed under DIR.
206
+ def concat_flags(*args)
207
+ args.compact.join(" ")
208
+ end
67
209
 
68
- --use-system-libraries
69
- Use system libraries instead of building and using the bundled
70
- libraries.
210
+ def local_have_library(lib, func = nil, headers = nil)
211
+ have_library(lib, func, headers) || have_library("lib#{lib}", func, headers)
212
+ end
71
213
 
72
- --with-xml2-dir=DIR / --with-xml2-config=CONFIG
73
- --with-xslt-dir=DIR / --with-xslt-config=CONFIG
74
- --with-exslt-dir=DIR / --with-exslt-config=CONFIG
75
- Use libxml2/libxslt/libexslt as specified.
214
+ def zlib_source(version_string)
215
+ # As of 2022-12, I'm starting to see failed downloads often enough from zlib.net that I want to
216
+ # change the default to github.
217
+ if ENV["NOKOGIRI_USE_CANONICAL_ZLIB_SOURCE"]
218
+ "https://zlib.net/fossils/zlib-#{version_string}.tar.gz"
219
+ else
220
+ "https://github.com/madler/zlib/releases/download/v#{version_string}/zlib-#{version_string}.tar.gz"
221
+ end
222
+ end
76
223
 
77
- --enable-cross-build
78
- Do cross-build.
79
- HELP
80
- exit! 0
224
+ def gnome_source
225
+ # As of 2022-02-20, some mirrors have expired SSL certificates. I'm able to retrieve from my home,
226
+ # but whatever host is resolved on the github actions workers see an expired cert.
227
+ #
228
+ # See https://github.com/sparklemotion/nokogiri/runs/5266206403?check_suite_focus=true
229
+ if ENV["NOKOGIRI_USE_CANONICAL_GNOME_SOURCE"]
230
+ "https://download.gnome.org"
231
+ else
232
+ "https://muug.ca/mirror/gnome" # old reliable
233
+ end
81
234
  end
82
235
 
83
- def do_clean
84
- require 'pathname'
85
- require 'fileutils'
236
+ LOCAL_PACKAGE_RESPONSE = Object.new
237
+ def LOCAL_PACKAGE_RESPONSE.%(package)
238
+ package ? "yes: #{package}" : "no"
239
+ end
86
240
 
87
- root = Pathname(ROOT)
88
- pwd = Pathname(Dir.pwd)
241
+ # wrapper around MakeMakefil#pkg_config and the PKGConfig gem
242
+ def try_package_configuration(pc)
243
+ unless ENV.key?("NOKOGIRI_TEST_PKG_CONFIG_GEM")
244
+ # try MakeMakefile#pkg_config, which uses the system utility `pkg-config`.
245
+ return if checking_for("#{pc} using `pkg_config`", LOCAL_PACKAGE_RESPONSE) do
246
+ pkg_config(pc)
247
+ end
248
+ end
89
249
 
90
- # Skip if this is a development work tree
91
- unless (root + '.git').exist?
92
- message "Cleaning files only used during build.\n"
250
+ # `pkg-config` probably isn't installed, which appears to be the case for lots of freebsd systems.
251
+ # let's fall back to the pkg-config gem, which knows how to parse .pc files, and wrap it with the
252
+ # same logic as MakeMakefile#pkg_config
253
+ begin
254
+ require "rubygems"
255
+ gem("pkg-config", REQUIRED_PKG_CONFIG_VERSION)
256
+ require "pkg-config"
93
257
 
94
- # (root + 'tmp') cannot be removed at this stage because
95
- # nokogiri.so is yet to be copied to lib.
258
+ checking_for("#{pc} using pkg-config gem version #{PKGConfig::VERSION}", LOCAL_PACKAGE_RESPONSE) do
259
+ if PKGConfig.have_package(pc)
260
+ cflags = PKGConfig.cflags(pc)
261
+ ldflags = PKGConfig.libs_only_L(pc)
262
+ libs = PKGConfig.libs_only_l(pc)
96
263
 
97
- # clean the ports build directory
98
- Pathname.glob(pwd.join('tmp', '*', 'ports')) do |dir|
99
- FileUtils.rm_rf(dir, verbose: true)
100
- end
264
+ Logging.message("pkg-config gem found package configuration for %s\n", pc)
265
+ Logging.message("cflags: %s\nldflags: %s\nlibs: %s\n\n", cflags, ldflags, libs)
101
266
 
102
- if enable_config('static')
103
- # ports installation can be safely removed if statically linked.
104
- FileUtils.rm_rf(root + 'ports', verbose: true)
105
- else
106
- FileUtils.rm_rf(root + 'ports' + 'archives', verbose: true)
267
+ [cflags, ldflags, libs]
268
+ end
107
269
  end
270
+ rescue LoadError
271
+ message("Please install either the `pkg-config` utility or the `pkg-config` rubygem.\n")
108
272
  end
109
-
110
- exit! 0
111
273
  end
112
274
 
113
- def package_config pkg, options={}
114
- package = pkg_config(pkg)
115
- return package if package
116
-
117
- begin
118
- require 'rubygems'
119
- gem 'pkg-config', (gem_ver='~> 1.1')
120
- require 'pkg-config' and message("Using pkg-config gem version #{PKGConfig::VERSION}\n")
121
- rescue LoadError
122
- message "pkg-config could not be used to find #{pkg}\nPlease install either `pkg-config` or the pkg-config gem per\n\n gem install pkg-config -v #{gem_ver.inspect}\n\n"
123
- else
124
- return nil unless PKGConfig.have_package(pkg)
275
+ # set up mkmf to link against the library if we can find it
276
+ def have_package_configuration(opt: nil, pc: nil, lib:, func:, headers:)
277
+ if opt
278
+ dir_config(opt)
279
+ dir_config("opt")
280
+ end
125
281
 
126
- cflags = PKGConfig.cflags(pkg)
127
- ldflags = PKGConfig.libs_only_L(pkg)
128
- libs = PKGConfig.libs_only_l(pkg)
282
+ # see if we have enough path info to do this without trying any harder
283
+ unless ENV.key?("NOKOGIRI_TEST_PKG_CONFIG")
284
+ return true if local_have_library(lib, func, headers)
285
+ end
129
286
 
130
- Logging::message "PKGConfig package configuration for %s\n", pkg
131
- Logging::message "cflags: %s\nldflags: %s\nlibs: %s\n\n", cflags, ldflags, libs
287
+ try_package_configuration(pc) if pc
132
288
 
133
- [cflags, ldflags, libs]
134
- end
289
+ # verify that we can compile and link against the library
290
+ local_have_library(lib, func, headers)
135
291
  end
136
292
 
137
- def nokogiri_try_compile
138
- try_compile "int main() {return 0;}", "", {werror: true}
293
+ def ensure_package_configuration(opt: nil, pc: nil, lib:, func:, headers:)
294
+ have_package_configuration(opt: opt, pc: pc, lib: lib, func: func, headers: headers) ||
295
+ abort_could_not_find_library(lib)
139
296
  end
140
297
 
141
- def check_libxml_version version=nil
142
- source = if version.nil?
143
- <<-SRC
144
- #include <libxml/xmlversion.h>
145
- SRC
146
- else
147
- version_int = sprintf "%d%2.2d%2.2d", *(version.split("."))
148
- <<-SRC
149
- #include <libxml/xmlversion.h>
150
- #if LIBXML_VERSION < #{version_int}
151
- #error libxml2 is older than #{version}
152
- #endif
153
- SRC
154
- end
155
-
156
- try_cpp source
157
- end
158
-
159
- def add_cflags(flags)
160
- print "checking if the C compiler accepts #{flags}... "
161
- with_cflags("#{$CFLAGS} #{flags}") do
162
- if nokogiri_try_compile
163
- puts 'yes'
164
- true
165
- else
166
- puts 'no'
167
- false
168
- end
169
- end
298
+ def ensure_func(func, headers = nil)
299
+ have_func(func, headers) || abort_could_not_find_library(func)
170
300
  end
171
301
 
172
302
  def preserving_globals
173
- values = [
174
- $arg_config,
175
- $CFLAGS, $CPPFLAGS,
176
- $LDFLAGS, $LIBPATH, $libs
177
- ].map(&:dup)
303
+ values = [$arg_config, $INCFLAGS, $CFLAGS, $CPPFLAGS, $LDFLAGS, $DLDFLAGS, $LIBPATH, $libs].map(&:dup)
178
304
  yield
179
305
  ensure
180
- $arg_config,
181
- $CFLAGS, $CPPFLAGS,
182
- $LDFLAGS, $LIBPATH, $libs =
183
- values
306
+ $arg_config, $INCFLAGS, $CFLAGS, $CPPFLAGS, $LDFLAGS, $DLDFLAGS, $LIBPATH, $libs = values
307
+ end
308
+
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-----")
312
+ end
313
+
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
184
349
  end
185
350
 
186
- def asplode(lib)
187
- abort "-----\n#{lib} is missing. Please locate mkmf.log to investigate how it is failing.\n-----"
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)
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 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,378 +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
522
 
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:
523
+ message(<<~EOM) if name != "libgumbo"
341
524
 
342
- gem install nokogiri -- --use-system-libraries
343
- [--with-xml2-config=/path/to/xml2-config]
344
- [--with-xslt-config=/path/to/xslt-config]
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:
345
529
 
346
- If you are using Bundler, tell it to use the option:
530
+ https://nokogiri.org/tutorials/installing_nokogiri.html#installing-using-standard-system-libraries
347
531
 
348
- bundle config build.nokogiri --use-system-libraries
349
- bundle install
350
- EOS
532
+ EOM
351
533
 
352
- message <<-"EOS" if name == 'libxml2'
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.
353
537
 
354
- Note, however, that nokogiri is not fully compatible with arbitrary
355
- versions of libxml2 provided by OS/package vendors.
356
- EOS
538
+ EOM
357
539
 
358
- message <<-"EOS"
359
- ************************************************************************
360
- EOS
361
-
362
- checkpoint = "#{recipe.target}/#{recipe.name}-#{recipe.version}-#{recipe.host}.installed"
363
- unless File.exist?(checkpoint)
364
- chdir_for_build do
365
- recipe.cook
366
- end
367
- FileUtils.touch checkpoint
540
+ chdir_for_build { recipe.cook }
541
+ FileUtils.touch(checkpoint)
368
542
  end
369
543
  recipe.activate
370
544
  end
371
545
  end
372
546
 
373
- def lib_a(ldflag)
374
- case ldflag
375
- when /\A-l(.+)/
376
- "lib#{$1}.#{$LIBEXT}"
547
+ def copy_packaged_libraries_headers(to_path:, from_recipes:)
548
+ FileUtils.rm_rf(to_path, secure: true)
549
+ FileUtils.mkdir(to_path)
550
+ from_recipes.each do |recipe|
551
+ FileUtils.cp_r(Dir[File.join(recipe.path, "include/*")], to_path)
377
552
  end
378
553
  end
379
554
 
380
- def using_system_libraries?
381
- arg_config('--use-system-libraries', !!ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'])
555
+ def do_help
556
+ print(NOKOGIRI_HELP_MESSAGE)
557
+ exit!(0)
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
582
+ end
583
+
584
+ exit!(0)
382
585
  end
383
586
 
587
+ # In ruby 3.2, symbol resolution changed on Darwin, to introduce the `-bundle_loader` flag to
588
+ # resolve symbols against the ruby binary.
384
589
  #
385
- # main
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).
386
593
  #
387
-
388
- case
389
- when arg_config('--help')
390
- do_help
391
- when arg_config('--clean')
392
- do_clean
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))
393
613
  end
394
614
 
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`"
615
+ #
616
+ # main
617
+ #
618
+ do_help if arg_config("--help")
619
+ do_clean if arg_config("--clean")
620
+
621
+ if openbsd? && !config_system_libraries?
622
+ unless %x(#{ENV["CC"] || "/usr/bin/cc"} -v 2>&1).include?("clang")
623
+ (ENV["CC"] ||= find_executable("egcc")) ||
624
+ abort("Please install gcc 4.9+ from ports using `pkg_add -v gcc`")
399
625
  end
400
- ENV['CFLAGS'] = "#{ENV['CFLAGS']} -I /usr/local/include"
626
+ append_cppflags "-I/usr/local/include"
401
627
  end
402
628
 
403
- if ENV['CC']
404
- RbConfig::CONFIG['CC'] = RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC']
629
+ if ENV["CC"]
630
+ RbConfig::CONFIG["CC"] = RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"]
405
631
  end
632
+
406
633
  # use same c compiler for libxml and libxslt
407
- ENV['CC'] = RbConfig::CONFIG['CC']
634
+ ENV["CC"] = RbConfig::CONFIG["CC"]
635
+
636
+ if arg_config("--prevent-strip")
637
+ old_cflags = $CFLAGS.split.join(" ")
638
+ old_ldflags = $LDFLAGS.split.join(" ")
639
+ old_dldflags = $DLDFLAGS.split.join(" ")
640
+ $CFLAGS = $CFLAGS.split.reject { |flag| flag == "-s" }.join(" ")
641
+ $LDFLAGS = $LDFLAGS.split.reject { |flag| flag == "-s" }.join(" ")
642
+ $DLDFLAGS = $DLDFLAGS.split.reject { |flag| flag == "-s" }.join(" ")
643
+ puts "Prevent stripping by removing '-s' from $CFLAGS" if old_cflags != $CFLAGS
644
+ puts "Prevent stripping by removing '-s' from $LDFLAGS" if old_ldflags != $LDFLAGS
645
+ puts "Prevent stripping by removing '-s' from $DLDFLAGS" if old_dldflags != $DLDFLAGS
646
+ end
408
647
 
409
- $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"])
410
653
 
411
- # Read CFLAGS from ENV and make sure compiling works.
412
- 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"])
413
657
 
414
- if windows?
415
- $CFLAGS << " -DXP_WIN -DXP_WIN32 -DUSE_INCLUDED_VASPRINTF"
416
- end
658
+ # gumbo html5 serialization is slower with O3, let's make sure we use O2
659
+ append_cflags("-O2")
417
660
 
418
- if solaris?
419
- $CFLAGS << " -DUSE_INCLUDED_VASPRINTF"
420
- end
661
+ # always include debugging information
662
+ append_cflags("-g")
421
663
 
422
- if darwin?
423
- # Let Apple LLVM/clang 5.1 ignore unknown compiler flags
424
- add_cflags("-Wno-error=unused-command-line-argument-hard-error-in-future")
425
- end
664
+ # we use at least one inline function in the C extension
665
+ append_cflags("-Winline")
426
666
 
427
- if nix?
428
- $CFLAGS << " -g -DXP_UNIX"
429
- end
667
+ # good to have no matter what Ruby was compiled with
668
+ append_cflags("-Wmissing-noreturn")
430
669
 
431
- if RUBY_PLATFORM =~ /mingw/i
432
- # Work around a character escaping bug in MSYS by passing an arbitrary
433
- # double quoted parameter to gcc. See https://sourceforge.net/p/mingw/bugs/2142
434
- $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")
435
675
  end
436
676
 
437
- if RbConfig::CONFIG['CC'] =~ /gcc/
438
- $CFLAGS << " -O3" unless $CFLAGS[/-O\d/]
439
- $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")
440
681
  end
441
682
 
442
- case
443
- when using_system_libraries?
444
- message "Building nokogiri using system libraries.\n"
445
-
446
- dir_config('zlib')
683
+ # these tend to be noisy, but on occasion useful during development
684
+ # append_cflags(["-Wcast-qual", "-Wwrite-strings"])
447
685
 
448
- # Using system libraries means we rely on the system libxml2 with
449
- # 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
450
691
 
451
- dir_config('xml2').any? or package_config('libxml-2.0')
452
- dir_config('xslt').any? or package_config('libxslt')
453
- 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?
454
695
 
455
- check_libxml_version or abort "ERROR: cannot discover where libxml2 is located on your system. please make sure `pkg-config` is installed."
456
- check_libxml_version("2.6.21") or abort "ERROR: libxml2 version 2.6.21 or later is required!"
457
- 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.")
458
731
 
459
732
  else
460
733
  message "Building nokogiri using packaged libraries.\n"
461
734
 
462
- # The gem version constraint in the Rakefile is not respected at install time.
463
- # Keep this version in sync with the one in the Rakefile !
464
- require 'rubygems'
465
- gem 'mini_portile2', '~> 2.4.0'
466
- require 'mini_portile2'
467
- message "Using mini_portile version #{MiniPortile::VERSION}\n"
735
+ static_p = config_static?
736
+ message "Static linking is #{static_p ? "enabled" : "disabled"}.\n"
468
737
 
469
- require 'yaml'
738
+ cross_build_p = config_cross_build?
739
+ message "Cross build is #{cross_build_p ? "enabled" : "disabled"}.\n"
470
740
 
471
- static_p = enable_config('static', true) or
472
- message "Static linking is disabled.\n"
741
+ if needs_darwin_linker_hack
742
+ append_ldflags("-Wl,-flat_namespace")
743
+ end
473
744
 
474
- dir_config('zlib')
745
+ require "yaml"
746
+ dependencies = YAML.load_file(File.join(PACKAGE_ROOT_DIR, "dependencies.yml"))
475
747
 
476
- dependencies = YAML.load_file(File.join(ROOT, "dependencies.yml"))
748
+ dir_config("zlib")
477
749
 
478
- cross_build_p = enable_config("cross-build")
479
750
  if cross_build_p || windows?
480
751
  zlib_recipe = process_recipe("zlib", dependencies["zlib"]["version"], static_p, cross_build_p) do |recipe|
481
752
  recipe.files = [{
482
- url: "http://zlib.net/fossils/#{recipe.name}-#{recipe.version}.tar.gz",
483
- sha256: dependencies["zlib"]["sha256"]
484
- }]
485
- class << recipe
486
- attr_accessor :cross_build_p
487
-
488
- def configure
489
- Dir.chdir work_path do
490
- mk = File.read 'win32/Makefile.gcc'
491
- File.open 'win32/Makefile.gcc', 'wb' do |f|
492
- f.puts "BINARY_PATH = #{path}/bin"
493
- f.puts "LIBRARY_PATH = #{path}/lib"
494
- f.puts "INCLUDE_PATH = #{path}/include"
495
- mk.sub!(/^PREFIX\s*=\s*$/, "PREFIX = #{host}-") if cross_build_p
496
- 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/)
497
776
  end
498
777
  end
499
- end
500
778
 
501
- def configured?
502
- Dir.chdir work_path do
503
- !! (File.read('win32/Makefile.gcc') =~ /^BINARY_PATH/)
779
+ def compile
780
+ execute("compile", "make -f win32/Makefile.gcc")
504
781
  end
505
- end
506
782
 
507
- def compile
508
- execute "compile", "make -f win32/Makefile.gcc"
783
+ def install
784
+ execute("install", "make -f win32/Makefile.gcc install")
785
+ end
509
786
  end
510
-
511
- def install
512
- 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
513
803
  end
514
804
  end
515
- recipe.cross_build_p = cross_build_p
516
805
  end
517
806
 
518
- libiconv_recipe = process_recipe("libiconv", dependencies["libiconv"]["version"], static_p, cross_build_p) do |recipe|
519
- recipe.files = [{
520
- url: "http://ftp.gnu.org/pub/gnu/libiconv/#{recipe.name}-#{recipe.version}.tar.gz",
521
- 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"],
522
817
  }]
523
- recipe.configure_options += [
524
- "CPPFLAGS=-Wall",
525
- "CFLAGS=-O2 -g",
526
- "CXXFLAGS=-O2 -g",
527
- "LDFLAGS="
528
- ]
529
- end
530
- else
531
- if darwin? && !have_header('iconv.h')
532
- abort <<'EOM'.chomp
533
- -----
534
- The file "iconv.h" is missing in your build environment,
535
- which means you haven't installed Xcode Command Line Tools properly.
536
-
537
- To install Command Line Tools, try running `xcode-select --install` on
538
- terminal and follow the instructions. If it fails, open Xcode.app,
539
- select from the menu "Xcode" - "Open Developer Tool" - "More Developer
540
- Tools" to open the developer site, download the installer for your OS
541
- version and run it.
542
- -----
543
- 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
544
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
+ )
545
858
  end
546
859
 
547
- unless windows?
548
- preserving_globals {
549
- have_library('z', 'gzdopen', 'zlib.h')
550
- } 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
+ )
551
870
  end
552
871
 
553
872
  libxml2_recipe = process_recipe("libxml2", dependencies["libxml2"]["version"], static_p, cross_build_p) do |recipe|
554
- recipe.files = [{
555
- url: "http://xmlsoft.org/sources/#{recipe.name}-#{recipe.version}.tar.gz",
556
- 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"],
557
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
+
558
916
  recipe.configure_options += [
559
917
  "--without-python",
560
918
  "--without-readline",
561
- *(zlib_recipe ? ["--with-zlib=#{zlib_recipe.path}", "CFLAGS=-I#{zlib_recipe.path}/include"] : []),
562
- *(libiconv_recipe ? "--with-iconv=#{libiconv_recipe.path}" : iconv_configure_flags),
563
919
  "--with-c14n",
564
920
  "--with-debug",
565
921
  "--with-threads",
566
- *(darwin? ? ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"] : "")
922
+ "CPPFLAGS=#{cppflags}",
923
+ "CFLAGS=#{cflags}",
567
924
  ]
568
925
  end
569
926
 
570
927
  libxslt_recipe = process_recipe("libxslt", dependencies["libxslt"]["version"], static_p, cross_build_p) do |recipe|
571
- recipe.files = [{
572
- url: "http://xmlsoft.org/sources/#{recipe.name}-#{recipe.version}.tar.gz",
573
- 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"],
574
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
+
575
957
  recipe.configure_options += [
576
958
  "--without-python",
577
959
  "--without-crypto",
578
960
  "--with-debug",
579
961
  "--with-libxml-prefix=#{sh_export_path(libxml2_recipe.path)}",
580
- *(darwin? ? ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"] : "")
962
+ "CFLAGS=#{cflags}",
581
963
  ]
582
964
  end
583
965
 
584
- $CFLAGS << ' ' << '-DNOKOGIRI_USE_PACKAGED_LIBRARIES'
585
- $LIBPATH = ["#{zlib_recipe.path}/lib"] | $LIBPATH if zlib_recipe
586
- $LIBPATH = ["#{libiconv_recipe.path}/lib"] | $LIBPATH if libiconv_recipe
587
-
588
- have_lzma = preserving_globals {
589
- have_library('lzma')
590
- }
966
+ append_cppflags("-DNOKOGIRI_PACKAGED_LIBRARIES")
967
+ append_cppflags("-DNOKOGIRI_PRECOMPILED_LIBRARIES") if cross_build_p
591
968
 
592
969
  $libs = $libs.shellsplit.tap do |libs|
593
970
  [libxml2_recipe, libxslt_recipe].each do |recipe|
594
971
  libname = recipe.name[/\Alib(.+)\z/, 1]
595
- 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|
596
974
  # call config scripts explicit with 'sh' for compat with Windows
597
- $CPPFLAGS = `sh #{config} --cflags`.strip << ' ' << $CPPFLAGS
598
- `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|
599
980
  case arg
600
981
  when /\A-L(.+)\z/
601
982
  # Prioritize ports' directories
602
- if $1.start_with?(ROOT + '/')
603
- $LIBPATH = [$1] | $LIBPATH
983
+ $LIBPATH = if Regexp.last_match(1).start_with?(PACKAGE_ROOT_DIR + "/")
984
+ [Regexp.last_match(1)] | $LIBPATH
604
985
  else
605
- $LIBPATH = $LIBPATH | [$1]
986
+ $LIBPATH | [Regexp.last_match(1)]
606
987
  end
607
988
  when /\A-l./
608
989
  libs.unshift(arg)
609
990
  else
610
- $LDFLAGS << ' ' << arg.shellescape
991
+ $LDFLAGS << " " << arg.shellescape
611
992
  end
612
993
  end
613
994
  end
614
995
 
615
- # Defining a macro that expands to a C string; double quotes are significant.
616
- $CPPFLAGS << ' ' << "-DNOKOGIRI_#{recipe.name.upcase}_PATH=\"#{recipe.path}\"".inspect
617
- $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}\\""])
618
998
 
619
999
  case libname
620
- when 'xml2'
1000
+ when "xml2"
621
1001
  # xslt-config --libs or pkg-config libxslt --libs does not include
622
1002
  # -llzma, so we need to add it manually when linking statically.
623
- if static_p && have_lzma
1003
+ if static_p && preserving_globals { local_have_library("lzma") }
624
1004
  # Add it at the end; GH #988
625
- libs << '-llzma'
1005
+ libs << "-llzma"
626
1006
  end
627
- when 'xslt'
1007
+ when "xslt"
628
1008
  # xslt-config does not have a flag to emit options including
629
1009
  # -lexslt, so add it manually.
630
- libs.unshift('-lexslt')
1010
+ libs.unshift("-lexslt")
631
1011
  end
632
1012
  end
633
1013
  end.shelljoin
634
1014
 
635
1015
  if static_p
1016
+ static_archive_ld_flag = needs_darwin_linker_hack ? ["-load_hidden"] : []
636
1017
  $libs = $libs.shellsplit.map do |arg|
637
1018
  case arg
638
- when '-lxml2'
639
- File.join(libxml2_recipe.path, 'lib', lib_a(arg))
640
- when '-lxslt', '-lexslt'
641
- 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))]
642
1023
  else
643
1024
  arg
644
1025
  end
645
- end.shelljoin
1026
+ end.flatten.shelljoin
646
1027
  end
647
- end
648
1028
 
649
- {
650
- "xml2" => ['xmlParseDoc', 'libxml/parser.h'],
651
- "xslt" => ['xsltParseStylesheetDoc', 'libxslt/xslt.h'],
652
- "exslt" => ['exsltFuncRegister', 'libexslt/exslt.h'],
653
- }.each do |lib, (func, header)|
654
- have_func(func, header) ||
655
- have_library(lib, func, header) ||
656
- have_library("lib#{lib}", func, header) or
657
- asplode("lib#{lib}")
1029
+ ensure_func("xmlParseDoc", "libxml/parser.h")
1030
+ ensure_func("xsltParseStylesheetDoc", "libxslt/xslt.h")
1031
+ ensure_func("exsltFuncRegister", "libexslt/exslt.h")
658
1032
  end
659
1033
 
660
- have_func('xmlHasFeature') or abort "xmlHasFeature() is missing."
661
- have_func('xmlFirstElementChild')
662
- have_func('xmlRelaxNGSetParserStructuredErrors')
663
- have_func('xmlRelaxNGSetParserStructuredErrors')
664
- have_func('xmlRelaxNGSetValidStructuredErrors')
665
- have_func('xmlSchemaSetValidStructuredErrors')
666
- 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
667
1113
 
668
- create_makefile('nokogiri/nokogiri')
1114
+ create_makefile("nokogiri/nokogiri")
669
1115
 
670
- if enable_config('clean', true)
1116
+ if config_clean?
671
1117
  # Do not clean if run in a development work tree.
672
- File.open('Makefile', 'at') do |mk|
673
- mk.print <<EOF
674
- all: clean-ports
1118
+ File.open("Makefile", "at") do |mk|
1119
+ mk.print(<<~EOF)
675
1120
 
676
- clean-ports: $(DLLIB)
677
- -$(Q)$(RUBY) $(srcdir)/extconf.rb --clean --#{static_p ? 'enable' : 'disable'}-static
678
- EOF
1121
+ all: clean-ports
1122
+ clean-ports: $(DLLIB)
1123
+ \t-$(Q)$(RUBY) $(srcdir)/extconf.rb --clean --#{static_p ? "enable" : "disable"}-static
1124
+ EOF
679
1125
  end
680
1126
  end
681
1127
 
682
- # :startdoc:
1128
+ # rubocop:enable Style/GlobalVars