vsgene/vs_json.cpp
2024-03-08 12:00:42 +08:00

168 lines
5.1 KiB
C++

#include "vs_json.h"
#include <fstream>
#include <list>
#include <set>
JsonCommand::JsonCommand() = default;
JsonCommand::~JsonCommand() = default;
void JsonCommand::set_expect(const std::string& exp) { expect_ = exp; }
void JsonCommand::set_out(const std::string& out) { out_ = out; }
bool JsonCommand::generate(const std::vector<ProjectInfo>& projs) {
Json::Value json_root{};
for (const auto& item : projs) {
const auto& cpps = get_cpp_paths(item.proj_root_);
std::string command = get_command(&item, projs);
for (const auto& cpp : cpps) {
Json::Value jsn{};
jsn["directory"] = item.proj_root_;
jsn["command"] = command + " -c " + cpp; // NOLINT
jsn["file"] = cpp;
json_root.append(jsn);
}
}
std::ofstream jsf(out_, std::ios::out);
if (!jsf.is_open()) {
std::cout << "不能打开文件:" << std::endl;
return false;
}
jsf << json_root.toStyledString();
jsf.close();
return true;
}
std::string JsonCommand::get_command(const ProjectInfo* proj,
const std::vector<ProjectInfo>& projs) {
std::string result{};
result.append(
R"("C:\PROGRA~2\Microsoft Visual Studio 14.0\VC\bin\amd64\cl.exe")");
std::string co_include = proj->addtion_;
std::string co_predefinitions = proj->predefinition_;
std::string speciaA("$(IncludePath)");
std::string speciaB("%(PreprocessorDefinitions)");
std::string speciaC("%(AdditionalIncludeDirectories)");
std::string speciaD("$(WindowsSDK_IncludePath)");
std::string speciaE("$(VC_IncludePath)");
replaceAll(co_include, speciaA, "");
replaceAll(co_include, speciaC, "");
replaceAll(co_include, speciaD, "");
replaceAll(co_include, speciaE, "");
replaceAll(co_predefinitions, speciaB, "");
auto include_vec = split(co_include, ";");
auto prede_vec = split(co_predefinitions, ";");
for (const auto& str : prede_vec) {
if (str.empty()) {
continue;
}
result.append(" -D" + str);
}
for (const auto& str : include_vec) {
if (str.empty()) {
continue;
}
if (expect_.find(str) != std::string::npos) {
continue;
}
result.append(" -I" + fs::path(proj->proj_root_).append(str).string());
}
std::list<std::string> proj_list{};
std::vector<std::string> re_relate{};
auto handle = [&](const std::vector<std::string>& lrelate) {
for (const auto& str : lrelate) {
proj_list.push_back(str);
}
};
for (const auto& str : proj->guid_relate_) {
// 这里的relate 子项目有别的依赖的话都需要加上
// 这里假定不会出现循环引用的情况 (理论也不应该出现)
for (const auto& pj : projs) {
if (pj.guid_ == str) {
handle(pj.guid_relate_);
re_relate.push_back(pj.path_);
break;
}
}
//std::string dir = fs::path(str).parent_path().string();
//result.append(" -I" + dir);
}
while (!proj_list.empty()) {
std::string& data = proj_list.front();
for (const auto& pj : projs) {
if (data == pj.guid_) {
handle(pj.guid_relate_);
re_relate.push_back(pj.path_);
break;
}
}
proj_list.pop_front();
}
// 去重
std::set<std::string> no_reply{};
for (const auto& str : re_relate) {
no_reply.insert(str);
}
for (const auto& str : no_reply) {
std::string dir = fs::path(str).parent_path().string();
result.append(" -I" + dir);
}
// std::cout << result << std::endl;
return result;
}
std::vector<std::string> JsonCommand::split(const std::string& source,
const std::string& sep) {
std::vector<std::string> tokens;
std::size_t start = 0;
std::size_t end = 0;
while ((end = source.find(sep, start)) != std::string::npos) {
tokens.push_back(source.substr(start, end - start));
start = end + sep.length();
}
tokens.push_back(source.substr(start));
return tokens;
}
std::vector<std::string> JsonCommand::get_cpp_paths(
const std::string& parent_path) {
std::vector<std::string> vec{};
try {
for (const auto& entry : fs::directory_iterator(parent_path)) {
if (!fs::is_regular_file(entry.path())) {
continue;
}
const fs::path& file_path(entry.path());
if (file_path.extension().string() == ".cpp") {
vec.push_back(file_path.string());
}
}
} catch (fs::filesystem_error& e) {
std::cout << "Error: " << e.what() << std::endl;
}
return vec;
}
void JsonCommand::replaceAll(std::string& str, const std::string& from,
const std::string& to) {
size_t start_pos = 0;
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length();
}
}