765 lines
25 KiB
C++
765 lines
25 KiB
C++
#include <math.h>
|
|
|
|
#include <condition_variable>
|
|
#include <fileHash.hpp>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <future>
|
|
#include <helper.hpp>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <json.hpp>
|
|
#include <mutex>
|
|
#include <random>
|
|
#include <sstream>
|
|
#include <stack>
|
|
#include <string>
|
|
#include <thread>
|
|
|
|
#define CCRED "\033[31m"
|
|
#define CCGREEN "\033[32m"
|
|
#define CCYELLOW "\033[33m"
|
|
#define CCBLUE "\033[34m"
|
|
#define CCMAGENTA "\033[35m"
|
|
#define CCCYAN "\033[36m"
|
|
#define CCRESET "\033[0m"
|
|
|
|
#define veccmp(vec1, vec2) (vec1.size() == vec2.size())
|
|
|
|
void updateProgressBar(float progress, std::string f) {
|
|
const int w = 50;
|
|
int pos = static_cast<int>(progress * w);
|
|
|
|
std::cout << CCYELLOW << "[";
|
|
|
|
for (int i = 0; i < w; ++i) {
|
|
if (i < pos)
|
|
std::cout << "=";
|
|
else if (i == pos)
|
|
std::cout << ">";
|
|
else
|
|
std::cout << " ";
|
|
}
|
|
|
|
std::cout << "] " << std::setw(3) << static_cast<int>(progress * 100.0)
|
|
<< "% " << CCRESET << '\r';
|
|
std::cout.flush();
|
|
}
|
|
|
|
template <typename T>
|
|
std::pair<T, bool> js_catch(const nlohmann::json &js, const std::string &at) {
|
|
bool exists = true;
|
|
if (!js.contains(at) || js[at].is_null()) exists = false;
|
|
return std::make_pair(js[at].get<T>(), exists);
|
|
}
|
|
|
|
void recursive_repl(std::string &i, char v1, char v2) {
|
|
std::replace(i.begin(), i.end(), v1, v2);
|
|
}
|
|
|
|
std::vector<std::filesystem::path> get_files_in_dir(
|
|
const std::vector<std::string> &dir_paths, const std::string &extension) {
|
|
std::vector<std::filesystem::path> files;
|
|
|
|
for (const auto &dir_path : dir_paths) {
|
|
if (!std::filesystem::exists(dir_path)) continue;
|
|
for (const auto &entry : std::filesystem::directory_iterator(dir_path)) {
|
|
if (std::filesystem::is_regular_file(entry.path())) {
|
|
std::string fn = entry.path().string();
|
|
if (fn.length() > extension.length()) {
|
|
if (fn.ends_with(extension)) {
|
|
files.push_back(fix_path(entry.path().string()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return files;
|
|
}
|
|
|
|
void Js2Vec(std::vector<std::string> &vec, nlohmann::json js) {
|
|
vec.clear();
|
|
for (auto const &it : js) {
|
|
vec.push_back(it.get<std::string>());
|
|
}
|
|
}
|
|
|
|
void Vec2Json(std::vector<std::string> vec, nlohmann::json &js,
|
|
NpiProject ref) {
|
|
int indx = 0;
|
|
for (auto const &it : vec) {
|
|
js[indx] = it;
|
|
indx++;
|
|
}
|
|
}
|
|
|
|
std::string Flags2Str(std::vector<std::string> flags) {
|
|
std::string res = "";
|
|
for (auto const &it : flags) res += "-" + it + " ";
|
|
return res;
|
|
}
|
|
|
|
std::string IncludeDirs(std::vector<std::string> dirs) {
|
|
std::string res = "";
|
|
for (auto const &it : dirs) res += "-I " + it + " ";
|
|
return res;
|
|
}
|
|
|
|
std::string LibIncludes(std::vector<std::string> dirs) {
|
|
std::string res = "";
|
|
for (auto const &it : dirs) res += "-I " + it + "include/ ";
|
|
return res;
|
|
}
|
|
|
|
void VecGetExtra(std::vector<std::string> &result,
|
|
std::vector<std::string> input, NpiProject ref) {
|
|
result.clear();
|
|
for (auto const &it : input) {
|
|
if (it == "[arch_flags]") {
|
|
for (auto const &af : ref.arch_flags) {
|
|
result.push_back(af);
|
|
}
|
|
} else if (it == "[c_flags]") {
|
|
for (auto const &cf : ref.c_flags) {
|
|
result.push_back(cf);
|
|
}
|
|
} else {
|
|
result.push_back(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReplVariables(std::string &str, const std::string &from,
|
|
const std::string &to) {
|
|
if (from.empty()) return;
|
|
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(); // In case 'to' contains 'from', like replacing
|
|
// 'x' with 'yx'
|
|
}
|
|
}
|
|
|
|
void AutoRepl(std::string &str) {
|
|
std::string dkp_env = getenv("DEVKITPRO");
|
|
std::string cwd = std::filesystem::current_path().string();
|
|
ReplVariables(str, "{DEVKITPRO}", dkp_env);
|
|
ReplVariables(str, "{cwd}", cwd);
|
|
}
|
|
|
|
void ReplVector(std::vector<std::string> &vec, const std::string &from,
|
|
const std::string &to) {
|
|
for (size_t i = 0; i < vec.size(); i++) ReplVariables(vec[i], from, to);
|
|
}
|
|
|
|
void AutoVecRepl(std::vector<std::string> &strs) {
|
|
for (size_t i = 0; i < strs.size(); i++) AutoRepl(strs[i]);
|
|
}
|
|
|
|
void ProcessPrj2Cmp(NpiProject *prj, NpiProject src) {
|
|
VecGetExtra(prj->arch_flags, src.arch_flags, src);
|
|
VecGetExtra(prj->c_flags, src.c_flags, src);
|
|
VecGetExtra(prj->cxx_flags, src.cxx_flags,
|
|
prj[0]); // Use Prj as ref cause arch_flags already written
|
|
VecGetExtra(prj->as_flags, src.as_flags, src);
|
|
VecGetExtra(prj->linker_flags, src.linker_flags, src);
|
|
}
|
|
|
|
std::string LinkerInput(std::vector<std::filesystem::path> o_files,
|
|
std::vector<std::filesystem::path> d_files) {
|
|
std::string res = "";
|
|
/*if (o_files.size() != d_files.size()) {
|
|
std::cerr << "The Number of .d and .o files is wrong";
|
|
return "";
|
|
}*/
|
|
for (size_t i = 0; i < o_files.size(); i++)
|
|
res += o_files[i].string() + " "; // + d_files[i].string() + " ";
|
|
return res;
|
|
}
|
|
|
|
std::string Libs(std::vector<std::string> libs) {
|
|
std::string res = "";
|
|
for (auto const &it : libs) res += "-l" + it + " ";
|
|
return res;
|
|
}
|
|
|
|
std::string LibPaths(std::vector<std::string> libs) {
|
|
std::string res = "";
|
|
for (auto const &it : libs) res += "-L" + it + "lib/ ";
|
|
return res;
|
|
}
|
|
|
|
void DeleteFiles(std::string path, std::vector<std::string> extensions) {
|
|
for (const auto &entry : std::filesystem::directory_iterator(path)) {
|
|
if (std::filesystem::is_directory(entry)) {
|
|
DeleteFiles(fix_path(entry.path().string()), extensions);
|
|
} else {
|
|
for (const auto &ext : extensions) {
|
|
if (entry.path().extension() == ext) {
|
|
std::filesystem::remove(entry);
|
|
std::cout << CCRED
|
|
<< "[*] Deleted file: " << fix_path(entry.path().string())
|
|
<< CCRESET << std::endl;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DeleteDirectory(std::string path) {
|
|
for (const auto &entry : std::filesystem::directory_iterator(path)) {
|
|
if (std::filesystem::is_directory(entry)) {
|
|
DeleteDirectory(fix_path(entry.path().string()));
|
|
} else {
|
|
std::filesystem::remove(entry);
|
|
std::cout << CCRED
|
|
<< "[*] Deleted file: " << fix_path(entry.path().string())
|
|
<< CCRESET << std::endl;
|
|
}
|
|
}
|
|
|
|
std::filesystem::remove(path);
|
|
std::cout << CCRED << "[*] Deleted directory: " << path << CCRESET
|
|
<< std::endl;
|
|
}
|
|
|
|
void GenerateHashes(NpiProject prj, std::string dir_) {
|
|
auto cpp_hashes = createHashes(prj.source_dirs, ".cpp");
|
|
auto c_hashes = createHashes(prj.source_dirs, ".c");
|
|
auto hpp_hashes = createHashes(prj.include_dirs, ".hpp");
|
|
auto h_hashes = createHashes(prj.include_dirs, ".h");
|
|
auto v_pica_hashes = createHashes(prj.source_dirs, ".v.pica");
|
|
auto shlist_hashes = createHashes(prj.source_dirs, ".shlist");
|
|
auto s_hashes = createHashes(prj.source_dirs, ".s");
|
|
auto t3s_hashes = createHashes({std::string(dir_ + "/gfx")}, ".t3s");
|
|
|
|
nlohmann::json jscpp_hashes;
|
|
for (auto const &it : cpp_hashes) jscpp_hashes[it.first] = it.second;
|
|
nlohmann::json jsc_hashes;
|
|
for (auto const &it : c_hashes) jsc_hashes[it.first] = it.second;
|
|
nlohmann::json jshpp_hashes;
|
|
for (auto const &it : hpp_hashes) jshpp_hashes[it.first] = it.second;
|
|
nlohmann::json jsh_hashes;
|
|
for (auto const &it : h_hashes) jsh_hashes[it.first] = it.second;
|
|
nlohmann::json jsv_pica_hashes;
|
|
for (auto const &it : v_pica_hashes) jsv_pica_hashes[it.first] = it.second;
|
|
nlohmann::json jsshlist_hashes;
|
|
for (auto const &it : shlist_hashes) jsshlist_hashes[it.first] = it.second;
|
|
nlohmann::json jss_hashes;
|
|
for (auto const &it : s_hashes) jss_hashes[it.first] = it.second;
|
|
nlohmann::json jst3s_hashes;
|
|
for (auto const &it : t3s_hashes) jst3s_hashes[it.first] = it.second;
|
|
|
|
nlohmann::json hashes;
|
|
hashes["cpp"] = jscpp_hashes;
|
|
hashes["c"] = jsc_hashes;
|
|
hashes["hpp"] = jshpp_hashes;
|
|
hashes["h"] = jsh_hashes;
|
|
hashes["v_pica"] = jsv_pica_hashes;
|
|
hashes["shlist"] = jsshlist_hashes;
|
|
hashes["s"] = jss_hashes;
|
|
hashes["t3s"] = jst3s_hashes;
|
|
|
|
std::ofstream hashes_file(dir_ + "/" + "build/hashes.json");
|
|
hashes_file << hashes.dump(4);
|
|
hashes_file.close();
|
|
}
|
|
|
|
std::map<std::string, std::string> GetHashMap(std::string dir_,
|
|
std::string extension) {
|
|
nlohmann::json js;
|
|
std::ifstream is(dir_ + "/build/hashes.json");
|
|
if (!is) {
|
|
std::cerr << "[-]hashes.json not in " << dir_ + "/build/"
|
|
<< "!\n";
|
|
exit(-1);
|
|
}
|
|
is >> js;
|
|
is.close();
|
|
|
|
std::string mod_ext = extension.substr(1);
|
|
std::replace(mod_ext.begin(), mod_ext.end(), '.', '_');
|
|
|
|
std::map<std::string, std::string> res;
|
|
for (auto &[filename, hash] : js[mod_ext].items()) {
|
|
res[filename] = hash;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
bool C_CXX_Compile(bool cxx, std::string dir_, std::filesystem::path it,
|
|
NpiProject prj) {
|
|
std::string command =
|
|
(cxx ? prj.cxx_compiler : prj.c_compiler) + " -MMD -MP -MF " + dir_ +
|
|
"/build/" + fix_path(it.stem().string()) + ".d " + "-c " +
|
|
fix_path(it.string()) + " -o " + dir_ + "/build/" +
|
|
fix_path(it.stem().string()) + ".o " +
|
|
Flags2Str((cxx ? prj.cxx_flags : prj.c_flags)) + " " +
|
|
IncludeDirs(prj.include_dirs) + " " + LibIncludes(prj.lib_dirs);
|
|
// std::cout << CCMAGENTA << "Compiling: " << CCCYAN <<
|
|
// fix_path(it.filename().string())
|
|
// << std::endl;
|
|
int reqres = system(command.c_str());
|
|
// std::cout << (reqres == 0 ? CCGREEN : CCRED)
|
|
// << (reqres == 0 ? "[+] " : "[-] ") <<
|
|
// fix_path(it.filename().string())
|
|
// << std::endl;
|
|
return reqres != 0;
|
|
}
|
|
|
|
bool Picasso_Compile(std::string dir_, std::string dkp_env,
|
|
std::filesystem::path it, NpiProject prj) {
|
|
std::string res_f =
|
|
dir_ + "/build/" + fix_path(it.stem().stem().string()) + ".shbin ";
|
|
std::string command =
|
|
dkp_env + "/tools/bin/picasso -o " + res_f + fix_path(it.string());
|
|
// std::cout << CCMAGENTA << "Generating: " << CCCYAN << res_f
|
|
// << std::endl;
|
|
int reqres = system(command.c_str());
|
|
// std::cout << (reqres == 0 ? CCGREEN : CCRED)
|
|
// << (reqres == 0 ? "[+] " : "[-] ") << res_f
|
|
// << std::endl;
|
|
if (reqres != 0) return true;
|
|
// Bin2o action
|
|
// Mod res_f
|
|
std::string erf = res_f;
|
|
recursive_repl(erf, '.', '_');
|
|
erf = erf.substr(0, erf.length() - 1);
|
|
std::string tmp = "t.s";
|
|
std::string obj = erf + ".o";
|
|
std::string hdr = erf + ".h";
|
|
|
|
// Convert bin2asm
|
|
std::string cmd = "bin2s -a 4 -H " + hdr + ' ' + res_f + " > " + tmp;
|
|
reqres = system(cmd.c_str());
|
|
if (reqres != 0) return true;
|
|
|
|
cmd = prj.cxx_compiler + " -x assembler-with-cpp " + tmp + " -c -o " + obj;
|
|
reqres = system(cmd.c_str());
|
|
// remove asm file
|
|
remove(tmp.c_str());
|
|
if (reqres != 0) return true;
|
|
return false;
|
|
}
|
|
|
|
bool Tex3ds_Compile(std::string dir_, std::string dkp_env,
|
|
std::filesystem::path it, NpiProject prj) {
|
|
std::string command =
|
|
dkp_env + "/tools/bin/tex3ds -i " + fix_path(it.string()) + " -H " +
|
|
dir_ + "/build/" + fix_path(it.stem().string()) + ".h" + " -d " + dir_ +
|
|
"/build/" + fix_path(it.stem().string()) + ".d" + " -o " + dir_ +
|
|
"/romfs/gfx//" + fix_path(it.stem().string()) + ".t3x";
|
|
// std::cout << CCMAGENTA << "Generating: " << CCCYAN <<
|
|
// fix_path(it.filename().string())
|
|
// << std::endl;
|
|
int reqres = system(command.c_str());
|
|
// std::cout << (reqres == 0 ? CCGREEN : CCRED)
|
|
// << (reqres == 0 ? "[+] " : "[-] ") <<
|
|
// fix_path(it.filename().string())
|
|
// << std::endl;
|
|
return reqres != 0;
|
|
}
|
|
|
|
void CompileProject(NpiProject &prj, std::string dir_, bool async = true) {
|
|
#ifdef _WIN32
|
|
std::string dkp_env = "C:/devkitPro/";
|
|
std::cout << CCYELLOW
|
|
<< "[+] Warning: Windows Usage Detected!\n[+] Make sure you have "
|
|
"devkitpro installed at <C:/devkitPro>!"
|
|
<< CCRESET << std::endl;
|
|
#else
|
|
std::string dkp_env = getenv("DEVKITPRO");
|
|
#endif
|
|
bool any_errors = false;
|
|
|
|
AutoVecRepl(prj.source_dirs);
|
|
AutoVecRepl(prj.include_dirs);
|
|
|
|
// Inject build dir as include dir
|
|
prj.include_dirs.push_back(dir_ + "/build");
|
|
|
|
std::vector<std::filesystem::path> cpp_files =
|
|
get_files_in_dir(prj.source_dirs, ".cpp");
|
|
std::vector<std::filesystem::path> c_files =
|
|
get_files_in_dir(prj.source_dirs, ".c");
|
|
std::vector<std::filesystem::path> hpp_files =
|
|
get_files_in_dir(prj.include_dirs, ".hpp");
|
|
std::vector<std::filesystem::path> h_files =
|
|
get_files_in_dir(prj.include_dirs, ".h");
|
|
std::vector<std::filesystem::path> v_pica_files =
|
|
get_files_in_dir(prj.source_dirs, ".v.pica");
|
|
std::vector<std::filesystem::path> shlist_files =
|
|
get_files_in_dir(prj.source_dirs, ".shlist");
|
|
std::vector<std::filesystem::path> t3s_files =
|
|
get_files_in_dir({std::string(dir_ + "/gfx")}, ".t3s");
|
|
std::vector<std::filesystem::path> s_files =
|
|
get_files_in_dir(prj.source_dirs, ".s");
|
|
|
|
std::filesystem::create_directories(dir_ + "/build");
|
|
|
|
std::vector<std::filesystem::path> cpp_files_;
|
|
std::vector<std::filesystem::path> c_files_;
|
|
std::vector<std::filesystem::path> v_pica_files_;
|
|
std::vector<std::filesystem::path> shlist_files_;
|
|
std::vector<std::filesystem::path> s_files_;
|
|
std::vector<std::filesystem::path> t3s_files_;
|
|
|
|
if (!std::filesystem::exists(
|
|
std::filesystem::path(dir_ + "/build/hashes.json"))) {
|
|
GenerateHashes(prj, dir_);
|
|
cpp_files_ = get_files_in_dir(prj.source_dirs, ".cpp");
|
|
c_files_ = get_files_in_dir(prj.source_dirs, ".c");
|
|
v_pica_files_ = get_files_in_dir(prj.source_dirs, ".v.pica");
|
|
shlist_files_ = get_files_in_dir(prj.source_dirs, ".shlist");
|
|
s_files_ = get_files_in_dir(prj.source_dirs, ".s");
|
|
t3s_files_ = get_files_in_dir({std::string(dir_ + "/gfx")}, ".t3s");
|
|
} else {
|
|
cpp_files_ = getChangedFiles(GetHashMap(dir_, ".cpp"));
|
|
c_files_ = getChangedFiles(GetHashMap(dir_, ".c"));
|
|
v_pica_files_ = getChangedFiles(GetHashMap(dir_, ".v.pica"));
|
|
shlist_files_ = getChangedFiles(GetHashMap(dir_, ".shlist"));
|
|
s_files_ = getChangedFiles(GetHashMap(dir_, ".s"));
|
|
t3s_files_ = getChangedFiles(GetHashMap(dir_, ".t3s"));
|
|
if ((getChangedFiles(GetHashMap(dir_, ".hpp")).size() != 0) ||
|
|
(getChangedFiles(GetHashMap(dir_, ".hpp")).size() != 0)) {
|
|
cpp_files_ = get_files_in_dir(prj.source_dirs, ".cpp");
|
|
c_files_ = get_files_in_dir(prj.source_dirs, ".c");
|
|
}
|
|
}
|
|
|
|
if (GetHashMap(dir_, ".cpp").size() != cpp_files.size() ||
|
|
GetHashMap(dir_, ".c").size() != c_files.size()) {
|
|
cpp_files_ = get_files_in_dir(prj.source_dirs, ".cpp");
|
|
c_files_ = get_files_in_dir(prj.source_dirs, ".c");
|
|
}
|
|
if (GetHashMap(dir_, ".hpp").size() != hpp_files.size() ||
|
|
GetHashMap(dir_, ".h").size() != h_files.size()) {
|
|
cpp_files_ = get_files_in_dir(prj.source_dirs, ".cpp");
|
|
c_files_ = get_files_in_dir(prj.source_dirs, ".c");
|
|
}
|
|
|
|
ReplVector(prj.lib_dirs, "{DEVKITPRO}", dkp_env);
|
|
|
|
ReplVariables(prj.cxx_compiler, "{DEVKITPRO}", dkp_env);
|
|
ReplVariables(prj.c_compiler, "{DEVKITPRO}", dkp_env);
|
|
ReplVariables(prj.asm_compiler, "{DEVKITPRO}", dkp_env);
|
|
ReplVariables(prj.linker, "{DEVKITPRO}", dkp_env);
|
|
|
|
int prgc = 0;
|
|
int wa = cpp_files_.size() + c_files_.size() + t3s_files_.size() +
|
|
v_pica_files_.size();
|
|
int prga = cpp_files_.size() + c_files_.size();
|
|
if (prga <= 0) {
|
|
prgc = 1;
|
|
prga = 1;
|
|
std::cout << CCGREEN << "[+] Everything is Up to date..." << CCRESET
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
|
|
for (auto const &it : t3s_files_) {
|
|
prgc++;
|
|
updateProgressBar(((float)prgc / (float)wa), it.filename().string());
|
|
Tex3ds_Compile(dir_, dkp_env, it, prj);
|
|
}
|
|
|
|
for (auto const &it : v_pica_files_) {
|
|
prgc++;
|
|
updateProgressBar(((float)prgc / (float)wa), it.filename().string());
|
|
Picasso_Compile(dir_, dkp_env, it, prj);
|
|
}
|
|
|
|
/*if (async)
|
|
{
|
|
|
|
}
|
|
else
|
|
{*/
|
|
for (auto const &it : cpp_files_) {
|
|
prgc++;
|
|
updateProgressBar(((float)prgc / (float)wa), it.filename().string());
|
|
C_CXX_Compile(true, dir_, it, prj);
|
|
}
|
|
|
|
for (auto const &it : c_files_) {
|
|
prgc++;
|
|
updateProgressBar(((float)prgc / (float)wa), it.filename().string());
|
|
C_CXX_Compile(false, dir_, it, prj);
|
|
}
|
|
//}
|
|
// updateProgressBar(1.f);
|
|
std::cout << std::endl;
|
|
|
|
std::vector<std::filesystem::path> o_files =
|
|
get_files_in_dir({dir_ + "/build/"}, ".o");
|
|
std::vector<std::filesystem::path> d_files =
|
|
get_files_in_dir({dir_ + "/build/"}, ".d");
|
|
|
|
if (!any_errors) {
|
|
std::string command = prj.linker + " -o " + dir_ + "/" + prj.name +
|
|
".elf " + LinkerInput(o_files, d_files) + " " +
|
|
Libs(prj.libraries) + " " + LibPaths(prj.lib_dirs) +
|
|
" " + Flags2Str(prj.linker_flags);
|
|
std::cout << CCBLUE << "[+] Linking..." << CCRESET << std::endl;
|
|
int reqres = system(command.c_str());
|
|
if (reqres != 0) any_errors = true;
|
|
if (prj.ctr_type) {
|
|
command =
|
|
"bannertool makebanner -i \"app/banner.png\" -a "
|
|
"\"app/BannerAudio.wav\" -o \"build/banner.bin\"";
|
|
std::cout << CCBLUE << "[+] Creating Banner..." << CCRESET << std::endl;
|
|
reqres = system(command.c_str());
|
|
std::cout << (reqres == 0 ? CCGREEN : CCRED)
|
|
<< (reqres == 0 ? "[+] " : "[-] ") << "Banner" << std::endl;
|
|
}
|
|
command = "bannertool makesmdh -i \"app/icon.png\" -s \"" + prj.name +
|
|
"\" -l \"Description\" -p \"" + prj.author +
|
|
"\" -o \"build/icon.bin\"";
|
|
std::cout << CCBLUE << "[+] Creating smdh..." << CCRESET << std::endl;
|
|
reqres = system(command.c_str());
|
|
std::cout << (reqres == 0 ? CCGREEN : CCRED)
|
|
<< (reqres == 0 ? "[+] " : "[-] ") << "Icon" << std::endl;
|
|
command = dkp_env += "/tools/bin/3dsxtool " + dir_ + "/" + prj.name +
|
|
".elf " + dir_ + "/" + prj.name + ".3dsx " +
|
|
"--smdh=" + dir_ + "/build/icon.bin" +
|
|
" --romfs=" + dir_ + "/romfs";
|
|
std::cout << CCBLUE << "[+] Creating 3dsx..." << CCRESET << std::endl;
|
|
reqres = system(command.c_str());
|
|
std::cout << (reqres == 0 ? CCGREEN : CCRED)
|
|
<< (reqres == 0 ? "[+] " : "[-] ") << prj.name + ".3dsx "
|
|
<< std::endl;
|
|
if (prj.ctr_type) {
|
|
command =
|
|
"makerom -f cia -target t -exefslogo -o " + dir_ + "/" + prj.name +
|
|
".cia -elf " + dir_ + "/" + prj.name + ".elf " + " -rsf " + dir_ +
|
|
"/" + prj.rsf_path + " -banner " + dir_ + "/build/banner.bin" +
|
|
" -icon " + dir_ + "/build/icon.bin" + " -logo " + dir_ + "/" +
|
|
prj.logo_lz11_path + " -DAPP_ROMFS=" + dir_ + "/" + prj.dir_romfs +
|
|
" -major " + std::to_string(prj.vmajor) + " -minor " +
|
|
std::to_string(prj.vminor) + " -micro " + std::to_string(prj.vbuild) +
|
|
" -DAPP_VERSION_MAJOR=" + std::to_string(prj.vmajor);
|
|
std::cout << CCBLUE << "[+] Creating Cia..." << CCRESET << std::endl;
|
|
reqres = system(command.c_str());
|
|
std::cout << (reqres == 0 ? CCGREEN : CCRED)
|
|
<< (reqres == 0 ? "[+] " : "[-] ") << prj.name + ".cia "
|
|
<< std::endl;
|
|
}
|
|
}
|
|
|
|
if (any_errors) {
|
|
std::cout
|
|
<< CCRED
|
|
<< "\nErrors Happened!\nTake a look at the Top of this Message...\n"
|
|
<< CCRESET;
|
|
}
|
|
|
|
GenerateHashes(prj, dir_);
|
|
|
|
std::cout << CCRESET << std::endl;
|
|
}
|
|
|
|
namespace helper {
|
|
std::string GenerateUniqueId() {
|
|
std::random_device rd;
|
|
std::mt19937 gen(rd());
|
|
std::uniform_int_distribution<> dis(0, 15);
|
|
|
|
std::stringstream ss;
|
|
ss << "0x";
|
|
for (int i = 0; i < 5; ++i) {
|
|
ss << std::hex << dis(gen);
|
|
}
|
|
|
|
std::string hex_str = ss.str();
|
|
return hex_str;
|
|
}
|
|
|
|
void ArrayToFile(unsigned char *array_, size_t size_, std::string filename) {
|
|
std::ofstream file(filename, std::ios::binary);
|
|
|
|
if (!file.is_open()) {
|
|
std::cerr << CCRED << "[-]: Could not open file" << CCRESET << std::endl;
|
|
return;
|
|
}
|
|
|
|
file.write(reinterpret_cast<char *>(array_), size_);
|
|
|
|
file.close();
|
|
}
|
|
|
|
void GenerateTemplateFile(std::string path, NpiProject prj) {
|
|
nlohmann::ordered_json js;
|
|
js["project_name"] = prj.name;
|
|
js["author"] = prj.author;
|
|
js["description"] = prj.description;
|
|
js["vmajor"] = prj.vmajor;
|
|
js["vminor"] = prj.vminor;
|
|
js["vbuild"] = prj.vbuild;
|
|
if (prj.ctr_type) {
|
|
js["unique_id"] = prj.unique_id;
|
|
js["prod_code"] = prj.prod;
|
|
}
|
|
js["platform"] = prj.platform;
|
|
if (prj.platform == "3ds") {
|
|
js["cia"] = prj.ctr_type;
|
|
}
|
|
|
|
nlohmann::json source_dirs;
|
|
Vec2Json(prj.source_dirs, source_dirs, prj);
|
|
js["source_dirs"] = source_dirs;
|
|
|
|
nlohmann::json include_dirs;
|
|
Vec2Json(prj.include_dirs, include_dirs, prj);
|
|
js["include_dirs"] = include_dirs;
|
|
|
|
nlohmann::json libraries;
|
|
Vec2Json(prj.libraries, libraries, prj);
|
|
js["libraries"] = libraries;
|
|
|
|
nlohmann::json lib_dirs;
|
|
Vec2Json(prj.lib_dirs, lib_dirs, prj);
|
|
js["lib_dirs"] = lib_dirs;
|
|
|
|
js["icon_path"] = prj.icon_path;
|
|
if (prj.ctr_type) {
|
|
js["banner_path"] = prj.banner_path;
|
|
js["banner_a_path"] = prj.banner_a_path;
|
|
js["rsf_path"] = prj.rsf_path;
|
|
js["logo_lz11_path"] = prj.logo_lz11_path;
|
|
}
|
|
|
|
js["dir_gfx"] = prj.dir_gfx;
|
|
js["dir_gfxbuild"] = prj.dir_gfxbuild;
|
|
js["dir_romfs"] = prj.dir_romfs;
|
|
|
|
nlohmann::json arch_flags;
|
|
Vec2Json(prj.arch_flags, arch_flags, prj);
|
|
js["arch_flags"] = arch_flags;
|
|
|
|
nlohmann::json c_flags;
|
|
Vec2Json(prj.c_flags, c_flags, prj);
|
|
js["c_flags"] = c_flags;
|
|
|
|
nlohmann::json cxx_flags;
|
|
Vec2Json(prj.cxx_flags, cxx_flags, prj);
|
|
js["cxx_flags"] = cxx_flags;
|
|
|
|
nlohmann::json as_flags;
|
|
Vec2Json(prj.as_flags, as_flags, prj);
|
|
js["as_flags"] = as_flags;
|
|
|
|
nlohmann::json linker_flags;
|
|
Vec2Json(prj.linker_flags, linker_flags, prj);
|
|
js["linker_flags"] = linker_flags;
|
|
|
|
js["cxx_compiler"] = prj.cxx_compiler;
|
|
js["c_compiler"] = prj.c_compiler;
|
|
js["asm_compiler"] = prj.asm_compiler;
|
|
js["linker"] = prj.linker;
|
|
|
|
std::ofstream fout(path);
|
|
fout << js.dump(4);
|
|
fout.close();
|
|
}
|
|
|
|
void CompileProject(std::string path, bool async) {
|
|
std::string dkp_env = getenv("DEVKITPRO");
|
|
if (dkp_env.c_str() == NULL) {
|
|
std::cerr << CCRED << "[-] Please set DEVKITPRO ENV Variable!\n" << CCRESET;
|
|
return;
|
|
}
|
|
nlohmann::json js;
|
|
std::ifstream is(path + "/build.json");
|
|
if (!is) {
|
|
std::cerr << CCRED << "[-] build.json not in " << path << "!\n" << CCRESET;
|
|
return;
|
|
}
|
|
is >> js;
|
|
|
|
is.close();
|
|
|
|
std::cout << CCBLUE << "[+] Compiling at " << path << " ...\n" << CCRESET;
|
|
|
|
NpiProject prj;
|
|
auto __name = js_catch<std::string>(js, "project_name");
|
|
auto __author = js_catch<std::string>(js, "author");
|
|
auto __vmajor = js_catch<int>(js, "vmajor");
|
|
auto __vminor = js_catch<int>(js, "vminor");
|
|
auto __vbuild = js_catch<int>(js, "vbuild");
|
|
auto __platform = js_catch<std::string>(js, "platform");
|
|
auto __ctr_type = js_catch<bool>(js, "cia");
|
|
auto __description = js_catch<std::string>(js, "description");
|
|
|
|
std::pair<std::string, bool> __unique_id;
|
|
std::pair<std::string, bool> __prod;
|
|
if (__ctr_type.first) {
|
|
__unique_id = js_catch<std::string>(js, "unique_id");
|
|
__prod = js_catch<std::string>(js, "prod_code");
|
|
}
|
|
|
|
std::pair<std::string, bool> __banner_path;
|
|
std::pair<std::string, bool> __banner_a_path;
|
|
std::pair<std::string, bool> __rsf_path;
|
|
std::pair<std::string, bool> __logo_lz11_path;
|
|
|
|
auto __icon_path = js_catch<std::string>(js, "icon_path");
|
|
if (__ctr_type.first) {
|
|
__banner_path = js_catch<std::string>(js, "banner_path");
|
|
__banner_a_path = js_catch<std::string>(js, "banner_a_path");
|
|
__rsf_path = js_catch<std::string>(js, "rsf_path");
|
|
__logo_lz11_path = js_catch<std::string>(js, "logo_lz11_path");
|
|
}
|
|
auto __dir_gfx = js_catch<std::string>(js, "dir_gfx");
|
|
auto __dir_gfxbuild = js_catch<std::string>(js, "dir_gfxbuild");
|
|
auto __dir_romfs = js_catch<std::string>(js, "dir_romfs");
|
|
|
|
auto __cxx_compiler = js_catch<std::string>(js, "cxx_compiler");
|
|
auto __c_compiler = js_catch<std::string>(js, "c_compiler");
|
|
auto __asm_compiler = js_catch<std::string>(js, "asm_compiler");
|
|
auto __linker = js_catch<std::string>(js, "linker");
|
|
|
|
prj.name = __name.first;
|
|
prj.author = __author.first;
|
|
prj.vmajor = __vmajor.first;
|
|
prj.vminor = __vminor.first;
|
|
prj.vbuild = __vbuild.first;
|
|
prj.description = __description.first;
|
|
prj.unique_id = __unique_id.first;
|
|
prj.prod = __prod.first;
|
|
prj.platform = __platform.first;
|
|
prj.ctr_type = __ctr_type.first;
|
|
|
|
prj.icon_path = __icon_path.first;
|
|
prj.banner_path = __banner_path.first;
|
|
prj.banner_a_path = __banner_a_path.first;
|
|
prj.rsf_path = __rsf_path.first;
|
|
prj.logo_lz11_path = __logo_lz11_path.first;
|
|
prj.dir_gfx = __dir_gfx.first;
|
|
prj.dir_gfxbuild = __dir_gfxbuild.first;
|
|
prj.dir_romfs = __dir_romfs.first;
|
|
|
|
Js2Vec(prj.arch_flags, js["arch_flags"]);
|
|
Js2Vec(prj.linker_flags, js["linker_flags"]);
|
|
Js2Vec(prj.c_flags, js["c_flags"]);
|
|
Js2Vec(prj.cxx_flags, js["cxx_flags"]);
|
|
Js2Vec(prj.as_flags, js["as_flags"]);
|
|
Js2Vec(prj.source_dirs, js["source_dirs"]);
|
|
Js2Vec(prj.include_dirs, js["include_dirs"]);
|
|
Js2Vec(prj.lib_dirs, js["lib_dirs"]);
|
|
Js2Vec(prj.libraries, js["libraries"]);
|
|
prj.cxx_compiler = __cxx_compiler.first;
|
|
prj.c_compiler = __c_compiler.first;
|
|
prj.asm_compiler = __asm_compiler.first;
|
|
prj.linker = __linker.first;
|
|
NpiProject _2build = prj;
|
|
ProcessPrj2Cmp(&_2build, prj);
|
|
CompileProject(_2build, path, async);
|
|
}
|
|
void CleanProject(std::string path) {
|
|
DeleteFiles(path, {".3dsx", ".cia", ".elf"});
|
|
DeleteFiles(path + "/" + "romfs", {".t3x"});
|
|
DeleteDirectory(path + "/build");
|
|
}
|
|
} // namespace helper
|