bootsnap 1.19.0 → 1.21.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71cd833fdf912a81069349b4de87a96cf15997710494eebb4535245aeeb02305
4
- data.tar.gz: e502571bd2d4863d5f548ce50dcd6502cc18a51dcbf00a101ad1b65f47510534
3
+ metadata.gz: 4ca69038da7071534a7279f36d694ec5bcf5687272d091b314372b1f3195831b
4
+ data.tar.gz: c5dc747c2c66a71881d99af980085c06bfc378134d25712c51221b7fb6a6c03a
5
5
  SHA512:
6
- metadata.gz: d5af0fb8cabbb09d026c8a73043c24d0669004a10edbf0ee3f5baaf8597ac99b7022c0bcaef1c25948dcd055cdd4dbac2ed614d9b2a5d6e58f1e94b6cc32f127
7
- data.tar.gz: db4c64829ebc8177ed9a83bda8cf801e570f6d48db3e27ddd4522dbd48043a0d619615ba583be4a9ff1a24049785e5dfeed362f36ef1b9115662e9c3b612973d
6
+ metadata.gz: 9da2aa5050b26d377f46d1de5e8424168e0a60b00160d43ebdaf9f93c4a9006931bf6463a24afa6dd76559ccedc4ce3798d48733d5000a7a5eac08d7c7a03510
7
+ data.tar.gz: 17a8da7a372189c22f400f5c059947f98c6aa7836390965c92e6e173970a61e2e6aa57d77d3dd11a9ecea0afd729512a115fd38a21c7a30850d1e9bd662b7d26
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Unreleased
2
2
 
3
+ # 1.21.1
4
+
5
+ * Prevent a Ruby crash while scanning load path if `opendir` fails without setting `errno`.
6
+ According to the C spec this should not happen, but according to user reports, it did.
7
+
8
+ # 1.21.0
9
+
10
+ * Fix the `require` decorator to handle `Bootsnap.unload_cache!` being called.
11
+ * Minor optimization: Eagerly clear cache buffers to appease the GC.
12
+
13
+ # 1.20.1
14
+
15
+ * Handle broken symlinks in load path scanning code.
16
+ Should fix `Errno::ENOENT fstatat` issues some users have encountered after upgrading to 1.20.0.
17
+
18
+ # 1.20.0
19
+
20
+ * Optimized load path scanning with a C extension. Should be about 2x faster on supported platforms.
21
+
3
22
  # 1.19.0
4
23
 
5
24
  * Remove JSON parsing cache. Recent versions of the `json` gem are as fast as `msgpack` if not faster.
@@ -11,7 +11,6 @@
11
11
  * here.
12
12
  */
13
13
 
14
- #include "bootsnap.h"
15
14
  #include "ruby.h"
16
15
  #include <stdint.h>
17
16
  #include <stdbool.h>
@@ -20,6 +19,11 @@
20
19
  #include <fcntl.h>
21
20
  #include <unistd.h>
22
21
  #include <sys/stat.h>
22
+ #include <dirent.h>
23
+
24
+ #ifndef RBIMPL_ATTR_NORETURN
25
+ #define RBIMPL_ATTR_NORETURN()
26
+ #endif
23
27
 
24
28
  #ifdef __APPLE__
25
29
  // The symbol is present, however not in the headers
@@ -96,7 +100,6 @@ static mode_t current_umask;
96
100
 
97
101
  /* Bootsnap::CompileCache::{Native, Uncompilable} */
98
102
  static VALUE rb_mBootsnap;
99
- static VALUE rb_mBootsnap_CompileCache;
100
103
  static VALUE rb_mBootsnap_CompileCache_Native;
101
104
  static VALUE rb_cBootsnap_CompileCache_UNCOMPILABLE;
102
105
  static ID instrumentation_method;
@@ -152,6 +155,118 @@ bs_rb_get_path(VALUE self, VALUE fname)
152
155
  return rb_get_path(fname);
153
156
  }
154
157
 
