sqlite3 1.4.2 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,100 +1,262 @@
1
- ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
2
-
3
- require 'mkmf'
4
-
5
- # :stopdoc:
6
-
7
- RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
8
-
9
- ldflags = cppflags = nil
10
- if RbConfig::CONFIG["host_os"] =~ /darwin/
11
- begin
12
- if with_config('sqlcipher')
13
- brew_prefix = `brew --prefix sqlcipher`.chomp
14
- ldflags = "#{brew_prefix}/lib"
15
- cppflags = "#{brew_prefix}/include/sqlcipher"
16
- pkg_conf = "#{brew_prefix}/lib/pkgconfig"
17
- else
18
- brew_prefix = `brew --prefix sqlite3`.chomp
19
- ldflags = "#{brew_prefix}/lib"
20
- cppflags = "#{brew_prefix}/include"
21
- pkg_conf = "#{brew_prefix}/lib/pkgconfig"
22
- end
1
+ require "mkmf"
2
+ require "mini_portile2"
3
+ require "yaml"
23
4
 
24
- # pkg_config should be less error prone than parsing compiler
25
- # commandline options, but we need to set default ldflags and cpp flags
26
- # in case the user doesn't have pkg-config installed
27
- ENV['PKG_CONFIG_PATH'] ||= pkg_conf
28
- rescue
29
- end
30
- end
5
+ module Sqlite3
6
+ module ExtConf
7
+ ENV_ALLOWLIST = ["CC", "CFLAGS", "LDFLAGS", "LIBS", "CPPFLAGS", "LT_SYS_LIBRARY_PATH", "CPP"]
31
8
 
32
- if with_config('sqlcipher')
33
- pkg_config("sqlcipher")
34
- else
35
- pkg_config("sqlite3")
36
- end
9
+ class << self
10
+ def configure
11
+ configure_cross_compiler
37
12
 
38
- # --with-sqlite3-{dir,include,lib}
39
- if with_config('sqlcipher')
40
- $CFLAGS << ' -DUSING_SQLCIPHER'
41
- dir_config("sqlcipher", cppflags, ldflags)
42
- else
43
- dir_config("sqlite3", cppflags, ldflags)
44
- end
13
+ if system_libraries?
14
+ message "Building sqlite3-ruby using system #{libname}.\n"
15
+ configure_system_libraries
16
+ else
17
+ message "Building sqlite3-ruby using packaged sqlite3.\n"
18
+ configure_packaged_libraries
19
+ end
45
20
 
46
- if RbConfig::CONFIG["host_os"] =~ /mswin/
47
- $CFLAGS << ' -W3'
48
- end
21
+ configure_extension
49
22
 
50
- if RUBY_VERSION < '2.7'
51
- $CFLAGS << ' -DTAINTING_SUPPORT'
52
- end
23
+ create_makefile('sqlite3/sqlite3_native')
24
+ end
53
25
 
54
- def asplode missing
55
- if RUBY_PLATFORM =~ /mingw|mswin/
56
- abort "#{missing} is missing. Install SQLite3 from " +
57
- "http://www.sqlite.org/ first."
58
- else
59
- abort <<-error
60
- #{missing} is missing. Try 'brew install sqlite3',
61
- 'yum install sqlite-devel' or 'apt-get install libsqlite3-dev'
62
- and check your shared library search path (the
63
- location where your sqlite3 shared library is located).
64
- error
65
- end
66
- end
26
+ def configure_cross_compiler
27
+ RbConfig::CONFIG["CC"] = RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"] if ENV["CC"]
28
+ ENV["CC"] = RbConfig::CONFIG["CC"]
29
+ end
67
30
 
68
- asplode('sqlite3.h') unless find_header 'sqlite3.h'
69
- find_library 'pthread', 'pthread_create' # 1.8 support. *shrug*
31
+ def system_libraries?
32
+ sqlcipher? || enable_config("system-libraries")
33
+ end
70
34
 
71
- have_library 'dl' # for static builds
35
+ def libname
36
+ sqlcipher? ? "sqlcipher" : "sqlite3"
37
+ end
72
38
 
