Skip to content

Commit b43371e

Browse files
author
Vladislav Kalugin
committed
refactoring after review 2
1 parent d3f04cb commit b43371e

11 files changed

+405
-346
lines changed

server/src/Server.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,9 +675,9 @@ Status Server::TestsGenServiceImpl::GetFileTargets(ServerContext *context,
675675
utbot::ProjectContext projectContext{ request->projectcontext() };
676676
auto buildDatabase = BuildDatabase::create(projectContext);
677677
fs::path path = request->path();
678-
auto targets = buildDatabase->getTargetsForSourceFile(path);
678+
auto targetPaths = buildDatabase->getTargetPathsForSourceFile(path);
679679
FileTargetsWriter targetsWriter{ response };
680-
targetsWriter.writeResponse(targets, projectContext);
680+
targetsWriter.writeResponse(targetPaths, projectContext);
681681
} catch (CompilationDatabaseException const& e) {
682682
return failedToLoadCDbStatus(e);
683683
}

server/src/building/BuildDatabase.cpp

Lines changed: 43 additions & 305 deletions
Large diffs are not rendered by default.

server/src/building/BuildDatabase.h

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ class BuildDatabase {
7575
[[nodiscard]] bool is32bits() const;
7676

7777
void setOutputFile(const fs::path &file);
78+
79+
static bool conflictPriorityMore(const std::shared_ptr<ObjectFileInfo> &left,
80+
const std::shared_ptr<ObjectFileInfo> &right);
7881
};
7982

