Skip to content

Commit d440bf1

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 52c2328 commit d440bf1

File tree

4 files changed

+48
-8
lines changed

4 files changed

+48
-8
lines changed

clang/include/clang-c/Dependencies.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@ CINDEX_LINKAGE void
339339
* the intermediate modules. Otherwise, reproduce building
340340
* the whole translation unit.
341341
* \param WorkingDirectory the directory in which the invocation runs.
342+
* \param ReproducerLocation the directory where to store the reproducer files.
343+
* If NULL, use a temporary location.
344+
* \param UseUniqueReproducerName if reproducer files should have unique names
345+
* to avoid collisions with existing files.
342346
* \param [out] MessageOut A pointer to store the human-readable message
343347
* describing the result of the operation. If non-NULL,
344348
* owned and should be disposed by the caller.
@@ -350,7 +354,8 @@ CINDEX_LINKAGE void
350354
CINDEX_LINKAGE enum CXErrorCode
351355
clang_experimental_DependencyScanner_generateReproducer(
352356
int argc, const char *const *argv, const char *ModuleName,
353-
const char *WorkingDirectory, CXString *MessageOut);
357+
const char *WorkingDirectory, const char *ReproducerLocation,
358+
bool UseUniqueReproducerName, CXString *MessageOut);
354359

355360
/**
356361
* Produces the dependency graph for a particular compiler invocation.

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,15 +925,18 @@ 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(
935936
Args.size(), Args.data(), /*ModuleName=*/nullptr,
936-
WorkingDirectory.c_str(), &MessageString);
937+
WorkingDirectory.c_str(),
938+
ReproLocation.empty() ? nullptr : ReproLocation.c_str(),
939+
/*UseUniqueReproducerName=*/ReproLocation.empty(), &MessageString);
937940
if (ExitCode == CXError_Success) {
938941
llvm::outs() << clang_getCString(MessageString) << "\n";
939942
} else {
@@ -1572,7 +1575,8 @@ int indextest_core_main(int argc, const char **argv) {
15721575
errs() << "error: missing -working-dir\n";
15731576
return 1;
15741577
}
1575-
return generateDepsReproducer(CompArgs, options::WorkingDir);
1578+
return generateDepsReproducer(CompArgs, options::WorkingDir,
1579+
options::OutputFile);
15761580
}
15771581

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

clang/tools/libclang/CDependencies.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,8 @@ class MessageEmitter {
345345

346346
enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer(
347347
int argc, const char *const *argv, const char *ModuleName,
348-
const char *WorkingDirectory, CXString *MessageOut) {
348+
const char *WorkingDirectory, const char *ReproducerLocation,
349+
bool UseUniqueReproducerName, CXString *MessageOut) {
349350
auto Report = [MessageOut](CXErrorCode ErrorCode) -> MessageEmitter {
350351
return MessageEmitter(ErrorCode, MessageOut);
351352
};
@@ -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)