73
- if with_config('sqlcipher')
74
- asplode('sqlcipher') unless find_library 'sqlcipher', 'sqlite3_libversion_number'
75
- else
76
- asplode('sqlite3') unless find_library 'sqlite3', 'sqlite3_libversion_number'
77
- end
39
+ def sqlcipher?
40
+ with_config("sqlcipher") ||
41
+ with_config("sqlcipher-dir") ||
42
+ with_config("sqlcipher-include") ||
43
+ with_config("sqlcipher-lib")
44
+ end
45
+
46
+ def configure_system_libraries
47
+ pkg_config(libname)
48
+ append_cppflags("-DUSING_SQLCIPHER") if sqlcipher?
49
+ end
50
+
51
+ def configure_packaged_libraries
52
+ minimal_recipe.tap do |recipe|
53
+ recipe.configure_options += ["--enable-shared=no", "--enable-static=yes"]
54
+ ENV.to_h.tap do |env|
55
+ additional_cflags = [
56
+ "-fPIC", # needed for linking the static library into a shared library
57
+ "-O2", # see https://github.com/sparklemotion/sqlite3-ruby/issues/335 for some benchmarks
58
+ ]
59
+ env["CFLAGS"] = [env["CFLAGS"], additional_cflags].flatten.join(" ")
60
+ recipe.configure_options += env.select { |k,v| ENV_ALLOWLIST.include?(k) }
61
+ .map { |key, value| "#{key}=#{value.strip}" }
62
+ end
63
+
64
+ unless File.exist?(File.join(recipe.target, recipe.host, recipe.name, recipe.version))
65
+ recipe.cook
66
+ end
67
+ recipe.activate
68
+
69
+ # on macos, pkg-config will not return --cflags without this
70
+ ENV["PKG_CONFIG_ALLOW_SYSTEM_CFLAGS"] = "t"
71
+
72
+ lib_path = File.join(recipe.path, "lib")
73
+ pcfile = File.join(lib_path, "pkgconfig", "sqlite3.pc")
74
+ abort_pkg_config("pkg_config") unless pkg_config(pcfile)
75
+
76
+ # see https://bugs.ruby-lang.org/issues/18490
77
+ flags = xpopen(["pkg-config", "--libs", "--static", pcfile], err: [:child, :out], &:read)
78
+ abort_pkg_config("xpopen") unless $?.success?
79
+ flags = flags.split
80
+
81
+ # see https://github.com/flavorjones/mini_portile/issues/118
82
+ "-L#{lib_path}".tap do |lib_path_flag|
83
+ flags.prepend(lib_path_flag) unless flags.include?(lib_path_flag)
84
+ end
85
+
86
+ flags.each { |flag| append_ldflags(flag) }
87
+ end
88
+ end
89
+
90
+ def configure_extension
91
+ if Gem::Requirement.new("< 2.7").satisfied_by?(Gem::Version.new(RUBY_VERSION))
92
+ append_cppflags("-DTAINTING_SUPPORT")
93
+ end
94
+
95
+ if find_header("sqlite3.h")
96
+ # noop
97
+ elsif sqlcipher? && find_header("sqlcipher/sqlite3.h")
98
+ append_cppflags("-DUSING_SQLCIPHER_INC_SUBDIR")
99
+ else
100
+ abort_could_not_find("sqlite3.h")
101
+ end
102
+
103
+ abort_could_not_find(libname) unless find_library(libname, "sqlite3_libversion_number", "sqlite3.h")
104
+
105
+ # Functions defined in 1.9 but not 1.8
106
+ have_func('rb_proc_arity')
107
+
108
+ # Functions defined in 2.1 but not 2.0
109
+ have_func('rb_integer_pack')
110
+
111
+ # These functions may not be defined
112
+ have_func('sqlite3_initialize')
113
+ have_func('sqlite3_backup_init')
114
+ have_func('sqlite3_column_database_name')
115
+ have_func('sqlite3_enable_load_extension')
116
+ have_func('sqlite3_load_extension')
117
+
118
+ unless have_func('sqlite3_open_v2') # https://www.sqlite.org/releaselog/3_5_0.html
119
+ abort("\nPlease use a version of SQLite3 >= 3.5.0\n\n")
120
+ end
121
+
122
+ have_func('sqlite3_prepare_v2')
123
+ have_type('sqlite3_int64', 'sqlite3.h')
124
+ have_type('sqlite3_uint64', 'sqlite3.h')
125
+ end
126
+
127
+ def minimal_recipe
128
+ MiniPortile.new(libname, sqlite3_config[:version]).tap do |recipe|
129
+ if sqlite_source_dir
130
+ recipe.source_directory = sqlite_source_dir
131
+ else
132
+ recipe.files = sqlite3_config[:files]
133
+ recipe.target = File.join(package_root_dir, "ports")
134
+ recipe.patch_files = Dir[File.join(package_root_dir, "patches", "*.patch")].sort
135
+ end
136
+ end
137
+ end
138
+
139
+ def package_root_dir
140
+ File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
141
+ end
142
+
143
+ def sqlite3_config
144
+ mini_portile_config[:sqlite3]
145
+ end
146
+
147
+ def mini_portile_config
148
+ # TODO: once Ruby 2.7 is no longer supported, use symbolize_names: true
149
+ YAML.load_file(File.join(package_root_dir, "dependencies.yml"))
150
+ end
151
+
152
+ def abort_could_not_find(missing)
153
+ abort("\nCould not find #{missing}.\nPlease visit https://github.com/sparklemotion/sqlite3-ruby for installation instructions.\n\n")
154
+ end
155
+
156
+ def abort_pkg_config(id)
157
+ abort("\nCould not configure the build properly (#{id}). Please install either the `pkg-config` utility or the `pkg-config` rubygem.\n\n")
158
+ end
78
159
 
