#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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(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(progress * 100.0) << "% " << CCRESET << '\r'; std::cout.flush(); } template std::pair 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(), exists); } void recursive_repl(std::string &i, char v1, char v2) { std::replace(i.begin(), i.end(), v1, v2); } std::vector get_files_in_dir( const std::vector &dir_paths, const std::string &extension) { std::vector 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 &vec, nlohmann::json js) { vec.clear(); for (auto const &it : js) { vec.push_back(it.get()); } } void Vec2Json(std::vector vec, nlohmann::json &js, NpiProject ref) { int indx = 0; for (auto const &it : vec) { js[indx] = it; indx++; } } std::string Flags2Str(std::vector flags) { std::string res = ""; for (auto const &it : flags) res += "-" + it + " "; return res; } std::string IncludeDirs(std::vector dirs) { std::string res = ""; for (auto const &it : dirs) res += "-I " + it + " "; return res; } std::string LibIncludes(std::vector dirs) { std::string res = ""; for (auto const &it : dirs) res += "-I " + it + "include/ "; return res; } void VecGetExtra(std::vector &result, std::vector 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 &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 &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 o_files, std::vector 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 libs) { std::string res = ""; for (auto const &it : libs) res += "-l" + it + " "; return res; } std::string LibPaths(std::vector libs) { std::string res = ""; for (auto const &it : libs) res += "-L" + it + "lib/ "; return res; } void DeleteFiles(std::string path, std::vector 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 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 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 !" << 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 cpp_files = get_files_in_dir(prj.source_dirs, ".cpp"); std::vector c_files = get_files_in_dir(prj.source_dirs, ".c"); std::vector hpp_files = get_files_in_dir(prj.include_dirs, ".hpp"); std::vector h_files = get_files_in_dir(prj.include_dirs, ".h"); std::vector v_pica_files = get_files_in_dir(prj.source_dirs, ".v.pica"); std::vector shlist_files = get_files_in_dir(prj.source_dirs, ".shlist"); std::vector t3s_files = get_files_in_dir({std::string(dir_ + "/gfx")}, ".t3s"); std::vector s_files = get_files_in_dir(prj.source_dirs, ".s"); std::filesystem::create_directories(dir_ + "/build"); std::vector cpp_files_; std::vector c_files_; std::vector v_pica_files_; std::vector shlist_files_; std::vector s_files_; std::vector 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 o_files = get_files_in_dir({dir_ + "/build/"}, ".o"); std::vector 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(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(js, "project_name"); auto __author = js_catch(js, "author"); auto __vmajor = js_catch(js, "vmajor"); auto __vminor = js_catch(js, "vminor"); auto __vbuild = js_catch(js, "vbuild"); auto __platform = js_catch(js, "platform"); auto __ctr_type = js_catch(js, "cia"); auto __description = js_catch(js, "description"); std::pair __unique_id; std::pair __prod; if (__ctr_type.first) { __unique_id = js_catch(js, "unique_id"); __prod = js_catch(js, "prod_code"); } std::pair __banner_path; std::pair __banner_a_path; std::pair __rsf_path; std::pair __logo_lz11_path; auto __icon_path = js_catch(js, "icon_path"); if (__ctr_type.first) { __banner_path = js_catch(js, "banner_path"); __banner_a_path = js_catch(js, "banner_a_path"); __rsf_path = js_catch(js, "rsf_path"); __logo_lz11_path = js_catch(js, "logo_lz11_path"); } auto __dir_gfx = js_catch(js, "dir_gfx"); auto __dir_gfxbuild = js_catch(js, "dir_gfxbuild"); auto __dir_romfs = js_catch(js, "dir_romfs"); auto __cxx_compiler = js_catch(js, "cxx_compiler"); auto __c_compiler = js_catch(js, "c_compiler"); auto __asm_compiler = js_catch(js, "asm_compiler"); auto __linker = js_catch(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