115 lines
3.4 KiB
Nix
115 lines
3.4 KiB
Nix
{
|
|
lib,
|
|
|
|
extensions,
|
|
nameSuffix,
|
|
version,
|
|
headers,
|
|
|
|
stdenv,
|
|
writeText,
|
|
|
|
...
|
|
}:
|
|
|
|
assert lib.assertMsg (extensions != [ ]) "This derivation should not be evaluated if there are no extensions to build.";
|
|
|
|
# TODO: assert no colliding init/shutdown symbols across extensions.
|
|
|
|
let
|
|
initSymbols = builtins.catAttrs "init" extensions;
|
|
shutdownSymbols = builtins.catAttrs "shutdown" extensions;
|
|
|
|
coreInitHeaders = writeText "sqlite-core-init.h" ''
|
|
int core_init(const char *dummy);
|
|
void core_shutdown(void);
|
|
|
|
${lib.concatMapStringsSep "\n" (sym: "int ${sym}(const char *dummy);") initSymbols}
|
|
${lib.concatMapStringsSep "\n" (sym: "void ${sym}(void);") shutdownSymbols}
|
|
'';
|
|
|
|
# TODO: how should shutdown be handled with use of sqlite3_auto_extension? Is there a separate place for registering these?
|
|
coreInitImpl = writeText "sqlite-core-init.c" ''
|
|
#include "${coreInitHeaders}"
|
|
#include <sqlite3.h>
|
|
|
|
int core_init(const char *dummy) {
|
|
${lib.concatMapStringsSep "\n" (sym: "sqlite3_auto_extension((void(*)(void))${sym});") initSymbols}
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
void core_shutdown(void) {
|
|
${lib.concatMapStringsSep "\n" (sym: "${sym}();") shutdownSymbols}
|
|
}
|
|
'';
|
|
in stdenv.mkDerivation (finalAttrs: {
|
|
pname = "sqlite-core-init${nameSuffix}";
|
|
version = version;
|
|
|
|
src = null;
|
|
dontUnpack = true;
|
|
|
|
buildInputs = [ headers ];
|
|
|
|
buildPhase = ''
|
|
runHook preBuild
|
|
"$CC" -c '${coreInitImpl}' -o sqlite-core-init.o
|
|
runHook postBuild
|
|
'';
|
|
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
install -Dm644 '${coreInitHeaders}' "$out/include/sqlite-core-init.h"
|
|
mkdir -p "$out/lib"
|
|
"$AR" rcs "$out/lib/libsqlite-core-init.a" sqlite-core-init.o
|
|
|
|
runHook postInstall
|
|
'';
|
|
|
|
doCheck = true;
|
|
checkPhase = ''
|
|
runHook preCheck
|
|
|
|
for ext in ${lib.escapeShellArgs (builtins.catAttrs "library" extensions)}; do
|
|
if nm -g --defined-only "$ext" | grep -q " sqlite_api$"; then
|
|
echo "Extension $ext appears to reference the 'sqlite_api' symbol, which is not expected for extensions which are going to be statically linked."
|
|
echo "If your are building the extension yourself, please ensure that it is built with \`-DSQLITE_CORE\`"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
declare -A expectedSymbols;
|
|
${lib.concatMapStringsSep "\n" (ext: "expectedSymbols[${lib.escapeShellArg ext.init}]=${lib.escapeShellArg ext.library};") extensions}
|
|
${lib.concatMapStringsSep "\n" (ext: "expectedSymbols[${lib.escapeShellArg ext.shutdown}]=${lib.escapeShellArg ext.library};") (lib.filter (ext: ext.shutdown or null != null) extensions)}
|
|
|
|
for sym in "''${!expectedSymbols[@]}"; do
|
|
if ! nm -g --defined-only "''${expectedSymbols[$sym]}" | grep -q " ''${sym}$"; then
|
|
echo "Expected symbol $sym not found in ''${expectedSymbols[$sym]}."
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
runHook postCheck
|
|
'';
|
|
|
|
|
|
passthru = {
|
|
extraLDFLAGS = [
|
|
"-L${finalAttrs.finalPackage}/lib"
|
|
"-lsqlite-core-init"
|
|
] ++ lib.concatMap (ext: [
|
|
"-L${lib.dirOf ext.library}"
|
|
"-l${lib.removeSuffix ".so" (lib.removeSuffix ".a" (lib.removePrefix "lib" (lib.baseNameOf ext.library)))}"
|
|
]) extensions;
|
|
|
|
extraMakeFlags = let
|
|
opts = [
|
|
"-DSQLITE_EXTRA_INIT=core_init"
|
|
"-DSQLITE_EXTRA_SHUTDOWN=core_shutdown"
|
|
"-DSQLITE_CUSTOM_INCLUDE=${placeholder "out"}/include/sqlite-core-init.h"
|
|
];
|
|
in map (opt: "OPTIONS+=${lib.escapeShellArg opt}") opts;
|
|
};
|
|
})
|