2 #include <score/tools/File.hpp>
5 #include <QDirIterator>
7 #include <QJsonDocument>
9 #include <QRegularExpression>
10 #include <QStringBuilder>
19 QJsonObject addon_info;
20 std::string unity_cpp;
22 std::vector<std::pair<QString, QString>> files;
23 std::vector<std::string> flags;
29 static void loadBasicAddon(
const QString& addon, AddonData& data)
31 std::string cpp_files;
32 std::vector<std::pair<QString, QString>> files;
36 QDir::Filter::Files | QDir::Filter::NoDotAndDotDot,
37 QDirIterator::Subdirectories};
41 if(QFile f(it.next()); f.open(QIODevice::ReadOnly))
44 if(fi.suffix() ==
"cpp")
46 data.unity_cpp.append(
"#include \"" + it.filePath().toStdString() +
"\"\n");
49 data.files.push_back({fi.filePath(), f.readAll()});
54 static void loadCMakeAddon(
const QString& addon, AddonData& data, QString cm)
56 static const QRegularExpression space{R
"_(\s+)_"};
57 static const QRegularExpression sourceFiles{
58 R
"_(add_library\(\s*[[:graph:]]+([a-zA-Z0-9_.\/\n ]*)\))_"};
59 static const QRegularExpression definitions{
60 R
"_(target_compile_definitions\(\s*[[:graph:]]+\s*[[:graph:]]+([a-zA-Z0-9_"= ]+)\))_"};
61 static const QRegularExpression includes{
62 R
"_(target_include_directories\(\s*[[:graph:]]+\s*[[:graph:]]+([a-zA-Z0-9_\/ ]+)\))_"};
64 auto files = sourceFiles.globalMatch(cm);
65 auto defs = definitions.globalMatch(cm);
66 auto incs = includes.globalMatch(cm);
68 while(files.hasNext())
70 auto m = files.next();
71 auto res = m.captured(1).replace(
'\n',
' ').split(space, Qt::SkipEmptyParts);
72 for(
const QString& file : res)
74 QString filename = QString{R
"_(%1/%2)_"}.arg(addon).arg(file);
76 QString path = QString{R"_(#include "%1/%2"
80 data.unity_cpp.append(path.toStdString());
83 f.open(QIODevice::ReadOnly);
84 data.files.push_back({filename, score::readFileAsQString(f)});
90 auto res = m.captured(1).replace(
'\n',
' ').split(space, Qt::SkipEmptyParts);
91 for(
const QString& define : res)
93 data.flags.push_back(QString{R
"_(-D%1)_"}.arg(define).toStdString());
100 auto res = m.captured(1).replace(
'\n',
' ').split(space, Qt::SkipEmptyParts);
102 for(
const QString& path : res)
104 data.flags.push_back(QString{R
"_(-I%1/%2)_"}.arg(addon).arg(path).toStdString());
109 static AddonData loadAddon(
const QString& addon)
112 if(QFile f(addon + QDir::separator() +
"addon.json"); f.open(QIODevice::ReadOnly))
114 qDebug() <<
"Loading addon info from: " << f.fileName();
115 f.setTextModeEnabled(
true);
116 data.addon_info = QJsonDocument::fromJson(f.readAll()).object();
119 if(QFile f(addon + QDir::separator() +
"CMakeLists.txt"); f.open(QIODevice::ReadOnly))
121 qDebug() <<
"Loading CMake-based add-on: " << f.fileName();
123 f.setTextModeEnabled(
true);
124 loadCMakeAddon(addon, data, f.readAll());
128 qDebug() <<
"Loading non-CMake-based add-on";
129 loadBasicAddon(addon, data);
137 static void generateCommandFiles(
138 const QString& output,
const QString& addon_path,
139 const std::vector<std::pair<QString, QString>>& files)
141 QRegularExpression decl(
142 "SCORE_COMMAND_DECL\\([A-Za-z_0-9,:<>\r\n\t "
143 "]*\\(\\)[A-Za-z_0-9,\"':<>\r\n\t ]*\\)");
144 QRegularExpression decl_t(
"SCORE_COMMAND_DECL_T\\([A-Za-z_0-9,:<>\r\n\t ]*\\)");
148 for(
const auto& f : files)
151 auto res = decl.globalMatch(f.second);
154 auto match = res.next();
155 if(
auto txt = match.capturedTexts(); !txt.empty())
157 if(
auto split = txt[0].split(
","); split.size() > 1)
159 auto filename = f.first;
160 filename.remove(addon_path +
"/");
161 includes +=
"#include <" + filename +
">\n";
162 commands += split[1] +
",\n";
168 commands.remove(commands.length() - 2, 2);
169 commands.push_back(
"\n");
170 QDir{}.mkpath(output);
171 auto out_name = QFileInfo{addon_path}.fileName().replace(
"-",
"_");
173 QFile cmd_f{output +
"/" + out_name +
"_commands_files.hpp"};
174 cmd_f.open(QIODevice::WriteOnly);
175 cmd_f.write(includes.toUtf8());
179 QFile cmd_f{output +
"/" + out_name +
"_commands.hpp"};
180 cmd_f.open(QIODevice::WriteOnly);
181 cmd_f.write(commands.toUtf8());
187 static void generateExportFile(
188 const QString& addon_files_path,
const QString& addon_name,
189 const QByteArray& addon_export)
191 QFile export_file = QString{addon_files_path +
"/" + addon_name +
"_export.h"};
192 export_file.open(QIODevice::WriteOnly);
193 QByteArray export_data{
194 "#ifndef " + addon_export +
"_EXPORT_H\n"
195 "#define " + addon_export +
"_EXPORT_H\n"
196 "#define " + addon_export +
"_EXPORT __attribute__((visibility(\"default\")))\n"
197 "#define " + addon_export +
"_DEPRECATED [[deprecated]]\n"
200 export_file.write(export_data);
206 static QString generateAddonFiles(
207 QString addon_name,
const QString& addon,
208 const std::vector<std::pair<QString, QString>>& files)
210 addon_name.replace(
"-",
"_");
211 QByteArray addon_export = addon_name.toUpper().toUtf8();
213 QString addon_files_path = QDir::tempPath() +
"/score-tmp-build/" + addon_name;
214 QDir{}.mkpath(addon_files_path);
215 generateExportFile(addon_files_path, addon_name, addon_export);
216 generateCommandFiles(addon_files_path, addon, files);
217 return addon_files_path;