Skip to content

Commit 16c3302

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 a90449f commit 16c3302

File tree

4 files changed

+52
-10
lines changed

4 files changed

+52
-10
lines changed

clang/include/clang-c/Dependencies.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,11 +608,16 @@ typedef struct CXOpaqueDependencyScannerReproducerOptions
608608
* the intermediate modules. Otherwise, reproduce building
609609
* the whole translation unit.
610610
* \param WorkingDirectory the directory in which the invocation runs.
611+
* \param ReproducerLocation the directory where to store the reproducer files.
612+
* If NULL, use a temporary location.
613+
* \param UseUniqueReproducerName if reproducer files should have unique names
614+
* to avoid collisions with existing files.
611615
*/
612616
CINDEX_LINKAGE CXDependencyScannerReproducerOptions
613617
clang_experimental_DependencyScannerReproducerOptions_create(
614618
int argc, const char *const *argv, const char *ModuleName,
615-
const char *WorkingDirectory);
619+
const char *WorkingDirectory, const char *ReproducerLocation,
620+
bool UseUniqueReproducerName);
616621

617622
CINDEX_LINKAGE void
618623
clang_experimental_DependencyScannerReproducerOptions_dispose(

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
@@ -927,11 +927,14 @@ static int scanDeps(ArrayRef<const char *> Args, std::string WorkingDirectory,
927927
}
928928

929929
static int generateDepsReproducer(ArrayRef<const char *> Args,
930-
std::string WorkingDirectory) {
930+
std::string WorkingDirectory,
931+
std::string ReproLocation) {
931932
CXDependencyScannerReproducerOptions Opts =
932933
clang_experimental_DependencyScannerReproducerOptions_create(
933934
Args.size(), Args.data(), /*ModuleName=*/nullptr,
934-
WorkingDirectory.c_str());
935+
WorkingDirectory.c_str(),
936+
ReproLocation.empty() ? nullptr : ReproLocation.c_str(),
937+
/*UseUniqueReproducerName=*/ReproLocation.empty());
935938
auto DisposeOpts = llvm::make_scope_exit([&] {
936939
clang_experimental_DependencyScannerReproducerOptions_dispose(Opts);
937940
});
@@ -1580,7 +1583,8 @@ int indextest_core_main(int argc, const char **argv) {
15801583
errs() << "error: missing -working-dir\n";
15811584
return 1;
15821585
}
1583-
return generateDepsReproducer(CompArgs, options::WorkingDir);
1586+
return generateDepsReproducer(CompArgs, options::WorkingDir,
1587+
options::OutputFile);
15841588
}
15851589

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

clang/tools/libclang/CDependencies.cpp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,8 @@ struct DependencyScannerReproducerOptions {
647647
const char *const *argv;
648648
const char *ModuleName;
649649
const char *WorkingDirectory;
650+
const char *ReproducerLocation;
651+
bool UseUniqueReproducerName;
650652
};
651653

652654
// Helper class to capture a returnable error code and to return a formatted
@@ -680,9 +682,11 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScannerReproducerOptions,
680682
CXDependencyScannerReproducerOptions
681683
clang_experimental_DependencyScannerReproducerOptions_create(
682684
int argc, const char *const *argv, const char *ModuleName,
683-
const char *WorkingDirectory) {
684-
return wrap(new DependencyScannerReproducerOptions{argc, argv, ModuleName,
685-
WorkingDirectory});
685+
const char *WorkingDirectory, const char *ReproducerLocation,
686+
bool UseUniqueReproducerName) {
687+
return wrap(new DependencyScannerReproducerOptions{
688+
argc, argv, ModuleName, WorkingDirectory, ReproducerLocation,
689+
UseUniqueReproducerName});
686690
}
687691

688692
void clang_experimental_DependencyScannerReproducerOptions_dispose(
@@ -702,10 +706,14 @@ enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer(
702706
DependencyScannerReproducerOptions &Opts = *unwrap(CXOptions);
703707
int argc = Opts.argc;
704708
const char *const *argv = Opts.argv;
709+
const char *ReproducerLocation = Opts.ReproducerLocation;
705710
if (argc < 2 || !argv)
706711
return Report(CXError_InvalidArguments) << "missing compilation command";
707712
if (!Opts.WorkingDirectory)
708713
return Report(CXError_InvalidArguments) << "missing working directory";
714+
if (!Opts.UseUniqueReproducerName && !ReproducerLocation)
715+
return Report(CXError_InvalidArguments)
716+
<< "non-unique reproducer is allowed only in a custom location";
709717

710718
CASOptions CASOpts;
711719
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> FS;
@@ -716,9 +724,24 @@ enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer(
716724

717725
llvm::SmallString<128> ReproScriptPath;
718726
int ScriptFD;
719-
if (auto EC = llvm::sys::fs::createTemporaryFile("reproducer", "sh", ScriptFD,
720-
ReproScriptPath)) {
721-
return ReportFailure() << "failed to create a reproducer script file";
727+
if (ReproducerLocation) {
728+
if (auto EC = llvm::sys::fs::create_directories(ReproducerLocation))
729+
return ReportFailure() << "failed to create a reproducer location '"
730+
<< ReproducerLocation << "'\n"
731+
<< EC.message();
732+
SmallString<128> Path(ReproducerLocation);
733+
llvm::sys::path::append(Path, "reproducer");
734+
const char *UniqueSuffix = Opts.UseUniqueReproducerName ? "-%%%%%%" : "";
735+
if (auto EC = llvm::sys::fs::createUniqueFile(Path + UniqueSuffix + ".sh",
736+
ScriptFD, ReproScriptPath))
737+
return ReportFailure() << "failed to create a reproducer script file\n"
738+
<< EC.message();
739+
} else {
740+
if (auto EC = llvm::sys::fs::createTemporaryFile(
741+
"reproducer", "sh", ScriptFD, ReproScriptPath)) {
742+
return ReportFailure() << "failed to create a reproducer script file\n"
743+
<< EC.message();
744+
}
722745
}
723746
SmallString<128> FileCachePath = ReproScriptPath;
724747
llvm::sys::path::replace_extension(FileCachePath, ".cache");

0 commit comments

Comments
 (0)