module Sqlite3::ExtConf

Constants

ENV_ALLOWLIST

Public Class Methods

abort_could_not_find(missing) click to toggle source
# File ext/sqlite3/extconf.rb, line 174
def abort_could_not_find(missing)
  abort("\nCould not find #{missing}.\nPlease visit https://github.com/sparklemotion/sqlite3-ruby for installation instructions.\n\n")
end
abort_pkg_config(id) click to toggle source
# File ext/sqlite3/extconf.rb, line 178
def abort_pkg_config(id)
  abort("\nCould not configure the build properly (#{id}). Please install the `pkg-config` utility.\n\n")
end
configure() click to toggle source
# File ext/sqlite3/extconf.rb, line 9
def configure
  configure_cross_compiler

  if system_libraries?
    message "Building sqlite3-ruby using system #{libname}.\n"
    configure_system_libraries
  else
    message "Building sqlite3-ruby using packaged sqlite3.\n"
    configure_packaged_libraries
  end

  configure_extension

  create_makefile("sqlite3/sqlite3_native")
end
configure_cross_compiler() click to toggle source
# File ext/sqlite3/extconf.rb, line 25
def configure_cross_compiler
  RbConfig::CONFIG["CC"] = RbConfig::MAKEFILE_CONFIG["CC"] = ENV["CC"] if ENV["CC"]
  ENV["CC"] = RbConfig::CONFIG["CC"]
end
configure_extension() click to toggle source
# File ext/sqlite3/extconf.rb, line 106
def configure_extension
  append_cflags("-fvisibility=hidden") # see https://github.com/rake-compiler/rake-compiler-dock/issues/87

  if find_header("sqlite3.h")
    # noop
  elsif sqlcipher? && find_header("sqlcipher/sqlite3.h")
    append_cppflags("-DUSING_SQLCIPHER_INC_SUBDIR")
  else
    abort_could_not_find("sqlite3.h")
  end

  abort_could_not_find(libname) unless find_library(libname, "sqlite3_libversion_number", "sqlite3.h")

  # Truffle Ruby doesn't support this yet:
  # https://github.com/oracle/truffleruby/issues/3408
  have_func("rb_enc_interned_str_cstr")

  # Functions defined in 1.9 but not 1.8
  have_func("rb_proc_arity")

  # Functions defined in 2.1 but not 2.0
  have_func("rb_integer_pack")

  # These functions may not be defined
  have_func("sqlite3_initialize")
  have_func("sqlite3_backup_init")
  have_func("sqlite3_column_database_name")
  have_func("sqlite3_enable_load_extension")
  have_func("sqlite3_load_extension")

  unless have_func("sqlite3_open_v2") # https://www.sqlite.org/releaselog/3_5_0.html
    abort("\nPlease use a version of SQLite3 >= 3.5.0\n\n")
  end

  have_func("sqlite3_prepare_v2")
  have_func("sqlite3_db_name", "sqlite3.h") # v3.39.0
  have_func("sqlite3_error_offset", "sqlite3.h") # v3.38.0

  have_type("sqlite3_int64", "sqlite3.h")
  have_type("sqlite3_uint64", "sqlite3.h")
