Skip to content

Commit cc8db13

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 d20063b commit cc8db13

File tree

4 files changed

+57
-11
lines changed

4 files changed

+57
-11
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: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -646,16 +646,23 @@ struct DependencyScannerReproducerOptions {
646646
std::vector<std::string> BuildArgs;
647647
std::optional<std::string> ModuleName;
648648
std::optional<std::string> WorkingDirectory;
649+
std::optional<std::string> ReproducerLocation;
650+
bool UseUniqueReproducerName;
649651

650652
DependencyScannerReproducerOptions(int argc, const char *const *argv,
651653
const char *ModuleName,
652-
const char *WorkingDirectory) {
654+
const char *WorkingDirectory,
655+
const char *ReproducerLocation,
656+
bool UseUniqueReproducerName)
657+
: UseUniqueReproducerName(UseUniqueReproducerName) {
653658
if (argv)
654659
BuildArgs.assign(argv, argv + argc);
655660
if (ModuleName)
656661
this->ModuleName = ModuleName;
657662
if (WorkingDirectory)
658663
this->WorkingDirectory = WorkingDirectory;
664+
if (ReproducerLocation)
665+
this->ReproducerLocation = ReproducerLocation;
659666
}
660667
};
661668

@@ -690,9 +697,11 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DependencyScannerReproducerOptions,
690697
CXDependencyScannerReproducerOptions
691698
clang_experimental_DependencyScannerReproducerOptions_create(
692699
int argc, const char *const *argv, const char *ModuleName,
693-
const char *WorkingDirectory) {
694-
return wrap(new DependencyScannerReproducerOptions{argc, argv, ModuleName,
695-
WorkingDirectory});
700+
const char *WorkingDirectory, const char *ReproducerLocation,
701+
bool UseUniqueReproducerName) {
702+
return wrap(new DependencyScannerReproducerOptions{
703+
argc, argv, ModuleName, WorkingDirectory, ReproducerLocation,
704+
UseUniqueReproducerName});
696705
}
697706

698707
void clang_experimental_DependencyScannerReproducerOptions_dispose(
@@ -714,6 +723,9 @@ enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer(
714723
return Report(CXError_InvalidArguments) << "missing compilation command";
715724
if (!Opts.WorkingDirectory)
716725
return Report(CXError_InvalidArguments) << "missing working directory";
726+
if (!Opts.UseUniqueReproducerName && !Opts.ReproducerLocation)
727+
return Report(CXError_InvalidArguments)
728+
<< "non-unique reproducer is allowed only in a custom location";
717729

718730
CASOptions CASOpts;
719731
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> FS;
@@ -724,9 +736,24 @@ enum CXErrorCode clang_experimental_DependencyScanner_generateReproducer(
724736

725737
llvm::SmallString<128> ReproScriptPath;
726738
int ScriptFD;
727-
if (auto EC = llvm::sys::fs::createTemporaryFile("reproducer", "sh", ScriptFD,
728-
ReproScriptPath)) {
729-
return ReportFailure() << "failed to create a reproducer script file";
739+
if (Opts.ReproducerLocation) {
740+
if (auto EC = llvm::sys::fs::create_directories(*Opts.ReproducerLocation))
741+
return ReportFailure() << "failed to create a reproducer location '"
742+
<< *Opts.ReproducerLocation << "'\n"
743+
<< EC.message();
744+
SmallString<128> Path(*Opts.ReproducerLocation);
745+
llvm::sys::path::append(Path, "reproducer");
746+
const char *UniqueSuffix = Opts.UseUniqueReproducerName ? "-%%%%%%" : "";
747+
if (auto EC = llvm::sys::fs::createUniqueFile(Path + UniqueSuffix + ".sh",
748+
ScriptFD, ReproScriptPath))
749+
return ReportFailure() << "failed to create a reproducer script file\n"
750+
<< EC.message();
751+
} else {
752+
if (auto EC = llvm::sys::fs::createTemporaryFile(
753+
"reproducer", "sh", ScriptFD, ReproScriptPath)) {
754+
return ReportFailure() << "failed to create a reproducer script file\n"
755+
<< EC.message();
756+
}
730757
}
731758
SmallString<128> FileCachePath = ReproScriptPath;
732759
llvm::sys::path::replace_extension(FileCachePath, ".cache");

0 commit comments

Comments
 (0)