From f1b014a37bd9a34a9c18bea6737445e799541df0 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Mon, 18 May 2026 18:59:14 +0900 Subject: [PATCH] Initial commit --- .gitignore | 4 ++ README.md | 9 +++ flake.lock | 27 +++++++++ flake.nix | 42 ++++++++++++++ src/amalgamation.nix | 83 ++++++++++++++++++++++++++ src/build-config.nix | 135 +++++++++++++++++++++++++++++++++++++++++++ src/mk-sqlite.nix | 69 ++++++++++++++++++++++ 7 files changed, 369 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 src/amalgamation.nix create mode 100644 src/build-config.nix create mode 100644 src/mk-sqlite.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..156e04a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +result +result-* +*.db +*.sqlite diff --git a/README.md b/README.md new file mode 100644 index 0000000..7cb4be4 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# nix-custom-sqlite + +This repository contains a collection of nix expressions that make it easy to compile a custom version of SQLite. + +Customizations include things such as: + +- Toggling compile-time features. +- Adding external plugins, either baking them in statically or using dynamic linking. +- Cross-compiling for various architectures. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..94e0bfb --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1778869304, + "narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d233902339c02a9c334e7e593de68855ad26c4cb", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..16a50dd --- /dev/null +++ b/flake.nix @@ -0,0 +1,42 @@ +{ + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = { self, nixpkgs }: + let + inherit (nixpkgs) lib; + + systems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + + forAllSystems = f: lib.genAttrs systems (system: f system nixpkgs.legacyPackages.${system}); + in { + mkSqlite = import ./src/mk-sqlite.nix { inherit lib; }; + + packages = forAllSystems (system: pkgs: let + productVars = { + enableMinimal = [ true false ]; + enableDebug = [ true false ]; + enableInteractive = [ true false ]; + }; + in lib.mergeAttrsList (lib.mapCartesianProduct (args@{ + enableMinimal, + enableDebug, + enableInteractive, + }: let + result = self.mkSqlite { + inherit + pkgs + enableMinimal + enableDebug + enableInteractive; + }; + in { + "sqlite-amalgamation${result.suffix}" = result.amalgamation; + }) productVars)); + }; +} + diff --git a/src/amalgamation.nix b/src/amalgamation.nix new file mode 100644 index 0000000..f1ef417 --- /dev/null +++ b/src/amalgamation.nix @@ -0,0 +1,83 @@ +{ + lib, + + src, + version, + nameSuffix, + + stdenv, + featureFlags ? [ ], + extensions ? [ ], + enableInteractive ? false, + + unzip, + zlib, + readline, + ncurses, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "sqlite-amalgamation${nameSuffix}"; + inherit version src; + + outputs = [ + # "bin" + "dev" + "out" + ]; + + nativeBuildInputs = [ + unzip + ]; + buildInputs = [ + zlib + ] + ++ lib.optionals enableInteractive [ + readline + ncurses + ]; + + # required for aarch64 but applied for all arches for simplicity + preConfigure = '' + patchShebangs configure + ''; + + # sqlite relies on autosetup now; so many of the + # previously-understood flags are gone. They should instead be set + # on a per-output basis. + setOutputFlags = false; + + configureFlags = [ + # "--bindir=${placeholder "bin"}/bin" + "--includedir=${placeholder "dev"}/include" + "--libdir=${placeholder "out"}/lib" + ] + ++ lib.optional (!enableInteractive) "--disable-readline" + # autosetup only looks up readline.h in predefined set of directories. + ++ lib.optional enableInteractive "--with-readline-header=${lib.getDev readline}/include/readline/readline.h" + ++ lib.optional (stdenv.hostPlatform.isStatic) "--disable-shared"; + + env.NIX_CFLAGS_COMPILE = toString featureFlags; + + # Test for features which may not be available at compile time + preBuild = '' + # Necessary for FTS5 on Linux + export NIX_CFLAGS_LINK="$NIX_CFLAGS_LINK -lm" + + echo "" + echo "NIX_CFLAGS_COMPILE = $NIX_CFLAGS_COMPILE" + echo "" + ''; + + makeTarget = "sqlite3.c"; + + installPhase = '' + runHook preInstall + + install -Dm444 sqlite3.{c,h} -t "$out" + + runHook postInstall + ''; + + # dontInstall = true; +}) diff --git a/src/build-config.nix b/src/build-config.nix new file mode 100644 index 0000000..144faf8 --- /dev/null +++ b/src/build-config.nix @@ -0,0 +1,135 @@ +{ config, lib, ... }: +{ + options = { + enableMinimal = lib.mkEnableOption "" // { + description = "Whether to disable most feature flags by default."; + }; + + enableDebug = lib.mkEnableOption "" // { + description = "Whether to compile with various debug options enabled."; + }; + + enableInteractive = lib.mkEnableOption "" // { + description = "Whether to compile with recommended libraries for interactive shell usage."; + }; + + # https://sqlite.org/compile.html + features = lib.mkOption { + default = { }; + type = lib.types.submodule { + freeformType = with lib.types; attrsOf (oneOf int bool str); + options = let + toggleDefaultIfNotMinimal = name: extraOpts: lib.mkEnableOption "" // { + description = "Whether to compile with `-DSQLITE_${name}` set."; + default = !config.enableMinimal; + defaultText = "!enableMinimal"; + } // extraOpts; + + toggleDefaultIfDebug = name: extraOpts: lib.mkEnableOption "" // { + description = "Whether to compile with `-DSQLITE_${name}` set."; + default = config.enableDebug; + defaultText = "enableDebug"; + } // extraOpts; + + toggleDefaultOff = name: extraOpts: lib.mkEnableOption "" // { + description = "Whether to compile with `-DSQLITE_${name}` set."; + } // extraOpts; + + toggleDefaultOn = name: extraOpts: lib.mkEnableOption "" // { + description = "Whether to compile with `-DSQLITE_${name}` set."; + default = true; + } // extraOpts; + + defaultIfDebugToggles = [ + "DEBUG" + "ENABLE_EXPLAIN_COMMENTS" + "ENABLE_IOTRACE" + "MEMDEBUG" + "STRICT_SUBTYPE" + ]; + + defaultIfNotMinimalToggles = [ + "ENABLE_FTS5" + "ENABLE_GEOPOLY" + # "ENABLE_JSON1" + "ENABLE_NORMALIZE" + "ENABLE_OFFSET_SQL_FUNC" + "ENABLE_PERCENTILE" + "ENABLE_PREUPDATE_HOOK" + "ENABLE_RBU" + "ENABLE_RTREE" + "SECURE_DELETE" + ]; + + defaultOffToggles = [ + "ENABLE_ALLOCA" + "ENABLE_API_ARMOR" + "ENABLE_ATOMIC_WRITE" + "ENABLE_BATCH_ATOMIC_WRITE" + "ENABLE_BYTECODE_VTAB" + "ENABLE_COLUMN_METADATA" + "ENABLE_DBSTAT_VTAB" + "ENABLE_FTS3" + "ENABLE_FTS3_PARENTHESIS" + "ENABLE_FTS3_TOKENIZER" + "ENABLE_FTS4" + "ENABLE_HIDDEN_COLUMNS" + "ENABLE_ICU" + "ENABLE_LOCKING_STYLE" + "ENABLE_MEMORY_MANAGEMENT" + "ENABLE_MEMSYS3" + "ENABLE_MEMSYS5" + "ENABLE_NULL_TRIM" + "ENABLE_ORDERED_SET_AGGREGATES" + "ENABLE_QPSG" + "ENABLE_SESSION" + "ENABLE_SNAPSHOT" + "ENABLE_SORTER_REFERENCES" + "ENABLE_SQLLOG" + "ENABLE_STMTVTAB" + "ENABLE_STMT_SCANSTATUS" + "ENABLE_STMT_SCANSTATUS" + "ENABLE_UNKNOWN_SQL_FUNCTION" + "ENABLE_UNLOCK_NOTIFY" + "SOUNDEX" + "USE_FCNTL_TRACE" + ]; + + defaultOnToggles = [ + "ENABLE_MATH_FUNCTIONS" + ]; + in lib.mergeAttrsList [ + (lib.genAttrs defaultIfDebugToggles (name: toggleDefaultIfDebug name { })) + (lib.genAttrs defaultIfNotMinimalToggles (name: toggleDefaultIfNotMinimal name { })) + (lib.genAttrs defaultOffToggles (name: toggleDefaultOff name { })) + (lib.genAttrs defaultOnToggles (name: toggleDefaultOn name { })) + { + MAX_VARIABLE_NUMBER = lib.mkOption { + default = 250000; + }; + + MAX_EXPR_DEPTH = lib.mkOption { + default = 10000; + }; + } + ]; + }; + }; + + featureFlags = lib.mkOption { + type = with lib.types; listOf str; + }; + }; + + config = { + # TODO: handle interactive mode, icu, zlib + # buildInputs = []; + + featureFlags = lib.filter (x: x != null) ( + lib.mapAttrsToList ( + k: v: if lib.isInt v then "-DSQLITE_${k}=${toString v}" else + if lib.isBool v then if v then "-DSQLITE_${k}" else null + else "-DSQLITE_${k}=${v}") + config.features); + }; +} diff --git a/src/mk-sqlite.nix b/src/mk-sqlite.nix new file mode 100644 index 0000000..238a307 --- /dev/null +++ b/src/mk-sqlite.nix @@ -0,0 +1,69 @@ +{ lib }: +{ + pkgs, + src ? pkgs.sqlite.src, + version ? pkgs.sqlite.version, + + # Controls whether the packages are compiled via the amalgamation. + amalgamate ? true, + + # Enables a few sqlite compile time flags useful for debugging. + enableDebug ? false, + + # Disables most sqlite extensions, creating a relatively minimal build. + enableMinimal ? false, + + # Enables building with readline and ncurses, providing better support for interactive + # use in a shell. + enableInteractive ? false, + + # Manually tweak compile time flags. + # See https://sqlite.org/compile.html for available options. + # + # Note that the `SQLITE_` prefix is stripped, so + # `SQLITE_OPTION_XYZ` should be set as `OPTION_XYZ` + features ? { }, + + # Custom SQLite extensions and their entrypoints. + # extensions ? [ ], + + # Additional libraries to link against, useful when the extensions + # use external libraries. + # extraLibraries ? [ ], +}: let + config = (lib.evalModules { + modules = [ + ./build-config.nix + { + inherit + enableMinimal + enableDebug + enableInteractive; + } + ]; + }).config; + + suffix = lib.pipe null [ + (null: [ + (lib.optionalString enableMinimal "minimal") + (lib.optionalString enableDebug "debug") + (lib.optionalString enableInteractive "interactive") + ]) + (lib.filter (x: x != "")) + (lib.concatStringsSep "-") + (x: if x == "" then "" else "-${x}") + ]; +in { + inherit config; + inherit suffix; + + # "sqlite" + # "sqlite-static" +} // lib.optionalAttrs amalgamate { + amalgamation = pkgs.callPackage ./amalgamation.nix { + inherit (pkgs.sqlite) version src; + nameSuffix = suffix; + inherit enableInteractive; + inherit (config) featureFlags; + }; +}