mirror of
https://github.com/pret/pokeplatinum.git
synced 2026-04-13 16:46:29 -05:00
679 lines
19 KiB
C
679 lines
19 KiB
C
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <fcntl.h>
|
|
#else
|
|
#include <spawn.h>
|
|
#include <sys/wait.h>
|
|
extern char **environ;
|
|
#endif
|
|
|
|
#define PROGRAM_NAME "mwrap"
|
|
|
|
#define DEFAULT_VER "2.0/sp2p2"
|
|
#define DEFAULT_CFG_FILE ".mwconfig"
|
|
#define VER_CFG 1
|
|
|
|
#ifdef _UNICODE
|
|
#define FMT_TS "%ls"
|
|
#else
|
|
#define FMT_TS "%s"
|
|
#endif
|
|
|
|
// POSIX-compatibility
|
|
#ifndef _WIN32
|
|
typedef char _TCHAR;
|
|
#define _tmain main
|
|
#define _T(...) __VA_ARGS__
|
|
#define _ftprintf(...) fprintf(__VA_ARGS__)
|
|
#define _sntprintf(...) snprintf(__VA_ARGS__)
|
|
#define _tcscat(...) strcat(__VA_ARGS__)
|
|
#define _tcscmp(...) strcmp(__VA_ARGS__)
|
|
#define _tcscspn(...) strcspn(__VA_ARGS__)
|
|
#define _tcsdup(...) strdup(__VA_ARGS__)
|
|
#define _tcslen(...) strlen(__VA_ARGS__)
|
|
#define _tcsrchr(...) strrchr(__VA_ARGS__)
|
|
#define _tfopen(...) fopen(__VA_ARGS__)
|
|
#define _tgetenv(...) getenv(__VA_ARGS__)
|
|
#endif
|
|
|
|
struct args {
|
|
_TCHAR *o;
|
|
_TCHAR *precompile;
|
|
bool M;
|
|
bool MD;
|
|
|
|
bool wrap_dbg;
|
|
_TCHAR *wrap_ver;
|
|
bool wrap_noipa;
|
|
};
|
|
|
|
struct args parse_args(int argc, _TCHAR *argv[], int *out_argc, _TCHAR ***out_argv)
|
|
{
|
|
struct args args = {
|
|
.o = NULL,
|
|
.precompile = NULL,
|
|
.M = false,
|
|
.MD = false,
|
|
.wrap_dbg = false,
|
|
.wrap_ver = NULL,
|
|
.wrap_noipa = false
|
|
};
|
|
|
|
int new_argc = 0;
|
|
_TCHAR **new_argv = malloc(sizeof(_TCHAR *) * (argc + 2));
|
|
new_argv[new_argc++] = NULL;
|
|
|
|
while (argc >= 1) {
|
|
int skip = 0;
|
|
int copy = 0;
|
|
|
|
if (_tcscmp(argv[0], _T("-o")) == 0 &&
|
|
argc >= 2) {
|
|
args.o = argv[1];
|
|
copy = 2;
|
|
} else if (_tcscmp(argv[0], _T("-precompile")) == 0 &&
|
|
argc >= 2) {
|
|
args.precompile = argv[1];
|
|
copy = 2;
|
|
} else if (_tcscmp(argv[0], _T("-M")) == 0) {
|
|
args.M = true;
|
|
copy = 1;
|
|
} else if (_tcscmp(argv[0], _T("-MD")) == 0) {
|
|
args.MD = true;
|
|
copy = 1;
|
|
} else if (_tcscmp(argv[0], _T("-wrap:dbg")) == 0) {
|
|
args.wrap_dbg = true;
|
|
skip = 1;
|
|
} else if (_tcscmp(argv[0], _T("-wrap:ver")) == 0 &&
|
|
argc >= 2) {
|
|
args.wrap_ver = argv[1];
|
|
skip = 2;
|
|
} else if (_tcscmp(argv[0], _T("-wrap:noipa")) == 0) {
|
|
args.wrap_noipa = true;
|
|
skip = 1;
|
|
} else {
|
|
copy = 1;
|
|
}
|
|
|
|
argc -= skip + copy;
|
|
while (skip--) argv++;
|
|
while (copy--) new_argv[new_argc++] = *argv++;
|
|
}
|
|
new_argv[new_argc] = NULL;
|
|
|
|
*out_argc = new_argc;
|
|
*out_argv = new_argv;
|
|
return args;
|
|
}
|
|
|
|
char *file_read(const _TCHAR *fname, size_t *size)
|
|
{
|
|
FILE *f = _tfopen(fname, _T("rb"));
|
|
if (!f) return NULL;
|
|
fseek(f, 0, SEEK_END);
|
|
*size = ftell(f);
|
|
char *file = malloc(*size);
|
|
rewind(f);
|
|
fread(file, *size, 1, f);
|
|
fclose(f);
|
|
return file;
|
|
}
|
|
|
|
char *tctoutf(const _TCHAR *str)
|
|
{
|
|
if (!str) return NULL;
|
|
#ifdef _UNICODE
|
|
size_t size = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
|
|
if (!size) return NULL;
|
|
char *res = malloc(size);
|
|
if (!res) return NULL;
|
|
WideCharToMultiByte(CP_UTF8, 0, str, -1, res, size, NULL, NULL);
|
|
return res;
|
|
#else
|
|
return strdup(str);
|
|
#endif
|
|
}
|
|
|
|
_TCHAR *utftotc(const char *str)
|
|
{
|
|
if (!str) return NULL;
|
|
#ifdef _UNICODE
|
|
size_t size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
|
if (!size) return NULL;
|
|
_TCHAR *res = malloc(size);
|
|
if (!res) return NULL;
|
|
MultiByteToWideChar(CP_UTF8, 0, str, -1, res, size);
|
|
return res;
|
|
#else
|
|
return strdup(str);
|
|
#endif
|
|
}
|
|
|
|
struct config {
|
|
char *wine;
|
|
char *path_unx;
|
|
char *path_win;
|
|
char *path_build_unx;
|
|
char *path_build_win;
|
|
};
|
|
|
|
const _TCHAR *cfg_file(void)
|
|
{
|
|
const _TCHAR *path = _tgetenv(_T("MWCONFIG"));
|
|
if (!path) path = _T(DEFAULT_CFG_FILE);
|
|
return path;
|
|
}
|
|
|
|
void cfg_save_writestr(FILE *f, const char *str)
|
|
{
|
|
if (str) fputs(str, f);
|
|
fputc('\0', f);
|
|
}
|
|
|
|
void cfg_save(struct config cfg)
|
|
{
|
|
FILE *f = _tfopen(cfg_file(), _T("wb"));
|
|
if (!f) {
|
|
fprintf(stderr, PROGRAM_NAME ": cfg_save: Failed to write config\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
const char head[] = {'M', 'W', 'R', VER_CFG};
|
|
fwrite(head, sizeof(head), 1, f);
|
|
cfg_save_writestr(f, cfg.wine);
|
|
cfg_save_writestr(f, cfg.path_unx);
|
|
cfg_save_writestr(f, cfg.path_win);
|
|
cfg_save_writestr(f, cfg.path_build_unx);
|
|
cfg_save_writestr(f, cfg.path_build_win);
|
|
fclose(f);
|
|
}
|
|
|
|
char *cfg_load_readstr(char *file, size_t *pos, size_t len)
|
|
{
|
|
// Check if a string is present
|
|
if (len < *pos + 1) return NULL;
|
|
if (file[*pos] == '\0') {
|
|
// Treat empty string as empty
|
|
(*pos)++;
|
|
return NULL;
|
|
}
|
|
|
|
// Look for the null byte
|
|
size_t readlen = strnlen(file + *pos, len - *pos);
|
|
if (len - *pos <= readlen) return NULL;
|
|
|
|
// If found, we can safely read it
|
|
char *readstr = strdup(file + *pos);
|
|
*pos += readlen + 1;
|
|
return readstr;
|
|
}
|
|
|
|
struct config cfg_load(void)
|
|
{
|
|
struct config cfg;
|
|
cfg.wine = NULL;
|
|
cfg.path_unx = NULL;
|
|
cfg.path_win = NULL;
|
|
cfg.path_build_unx = NULL;
|
|
cfg.path_build_win = NULL;
|
|
|
|
size_t file_len = 0;
|
|
char *file = file_read(cfg_file(), &file_len);
|
|
if (!file) return cfg;
|
|
size_t file_pos = 0;
|
|
|
|
const char head[] = {'M', 'W', 'R', VER_CFG};
|
|
if (file_len < file_pos + sizeof(head)) return cfg;
|
|
if (memcmp(file + file_pos, head, sizeof(head)) != 0) return cfg;
|
|
file_pos += sizeof(head);
|
|
|
|
cfg.wine = cfg_load_readstr(file, &file_pos, file_len);
|
|
cfg.path_unx = cfg_load_readstr(file, &file_pos, file_len);
|
|
cfg.path_win = cfg_load_readstr(file, &file_pos, file_len);
|
|
cfg.path_build_unx = cfg_load_readstr(file, &file_pos, file_len);
|
|
cfg.path_build_win = cfg_load_readstr(file, &file_pos, file_len);
|
|
|
|
free(file);
|
|
return cfg;
|
|
}
|
|
|
|
void cfg_free(struct config cfg)
|
|
{
|
|
free(cfg.path_win);
|
|
free(cfg.path_unx);
|
|
free(cfg.path_build_win);
|
|
free(cfg.path_build_unx);
|
|
free(cfg.wine);
|
|
}
|
|
|
|
void configure(int argc, _TCHAR *argv[])
|
|
{
|
|
_TCHAR *wine = NULL;
|
|
_TCHAR *path_unx = NULL;
|
|
_TCHAR *path_win = NULL;
|
|
_TCHAR *path_build_unx = NULL;
|
|
_TCHAR *path_build_win = NULL;
|
|
|
|
while (argc >= 1) {
|
|
if (_tcscmp(argv[0], _T("-wine")) == 0) {
|
|
wine = argv[1];
|
|
argv += 2; argc -= 2;
|
|
} else if (_tcscmp(argv[0], _T("-path_unx")) == 0) {
|
|
path_unx = argv[1];
|
|
argv += 2; argc -= 2;
|
|
} else if (_tcscmp(argv[0], _T("-path_win")) == 0) {
|
|
path_win = argv[1];
|
|
argv += 2; argc -= 2;
|
|
} else if (_tcscmp(argv[0], _T("-path_build_unx")) == 0) {
|
|
path_build_unx = argv[1];
|
|
argv += 2; argc -= 2;
|
|
} else if (_tcscmp(argv[0], _T("-path_build_win")) == 0) {
|
|
path_build_win = argv[1];
|
|
argv += 2; argc -= 2;
|
|
} else {
|
|
fprintf(stderr,
|
|
PROGRAM_NAME ": configure: Invalid argument: " FMT_TS "\n",
|
|
*argv);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
struct config cfg;
|
|
cfg.wine = tctoutf(wine);
|
|
cfg.path_unx = tctoutf(path_unx);
|
|
cfg.path_win = tctoutf(path_win);
|
|
cfg.path_build_unx = tctoutf(path_build_unx);
|
|
cfg.path_build_win = tctoutf(path_build_win);
|
|
if ((wine && !cfg.wine) ||
|
|
(path_unx && !cfg.path_unx) ||
|
|
(path_win && !cfg.path_win) ||
|
|
(path_build_unx && !cfg.path_build_unx) ||
|
|
(path_build_win && !cfg.path_build_win)) {
|
|
fprintf(stderr, PROGRAM_NAME ": configure: Conversion failed\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
cfg_save(cfg);
|
|
cfg_free(cfg);
|
|
}
|
|
|
|
_TCHAR *my_dirname(const _TCHAR *str)
|
|
{
|
|
_TCHAR *dir = _tcsdup(str);
|
|
size_t sep = _tcslen(dir);
|
|
while (sep > 0) {
|
|
if (dir[sep] == '/') goto found;
|
|
#ifdef _WIN32
|
|
if (dir[sep] == '\\') goto found;
|
|
#endif
|
|
sep--;
|
|
}
|
|
// Indicate current dir if no slash was found
|
|
dir[0] = '.';
|
|
sep = 1;
|
|
found:
|
|
dir = realloc(dir, sizeof(*dir) * (sep + 1));
|
|
dir[sep] = '\0';
|
|
return dir;
|
|
}
|
|
|
|
void str_resize(_TCHAR **str, size_t *max, size_t req)
|
|
{
|
|
if (*max < req) {
|
|
while (*max < req) *max += 1024;
|
|
*str = realloc(*str, sizeof(**str) * *max);
|
|
}
|
|
}
|
|
|
|
// Windows argv[] strings are passed as a whole, instead of being split up into
|
|
// an array. This means that *we* have to make sure to quote our arguments, and
|
|
// for some reason nobody every thought to make a library for this.
|
|
_TCHAR *win_argv_build(const _TCHAR *const *argv)
|
|
{
|
|
size_t args_max = 1024;
|
|
size_t args_pos = 0;
|
|
_TCHAR *args = malloc(sizeof(_TCHAR) * args_max);
|
|
|
|
bool first = true;
|
|
|
|
while (*argv) {
|
|
const _TCHAR *arg = *argv;
|
|
|
|
// Add a space between arguments
|
|
if (!first) {
|
|
str_resize(&args, &args_max, args_pos + 1);
|
|
args[args_pos++] = ' ';
|
|
}
|
|
first = false;
|
|
|
|
// If it doesn't contain any special chars, copy as-is
|
|
size_t arg_len = _tcslen(arg);
|
|
if (_tcscspn(arg, _T(" \t\n\r")) == arg_len) {
|
|
str_resize(&args, &args_max, args_pos + arg_len);
|
|
memcpy(args + args_pos, arg, sizeof(_TCHAR) * arg_len);
|
|
args_pos += arg_len;
|
|
argv++;
|
|
continue;
|
|
}
|
|
|
|
// Quote the argument
|
|
int backslashes = 0;
|
|
str_resize(&args, &args_max, args_pos + 1);
|
|
args[args_pos++] = '"';
|
|
while (*arg) {
|
|
if (*arg == '\\') {
|
|
backslashes++;
|
|
} else if (*arg == '"') {
|
|
// Add extra backslashes to escape the quote
|
|
backslashes++;
|
|
str_resize(&args, &args_max, args_pos + backslashes);
|
|
while (backslashes--) args[args_pos++] = '\\';
|
|
backslashes = 0;
|
|
} else {
|
|
backslashes = 0;
|
|
}
|
|
|
|
str_resize(&args, &args_max, args_pos + 1);
|
|
args[args_pos++] = *arg;
|
|
|
|
arg++;
|
|
}
|
|
// Add extra backslashes to avoid escaping the final quote
|
|
if (backslashes) {
|
|
str_resize(&args, &args_max, args_pos + backslashes);
|
|
while (backslashes--) args[args_pos++] = '\\';
|
|
}
|
|
str_resize(&args, &args_max, args_pos + 1);
|
|
args[args_pos++] = '"';
|
|
|
|
argv++;
|
|
}
|
|
|
|
args = realloc(args, sizeof(*args) * (args_pos + 1));
|
|
args[args_pos] = '\0';
|
|
|
|
return args;
|
|
}
|
|
|
|
void fix_depfile(_TCHAR *fname, const char *path_unx, const char *path_win, const char *path_build_unx, const char *path_build_win)
|
|
{
|
|
size_t file_size;
|
|
char *file = file_read(fname, &file_size);
|
|
if (!file) return;
|
|
|
|
FILE *f = _tfopen(fname, _T("wb"));
|
|
if (!f) {
|
|
free(file);
|
|
return;
|
|
}
|
|
|
|
size_t size_win = strlen(path_win);
|
|
size_t size_build_win = 0;
|
|
if (path_build_win && path_build_unx) {
|
|
size_build_win = strlen(path_build_win);
|
|
}
|
|
|
|
bool blankline = false;
|
|
|
|
// Replace any instances of path_win at the beginning of a line with
|
|
// path_unx, and backslashes with forward slashes.
|
|
for (size_t x = 0; x < file_size;) {
|
|
if (blankline &&
|
|
file_size - x > size_win &&
|
|
memcmp(file + x, path_win, size_win) == 0) {
|
|
fputs(path_unx, f);
|
|
x += size_win;
|
|
} else if (blankline && size_build_win &&
|
|
file_size - x > size_build_win &&
|
|
memcmp(file + x, path_build_win, size_build_win) == 0) {
|
|
fputs(path_build_unx, f);
|
|
x += size_build_win;
|
|
} else if (file_size - x > 2 && file[x] == '\\' &&
|
|
file[x + 1] != '\r' && file[x + 1] != '\n') {
|
|
fputc('/', f);
|
|
x++;
|
|
} else {
|
|
if (blankline && file[x] != ' ' && file[x] != '\t') {
|
|
blankline = false;
|
|
}
|
|
if (file[x] == '\n') blankline = true;
|
|
fputc(file[x++], f);
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
free(file);
|
|
}
|
|
|
|
char *replace_str(char *str, char *orig, char *rep, int start)
|
|
{
|
|
static char temp[4096];
|
|
static char buffer[4096];
|
|
char *p;
|
|
|
|
strcpy(temp, str + start);
|
|
|
|
if(!(p = strstr(temp, orig))) // Is 'orig' even in 'temp'?
|
|
return temp;
|
|
|
|
strncpy(buffer, temp, p-temp); // Copy characters from 'temp' start to 'orig' str
|
|
buffer[p-temp] = '\0';
|
|
|
|
sprintf(buffer + (p - temp), "%s%s", rep, p + strlen(orig));
|
|
sprintf(str + start, "%s", buffer);
|
|
|
|
return str;
|
|
}
|
|
|
|
void remove_ipa_arguments(int *argc, _TCHAR **argv)
|
|
{
|
|
int new_argc = 0;
|
|
for (int i = 0; i < *argc; i++) {
|
|
if (argv[i] && _tcscmp(argv[i], _T("-ipa")) == 0 && (i + 1) < *argc) {
|
|
// Skip the current "-ipa" argument and the following argument.
|
|
i++; // Increment to skip the next argument.
|
|
} else {
|
|
// Keep this argument, by moving it down if necessary.
|
|
argv[new_argc] = argv[i];
|
|
new_argc++;
|
|
}
|
|
}
|
|
|
|
// Update the original argc to the new count of arguments.
|
|
*argc = new_argc;
|
|
argv[*argc] = NULL;
|
|
}
|
|
|
|
int _tmain(int argc, _TCHAR *argv[])
|
|
{
|
|
if (argc < 2) {
|
|
fprintf(stderr, PROGRAM_NAME ": Too few arguments\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (_tcscmp(argv[1], _T("-test")) == 0) return EXIT_SUCCESS;
|
|
if (_tcscmp(argv[1], _T("-conf")) == 0) {
|
|
configure(argc - 2, argv + 2);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
struct config cfg = cfg_load();
|
|
|
|
_TCHAR *tool_dir = my_dirname(argv[0]);
|
|
const _TCHAR *tool_ver = _T(DEFAULT_VER);
|
|
const _TCHAR *tool_bin = argv[1];
|
|
|
|
int new_argc;
|
|
_TCHAR **new_argv;
|
|
struct args args = parse_args(argc - 2, argv + 2, &new_argc, &new_argv);
|
|
|
|
if (args.wrap_ver) tool_ver = args.wrap_ver;
|
|
|
|
if (args.wrap_noipa) {
|
|
remove_ipa_arguments(&new_argc, new_argv);
|
|
}
|
|
|
|
// Make a path of the chosen tool
|
|
size_t tool_size = _tcslen(tool_dir) + 1 + _tcslen(tool_ver) + 1 +
|
|
_tcslen(tool_bin) + 5;
|
|
_TCHAR *tool = malloc(sizeof(_TCHAR) * tool_size);
|
|
_sntprintf(tool, tool_size, _T(FMT_TS "/" FMT_TS "/" FMT_TS ".exe"),
|
|
tool_dir, tool_ver, tool_bin);
|
|
new_argv[0] = tool;
|
|
|
|
// Add the wine command if requested
|
|
_TCHAR *wine = utftotc(cfg.wine);
|
|
if (wine) {
|
|
new_argc += 1;
|
|
new_argv = realloc(new_argv, sizeof(*new_argv) * (new_argc + 1));
|
|
memmove(new_argv + 1, new_argv, sizeof(*new_argv) * new_argc);
|
|
new_argv[0] = wine;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
#define PATHSEP ";"
|
|
#else
|
|
#define PATHSEP ":"
|
|
#endif
|
|
|
|
// Build standard library paths for environment variables
|
|
size_t mwcincludes_size = _tcslen(tool_dir) * 3 + 46;
|
|
_TCHAR *MWCIncludes = malloc(sizeof(_TCHAR) * mwcincludes_size);
|
|
_sntprintf(MWCIncludes, mwcincludes_size, _T(
|
|
FMT_TS "/" FMT_TS PATHSEP
|
|
FMT_TS "/" FMT_TS PATHSEP
|
|
FMT_TS "/" FMT_TS),
|
|
tool_dir, _T("include"),
|
|
tool_dir, _T("include/MSL_C"),
|
|
tool_dir, _T("include/MSL_Extras"));
|
|
|
|
size_t mwclibraries_size = _tcslen(tool_dir) + 5;
|
|
_TCHAR *MWLibraries = malloc(sizeof(_TCHAR) * mwclibraries_size);
|
|
_sntprintf(MWLibraries, mwclibraries_size, _T(
|
|
FMT_TS "/" FMT_TS),
|
|
tool_dir, _T("lib"));
|
|
|
|
size_t mwclibraryfiles_size = 107;
|
|
_TCHAR *MWLibraryFiles = malloc(sizeof(_TCHAR) * mwclibraryfiles_size);
|
|
_sntprintf(MWLibraryFiles, mwclibraryfiles_size, _T(
|
|
"MSL_C_NITRO_Ai_LE.a" PATHSEP
|
|
"MSL_Extras_NITRO_Ai_LE.a" PATHSEP
|
|
"MSL_CPP_NITRO_Ai_LE.a" PATHSEP
|
|
"FP_fastI_v5t_LE.a" PATHSEP
|
|
"NITRO_Runtime_Ai_LE.a"));
|
|
|
|
#ifdef _WIN32
|
|
// Set up the environment
|
|
SetEnvironmentVariable(_T("MWCIncludes"), MWCIncludes);
|
|
SetEnvironmentVariable(_T("MWLibraries"), MWLibraries);
|
|
SetEnvironmentVariable(_T("MWLibraryFiles"), MWLibraryFiles);
|
|
|
|
// Execute the tool
|
|
_TCHAR *argv_quoted = win_argv_build((const _TCHAR **)new_argv);
|
|
if (args.wrap_dbg) fprintf(stderr, FMT_TS "\n", argv_quoted);
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
DWORD exitcode;
|
|
ZeroMemory(&si, sizeof(si));
|
|
ZeroMemory(&pi, sizeof(pi));
|
|
si.cb = sizeof(si);
|
|
if (!CreateProcess(new_argv[0], argv_quoted, NULL, NULL, FALSE, 0,
|
|
NULL, NULL, &si, &pi)) {
|
|
fprintf(stderr, PROGRAM_NAME ": CreateProcess failed\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
GetExitCodeProcess(pi.hProcess, &exitcode);
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
if (exitcode) return exitcode;
|
|
free(argv_quoted);
|
|
#else
|
|
// Set up the environment
|
|
setenv("MWCIncludes", MWCIncludes, true);
|
|
setenv("MWLibraries", MWLibraries, true);
|
|
setenv("MWLibraryFiles", MWLibraryFiles, true);
|
|
|
|
#ifndef __CYGWIN__
|
|
// Pass environment variables to Windows if running in WSL
|
|
setenv("WSLENV", "MWCIncludes/p:MWLibraries/p:MWLibraryFiles", true);
|
|
#endif
|
|
|
|
// Execute the tool
|
|
if (args.wrap_dbg) {
|
|
for (int x = 0; x < new_argc; x++) {
|
|
printf(x ? " %s" : "%s", new_argv[x]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
pid_t pid;
|
|
if (posix_spawn(&pid, new_argv[0], NULL, NULL, new_argv, environ) != 0) {
|
|
perror(PROGRAM_NAME ": posix_spawn");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
int exitcode;
|
|
waitpid(pid, &exitcode, 0);
|
|
if (WEXITSTATUS(exitcode)) return WEXITSTATUS(exitcode);
|
|
#endif
|
|
|
|
if (wine) free(wine);
|
|
free(tool);
|
|
free(new_argv);
|
|
free(tool_dir);
|
|
|
|
free(MWCIncludes);
|
|
free(MWLibraries);
|
|
free(MWLibraryFiles);
|
|
|
|
// Fix dependency file if generated
|
|
if (cfg.path_unx && cfg.path_win) {
|
|
_TCHAR *depfile = NULL;
|
|
if (args.M) {
|
|
// Only generated a depfile
|
|
depfile = _tcsdup(args.o);
|
|
} else if (args.MD) {
|
|
// Generating a depfile as a side-effect of compilation
|
|
_TCHAR *out = NULL;
|
|
if (args.o) out = args.o;
|
|
if (args.precompile) out = args.precompile;
|
|
|
|
// Replace filename extension with .d
|
|
if (out) {
|
|
out = _tcsdup(out);
|
|
_TCHAR *dot = _tcsrchr(out, '.');
|
|
if (!dot) dot = _tcsrchr(out, '\0');
|
|
*dot = '\0';
|
|
|
|
size_t len = dot - out + 3;
|
|
out = realloc(out, sizeof(*out) * len);
|
|
_tcscat(out, _T(".d"));
|
|
}
|
|
depfile = out;
|
|
}
|
|
|
|
if (depfile) {
|
|
if (args.wrap_dbg) {
|
|
fprintf(stderr, "dep: " FMT_TS "\n", depfile);
|
|
fprintf(stderr, "path_unx: %s\n", cfg.path_unx);
|
|
fprintf(stderr, "path_win: %s\n", cfg.path_win);
|
|
if (cfg.path_build_unx && cfg.path_build_win) {
|
|
fprintf(stderr, "path_build_unx: %s\n", cfg.path_build_unx);
|
|
fprintf(stderr, "path_build_win: %s\n", cfg.path_build_win);
|
|
}
|
|
}
|
|
fix_depfile(depfile,
|
|
cfg.path_unx, cfg.path_win,
|
|
cfg.path_build_unx, cfg.path_build_win);
|
|
free(depfile);
|
|
}
|
|
}
|
|
|
|
cfg_free(cfg);
|
|
return EXIT_SUCCESS;
|
|
}
|