diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -859,6 +859,8 @@ - Introduced the new function ``clang_CXXMethod_isMoveAssignmentOperator``, which identifies whether a method cursor is a move-assignment operator. +- Introduced the new function ``clang_setTemporaryDirectory``, + which allows to override the temporary directory path used by Clang. - ``clang_Cursor_getNumTemplateArguments``, ``clang_Cursor_getTemplateArgumentKind``, ``clang_Cursor_getTemplateArgumentType``, ``clang_Cursor_getTemplateArgumentValue`` and ``clang_Cursor_getTemplateArgumentUnsignedValue`` now work on struct, class, diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -34,7 +34,7 @@ * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. */ #define CINDEX_VERSION_MAJOR 0 -#define CINDEX_VERSION_MINOR 62 +#define CINDEX_VERSION_MINOR 63 #define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1)) @@ -69,6 +69,17 @@ * @{ */ +/** + * Override the temporary directory path used by Clang. + * + * \param tempDirUtf8 UTF-8-encoded path to the desired temporary directory. + * The pointer is owned by the caller and must be always valid. Pass nullptr to + * this function in order to reset the temporary directory to the default value + * from the environment. Such a resetting should be done before deleting a + * tempDirUtf8 pointer previously passed to this function. + */ +CINDEX_LINKAGE void clang_setTemporaryDirectory(const char *tempDirUtf8); + /** * An "index" that consists of a set of translation units that would * typically be linked together into an executable or library. diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -48,6 +48,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/Signals.h" @@ -3637,6 +3638,12 @@ static llvm::ManagedStatic RegisterFatalErrorHandlerOnce; +void clang_setTemporaryDirectory(const char *tempDirUtf8) { + // libclang uses only erased-on-reboot temporary directory, so only it needs + // to be set here. + llvm::sys::path::set_system_temp_directory_erased_on_reboot(tempDirUtf8); +} + CXIndex clang_createIndex(int excludeDeclarationsFromPCH, int displayDiagnostics) { // We use crash recovery to make some of our APIs more reliable, implicitly diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map --- a/clang/tools/libclang/libclang.map +++ b/clang/tools/libclang/libclang.map @@ -407,6 +407,7 @@ LLVM_16 { global: + clang_setTemporaryDirectory; clang_getUnqualifiedType; clang_getNonReferenceType; clang_CXXMethod_isDeleted; diff --git a/llvm/include/llvm/Support/Path.h b/llvm/include/llvm/Support/Path.h --- a/llvm/include/llvm/Support/Path.h +++ b/llvm/include/llvm/Support/Path.h @@ -412,6 +412,16 @@ /// @param result Holds the resulting path name. void system_temp_directory(bool erasedOnReboot, SmallVectorImpl &result); +/// Override the temporary directory path returned by +/// system_temp_directory(true, result). +/// +/// @param tempDirUtf8 UTF-8-encoded path to the desired temporary directory. +/// The pointer is owned by the caller and must be always valid. Pass nullptr to +/// this function in order to reset the temporary directory to the default value +/// from the environment. Such a resetting should be done before deleting a +/// tempDirUtf8 pointer previously passed to this function. +void set_system_temp_directory_erased_on_reboot(const char *tempDirUtf8); + /// Get the user's home directory. /// /// @param result Holds the resulting path name. diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp --- a/llvm/lib/Support/Path.cpp +++ b/llvm/lib/Support/Path.cpp @@ -780,6 +780,12 @@ return true; } +static const char *tempDirErasedOnRebootUtf8 = nullptr; + +void set_system_temp_directory_erased_on_reboot(const char *tempDirUtf8) { + tempDirErasedOnRebootUtf8 = tempDirUtf8; +} + } // end namespace path namespace fs { diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -1451,8 +1451,11 @@ Result.clear(); if (ErasedOnReboot) { + const char *RequestedDir = tempDirErasedOnRebootUtf8; // There is no env variable for the cache directory. - if (const char *RequestedDir = getEnvTempDir()) { + if (!RequestedDir) + RequestedDir = getEnvTempDir(); + if (RequestedDir) { Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); return; } diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -1472,11 +1472,16 @@ (void)ErasedOnReboot; Result.clear(); + if (tempDirErasedOnRebootUtf8) { + const auto len = strlen(tempDirErasedOnRebootUtf8); + Result.append(tempDirErasedOnRebootUtf8, tempDirErasedOnRebootUtf8 + len); + } + // Check whether the temporary directory is specified by an environment var. // This matches GetTempPath logic to some degree. GetTempPath is not used // directly as it cannot handle evn var longer than 130 chars on Windows 7 // (fixed on Windows 8). - if (getTempDirEnvVar(Result)) { + if (!Result.empty() || getTempDirEnvVar(Result)) { assert(!Result.empty() && "Unexpected empty path"); native(Result); // Some Unix-like shells use Unix path separator in $TMP. fs::make_absolute(Result); // Make it absolute if not already. diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -591,6 +591,26 @@ EXPECT_TRUE(!TempDir.empty()); } +TEST(Support, SetTempDirectory) { + SmallString<64> DefaultTempDir; + path::system_temp_directory(true, DefaultTempDir); + EXPECT_TRUE(!DefaultTempDir.empty()); + + auto CustomTempDir = DefaultTempDir; + path::append(CustomTempDir, "/llvm/test_temp_dir"); + path::native(CustomTempDir); + path::set_system_temp_directory_erased_on_reboot(CustomTempDir.c_str()); + + SmallString<64> TempDir; + path::system_temp_directory(true, TempDir); + EXPECT_EQ(CustomTempDir, TempDir); + + path::set_system_temp_directory_erased_on_reboot(nullptr); + TempDir.clear(); + path::system_temp_directory(true, TempDir); + EXPECT_EQ(DefaultTempDir, TempDir); +} + #ifdef _WIN32 static std::string path2regex(std::string Path) { size_t Pos = 0;