79
- # Functions defined in 1.9 but not 1.8
80
- have_func('rb_proc_arity')
160
+ def cross_build?
161
+ enable_config("cross-build")
162
+ end
81
163
 
82
- # Functions defined in 2.1 but not 2.0
83
- have_func('rb_integer_pack')
164
+ def sqlite_source_dir
165
+ arg_config("--with-sqlite-source-dir")
166
+ end
84
167
 
85
- # These functions may not be defined
86
- have_func('sqlite3_initialize')
87
- have_func('sqlite3_backup_init')
88
- have_func('sqlite3_column_database_name')
89
- have_func('sqlite3_enable_load_extension')
90
- have_func('sqlite3_load_extension')
168
+ def download
169
+ minimal_recipe.download
170
+ end
91
171
 
92
- unless have_func('sqlite3_open_v2')
93
- abort "Please use a newer version of SQLite3"
172
+ def print_help
173
+ print(<<~TEXT)
174
+ USAGE: ruby #{$PROGRAM_NAME} [options]
175
+
176
+ Flags that are always valid:
177
+
178
+ --disable-system-libraries
179
+ Use the packaged libraries, and ignore the system libraries.
180
+ (This is the default behavior.)
181
+
182
+ --enable-system-libraries
183
+ Use system libraries instead of building and using the packaged libraries.
184
+
185
+ --with-sqlcipher
186
+ Use libsqlcipher instead of libsqlite3.
187
+ (Implies `--enable-system-libraries`.)
188
+
189
+ --with-sqlite-source-dir=DIRECTORY
190
+ (dev only) Build sqlite from the source code in DIRECTORY
191
+
192
+ --help
193
+ Display this message.
194
+
195
+
196
+ Flags only used when using system libraries:
197
+
198
+ General (applying to all system libraries):
199
+
200
+ --with-opt-dir=DIRECTORY
201
+ Look for headers and libraries in DIRECTORY.
202
+
203
+ --with-opt-lib=DIRECTORY
204
+ Look for libraries in DIRECTORY.
205
+
206
+ --with-opt-include=DIRECTORY
207
+ Look for headers in DIRECTORY.
208
+
209
+ Related to sqlcipher:
210
+
211
+ --with-sqlcipher-dir=DIRECTORY
212
+ Look for sqlcipher headers and library in DIRECTORY.
213
+ (Implies `--with-sqlcipher` and `--enable-system-libraries`.)
214
+
215
+ --with-sqlcipher-lib=DIRECTORY
216
+ Look for sqlcipher library in DIRECTORY.
217
+ (Implies `--with-sqlcipher` and `--enable-system-libraries`.)
218
+
219
+ --with-sqlcipher-include=DIRECTORY
220
+ Look for sqlcipher headers in DIRECTORY.
221
+ (Implies `--with-sqlcipher` and `--enable-system-libraries`.)
222
+
223
+
224
+ Flags only used when building and using the packaged libraries:
225
+
226
+ --enable-cross-build
227
+ Enable cross-build mode. (You probably do not want to set this manually.)
228
+
229
+
230
+ Environment variables used for compiling the C extension:
231
+
232
+ CC
233
+ Use this path to invoke the compiler instead of `RbConfig::CONFIG['CC']`
234
+
235
+
236
+ Environment variables passed through to the compilation of packaged libraries:
237
+
238
+ CC
239
+ CPPFLAGS
240
+ CFLAGS
241
+ LDFLAGS
242
+ LIBS
243
+ LT_SYS_LIBRARY_PATH
244
+ CPP
245
+
246
+ TEXT
247
+ end
248
+ end
249
+ end
94
250
  end