8083
/*
@@ -95,18 +98,11 @@ class BuildDatabase {
9598
};
9699

97100
public:
98-
BuildDatabase(fs::path _buildCommandsJsonPath,
99-
fs::path _serverBuildDir,
100-
utbot::ProjectContext _projectContext);
101-
102-
static std::shared_ptr<BuildDatabase> create(const utbot::ProjectContext &projectContext);
103-
std::shared_ptr<BuildDatabase> createBuildDatabaseForSourceOrTarget(const std::string &_targetOrSourcePath);
104-
105101
const fs::path &getCompileCommandsJson();
106102
const fs::path &getLinkCommandsJson();
107103

108104
/**
109-
* @brief Returns all object files files that are contained in a library or executable
105+
* @brief Returns all object files that are contained in a library or executable
110106
*
111107
* Recursively iterates over all libraries inside current library or executable. Returns all
112108
* found object files
@@ -197,56 +193,45 @@ class BuildDatabase {
197193
std::vector<std::shared_ptr<ObjectFileInfo>> getAllCompileCommands() const;
198194

199195
std::vector<std::shared_ptr<TargetInfo>> getRootTargets() const;
200-
std::vector<std::shared_ptr<TargetInfo>> getAllTargets() const;
201-
202-
std::vector<fs::path>
203-
targetListForFile(const fs::path &sourceFilePath, const fs::path &objectFile) const;
196+
virtual std::vector<std::shared_ptr<TargetInfo>> getAllTargets() const = 0;
204197

205-
std::vector<std::shared_ptr<TargetInfo>>
206-
getTargetsForSourceFile(fs::path const &sourceFilePath) const;
198+
virtual std::vector<fs::path>
199+
getTargetPathsForSourceFile(const fs::path &sourceFilePath) const;
200+
virtual std::vector<fs::path>
201+
getTargetPathsForObjectFile(const fs::path &objectFile) const;
207202

208203
std::shared_ptr<TargetInfo> getPriorityTarget() const;
209204

210205
CollectionUtils::FileSet getSourceFilesForTarget(const fs::path &_target);
211206

212-
bool hasAutoTarget() const;
207+
virtual bool hasAutoTarget() const = 0;
213208

214209
fs::path getTargetPath() const;
215210

216211
std::shared_ptr<CompilationDatabase> compilationDatabase;
217-
private:
218-
BuildDatabase(BuildDatabase& baseBuildDatabase,
219-
const std::string &_target);
212+
protected:
213+
BuildDatabase() ;
220214

221215
const fs::path serverBuildDir;
222216
const utbot::ProjectContext projectContext;
223217
const fs::path buildCommandsJsonPath;
224218
const fs::path linkCommandsJsonPath;
225219
const fs::path compileCommandsJsonPath;
226-
fs::path target;
227-
bool isAutoTarget;
228220
CollectionUtils::MapFileTo<std::vector<std::shared_ptr<ObjectFileInfo>>> sourceFileInfos;
229221
CollectionUtils::MapFileTo<std::shared_ptr<ObjectFileInfo>> objectFileInfos;
230222
CollectionUtils::MapFileTo<std::shared_ptr<TargetInfo>> targetInfos;
231223
CollectionUtils::MapFileTo<std::vector<fs::path>> objectFileTargets;
232224

233-
234225
std::vector<std::pair<nlohmann::json, std::shared_ptr<ObjectFileInfo>>> compileCommands_temp;
235226

236-
static bool conflictPriorityMore(const std::shared_ptr<ObjectFileInfo> &left,
237-
const std::shared_ptr<ObjectFileInfo> &right);
238-
239-
void filterInstalledFiles();
240-
void addLocalSharedLibraries();
241-
void fillTargetInfoParents();
242227
static fs::path getCorrespondingBitcodeFile(const fs::path &filepath);
243-
void initObjects(const nlohmann::json &compileCommandsJson);
244-
void initInfo(const nlohmann::json &linkCommandsJson);
245228
void createClangCompileCommandsJson();
246229
void mergeLibraryOptions(std::vector<std::string> &jsonArguments) const;
247230
fs::path newDirForFile(fs::path const& file) const;
248231
fs::path createExplicitObjectFileCompilationCommand(const std::shared_ptr<ObjectFileInfo> &objectInfo);
249232

233+
std::vector<std::shared_ptr<TargetInfo>> getTargetsForSourceFile(fs::path const &sourceFilePath) const;
234+
250235
using sharedLibrariesMap = std::unordered_map<std::string, CollectionUtils::MapFileTo<fs::path>>;
251236

252237
void addLibrariesForCommand(utbot::BaseCommand &command,

server/src/building/Linker.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ void Linker::linkForOneFile(const fs::path &sourceFilePath) {
9696
if (!testGen.getBuildDatabase(false)->isFirstObjectFileForSource(objectFile)) {
9797
return;
9898
}
99-
std::vector <fs::path> targets = testGen.getBuildDatabase(false)->targetListForFile(sourceFilePath, objectFile);
99+
std::vector <fs::path> targets = testGen.getBuildDatabase(false)->getTargetPathsForObjectFile(objectFile);
100100
LOG_S(DEBUG) << "Linking bitcode for file " << sourceFilePath.filename();
101101
for (size_t i = 0; i < targets.size(); i++) {
102102
const auto& target = targets[i];
@@ -174,7 +174,8 @@ void Linker::linkForProject() {
174174
<< sourceFile;
175175
return;
176176
}
177-
std::vector <fs::path> targets = testGen.getBuildDatabase(false)->targetListForFile(sourceFile, objectFile);
177+
std::vector <fs::path> targets = testGen.getBuildDatabase(false)->getTargetPathsForObjectFile(
178+
objectFile);
178179
bool success = false;
179180
for (const auto &target : targets) {
180181
if (!CollectionUtils::contains(triedTargets, target)) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef UTBOTCPP_PROJECTBUILDDATABASE_H
2+
#define UTBOTCPP_PROJECTBUILDDATABASE_H
3+
4+
#include "BuildDatabase.h"
5+
6+
class ProjectBuildDatabase : BuildDatabase {
7+
private:
8+
ProjectBuildDatabase(fs::path _buildCommandsJsonPath, fs::path _serverBuildDir,
9+
utbot::ProjectContext _projectContext);
10+
11+
public:
12+
static std::shared_ptr<ProjectBuildDatabase> create(const utbot::ProjectContext &projectContext);
13+
bool hasAutoTarget() const override;
14+
};
15+
16+
17+
#endif //UTBOTCPP_PROJECTBUILDDATABASE_H
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
#include "ProjectBuildDatabase.h"
2+
3+
ProjectBuildDatabase::ProjectBuildDatabase(fs::path _buildCommandsJsonPath,
4+
fs::path _serverBuildDir,
5+
utbot::ProjectContext _projectContext) :
6+
serverBuildDir(std::move(_serverBuildDir)),
7+
projectContext(std::move(_projectContext)),
8+
buildCommandsJsonPath(std::move(_buildCommandsJsonPath)),
9+
linkCommandsJsonPath(fs::canonical(buildCommandsJsonPath / "link_commands.json")),
10+
compileCommandsJsonPath(fs::canonical(buildCommandsJsonPath / "compile_commands.json")) {
11+
if (!fs::exists(linkCommandsJsonPath) || !fs::exists(compileCommandsJsonPath)) {
12+
throw CompilationDatabaseException("Couldn't open link_commands.json or compile_commands.json files");
13+
}
14+
15+
auto linkCommandsJson = JsonUtils::getJsonFromFile(linkCommandsJsonPath);
16+
auto compileCommandsJson = JsonUtils::getJsonFromFile(compileCommandsJsonPath);
17+
18+
initObjects(compileCommandsJson);
19+
initInfo(linkCommandsJson);
20+
filterInstalledFiles();
21+
addLocalSharedLibraries();
22+
fillTargetInfoParents();
23+
createClangCompileCommandsJson();
24+
target = GrpcUtils::UTBOT_AUTO_TARGET_PATH;
25+
}
26+
27+
std::shared_ptr<BuildDatabase> BuildDatabase::create(const utbot::ProjectContext &projectContext) {
28+
fs::path compileCommandsJsonPath =
29+
CompilationUtils::substituteRemotePathToCompileCommandsJsonPath(
30+
projectContext.projectPath, projectContext.buildDirRelativePath);
31+
fs::path serverBuildDir = Paths::getUtbotBuildDir(projectContext);
32+
std::shared_ptr<BuildDatabase> buildDatabase = std::make_shared<BuildDatabase>(compileCommandsJsonPath,
33+
serverBuildDir, projectContext);
34+
return buildDatabase;
35+
}
36+
37+
38+
void BuildDatabase::initObjects(const nlohmann::json &compileCommandsJson) {
39+
for (const nlohmann::json &compileCommand: compileCommandsJson) {
40+
auto objectInfo = std::make_shared<ObjectFileInfo>();
41+
42+
fs::path directory = compileCommand.at("directory").get<std::string>();
43+
fs::path jsonFile = compileCommand.at("file").get<std::string>();
44+
fs::path sourceFile = Paths::getCCJsonFileFullPath(jsonFile, directory);
45+
46+
std::vector<std::string> jsonArguments;
47+
if (compileCommand.contains("command")) {
48+
std::string command = compileCommand.at("command");
49+
jsonArguments = StringUtils::splitByWhitespaces(command);
50+
} else {
51+
jsonArguments = std::vector<std::string>(compileCommand.at("arguments"));
52+
}
53+
std::transform(jsonArguments.begin(), jsonArguments.end(), jsonArguments.begin(),
54+
[&directory](const std::string &argument) {
55+
return tryConvertOptionToPath(argument, directory);
56+
});
57+
objectInfo->command = utbot::CompileCommand(jsonArguments, directory, sourceFile);
58+
objectInfo->command.removeWerror();
59+
fs::path outputFile = objectInfo->getOutputFile();
60+
fs::path kleeFilePathTemplate =
61+
Paths::createNewDirForFile(sourceFile, projectContext.buildDir(), serverBuildDir);
62+
fs::path kleeFile = Paths::addSuffix(kleeFilePathTemplate, "_klee");
63+
objectInfo->kleeFilesInfo = std::make_shared<KleeFilesInfo>(kleeFile);
64+
65+
if (CollectionUtils::containsKey(objectFileInfos, outputFile) ||
66+
CollectionUtils::containsKey(targetInfos, outputFile)) {
67+
/*
68+
* If the condition above is true, that means that the output file
69+
* is built from multiple sources. Hence, it is not an object file,
70+
* but an executable, and it should be treated as a target.
71+
* This is a hack. This inconsistency is produced by Bear
72+
* when it treats a Makefile command like
73+
* gcc -o output a.c b.c c.c
74+
* This code is creating artificial compile and link commands, similar
75+
* to commands Bear generates from CMake command like
76+
* add_executable(output a.c b.c c.c)
77+
*/
78+
auto targetInfo = targetInfos[outputFile];
79+
if (targetInfo == nullptr) {
80+
LOG_S(DEBUG) << outputFile << " is treated as a target instead of an object file";
81+
auto targetObjectInfo = objectFileInfos[outputFile];
82+
auto tmpObjectFileName = createExplicitObjectFileCompilationCommand(targetObjectInfo);
83+
objectFileInfos.erase(outputFile);
84+
85+
//create targetInfo
86+
targetInfo = targetInfos[outputFile] = std::make_shared<TargetInfo>();
87+
targetInfo->commands.emplace_back(
88+
std::initializer_list<std::string>{targetObjectInfo->command.getBuildTool(),
89+
"-o", outputFile, tmpObjectFileName},
90+
directory);
91+
targetInfo->addFile(tmpObjectFileName);
92+
}
93+
//redirect new compilation command to temporary file
94+
auto tmpObjectFileName = createExplicitObjectFileCompilationCommand(objectInfo);
95+
96+
//add new dependency to an implicit target
97+
targetInfo->commands[0].addFlagToEnd(tmpObjectFileName);
98+
targetInfo->addFile(tmpObjectFileName);
99+
} else {
100+
objectFileInfos[outputFile] = objectInfo;
101+
}
102+
compileCommands_temp.emplace_back(compileCommand, objectInfo);
103+
const fs::path &sourcePath = objectInfo->getSourcePath();
104+
sourceFileInfos[sourcePath].emplace_back(objectInfo);
105+
}
106+
for (auto &[sourceFile, objectInfos]: sourceFileInfos) {
107+
std::sort(objectInfos.begin(), objectInfos.end(), BuildDatabase::ObjectFileInfo::conflictPriorityMore);
108+
}
109+
}
110+
111+
void BuildDatabase::initInfo(const nlohmann::json &linkCommandsJson) {
112+
for (nlohmann::json const &linkCommand : linkCommandsJson) {
113+
fs::path directory = linkCommand.at("directory").get<std::string>();
114+
std::vector<std::string> jsonArguments;
115+
if (linkCommand.contains("command")) {
116+
std::string command = linkCommand.at("command");
117+
jsonArguments = StringUtils::splitByWhitespaces(command);
118+
} else {
119+
jsonArguments = std::vector<std::string>(linkCommand.at("arguments"));
120+
}
121+
if (StringUtils::endsWith(jsonArguments[0], "ranlib") ||
122+
StringUtils::endsWith(jsonArguments[0], "cmake")) {
123+
continue;
124+
}
125+
std::transform(jsonArguments.begin(), jsonArguments.end(), jsonArguments.begin(),
126+
[&directory](const std::string &argument) {
127+
return tryConvertOptionToPath(argument, directory);
128+
});
129+
130+
mergeLibraryOptions(jsonArguments);
131+
132+
utbot::LinkCommand command(jsonArguments, directory);
133+
fs::path const &output = command.getOutput();
134+
auto targetInfo = targetInfos[output];
135+
if (targetInfo == nullptr) {
136+
targetInfo = targetInfos[output] = std::make_shared<TargetInfo>();
137+
} else {
138+
LOG_S(WARNING) << "Multiple commands for one file: " << output.string();
139+
}
140+
for (nlohmann::json const &jsonFile: linkCommand.at("files")) {
141+
auto filename = jsonFile.get<std::string>();
142+
fs::path currentFile = Paths::getCCJsonFileFullPath(filename, command.getDirectory());
143+
targetInfo->addFile(currentFile);
144+
if (Paths::isObjectFile(currentFile)) {
145+
if (!CollectionUtils::containsKey(objectFileInfos, currentFile)) {
146+
throw CompilationDatabaseException("compile_commands.json doesn't contain a command for object file "
147+
+ currentFile.string());
148+
}
149+
objectFileInfos[currentFile]->linkUnit = output;
150+
}
151+
}
152+
targetInfo->commands.emplace_back(command);
153+
}
154+
}
155+
156+
157+
void BuildDatabase::filterInstalledFiles() {
158+
for (auto &it : targetInfos) {
159+
auto &linkFile = it.first;
160+
auto &targetInfo = it.second;
161+
CollectionUtils::OrderedFileSet fileset;
162+
targetInfo->installedFiles =
163+
CollectionUtils::filterOut(targetInfo->files, [this](fs::path const &file) {
164+
return CollectionUtils::containsKey(targetInfos, file) ||
165+
CollectionUtils::containsKey(objectFileInfos, file);
166+
});
167+
if (!targetInfo->installedFiles.empty()) {
168+
LOG_S(DEBUG) << "Target " << linkFile << " depends on " << targetInfo->installedFiles.size() << " installed files";
169+
}
170+
CollectionUtils::erase_if(targetInfo->files, [&targetInfo](fs::path const &file) {
171+
return CollectionUtils::contains(targetInfo->installedFiles, file);
172+
});
173+
}
174+
}
175+
176+
void BuildDatabase::addLocalSharedLibraries() {
177+
sharedLibrariesMap sharedLibraryFiles;
178+
for (const auto &[linkFile, linkUnit] : targetInfos) {
179+
if (Paths::isSharedLibraryFile(linkFile)) {
180+
auto withoutVersion = CompilationUtils::removeSharedLibraryVersion(linkFile);
181+
sharedLibraryFiles[withoutVersion.filename()][linkFile.parent_path()] = linkFile;
182+
}
183+
}
184+
for (auto &[linkFile, targetInfo] : targetInfos) {
185+
for (auto &command : targetInfo->commands) {
186+
addLibrariesForCommand(command, *targetInfo, sharedLibraryFiles);
187+
}
188+
}
189+
for (auto &[objectFile, objectInfo] : objectFileInfos) {
190+
addLibrariesForCommand(objectInfo->command, *objectInfo, sharedLibraryFiles, true);
191+
}
192+
}
193+
194+
void BuildDatabase::fillTargetInfoParents() {
195+
CollectionUtils::MapFileTo<std::vector<fs::path>> parentTargets;
196+
for (const auto &[linkFile, linkUnit] : targetInfos) {
197+
for (const fs::path &dependencyFile : linkUnit->files) {
198+
if (Paths::isLibraryFile(dependencyFile)) {
199+
parentTargets[dependencyFile].emplace_back(linkFile);
200+
}
201+
if (Paths::isObjectFile(dependencyFile)) {
202+
objectFileTargets[dependencyFile].emplace_back(linkFile);
203+
}
204+
}
205+
}
206+
for (auto &[library, parents] : parentTargets) {
207+
if (!CollectionUtils::containsKey(targetInfos, library)) {
208+
throw CompilationDatabaseException(
209+
"link_commands.json doesn't contain a command for building library: " +
210+
library.string() + "\nReferenced from command for: " + (parents.empty() ? "none" : parents[0].string()));
211+
}
212+
targetInfos[library]->parentLinkUnits = std::move(parents);
213+
}
214+
}
215+

0 commit comments

Comments
 (0)