feat: Add temp-dir setting
This adds a new temp-dir setting for controlling the temporary directory
without having to change the TMPDIR env var. This can be used to e.g.
use a path on a case-sensitive store on macOS for temporary files
without changing the TMPDIR var used by interactive shells or commands
invoked with `nix run`.
This also stops unsetting `TMPDIR` on darwin when the env var value
starts with `/var/folders/`, preferring instead to just do the check
when reading `TMPDIR`. This way the inherited `TMPDIR` env var is
preserved for child processes (such as interactive shells).
As a side effect this changes the behavior of `nix-build -o ''` to act
like `nix-build --no-out-link` instead of failing with an error caused
by trying to create a symlink at the cwd.
Fixes: #253
Fixes: #112
Change-Id: I9ee826323f2deca62854715a77ca7a373a948a29
This commit is contained in:
parent
72cce7be3f
commit
3c8096e5cb
13
doc/manual/rl-next/nix-build-out-link.md
Normal file
13
doc/manual/rl-next/nix-build-out-link.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
synopsis: Change `nix-build -o ""` to behave like `--no-out-link`
|
||||
cls: [2103]
|
||||
category: Fixes
|
||||
credits: lilyball
|
||||
---
|
||||
|
||||
[`nix-build`](@docroot@/command-ref/nix-build.md)now treats <code>[--out-link](@docroot@/command-ref/nix-build.md#opt-out-link) ''</code>
|
||||
the same as [`--no-out-link`](@docroot@/command-ref/nix-build.md#opt-no-out-link). This matches
|
||||
[`nix build`](@docroot@/command-ref/new-cli/nix3-build.md) behavior. Previously when building the default output it
|
||||
would have resulted in throwing an error saying the current working directory already exists, and when building any
|
||||
other output it would have resulted in a symlink starting with a hyphen such as `-doc`, which is a footgun for
|
||||
terminal commands.
|
15
doc/manual/rl-next/temp-dir.md
Normal file
15
doc/manual/rl-next/temp-dir.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
synopsis: Add a `temp-dir` setting to set the temporary directory location
|
||||
issues: [7731, 8995, fj#112, fj#253]
|
||||
cls: [2103]
|
||||
category: Improvements
|
||||
credits: lilyball
|
||||
---
|
||||
|
||||
[`temp-dir`](@docroot@/command-ref/conf-file.md#conf-temp-dir) can now be set in the Nix
|
||||
configuration to change the temporary directory. This can be used to relocate all temporary files
|
||||
to another filesystem without affecting the `TMPDIR` env var inherited by interactive
|
||||
`nix-shell`/`nix shell` shells or `nix run` commands.
|
||||
|
||||
Also on macOS, the `TMPDIR` env var is no longer unset for interactive shells when pointing
|
||||
to a per-session `/var/folders/` directory.
|
|
@ -25,6 +25,7 @@
|
|||
#include "legacy.hh"
|
||||
#include "shlex.hh"
|
||||
#include "nix-build.hh"
|
||||
#include "temporary-dir.hh"
|
||||
|
||||
extern char * * environ __attribute__((weak)); // Man what even is this
|
||||
|
||||
|
@ -55,8 +56,6 @@ static void main_nix_build(int argc, char * * argv)
|
|||
std::string script;
|
||||
std::vector<std::string> savedArgs;
|
||||
|
||||
AutoDelete tmpDir(createTempDir("", myName));
|
||||
|
||||
std::string outLink = "./result";
|
||||
|
||||
// List of environment variables kept for --pure
|
||||
|
@ -102,7 +101,6 @@ static void main_nix_build(int argc, char * * argv)
|
|||
|
||||
MyArgs myArgs(myName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||
if (*arg == "--help") {
|
||||
deletePath(tmpDir);
|
||||
showManPage(myName);
|
||||
}
|
||||
|
||||
|
@ -113,7 +111,7 @@ static void main_nix_build(int argc, char * * argv)
|
|||
; // obsolete
|
||||
|
||||
else if (*arg == "--no-out-link" || *arg == "--no-link")
|
||||
outLink = (Path) tmpDir + "/result";
|
||||
outLink = "";
|
||||
|
||||
else if (*arg == "--attr" || *arg == "-A")
|
||||
attrPaths.push_back(getArg(*arg, arg, end));
|
||||
|
@ -198,6 +196,10 @@ static void main_nix_build(int argc, char * * argv)
|
|||
if (packages && fromArgs)
|
||||
throw UsageError("'-p' and '-E' are mutually exclusive");
|
||||
|
||||
AutoDelete tmpDir(createTempDir("", myName));
|
||||
if (outLink.empty())
|
||||
outLink = (Path) tmpDir + "/result";
|
||||
|
||||
auto store = openStore();
|
||||
auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store;
|
||||
|
||||
|
@ -416,8 +418,6 @@ static void main_nix_build(int argc, char * * argv)
|
|||
// Set the environment.
|
||||
auto env = getEnv();
|
||||
|
||||
auto tmp = defaultTempDir();
|
||||
|
||||
if (pure) {
|
||||
decltype(env) newEnv;
|
||||
for (auto & i : env)
|
||||
|
@ -428,7 +428,8 @@ static void main_nix_build(int argc, char * * argv)
|
|||
env["__ETC_PROFILE_SOURCED"] = "1";
|
||||
}
|
||||
|
||||
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmp;
|
||||
// Don't use defaultTempDir() here! We want to preserve the user's TMPDIR for the shell
|
||||
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = getEnvNonEmpty("TMPDIR").value_or("/tmp");
|
||||
env["NIX_STORE"] = store->storeDir;
|
||||
env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores);
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "legacy.hh"
|
||||
#include "fetchers.hh"
|
||||
#include "eval-settings.hh" // for defexpr
|
||||
#include "temporary-dir.hh"
|
||||
#include "users.hh"
|
||||
#include "nix-channel.hh"
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "logging.hh"
|
||||
#include "names.hh"
|
||||
#include "store-api.hh"
|
||||
#include "temporary-dir.hh"
|
||||
#include "url-name.hh"
|
||||
|
||||
namespace nix
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "processes.hh"
|
||||
#include "tarfile.hh"
|
||||
#include "store-api.hh"
|
||||
#include "temporary-dir.hh"
|
||||
#include "url-parts.hh"
|
||||
#include "pathlocks.hh"
|
||||
#include "users.hh"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "cache.hh"
|
||||
#include "processes.hh"
|
||||
#include "store-api.hh"
|
||||
#include "temporary-dir.hh"
|
||||
#include "url-parts.hh"
|
||||
#include "users.hh"
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "store-api.hh"
|
||||
#include "archive.hh"
|
||||
#include "tarfile.hh"
|
||||
#include "temporary-dir.hh"
|
||||
#include "types.hh"
|
||||
#include "split.hh"
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "remote-fs-accessor.hh"
|
||||
#include "nar-info-disk-cache.hh" // IWYU pragma: keep
|
||||
#include "nar-accessor.hh"
|
||||
#include "temporary-dir.hh"
|
||||
#include "thread-pool.hh"
|
||||
#include "signals.hh"
|
||||
#include "strings.hh"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "indirect-root-store.hh"
|
||||
#include "machines.hh"
|
||||
#include "store-api.hh"
|
||||
#include "temporary-dir.hh"
|
||||
#include "worker.hh"
|
||||
#include "builtins.hh"
|
||||
#include "builtins/buildenv.hh"
|
||||
|
|
|
@ -468,11 +468,6 @@ void initLibStore() {
|
|||
[1] https://github.com/apple-oss-distributions/objc4/blob/01edf1705fbc3ff78a423cd21e03dfc21eb4d780/runtime/objc-initialize.mm#L614-L636
|
||||
*/
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
/* On macOS, don't use the per-session TMPDIR (as set e.g. by
|
||||
sshd). This breaks build users because they don't have access
|
||||
to the TMPDIR, in particular in ‘nix-store --serve’. */
|
||||
if (defaultTempDir().starts_with("/var/folders/"))
|
||||
unsetenv("TMPDIR");
|
||||
#endif
|
||||
|
||||
registerStoreImplementations();
|
||||
|
|
|
@ -615,11 +615,11 @@ public:
|
|||
)"};
|
||||
#endif
|
||||
|
||||
Setting<std::optional<Path>> buildDir{this, std::nullopt, "build-dir",
|
||||
PathsSetting<std::optional<Path>> buildDir{this, std::nullopt, "build-dir",
|
||||
R"(
|
||||
The directory on the host, in which derivations' temporary build directories are created.
|
||||
|
||||
If not set, Nix will use the system temporary directory indicated by the `TMPDIR` environment variable.
|
||||
If not set, Nix will use the [`temp-dir`](#conf-temp-dir) setting if set, otherwise the system temporary directory indicated by the `TMPDIR` environment variable.
|
||||
Note that builds are often performed by the Nix daemon, so its `TMPDIR` is used, and not that of the Nix command line interface.
|
||||
|
||||
This is also the location where [`--keep-failed`](@docroot@/command-ref/opt-common.md#opt-keep-failed) leaves its files.
|
||||
|
@ -627,6 +627,18 @@ public:
|
|||
If Nix runs without sandbox, or if the platform does not support sandboxing with bind mounts (e.g. macOS), then the [`builder`](@docroot@/language/derivations.md#attr-builder)'s environment will contain this directory, instead of the virtual location [`sandbox-build-dir`](#conf-sandbox-build-dir).
|
||||
)"};
|
||||
|
||||
PathsSetting<std::optional<Path>> tempDir{this, std::nullopt, "temp-dir",
|
||||
R"(
|
||||
The directory on the host used as the default temporary directory.
|
||||
|
||||
If not set, Nix will use the system temporary directory indicated by the `TMPDIR` environment variable.
|
||||
|
||||
This will be used for anything that would otherwise fall back to `TMPDIR`, and the inherited `TMPDIR` value will be preserved for child processes to use.
|
||||
If [`build-dir`](#conf-build-dir) is set, that takes precedence over this where it applies.
|
||||
|
||||
If set, the value must be a path that exists and is accessible to all users.
|
||||
)"};
|
||||
|
||||
Setting<PathSet> allowedImpureHostPrefixes{this, {}, "allowed-impure-host-deps",
|
||||
"Which prefixes to allow derivations to ask for access to (primarily for Darwin)."};
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "globals.hh"
|
||||
#include "archive.hh"
|
||||
#include "pathlocks.hh"
|
||||
#include "temporary-dir.hh"
|
||||
#include "worker-protocol.hh"
|
||||
#include "derivations.hh"
|
||||
#include "nar-info.hh"
|
||||
|
|
|
@ -77,6 +77,7 @@ libstore_sources = files(
|
|||
'ssh-store.cc',
|
||||
'ssh.cc',
|
||||
'store-api.cc',
|
||||
'temporary-dir.cc',
|
||||
'uds-remote-store.cc',
|
||||
'worker-protocol.cc',
|
||||
'build/child.cc',
|
||||
|
@ -160,6 +161,7 @@ libstore_headers = files(
|
|||
'ssh-store.hh',
|
||||
'store-api.hh',
|
||||
'store-cast.hh',
|
||||
'temporary-dir.hh',
|
||||
'uds-remote-store.hh',
|
||||
'worker-protocol-impl.hh',
|
||||
'worker-protocol.hh',
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "finally.hh"
|
||||
#include "logging.hh"
|
||||
#include "strings.hh"
|
||||
#include "temporary-dir.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
42
src/libstore/temporary-dir.cc
Normal file
42
src/libstore/temporary-dir.cc
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "temporary-dir.hh"
|
||||
|
||||
#include "file-system.hh"
|
||||
#include "globals.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
Path createTempDir(const Path & tmpRoot, const Path & prefix,
|
||||
bool includePid, bool useGlobalCounter, mode_t mode)
|
||||
{
|
||||
return createTempSubdir(tmpRoot.empty() ? defaultTempDir() : tmpRoot, prefix, includePid, useGlobalCounter, mode);
|
||||
}
|
||||
|
||||
std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
|
||||
{
|
||||
Path tmpl(defaultTempDir() + "/" + prefix + ".XXXXXX");
|
||||
// FIXME: use O_TMPFILE.
|
||||
AutoCloseFD fd(mkstemp(tmpl.data()));
|
||||
if (!fd)
|
||||
throw SysError("creating temporary file '%s'", tmpl);
|
||||
closeOnExec(fd.get());
|
||||
return {std::move(fd), tmpl};
|
||||
}
|
||||
|
||||
Path defaultTempDir()
|
||||
{
|
||||
return settings.tempDir.get().or_else([] {
|
||||
return getEnvNonEmpty("TMPDIR").and_then([](auto val) -> std::optional<Path> {
|
||||
#if __APPLE__
|
||||
/* On macOS, don't use the per-session TMPDIR (as set e.g. by
|
||||
sshd). This breaks build users because they don't have access
|
||||
to the TMPDIR, in particular in ‘nix-store --serve’. */
|
||||
if (val.starts_with("/var/folders/")) {
|
||||
return std::nullopt;
|
||||
}
|
||||
#endif
|
||||
return val;
|
||||
});
|
||||
}).value_or("/tmp");
|
||||
}
|
||||
|
||||
}
|
24
src/libstore/temporary-dir.hh
Normal file
24
src/libstore/temporary-dir.hh
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "file-system.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* Create a temporary directory.
|
||||
*/
|
||||
Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix",
|
||||
bool includePid = true, bool useGlobalCounter = true, mode_t mode = 0755);
|
||||
|
||||
/**
|
||||
* Create a temporary file, returning a file handle and its path.
|
||||
*/
|
||||
std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix = "nix");
|
||||
|
||||
/**
|
||||
* Return settings.tempDir, `TMPDIR`, or the default temporary directory if unset or empty.
|
||||
*/
|
||||
Path defaultTempDir();
|
||||
|
||||
}
|
|
@ -562,21 +562,17 @@ void AutoDelete::reset(const Path & p, bool recursive) {
|
|||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string defaultTempDir() {
|
||||
return getEnvNonEmpty("TMPDIR").value_or("/tmp");
|
||||
}
|
||||
|
||||
static Path tempName(Path tmpRoot, const Path & prefix, bool includePid,
|
||||
static Path tempName(PathView parent, const Path & prefix, bool includePid,
|
||||
std::atomic<unsigned int> & counter)
|
||||
{
|
||||
tmpRoot = canonPath(tmpRoot.empty() ? defaultTempDir() : tmpRoot, true);
|
||||
auto tmpRoot = canonPath(parent, true);
|
||||
if (includePid)
|
||||
return fmt("%1%/%2%-%3%-%4%", tmpRoot, prefix, getpid(), counter++);
|
||||
else
|
||||
return fmt("%1%/%2%-%3%", tmpRoot, prefix, counter++);
|
||||
}
|
||||
|
||||
Path createTempDir(const Path & tmpRoot, const Path & prefix,
|
||||
Path createTempSubdir(const Path & parent, const Path & prefix,
|
||||
bool includePid, bool useGlobalCounter, mode_t mode)
|
||||
{
|
||||
static std::atomic<unsigned int> globalCounter = 0;
|
||||
|
@ -585,7 +581,7 @@ Path createTempDir(const Path & tmpRoot, const Path & prefix,
|
|||
|
||||
while (1) {
|
||||
checkInterrupt();
|
||||
Path tmpDir = tempName(tmpRoot, prefix, includePid, counter);
|
||||
Path tmpDir = tempName(parent, prefix, includePid, counter);
|
||||
if (mkdir(tmpDir.c_str(), mode) == 0) {
|
||||
#if __FreeBSD__
|
||||
/* Explicitly set the group of the directory. This is to
|
||||
|
@ -606,18 +602,6 @@ Path createTempDir(const Path & tmpRoot, const Path & prefix,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
|
||||
{
|
||||
Path tmpl(defaultTempDir() + "/" + prefix + ".XXXXXX");
|
||||
// FIXME: use O_TMPFILE.
|
||||
AutoCloseFD fd(mkstemp(tmpl.data()));
|
||||
if (!fd)
|
||||
throw SysError("creating temporary file '%s'", tmpl);
|
||||
closeOnExec(fd.get());
|
||||
return {std::move(fd), tmpl};
|
||||
}
|
||||
|
||||
Path makeTempPath(const Path & root, const Path & suffix)
|
||||
{
|
||||
// start the counter at a random value to minimize issues with preexisting temp paths
|
||||
|
@ -721,7 +705,7 @@ void moveFile(const Path & oldName, const Path & newName)
|
|||
auto newPath = fs::path(newName);
|
||||
// For the move to be as atomic as possible, copy to a temporary
|
||||
// directory
|
||||
fs::path temp = createTempDir(newPath.parent_path(), "rename-tmp");
|
||||
fs::path temp = createTempSubdir(newPath.parent_path(), "rename-tmp");
|
||||
Finally removeTemp = [&]() { fs::remove(temp); };
|
||||
auto tempCopyTarget = temp / "copy-target";
|
||||
if (e.code().value() == EXDEV) {
|
||||
|
|
|
@ -288,21 +288,11 @@ struct DIRDeleter
|
|||
typedef std::unique_ptr<DIR, DIRDeleter> AutoCloseDir;
|
||||
|
||||
/**
|
||||
* Create a temporary directory.
|
||||
* Create a temporary directory in a given parent directory.
|
||||
*/
|
||||
Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix",
|
||||
Path createTempSubdir(const Path & parent, const Path & prefix = "nix",
|
||||
bool includePid = true, bool useGlobalCounter = true, mode_t mode = 0755);
|
||||
|
||||
/**
|
||||
* Create a temporary file, returning a file handle and its path.
|
||||
*/
|
||||
std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix = "nix");
|
||||
|
||||
/**
|
||||
* Return `TMPDIR`, or the default temporary directory if unset or empty.
|
||||
*/
|
||||
Path defaultTempDir();
|
||||
|
||||
/**
|
||||
* Return temporary path constructed by appending a suffix to a root path.
|
||||
*
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "outputs-spec.hh"
|
||||
#include "derivations.hh"
|
||||
#include "run.hh"
|
||||
#include "temporary-dir.hh"
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "attr-path.hh"
|
||||
#include "eval-inline.hh" // IWYU pragma: keep
|
||||
#include "legacy.hh"
|
||||
#include "temporary-dir.hh"
|
||||
#include "terminal.hh"
|
||||
#include "prefetch-command.hh"
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "current-process.hh"
|
||||
|
||||
#if __linux__
|
||||
#include "temporary-dir.hh"
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
|
||||
|
|
|
@ -49,6 +49,50 @@ test_custom_build_dir() {
|
|||
}
|
||||
test_custom_build_dir
|
||||
|
||||
test_custom_temp_dir() {
|
||||
# like test_custom_build_dir(), but uses the temp-dir setting instead
|
||||
# build-dir inherits from temp-dir when build-dir is unset
|
||||
local customTempDir="$TEST_ROOT/custom-temp-dir"
|
||||
|
||||
mkdir "$customTempDir"
|
||||
nix-build check.nix -A failed --argstr checkBuildId $checkBuildId \
|
||||
--no-out-link --keep-failed --option temp-dir "$customTempDir" 2> $TEST_ROOT/log || status=$?
|
||||
[ "$status" = "100" ]
|
||||
[[ 1 == "$(count "$customTempDir/nix-build-"*)" ]]
|
||||
local buildDir="$customTempDir/nix-build-"*
|
||||
grep $checkBuildId $buildDir/checkBuildId
|
||||
|
||||
# also check a separate code path that doesn't involve build-dir
|
||||
# nix-shell uses temp-dir for its rcfile path
|
||||
rcpath=$(NIX_BUILD_SHELL=$SHELL nix-shell check.nix -A deterministic --option temp-dir "$customTempDir" --run 'echo $0' 2> $TEST_ROOT/log)
|
||||
# rcpath is <temp-dir>/nix-shell-*/rc
|
||||
[[ $rcpath = "$customTempDir"/* ]]
|
||||
}
|
||||
test_custom_temp_dir
|
||||
|
||||
test_shell_preserves_tmpdir() {
|
||||
# ensure commands that spawn interactive shells don't overwrite TMPDIR with temp-dir
|
||||
local envTempDir=$TEST_ROOT/shell-temp-dir-env
|
||||
mkdir $envTempDir
|
||||
local settingTempDir=$TEST_ROOT/shell-temp-dir-setting
|
||||
mkdir $settingTempDir
|
||||
|
||||
# FIXME: switch to check.nix's deterministic once `nix develop` doesn't need `outputs`
|
||||
# https://git.lix.systems/lix-project/lix/issues/556
|
||||
local expr='with import ./config.nix; mkDerivation { name = "foo"; buildCommand = "echo foo > $out"; outputs = [ "out" ]; }'
|
||||
|
||||
local output
|
||||
output=$(TMPDIR=$envTempDir NIX_BUILD_SHELL=$SHELL nix-shell -E "$expr" --option temp-dir "$settingTempDir" --command 'echo $TMPDIR' 2> $TEST_ROOT/log)
|
||||
[[ $output = "$envTempDir" ]]
|
||||
|
||||
output=$(TMPDIR=$envTempDir nix develop --impure -E "$expr" --option temp-dir "$settingTempDir" --command bash -c 'echo $TMPDIR' 2> $TEST_ROOT/log)
|
||||
[[ $output = "$envTempDir"/nix-shell.* ]]
|
||||
|
||||
output=$(TMPDIR=$envTempDir nix shell --impure -E "$expr" --option temp-dir "$settingTempDir" --command bash -c 'echo $TMPDIR' 2> $TEST_ROOT/log)
|
||||
[[ $output = "$envTempDir" ]]
|
||||
}
|
||||
test_shell_preserves_tmpdir
|
||||
|
||||
nix-build check.nix -A deterministic --argstr checkBuildId $checkBuildId \
|
||||
--no-out-link 2> $TEST_ROOT/log
|
||||
checkBuildTempDirRemoved $TEST_ROOT/log
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <rapidcheck/gtest.h>
|
||||
#include "sqlite.hh"
|
||||
#include "temporary-dir.hh"
|
||||
#include <sqlite3.h>
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue