Skip to content

Commit 9977985

Browse files
committed
[libclang] Allow to put a reproducer into a custom location. (#10577)
Tools using the reproducers can specify a custom location to support scenarios similar to those covered by `-fcrash-diagnostics-dir` and `CLANG_CRASH_DIAGNOSTICS_DIR`.
1 parent 929e5cc commit 9977985

File tree

4 files changed

+46
-6
lines changed

4 files changed

+46
-6
lines changed

clang/include/clang-c/Dependencies.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,10 @@ CINDEX_LINKAGE void
336336
* \param argc the number of compiler invocation arguments (including argv[0]).
337337
* \param argv the compiler driver invocation arguments (including argv[0]).
338338
* \param WorkingDirectory the directory in which the invocation runs.
339+
* \param ReproducerLocation the directory where to store the reproducer files.
340+
* If NULL, use a temporary location.
341+
* \param UseUniqueReproducerName if reproducer files should have unique names
342+
* to avoid collisions with existing files.
339343
* \param [out] MessageOut A pointer to store the human-readable message
340344
* describing the result of the operation. If non-NULL,
341345
* owned and should be disposed by the caller.
@@ -347,6 +351,7 @@ CINDEX_LINKAGE void
347351
CINDEX_LINKAGE enum CXErrorCode
348352
clang_experimental_DependencyScanner_generateReproducer(
349353
int argc, const char *const *argv, const char *WorkingDirectory,
354+
const char *ReproducerLocation, bool UseUniqueReproducerName,
350355
CXString *MessageOut);
351356

352357
/**

clang/test/Modules/reproducer-with-module-dependencies.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
// RUN: -- clang-executable -c %t/failed-reproducer.c -o %t/reproducer.o \
1414
// RUN: -fmodules -fmodules-cache-path=%t 2>&1 | FileCheck %t/failed-reproducer.c
1515

16+
// Test the content of a reproducer script.
17+
// RUN: c-index-test core -gen-deps-reproducer -working-dir %t -o %t/repro-content \
18+
// RUN: -- clang-executable -c %t/reproducer.c -o %t/reproducer.o \
19+
// RUN: -fmodules -fmodules-cache-path=%t
20+
// RUN: FileCheck %t/script-expectations.txt --input-file %t/repro-content/reproducer.sh
21+
1622
//--- modular-header.h
1723
void fn_in_modular_header(void);
1824

@@ -30,3 +36,7 @@ void test(void) {
3036
//--- failed-reproducer.c
3137
// CHECK: fatal error: 'non-existing-header.h' file not found
3238
#include "non-existing-header.h"
39+
40+
//--- script-expectations.txt
41+
CHECK: clang-executable
42+
CHECK: -fmodule-file=Test=reproducer.cache/explicitly-built-modules/Test-{{.*}}.pcm

clang/tools/c-index-test/core_main.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -925,14 +925,17 @@ static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory,
925925
}
926926

927927
static int generateDepsReproducer(ArrayRef<const char *> Args,
928-
std::string WorkingDirectory) {
928+
std::string WorkingDirectory,
929+
std::string ReproLocation) {
929930
CXString MessageString;
930931
auto DisposeMessageString = llvm::make_scope_exit([&]() {
931932
clang_disposeString(MessageString);
932933
});
933934
CXErrorCode ExitCode =
934935
clang_experimental_DependencyScanner_generateReproducer(
935-
Args.size(), Args.data(), WorkingDirectory.c_str(), &MessageString);
936+
Args.size(), Args.data(), WorkingDirectory.c_str(),
937+
ReproLocation.empty() ? nullptr : ReproLocation.c_str(),
938+
/*UseUniqueReproducerName=*/ReproLocation.empty(), &MessageString);
936939
if (ExitCode == CXError_Success) {
937940
llvm::outs() << clang_getCString(MessageString) << "\n";
938941
} else {
@@ -1571,7 +1574,8 @@ int indextest_core_main(int argc, const char **argv) {
15711574
errs() << "error: missing -working-dir\n";
15721575
return 1;
15731576
}
1574-
return generateDepsReproducer(CompArgs, options::WorkingDir);
1577+
return generateDepsReproducer(CompArgs, options::WorkingDir,
1578+
options::OutputFile);
15751579
}
15761580

15771581
if (options::Action == ActionType::UploadCachedJob) {

clang/tools/libclang/CDependencies.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ class MessageEmitter {
345345

346346
enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer(
347347
int argc, const char *const *argv, const char *WorkingDirectory,
348+
const char *ReproducerLocation, bool UseUniqueReproducerName,
348349
CXString *MessageOut) {
349350
auto Report = [MessageOut](CXErrorCode ErrorCode) -> MessageEmitter {
350351
return MessageEmitter(ErrorCode, MessageOut);
@@ -357,6 +358,9 @@ enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer(
357358
return Report(CXError_InvalidArguments) << "missing compilation command";
358359
if (!WorkingDirectory)
359360
return Report(CXError_InvalidArguments) << "missing working directory";
361+
if (!UseUniqueReproducerName && !ReproducerLocation)
362+
return Report(CXError_InvalidArguments)
363+
<< "non-unique reproducer is allowed only in a custom location";
360364

361365
CASOptions CASOpts;
362366
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> FS;
@@ -367,9 +371,26 @@ enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer(
367371

368372
llvm::SmallString<128> ReproScriptPath;
369373
int ScriptFD;
370-
if (auto EC = llvm::sys::fs::createTemporaryFile("reproducer", "sh", ScriptFD,
371-
ReproScriptPath)) {
372-
return ReportFailure() << "failed to create a reproducer script file";
374+
if (ReproducerLocation) {
375+
if (!llvm::sys::fs::exists(ReproducerLocation)) {
376+
if (auto EC = llvm::sys::fs::create_directories(ReproducerLocation))
377+
return ReportFailure() << "failed to create a reproducer location '"
378+
<< ReproducerLocation << "'\n"
379+
<< EC.message();
380+
}
381+
SmallString<128> Path(ReproducerLocation);
382+
llvm::sys::path::append(Path, "reproducer");
383+
const char *UniqueSuffix = UseUniqueReproducerName ? "-%%%%%%" : "";
384+
if (auto EC = llvm::sys::fs::createUniqueFile(Path + UniqueSuffix + ".sh",
385+
ScriptFD, ReproScriptPath))
386+
return ReportFailure() << "failed to create a reproducer script file\n"
387+
<< EC.message();
388+
} else {
389+
if (auto EC = llvm::sys::fs::createTemporaryFile(
390+
"reproducer", "sh", ScriptFD, ReproScriptPath)) {
391+
return ReportFailure() << "failed to create a reproducer script file\n"
392+
<< EC.message();
393+
}
373394
}
374395
SmallString<128> FileCachePath = ReproScriptPath;
375396
llvm::sys::path::replace_extension(FileCachePath, ".cache");

0 commit comments

Comments
 (0)