158
+ #ifdef HAVE_FSTATAT
159
+
160
+ RBIMPL_ATTR_NORETURN()
161
+ static void
162
+ bs_syserr_fail_path(const char *func_name, int n, VALUE path)
163
+ {
164
+ rb_syserr_fail_str(n, rb_sprintf("%s @ %s", func_name, RSTRING_PTR(path)));
165
+ }
166
+
167
+ RBIMPL_ATTR_NORETURN()
168
+ static void
169
+ bs_syserr_fail_dir_entry(const char *func_name, int n, VALUE dir, const char *d_name)
170
+ {
171
+ rb_syserr_fail_str(n, rb_sprintf("%s @ %s/%s", func_name, RSTRING_PTR(dir), d_name));
172
+ }
173
+
174
+ static VALUE
175
+ bs_rb_scan_dir(VALUE self, VALUE abspath)
176
+ {
177
+ Check_Type(abspath, T_STRING);
178
+
179
+ DIR *dirp = opendir(RSTRING_PTR(abspath));
180
+
181
+ VALUE dirs = rb_ary_new();
182
+ VALUE requirables = rb_ary_new();
183
+ VALUE result = rb_ary_new_from_args(2, requirables, dirs);
184
+
185
+ if (dirp == NULL) {
186
+ if (errno == ENOTDIR || errno == ENOENT) {
187
+ return result;
188
+ }
189
+
190
+ // BUG: Some users reported a crash here because Ruby's syserr trigger
191
+ // a crash if called with `errno == 0`.
192
+ // The opendir spec is quite clear that if it returns NULL, then `errno` must
193
+ // be set, and yet here we are.
194
+ // So turning no errno into EINVAL, and from there I hope to get to the bottom of things.
195
+ if (errno == 0) {
196
+ errno = EINVAL;
197
+ }
198
+
199
+ bs_syserr_fail_path("opendir", errno, abspath);
200
+ return Qundef;
201
+ }
202
+
203
+ struct dirent *entry;
204
+ struct stat st;
205
+ int dfd = -1;
206
+
207
+ errno = 0;
208
+ while ((entry = readdir(dirp))) {
209
+ if (entry->d_name[0] == '.') continue;
210
+
211
+ if (RB_UNLIKELY(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK)) {
212
+ // Note: the original implementation of LoadPathCache did follow symlink.
213
+ // So this is replicated here, but I'm not sure it's a good idea.
214
+ if (dfd < 0) {
215
+ dfd = dirfd(dirp);
216
+ if (dfd < 0) {
217
+ int err = errno;
218
+ closedir(dirp);
219
+ bs_syserr_fail_path("dirfd", err, abspath);
220
+ return Qundef;
221
+ }
222
+ }
223
+
224
+ if (fstatat(dfd, entry->d_name, &st, 0)) {
225
+ if (errno == ENOENT) {
226
+ // Broken symlinK
227
+ errno = 0;
228
+ continue;
229
+ }
230
+ int err = errno;
231
+ closedir(dirp);
232
+ bs_syserr_fail_dir_entry("fstatat", err, abspath, entry->d_name);
233
+ return Qundef;
234
+ }
235
+
236
+ if (S_ISREG(st.st_mode)) {
237
+ entry->d_type = DT_REG;
238
+ } else if (S_ISDIR(st.st_mode)) {
239
+ entry->d_type = DT_DIR;
240
+ }
241
+ }
242
+
243
+ if (entry->d_type == DT_DIR) {
244
+ rb_ary_push(dirs, rb_utf8_str_new_cstr(entry->d_name));
245
+ continue;
246
+ } else if (entry->d_type == DT_REG) {
247
+ size_t len = strlen(entry->d_name);
248
+ bool is_requirable = (
249
+ // Comparing 4B allows compiler to optimize this into a single 32b integer comparison.
250
+ (len > 3 && memcmp(entry->d_name + (len - 3), ".rb", 4) == 0)
251
+ || (len > DLEXT_MAXLEN && memcmp(entry->d_name + (len - DLEXT_MAXLEN), DLEXT, DLEXT_MAXLEN + 1) == 0)
252
+ #ifdef DLEXT2
253
+ || (len > DLEXT2_MAXLEN && memcmp(entry->d_name + (len - DLEXT2_MAXLEN), DLEXT2, DLEXT2_MAXLEN + 1) == 0)
254
+ #endif
255
+ );
256
+ if (is_requirable) {
257
+ rb_ary_push(requirables, rb_utf8_str_new(entry->d_name, len));
258
+ }
259
+ }
260
+ }
261
+
262
+ if (closedir(dirp)) {
263
+ bs_syserr_fail_path("closedir", errno, abspath);
264
+ return Qundef;
265
+ }
266
+ return result;
267
+ }
268
+ #endif
269
+
155
270
  /*
156
271
  * Ruby C extensions are initialized by calling Init_<extname>.
157
272
  *
@@ -166,7 +281,14 @@ Init_bootsnap(void)
166
281
 
167
282
  rb_define_singleton_method(rb_mBootsnap, "rb_get_path", bs_rb_get_path, 1);
168
283
 
169
- rb_mBootsnap_CompileCache = rb_define_module_under(rb_mBootsnap, "CompileCache");
284
+ #ifdef HAVE_FSTATAT
285
+ VALUE rb_mBootsnap_LoadPathCache = rb_define_module_under(rb_mBootsnap, "LoadPathCache");
286
+ VALUE rb_mBootsnap_LoadPathCache_Native = rb_define_module_under(rb_mBootsnap_LoadPathCache, "Native");
287
+
288
+ rb_define_singleton_method(rb_mBootsnap_LoadPathCache_Native, "scan_dir", bs_rb_scan_dir, 1);
289
+ #endif
290
+
291
+ VALUE rb_mBootsnap_CompileCache = rb_define_module_under(rb_mBootsnap, "CompileCache");
170
292
  rb_mBootsnap_CompileCache_Native = rb_define_module_under(rb_mBootsnap_CompileCache, "Native");
171
293
  rb_cBootsnap_CompileCache_UNCOMPILABLE = rb_const_get(rb_mBootsnap_CompileCache, rb_intern("UNCOMPILABLE"));
172
294
  rb_global_variable(&rb_cBootsnap_CompileCache_UNCOMPILABLE);
@@ -4,6 +4,7 @@ require "mkmf"
4
4
 
5
5
  if %w[ruby truffleruby].include?(RUBY_ENGINE)
6
6
  have_func "fdatasync", "unistd.h"
7
+ have_func "fstatat", "sys/stat.h"
7
8
 
8
9
  unless RUBY_PLATFORM.match?(/mswin|mingw|cygwin/)
9
10
  append_cppflags ["-D_GNU_SOURCE"] # Needed of O_NOATIME
@@ -50,7 +50,9 @@ module Bootsnap
50
50
  end
51
51
 
52
52
  def self.storage_to_output(binary, _args)
53
- RubyVM::InstructionSequence.load_from_binary(binary)
53
+ iseq = RubyVM::InstructionSequence.load_from_binary(binary)
54
+ binary.clear
55
+ iseq
54
56
  rescue RuntimeError => error
55
57
  if error.message == "broken binary format"
56
58
  $stderr.puts("[Bootsnap::CompileCache] warning: rejecting broken binary")
@@ -170,7 +170,9 @@ module Bootsnap
170
170
  unpacker = CompileCache::YAML.msgpack_factory.unpacker(kwargs)
171
171
  unpacker.feed(data)
172
172
  _safe_loaded = unpacker.unpack
173
- unpacker.unpack
173
+ result = unpacker.unpack
174
+ data.clear
175
+ result
174
176
  end
175
177
 
176
178
  def input_to_output(data, kwargs)
@@ -11,19 +11,19 @@ module Bootsnap
11
11
  @development_mode = development_mode
12
12
  @store = store
13
13
  @mutex = Mutex.new
14
- @path_obj = path_obj.map! { |f| PathScanner.os_path(File.exist?(f) ? File.realpath(f) : f.dup) }
14
+ @path_obj = path_obj.map! do |f|
15
+ if File.exist?(f)
16
+ File.realpath(f).freeze
17
+ elsif f.frozen?
18
+ f
19
+ else
20
+ f.dup.freeze
21
+ end
22
+ end
15
23
  @has_relative_paths = nil
16
24
  reinitialize
17
25
  end
18
26
 
19
- # What is the path item that contains the dir as child?
20
- # e.g. given "/a/b/c/d" exists, and the path is ["/a/b"], load_dir("c/d")
21
- # is "/a/b".
22
- def load_dir(dir)
23
- reinitialize if stale?
24
- @mutex.synchronize { @dirs[dir] }
25
- end
26
-
27
27
  TRUFFLERUBY_LIB_DIR_PREFIX = if RUBY_ENGINE == "truffleruby"
28
28
  "#{File.join(RbConfig::CONFIG['libdir'], 'truffle')}#{File::SEPARATOR}"
29
29
  end
@@ -124,7 +124,6 @@ module Bootsnap
124
124
  @path_obj = path_obj
125
125
  ChangeObserver.register(@path_obj, self)
126
126
  @index = {}
127
- @dirs = {}
128
127
  @generated_at = now
129
128
  push_paths_locked(*@path_obj)
130
129
  end
@@ -152,9 +151,8 @@ module Bootsnap
152
151
  p = p.to_realpath
153
152
 
154
153
  expanded_path = p.expanded_path
155
- entries, dirs = p.entries_and_dirs(@store)
154
+ entries = p.entries(@store)
156
155
  # push -> low precedence -> set only if unset
157
- dirs.each { |dir| @dirs[dir] ||= path }
158
156
  entries.each { |rel| @index[rel] ||= expanded_path }
159
157
  end
160
158
  end
@@ -169,9 +167,8 @@ module Bootsnap
169
167
  p = p.to_realpath
170
168
 
171
169
  expanded_path = p.expanded_path
172
- entries, dirs = p.entries_and_dirs(@store)
170
+ entries = p.entries(@store)
173
171
  # unshift -> high precedence -> unconditional set
174
- dirs.each { |dir| @dirs[dir] = path }
175
172
  entries.each { |rel| @index[rel] = expanded_path }
176
173
  end
177
174
  end
@@ -15,8 +15,11 @@ module Kernel
15
15
  if Bootsnap::LoadPathCache::FALLBACK_SCAN.equal?(resolved)
16
16
  if (cursor = Bootsnap::LoadPathCache.loaded_features_index.cursor(string_path))
17
17
  ret = require_without_bootsnap(path)
18
- resolved = Bootsnap::LoadPathCache.loaded_features_index.identify(string_path, cursor)
19
- Bootsnap::LoadPathCache.loaded_features_index.register(string_path, resolved)
18
+
19
+ # The file we required may have unloaded the cache
20
+ resolved = Bootsnap::LoadPathCache.loaded_features_index&.identify(string_path, cursor)
21
+ Bootsnap::LoadPathCache.loaded_features_index&.register(string_path, resolved)
22
+
20
23
  return ret
21
24
  else
22
25
  return require_without_bootsnap(path)
@@ -28,7 +31,9 @@ module Kernel
28
31
  else
29
32
  # Note that require registers to $LOADED_FEATURES while load does not.
30
33
  ret = require_without_bootsnap(resolved)
31
- Bootsnap::LoadPathCache.loaded_features_index.register(string_path, resolved)
34
+
35
+ # The file we required may have unloaded the cache
36
+ Bootsnap::LoadPathCache.loaded_features_index&.register(string_path, resolved)
32
37
  return ret
33
38
  end
34
39
  end
@@ -54,29 +54,28 @@ module Bootsnap
54
54
  !path.start_with?(SLASH)
55
55
  end
56
56
 
57
- # Return a list of all the requirable files and all of the subdirectories
58
- # of this +Path+.
59
- def entries_and_dirs(store)
57
+ # Return a list of all the requirable files of this +Path+.
58
+ def entries(store)
60
59
  if stable?
61
60
  # the cached_mtime field is unused for 'stable' paths, but is
62
61
  # set to zero anyway, just in case we change the stability heuristics.
63
- _, entries, dirs = store.get(expanded_path)
64
- return [entries, dirs] if entries # cache hit
62
+ _, entries, = store.get(expanded_path)
63
+ return entries if entries # cache hit
65
64
 
66
- entries, dirs = scan!
67
- store.set(expanded_path, [0, entries, dirs])
68
- return [entries, dirs]
65
+ entries = PathScanner.call(expanded_path)
66
+ store.set(expanded_path, [0, entries])
67
+ return entries
69
68
  end
70
69
 
71
- cached_mtime, entries, dirs = store.get(expanded_path)
70
+ cached_mtime, entries = store.get(expanded_path)
72
71
 
73
- current_mtime = latest_mtime(expanded_path, dirs || [])
74
- return [[], []] if current_mtime == -1 # path does not exist
75
- return [entries, dirs] if cached_mtime == current_mtime
72
+ current_mtime = latest_mtime(expanded_path, entries || [])
73
+ return [] if current_mtime == -1 # path does not exist
74
+ return entries if cached_mtime == current_mtime
76
75
 
77
- entries, dirs = scan!
78
- store.set(expanded_path, [current_mtime, entries, dirs])
79
- [entries, dirs]
76
+ entries = PathScanner.call(expanded_path)
77
+ store.set(expanded_path, [current_mtime, entries])
78
+ entries
80
79
  end
81
80
 
82
81
  def expanded_path
@@ -89,23 +88,31 @@ module Bootsnap
89
88
 
90
89
  private
91
90
 
92
- def scan! # (expensive) returns [entries, dirs]
93
- PathScanner.call(expanded_path)
94
- end
95
-
96
91
  # last time a directory was modified in this subtree. +dirs+ should be a
97
92
  # list of relative paths to directories under +path+. e.g. for /a/b and
98
93
  # /a/b/c, pass ('/a/b', ['c'])
99
- def latest_mtime(path, dirs)
100
- max = -1
101
- ["", *dirs].each do |dir|
102
- curr = begin
103
- File.mtime("#{path}/#{dir}").to_i
104
- rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
105
- -1
94
+ def latest_mtime(root_path, entries)
95
+ max = begin
96
+ File.mtime(root_path).to_i
97
+ rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
98
+ -1
99
+ end
100
+
101
+ visited = {"." => true}
102
+
103
+ entries.each do |relpath|
104
+ dirname = File.dirname(relpath)
105
+ visited[dirname] ||= begin
106
+ begin
107
+ current = File.mtime(File.join(root_path, dirname)).to_i
108
+ max = current if current > max
109
+ rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EINVAL
110
+ # ignore
111
+ end
112
+ true
106
113
  end
107
- max = curr if curr > max
108
114
  end
115
+
109
116
  max
110
117
  end
111
118
 
@@ -6,8 +6,6 @@ module Bootsnap
6
6
  module LoadPathCache
7
7
  module PathScanner
8
8
  REQUIRABLE_EXTENSIONS = [DOT_RB] + DL_EXTENSIONS
9
- NORMALIZE_NATIVE_EXTENSIONS = !DL_EXTENSIONS.include?(LoadPathCache::DOT_SO)
10
- ALTERNATIVE_NATIVE_EXTENSIONS_PATTERN = /\.(o|bundle|dylib)\z/.freeze
11
9
 
12
10
  BUNDLE_PATH = if Bootsnap.bundler?
13
11
  (Bundler.bundle_path.cleanpath.to_s << LoadPathCache::SLASH).freeze
@@ -20,9 +18,9 @@ module Bootsnap
20
18
  class << self
21
19
  attr_accessor :ignored_directories
22
20
 
23
- def call(path)
21
+ def ruby_call(path)
24
22
  path = File.expand_path(path.to_s).freeze
25
- return [[], []] unless File.directory?(path)
23
+ return [] unless File.directory?(path)
26
24
 
27
25
  # If the bundle path is a descendent of this path, we do additional
28
26
  # checks to prevent recursing into the bundle path as we recurse
@@ -33,17 +31,15 @@ module Bootsnap
33
31
  # and the bundle path is '.bundle'.
34
32
  contains_bundle_path = BUNDLE_PATH.start_with?(path)
35
33
 
36
- dirs = []
37
34
  requirables = []
38
35
  walk(path, nil) do |relative_path, absolute_path, is_directory|
39
36
  if is_directory
40
- dirs << os_path(relative_path)
41
37
  !contains_bundle_path || !absolute_path.start_with?(BUNDLE_PATH)
42
38
  elsif relative_path.end_with?(*REQUIRABLE_EXTENSIONS)
43
- requirables << os_path(relative_path)
39
+ requirables << relative_path.freeze
44
40
  end
45
41
  end
46
- [requirables, dirs]
42
+ requirables
47
43
  end
48
44
 
49
45
  def walk(absolute_dir_path, relative_dir_path, &block)
@@ -65,15 +61,58 @@ module Bootsnap
65
61
  end
66
62
  end
67
63
 
68
- if RUBY_VERSION >= "3.1"
69
- def os_path(path)
70
- path.freeze
64
+ if RUBY_ENGINE == "ruby" && RUBY_PLATFORM.match?(/darwin|linux|bsd|mswin|mingw|cygwin/)
65
+ require "bootsnap/bootsnap"
66
+ end
67
+
68
+ if defined?(Native.scan_dir)
69
+ def native_call(root_path)
70
+ # NOTE: if https://bugs.ruby-lang.org/issues/21800 is accepted we should be able
71
+ # to have similar performance with pure Ruby
72
+
73
+ # If the bundle path is a descendent of this path, we do additional
74
+ # checks to prevent recursing into the bundle path as we recurse
75
+ # through this path. We don't want to scan the bundle path because
76
+ # anything useful in it will be present on other load path items.
77
+ #
78
+ # This can happen if, for example, the user adds '.' to the load path,
79
+ # and the bundle path is '.bundle'.
80
+ contains_bundle_path = BUNDLE_PATH.start_with?(root_path)
81
+
82
+ all_requirables, queue = Native.scan_dir(root_path)
83
+ all_requirables.each(&:freeze)
84
+
85
+ queue.reject! do |dir|
86
+ ignored_directories.include?(dir) ||
87
+ (contains_bundle_path && dir.start_with?(BUNDLE_PATH))
88
+ end
89
+
90
+ while (path = queue.pop)
91
+ requirables, dirs = Native.scan_dir(File.join(root_path, path))
92
+ dirs.reject! { |dir| ignored_directories.include?(dir) }
93
+ dirs.map! { |f| File.join(path, f).freeze }
94
+ requirables.map! { |f| File.join(path, f).freeze }
95
+
96
+ if contains_bundle_path
97
+ dirs.reject! { |dir| dir.start_with?(BUNDLE_PATH) }
98
+ end
99
+
100
+ all_requirables.concat(requirables)
101
+ queue.concat(dirs)
102
+ end
103
+
104
+ all_requirables
105
+ rescue SystemCallError => error
106
+ if ENV["BOOTSNAP_DEBUG"]
107
+ raise
108
+ else
109
+ Bootsnap.logger&.call("Unexpected error: #{error.class}: #{error.message}")
110
+ ruby_call(root_path)
111
+ end
71
112
  end
113
+ alias_method :call, :native_call
72
114
  else
73
- def os_path(path)
74
- path.force_encoding(Encoding::US_ASCII) if path.ascii_only?
75
- path.freeze
76
- end
115
+ alias_method :call, :ruby_call
77
116
  end
78
117
  end
79
118
  end
@@ -8,7 +8,7 @@ module Bootsnap
8
8
  module LoadPathCache
9
9
  class Store
10
10
  VERSION_KEY = "__bootsnap_ruby_version__"
11
- CURRENT_VERSION = "#{RUBY_REVISION}-#{RUBY_PLATFORM}".freeze # rubocop:disable Style/RedundantFreeze
11
+ CURRENT_VERSION = "#{VERSION}-#{RUBY_REVISION}-#{RUBY_PLATFORM}".freeze # rubocop:disable Style/RedundantFreeze
12
12
 
13
13
  NestedTransactionError = Class.new(StandardError)
14
14
  SetOutsideTransactionNotAllowed = Class.new(StandardError)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bootsnap
4
- VERSION = "1.19.0"
4
+ VERSION = "1.21.1"
5
5
  end
data/lib/bootsnap.rb CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  require_relative "bootsnap/version"
4
4
  require_relative "bootsnap/bundler"
5
- require_relative "bootsnap/load_path_cache"
6
- require_relative "bootsnap/compile_cache"
7
5
 
8
6
  module Bootsnap
9
7
  InvalidConfiguration = Class.new(StandardError)
@@ -164,3 +162,6 @@ module Bootsnap
164
162
  end
165
163
  end
166
164
  end
165
+
166
+ require_relative "bootsnap/compile_cache"
167
+ require_relative "bootsnap/load_path_cache"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bootsnap
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.19.0
4
+ version: 1.21.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Burke Libbey
@@ -37,7 +37,6 @@ files:
37
37
  - README.md
38
38
  - exe/bootsnap
39
39
  - ext/bootsnap/bootsnap.c
40
- - ext/bootsnap/bootsnap.h
41
40
  - ext/bootsnap/extconf.rb
42
41
  - lib/bootsnap.rb
43
42
  - lib/bootsnap/bundler.rb
@@ -80,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
79
  - !ruby/object:Gem::Version
81
80
  version: '0'
82
81
  requirements: []
83
- rubygems_version: 3.6.9
82
+ rubygems_version: 4.0.3
84
83
  specification_version: 4
85
84
  summary: Boot large ruby/rails apps faster
86
85
  test_files: []
@@ -1,6 +0,0 @@
1
- #ifndef BOOTSNAP_H
2
- #define BOOTSNAP_H 1
3
-
4
- /* doesn't expose anything */
5
-
6
- #endif /* BOOTSNAP_H */