mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2026-05-08 01:41:46 +00:00
Implement mod file creation on posix systems
This commit is contained in:
parent
2ec49adc39
commit
b4ad9af47e
1 changed files with 72 additions and 12 deletions
|
|
@ -13,7 +13,8 @@
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#else
|
#else
|
||||||
# error "Not implemented yet"
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr std::string_view symbol_filename = "mod_syms.bin";
|
constexpr std::string_view symbol_filename = "mod_syms.bin";
|
||||||
|
|
@ -202,10 +203,10 @@ static std::vector<std::filesystem::path> get_toml_path_array(const toml::array&
|
||||||
ret.reserve(toml_array.size());
|
ret.reserve(toml_array.size());
|
||||||
toml_array.for_each([&ret, &basedir](auto&& el) {
|
toml_array.for_each([&ret, &basedir](auto&& el) {
|
||||||
if constexpr (toml::is_string<decltype(el)>) {
|
if constexpr (toml::is_string<decltype(el)>) {
|
||||||
ret.emplace_back(concat_if_not_empty(basedir, el.ref<std::string>()));
|
ret.emplace_back(concat_if_not_empty(basedir, el.template ref<std::string>()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw toml::parse_error("Invalid type for data reference symbol file entry", el.source());
|
throw toml::parse_error("Invalid type for file entry", el.source());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -229,7 +230,7 @@ ModManifest parse_mod_config_manifest(const std::filesystem::path& basedir, cons
|
||||||
const toml::array& authors_array = read_toml_array(manifest_table, "authors", true);
|
const toml::array& authors_array = read_toml_array(manifest_table, "authors", true);
|
||||||
authors_array.for_each([&ret](auto&& el) {
|
authors_array.for_each([&ret](auto&& el) {
|
||||||
if constexpr (toml::is_string<decltype(el)>) {
|
if constexpr (toml::is_string<decltype(el)>) {
|
||||||
ret.authors.emplace_back(el.ref<std::string>());
|
ret.authors.emplace_back(el.template ref<std::string>());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw toml::parse_error("Invalid type for author entry", el.source());
|
throw toml::parse_error("Invalid type for author entry", el.source());
|
||||||
|
|
@ -260,7 +261,7 @@ ModManifest parse_mod_config_manifest(const std::filesystem::path& basedir, cons
|
||||||
std::vector<std::string> cur_funcs{};
|
std::vector<std::string> cur_funcs{};
|
||||||
funcs_array.for_each([&ret, &cur_funcs](const auto& func_el) {
|
funcs_array.for_each([&ret, &cur_funcs](const auto& func_el) {
|
||||||
if constexpr (toml::is_string<decltype(func_el)>) {
|
if constexpr (toml::is_string<decltype(func_el)>) {
|
||||||
cur_funcs.emplace_back(func_el.ref<std::string>());
|
cur_funcs.emplace_back(func_el.template ref<std::string>());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw toml::parse_error("Invalid type for native library function entry", func_el.source());
|
throw toml::parse_error("Invalid type for native library function entry", func_el.source());
|
||||||
|
|
@ -283,15 +284,15 @@ ModManifest parse_mod_config_manifest(const std::filesystem::path& basedir, cons
|
||||||
if constexpr (toml::is_string<decltype(el)>) {
|
if constexpr (toml::is_string<decltype(el)>) {
|
||||||
size_t dependency_id_length;
|
size_t dependency_id_length;
|
||||||
bool dependency_version_has_label;
|
bool dependency_version_has_label;
|
||||||
if (!validate_dependency_string(el.ref<std::string>(), dependency_id_length, dependency_version_has_label)) {
|
if (!validate_dependency_string(el.template ref<std::string>(), dependency_id_length, dependency_version_has_label)) {
|
||||||
throw toml::parse_error("Invalid dependency entry", el.source());
|
throw toml::parse_error("Invalid dependency entry", el.source());
|
||||||
}
|
}
|
||||||
if (dependency_version_has_label) {
|
if (dependency_version_has_label) {
|
||||||
throw toml::parse_error("Dependency versions may not have labels", el.source());
|
throw toml::parse_error("Dependency versions may not have labels", el.source());
|
||||||
}
|
}
|
||||||
std::string dependency_id = el.ref<std::string>().substr(0, dependency_id_length);
|
std::string dependency_id = el.template ref<std::string>().substr(0, dependency_id_length);
|
||||||
ret.dependencies.emplace_back(dependency_id);
|
ret.dependencies.emplace_back(dependency_id);
|
||||||
ret.full_dependency_strings.emplace_back(el.ref<std::string>());
|
ret.full_dependency_strings.emplace_back(el.template ref<std::string>());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw toml::parse_error("Invalid type for dependency entry", el.source());
|
throw toml::parse_error("Invalid type for dependency entry", el.source());
|
||||||
|
|
@ -360,7 +361,7 @@ ModConfig parse_mod_config(const std::filesystem::path& config_path, bool& good)
|
||||||
// Find the manifest section and validate its type.
|
// Find the manifest section and validate its type.
|
||||||
const toml::node* manifest_data_ptr = toml_data.get("manifest");
|
const toml::node* manifest_data_ptr = toml_data.get("manifest");
|
||||||
if (manifest_data_ptr == nullptr) {
|
if (manifest_data_ptr == nullptr) {
|
||||||
throw toml::parse_error("Mod toml is missing manifest section", {});
|
throw toml::parse_error("Mod toml is missing manifest section", toml::source_region{});
|
||||||
}
|
}
|
||||||
if (!manifest_data_ptr->is_table()) {
|
if (!manifest_data_ptr->is_table()) {
|
||||||
throw toml::parse_error("Incorrect type for mod toml manifest section", manifest_data_ptr->source());
|
throw toml::parse_error("Incorrect type for mod toml manifest section", manifest_data_ptr->source());
|
||||||
|
|
@ -370,7 +371,7 @@ ModConfig parse_mod_config(const std::filesystem::path& config_path, bool& good)
|
||||||
// Find the inputs section and validate its type.
|
// Find the inputs section and validate its type.
|
||||||
const toml::node* inputs_data_ptr = toml_data.get("inputs");
|
const toml::node* inputs_data_ptr = toml_data.get("inputs");
|
||||||
if (inputs_data_ptr == nullptr) {
|
if (inputs_data_ptr == nullptr) {
|
||||||
throw toml::parse_error("Mod toml is missing inputs section", {});
|
throw toml::parse_error("Mod toml is missing inputs section", toml::source_region{});
|
||||||
}
|
}
|
||||||
if (!inputs_data_ptr->is_table()) {
|
if (!inputs_data_ptr->is_table()) {
|
||||||
throw toml::parse_error("Incorrect type for mod toml inputs section", inputs_data_ptr->source());
|
throw toml::parse_error("Incorrect type for mod toml inputs section", inputs_data_ptr->source());
|
||||||
|
|
@ -383,7 +384,7 @@ ModConfig parse_mod_config(const std::filesystem::path& config_path, bool& good)
|
||||||
ret.inputs = parse_mod_config_inputs(basedir, inputs_table);
|
ret.inputs = parse_mod_config_inputs(basedir, inputs_table);
|
||||||
}
|
}
|
||||||
catch (const toml::parse_error& err) {
|
catch (const toml::parse_error& err) {
|
||||||
std::cerr << "Syntax error parsing toml: " << *err.source().path << " (" << err.source().begin << "):\n" << err.description() << std::endl;
|
std::cerr << "Syntax error parsing toml: " << config_path << " (" << err.source().begin << "):\n" << err.description() << std::endl;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -944,7 +945,66 @@ bool create_mod_zip(const std::filesystem::path& output_dir, const ModConfig& co
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# error "Not implemented yet"
|
std::string args_string{};
|
||||||
|
std::vector<size_t> arg_positions{};
|
||||||
|
|
||||||
|
// Adds an argument with a null terminator to args_string, which is used as a buffer to hold null terminated arguments.
|
||||||
|
// Also adds the argument's offset into the string into arg_positions for creating the array of character pointers for the exec.
|
||||||
|
auto add_arg = [&args_string, &arg_positions](const std::string& arg){
|
||||||
|
arg_positions.emplace_back(args_string.size());
|
||||||
|
args_string += (arg + '\x00');
|
||||||
|
};
|
||||||
|
|
||||||
|
add_arg("zip"); // The program name (argv[0]).
|
||||||
|
add_arg("-q"); // Quiet mode.
|
||||||
|
add_arg("-9"); // Maximum compression level.
|
||||||
|
add_arg("-MM"); // Error if any files aren't found.
|
||||||
|
add_arg("-j"); // Junk the paths (store just as the provided filename).
|
||||||
|
add_arg("-T"); // Test zip integrity.
|
||||||
|
add_arg(output_path.string());
|
||||||
|
add_arg((output_dir / symbol_filename).string());
|
||||||
|
add_arg((output_dir / binary_filename).string());
|
||||||
|
add_arg((output_dir / manifest_filename).string());
|
||||||
|
|
||||||
|
// Add arguments for every additional file in the archive.
|
||||||
|
for (const auto& cur_file : config.inputs.additional_files) {
|
||||||
|
add_arg(cur_file.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the argument char* array in a vector.
|
||||||
|
std::vector<char*> arg_pointers{};
|
||||||
|
for (size_t arg_index = 0; arg_index < arg_positions.size(); arg_index++) {
|
||||||
|
arg_pointers.emplace_back(args_string.data() + arg_positions[arg_index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Termimate the argument list with a null pointer.
|
||||||
|
arg_pointers.emplace_back(nullptr);
|
||||||
|
|
||||||
|
// Delete the output file if it exists already.
|
||||||
|
std::filesystem::remove(output_path);
|
||||||
|
|
||||||
|
// Fork-exec to run zip.
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == -1) {
|
||||||
|
fmt::print(stderr, "Failed to run \"zip\"\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (pid == 0) {
|
||||||
|
// This is the child process, so exec zip with the arguments.
|
||||||
|
execvp(arg_pointers[0], arg_pointers.data());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// This is the parent process, so wait for the child process to complete and check its exit code.
|
||||||
|
int status;
|
||||||
|
if (waitpid(pid, &status, 0) == (pid_t)-1) {
|
||||||
|
fmt::print(stderr, "Waiting for \"zip\" failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (status != EXIT_SUCCESS) {
|
||||||
|
fmt::print(stderr, "\"zip\" failed with exit code {}\n", status);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue