201 lines
6.0 KiB
C++
201 lines
6.0 KiB
C++
|
|
#include "vs_generate.h"
|
|
|
|
#include <cassert>
|
|
#include <fstream>
|
|
#include <regex>
|
|
#include <string>
|
|
|
|
VsParseSln::VsParseSln() = default;
|
|
|
|
// 解析关联
|
|
void VsParseSln::parse_relate() {
|
|
for (auto& proj : projs_) {
|
|
for (auto& relate : proj.guid_relate_) {
|
|
std::string opth = hashmap_[relate];
|
|
proj.relate_.push_back(opth);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool VsParseSln::parse(const std::string& path) {
|
|
std::ifstream sln_file(path, std::ios::in);
|
|
if (!sln_file.is_open()) {
|
|
std::cout << "没有找到 sln 文件或者打开文件失败,路径:" << path
|
|
<< "\n";
|
|
return false;
|
|
}
|
|
fs::path full_path(path);
|
|
fs::path parent_path = full_path.parent_path();
|
|
|
|
projs_.clear();
|
|
std::string tmp{};
|
|
std::regex re(R"(\"(.*?)\")");
|
|
std::regex re2(R"((\{.*?\}))");
|
|
std::smatch match{};
|
|
ProjectInfo proj{};
|
|
bool related = false;
|
|
bool add = false;
|
|
while (std::getline(sln_file, tmp)) {
|
|
if (tmp.find("Project") != std::string::npos &&
|
|
tmp.find(".vcxproj") != std::string::npos) {
|
|
std::vector<std::string> vec{};
|
|
while (std::regex_search(tmp, match, re)) {
|
|
vec.push_back(match[1]);
|
|
tmp = match.suffix().str();
|
|
}
|
|
// 这里应该有4个结果
|
|
assert(vec.size() == 4);
|
|
proj.guid_ = vec[3];
|
|
proj.path_ = parent_path.string() + "\\" + vec[2];
|
|
add = true;
|
|
}
|
|
if (tmp.find("ProjectDependencies") != std::string::npos) {
|
|
related = true;
|
|
continue;
|
|
}
|
|
if (tmp.find("EndProjectSection") != std::string::npos) {
|
|
related = false;
|
|
continue;
|
|
}
|
|
if (related) {
|
|
// 这里要简单处理一下
|
|
if (std::regex_search(tmp, match, re2)) {
|
|
std::string restr = match[1];
|
|
proj.guid_relate_.push_back(restr);
|
|
}
|
|
}
|
|
if (tmp.find("EndProject") != std::string::npos && add) {
|
|
projs_.push_back(proj);
|
|
hashmap_[proj.guid_] = proj.path_;
|
|
proj.guid_relate_.clear();
|
|
add = false;
|
|
}
|
|
}
|
|
|
|
parse_relate();
|
|
sln_file.close();
|
|
return true;
|
|
}
|
|
|
|
std::vector<ProjectInfo> VsParseSln::get_project() const { return projs_; }
|
|
|
|
void VsParsePro::handle_include(tinyxml2::XMLElement* node,
|
|
const std::string& key) const {
|
|
if (!node) {
|
|
return;
|
|
}
|
|
const char* data = node->Attribute("Condition");
|
|
if (!data) {
|
|
return;
|
|
}
|
|
if (std::string(data).find(key) == std::string::npos) {
|
|
return;
|
|
}
|
|
tinyxml2::XMLElement* purpose = node->FirstChildElement();
|
|
while (purpose) {
|
|
const char* name = purpose->Name();
|
|
if (std::strcmp(name, "IncludePath") != 0) {
|
|
purpose = purpose->NextSiblingElement();
|
|
continue;
|
|
}
|
|
const char* include_path = purpose->GetText();
|
|
current_proj_->addtion_.append(";");
|
|
current_proj_->addtion_.append(include_path);
|
|
break;
|
|
}
|
|
}
|
|
void VsParsePro::additon_include_and_predefine(tinyxml2::XMLElement* node,
|
|
const std::string& key) const {
|
|
if (!node) {
|
|
return;
|
|
}
|
|
const char* data = node->Attribute("Condition");
|
|
if (!data) {
|
|
return;
|
|
}
|
|
if (std::string(data).find(key) == std::string::npos) {
|
|
return;
|
|
}
|
|
tinyxml2::XMLElement* cl = get_child_element(node, "ClCompile");
|
|
const tinyxml2::XMLElement* purpose =
|
|
get_child_element(cl, "AdditionalIncludeDirectories");
|
|
if (purpose) {
|
|
const char* addtion_dir = purpose->GetText();
|
|
current_proj_->addtion_.append(";");
|
|
current_proj_->addtion_.append(addtion_dir);
|
|
}
|
|
|
|
purpose = get_child_element(cl, "PreprocessorDefinitions");
|
|
if (purpose) {
|
|
const char* predefinition = purpose->GetText();
|
|
current_proj_->predefinition_.append(";");
|
|
current_proj_->predefinition_.append(predefinition);
|
|
}
|
|
}
|
|
|
|
tinyxml2::XMLElement* VsParsePro::get_child_element(tinyxml2::XMLElement* node,
|
|
const std::string& key) {
|
|
tinyxml2::XMLElement* result{};
|
|
if (!node) {
|
|
return result;
|
|
}
|
|
tinyxml2::XMLElement* n = node->FirstChildElement();
|
|
while (n) {
|
|
if (std::strcmp(n->Name(), key.c_str()) == 0) {
|
|
result = n;
|
|
break;
|
|
}
|
|
n = n->NextSiblingElement();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool VsParsePro::parse(ProjectInfo* proj, const std::string& key) {
|
|
current_proj_ = proj;
|
|
supplement(current_proj_);
|
|
|
|
int ret = m_doc_.LoadFile(current_proj_->path_.c_str());
|
|
if (ret != 0) {
|
|
std::cout << "解析失败:" << current_proj_->path_ << "\n";
|
|
return false;
|
|
}
|
|
|
|
tinyxml2::XMLElement* element = m_doc_.FirstChildElement();
|
|
if (std::strcmp(element->Name(), "Project") != 0) {
|
|
std::cout << "不是合法的vcxproj文件。" << current_proj_->path_ << "\n";
|
|
return false;
|
|
}
|
|
|
|
addition_dir_.clear();
|
|
tinyxml2::XMLElement* node = element->FirstChildElement();
|
|
while (node) {
|
|
if (std::strcmp(node->Name(), "PropertyGroup") == 0) {
|
|
handle_include(node, key);
|
|
}
|
|
if (std::strcmp(node->Name(), "ItemDefinitionGroup") == 0) {
|
|
additon_include_and_predefine(node, key);
|
|
}
|
|
node = node->NextSiblingElement();
|
|
}
|
|
tidy(current_proj_);
|
|
return true;
|
|
}
|
|
|
|
// 对初步解析出的工程进行整理
|
|
void VsParsePro::tidy(ProjectInfo* proj) {}
|
|
|
|
// 补充其他信息
|
|
void VsParsePro::supplement(ProjectInfo* proj) {
|
|
if (proj->path_.empty() || !fs::exists(proj->path_)) {
|
|
return;
|
|
}
|
|
fs::path path(proj->path_);
|
|
if (proj->proj_root_.empty()) {
|
|
proj->proj_root_ = path.parent_path().string();
|
|
}
|
|
if (proj->name_.empty()) {
|
|
proj->name_ = path.filename().string();
|
|
}
|
|
}
|