end
configure_packaged_libraries() click to toggle source
# File ext/sqlite3/extconf.rb, line 50
def configure_packaged_libraries
  minimal_recipe.tap do |recipe|
    recipe.configure_options += [
      "--disable-shared",
      "--enable-static",
      "--disable-tcl",
      "--enable-fts5"
    ]
    ENV.to_h.tap do |env|
      user_cflags = with_config("sqlite-cflags")
      more_cflags = [
        "-fPIC", # needed for linking the static library into a shared library
        "-O2", # see https://github.com/sparklemotion/sqlite3-ruby/issues/335 for some benchmarks
        "-fvisibility=hidden", # see https://github.com/rake-compiler/rake-compiler-dock/issues/87
        "-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1",
        "-DSQLITE_USE_URI=1",
        "-DSQLITE_ENABLE_DBPAGE_VTAB=1",
        "-DSQLITE_ENABLE_DBSTAT_VTAB=1"
      ]
      env["CFLAGS"] = [user_cflags, env["CFLAGS"], more_cflags].flatten.join(" ")
      recipe.configure_options += env.select { |k, v| ENV_ALLOWLIST.include?(k) }
        .map { |key, value| "#{key}=#{value.strip}" }
    end

    unless File.exist?(File.join(recipe.target, recipe.host, recipe.name, recipe.version))
      recipe.cook
    end
    recipe.activate

    # on macos, pkg-config will not return --cflags without this
    ENV["PKG_CONFIG_ALLOW_SYSTEM_CFLAGS"] = "t"

    # only needed for Ruby 3.1.3, see https://bugs.ruby-lang.org/issues/19233
    RbConfig::CONFIG["PKG_CONFIG"] = config_string("PKG_CONFIG") || "pkg-config"

    lib_path = File.join(recipe.path, "lib")
    pcfile = File.join(lib_path, "pkgconfig", "sqlite3.pc")
    abort_pkg_config("pkg_config") unless pkg_config(pcfile)

    # see https://bugs.ruby-lang.org/issues/18490
    ldflags = xpopen(["pkg-config", "--libs", "--static", pcfile], err: [:child, :out], &:read)
    abort_pkg_config("xpopen") unless $?.success?
    ldflags = ldflags.split

    # see https://github.com/flavorjones/mini_portile/issues/118
    "-L#{lib_path}".tap do |lib_path_flag|
      ldflags.prepend(lib_path_flag) unless ldflags.include?(lib_path_flag)
    end

    ldflags.each { |ldflag| append_ldflags(ldflag) }

    append_cppflags("-DUSING_PACKAGED_LIBRARIES")
    append_cppflags("-DUSING_PRECOMPILED_LIBRARIES") if cross_build?
  end
end
configure_system_libraries() click to toggle source
# File ext/sqlite3/extconf.rb, line 45
def configure_system_libraries
  pkg_config(libname)
  append_cppflags("-DUSING_SQLCIPHER") if sqlcipher?
end
cross_build?() click to toggle source
# File ext/sqlite3/extconf.rb, line 182
def cross_build?
  enable_config("cross-build")
end
darwin?() click to toggle source
# File ext/sqlite3/extconf.rb, line 194
def darwin?
  RbConfig::CONFIG["target_os"].include?("darwin")
end
download() click to toggle source
# File ext/sqlite3/extconf.rb, line 190
def download
  minimal_recipe.download
end
libname() click to toggle source
# File ext/sqlite3/extconf.rb, line 34
def libname
  sqlcipher? ? "sqlcipher" : "sqlite3"
end
mini_portile_config() click to toggle source
# File ext/sqlite3/extconf.rb, line 170
def mini_portile_config
  YAML.load_file(File.join(package_root_dir, "dependencies.yml"), symbolize_names: true)
end
minimal_recipe() click to toggle source
# File ext/sqlite3/extconf.rb, line 148
def minimal_recipe
  require "mini_portile2"

  MiniPortile.new(libname, sqlite3_config[:version]).tap do |recipe|
    if sqlite_source_dir
      recipe.source_directory = sqlite_source_dir
    else
      recipe.files = sqlite3_config[:files]
      recipe.target = File.join(package_root_dir, "ports")
      recipe.patch_files = Dir[File.join(package_root_dir, "patches", "*.patch")].sort
    end
  end
end
package_root_dir() click to toggle source
# File ext/sqlite3/extconf.rb, line 162
def package_root_dir
  File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
end
print_help() click to toggle source
sqlcipher?() click to toggle source
# File ext/sqlite3/extconf.rb, line 38
def sqlcipher?
  with_config("sqlcipher") ||
    with_config("sqlcipher-dir") ||
    with_config("sqlcipher-include") ||
    with_config("sqlcipher-lib")
end
sqlite3_config() click to toggle source
# File ext/sqlite3/extconf.rb, line 166
def sqlite3_config
  mini_portile_config[:sqlite3]
end
sqlite_source_dir() click to toggle source
# File ext/sqlite3/extconf.rb, line 186
def sqlite_source_dir
  arg_config("--with-sqlite-source-dir")
end
system_libraries?() click to toggle source
# File ext/sqlite3/extconf.rb, line 30
def system_libraries?
  sqlcipher? || enable_config("system-libraries")
end