95
251
 
96
- have_func('sqlite3_prepare_v2')
97
- have_type('sqlite3_int64', 'sqlite3.h')
98
- have_type('sqlite3_uint64', 'sqlite3.h')
252
+ if arg_config("--help")
253
+ Sqlite3::ExtConf.print_help
254
+ exit!(0)
255
+ end
256
+
257
+ if arg_config("--download-dependencies")
258
+ Sqlite3::ExtConf.download
259
+ exit!(0)
260
+ end
99
261
 
100
- create_makefile('sqlite3/sqlite3_native')
262
+ Sqlite3::ExtConf.configure
@@ -158,4 +158,6 @@ void Init_sqlite3_native()
158
158
  rb_define_singleton_method(mSqlite3, "threadsafe", threadsafe_p, 0);
159
159
  rb_define_const(mSqlite3, "SQLITE_VERSION", rb_str_new2(SQLITE_VERSION));
160
160
  rb_define_const(mSqlite3, "SQLITE_VERSION_NUMBER", INT2FIX(SQLITE_VERSION_NUMBER));
161
+ rb_define_const(mSqlite3, "SQLITE_LOADED_VERSION", rb_str_new2(sqlite3_libversion()));
162
+
161
163
  }
@@ -21,8 +21,11 @@
21
21
  #define SQLITE3_UTF8_STR_NEW2(_obj) \
22
22
  (rb_enc_associate_index(rb_str_new2(_obj), rb_utf8_encindex()))
23
23
 
24
-
25
- #include <sqlite3.h>
24
+ #ifdef USING_SQLCIPHER_INC_SUBDIR
25
+ # include <sqlcipher/sqlite3.h>
26
+ #else
27
+ # include <sqlite3.h>
28
+ #endif
26
29
 
27
30
  #ifndef HAVE_TYPE_SQLITE3_INT64
28
31
  typedef sqlite_int64 sqlite3_int64;
@@ -290,7 +290,7 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
290
290
  /* call-seq: stmt.reset!
291
291
  *
292
292
  * Resets the statement. This is typically done internally, though it might
293
- * occassionally be necessary to manually reset the statement.
293
+ * occasionally be necessary to manually reset the statement.
294
294
  */
295
295
  static VALUE reset_bang(VALUE self)
296
296
  {
@@ -309,7 +309,7 @@ static VALUE reset_bang(VALUE self)
309
309
  /* call-seq: stmt.clear_bindings!
310
310
  *
311
311
  * Resets the statement. This is typically done internally, though it might
312
- * occassionally be necessary to manually reset the statement.
312
+ * occasionally be necessary to manually reset the statement.
313
313
  */
314
314
  static VALUE clear_bindings_bang(VALUE self)
315
315
  {