mame/src/osd/windows/vconv.c
Oliver Stöneberg 42f03a6943 vconv: documented all disabled warnings / added VS2013 define (nw)
also removed some warnings, that don't happen anymore and don't like
like they should be disabled
2015-01-21 16:10:17 +01:00

591 lines
20 KiB
C

// license:BSD-3-Clause
// copyright-holders:Aaron Giles
//============================================================
//
// vconv.c - VC++ parameter conversion code
//
//============================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
//============================================================
// CONSTANTS
//============================================================
#define PRINT_COMMAND_LINE 0
#define VS6 0x00060000
#define VS7 0x00070000
#define VS71 0x0007000a
#define VS2005 0x00080000
#define VS2008 0x00090000
#define VS2010 0x00100000
#define VS2012 0x00110000
#define VS2013 0x00120000
//============================================================
// TYPE DEFINITIONS
//============================================================
typedef struct
{
DWORD vc_version;
const char *gcc_option;
const char *vc_option;
} translation_info;
//============================================================
// TRANSLATION TABLES
//============================================================
static const translation_info gcc_translate[] =
{
{ 0, "-D*", "/D*" },
{ 0, "-U*", "/U*" },
{ 0, "-I*", "/I*" },
{ 0, "-o*", "~*" },
{ 0, "-include*", "/FI*" },
{ 0, "-c", "/c~/Fo" },
{ 0, "-E", "/c~/E >" },
{ 0, "-S", "/c~/Fa" },
{ VS7, "-O0", "/Od /GS /Oi" },
{ 0, "-O0", "/Od" },
{ 0, "-O1", "/O2" },
{ 0, "-O2", "/O2" },
{ 0, "-O3", "/Ox" },
{ 0, "-Os", "/O1" },
{ 0, "-g*", "/Zi" },
{ VS2005, "-fno-strict-aliasing", "" }, // deprecated in VS2005
{ 0, "-fno-strict-aliasing", "/Oa" },
{ 0, "-fno-omit-frame-pointer", "" },
{ 0, "-fomit-frame-pointer", "" },
{ 0, "-Werror", "/WX" },
// warning C4003: not enough actual parameters for macro 'xxx'
// warning C4018: 'x' : signed/unsigned mismatch
// warning C4061: enumerator 'xxx' in switch of enum 'xxx' is not explicitly handled by a case label
// warning C4100: 'xxx' : unreferenced formal parameter
// warning C4127: conditional expression is constant
// warning C4131: 'xxx' : uses old-style declarator
// warning C4141: 'xxx' : used more than once
// warning C4146: unary minus operator applied to unsigned type, result still unsigned
// warning C4150: deletion of pointer to incomplete type 'xxx'; no destructor called
// warning C4189: 'xxx' : local variable is initialized but not referenced
// warning C4201: nonstandard extension used : nameless struct/union
// warning C4242: 'x' : conversion from 'xxx' to 'xxx', possible loss of data
// warning C4244: 'argument' : conversion from 'xxx' to 'xxx', possible loss of data
// warning C4250: 'xxx' : inherits 'xxx' via dominance
// warning C4255: 'xxx' : no function prototype given: converting '()' to '(void)'
// warning C4296: 'x' : expression is always false
// warning C4310: cast truncates constant value
// warning C4324: 'xxx' : structure was padded due to __declspec(align())
// warning C4347: behavior change: 'xxx' is called instead of 'xxx' // obsolete VS2005 - VS2010 only
// warning C4435: 'xxx' : Object layout under /vd2 will change due to virtual base 'xxx'
// warning C4510: 'xxx' : default constructor could not be generated
// warning C4512: 'xxx' : assignment operator could not be generated
// warning C4514: 'xxx' : unreferenced inline function has been removed
// warning C4619: #pragma warning : there is no warning number 'xxx'
// warning C4571: Informational: catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught
// warning C4610: struct 'xxx' can never be instantiated - user defined constructor required
// warning C4625: 'xxx' : copy constructor could not be generated because a base class copy constructor is inaccessible or deleted
// warning C4626: 'xxx' : assignment operator could not be generated because a base class assignment operator is inaccessible or deleted
// warning C4668: 'xxx' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
// warning C4702: unreachable code
// warning C4706: assignment within conditional expression
// warning C4710: 'xxx' : function not inlined
// warning C4711: function 'xxx' selected for automatic inline expansion // optimized only
// warning C4805: 'x' : unsafe mix of type 'xxx' and type 'xxx' in operation
// warning C4820: 'xxx' : 'x' bytes padding added after data member 'xxx'
/wd4619
{ VS7, "-Wall", "/Wall /W4 /wd4003 /wd4018 /wd4061 /wd4100 /wd4127 /wd4131 /wd4141 /wd4146 /wd4150 /wd4189 /wd4201 /wd4242 /wd4244 /wd4250 /wd4255 /wd4296 /wd4310 /wd4324 /wd4347 /wd4435 /wd4510 /wd4512 /wd4514 /wd4571 /wd4610 /wd4619 /wd4625 /wd4626 /wd4668 /wd4702 /wd4706 /wd4710 /wd4711 /wd4805 /wd4820" },
{ 0, "-Wall", "/W0" },
{ VS7, "-Wno-unused", "/wd4100 /wd4101 /wd4102 /wd4505" },
{ 0, "-Wno-sign-compare", "/wd4365 /wd4389 /wd4245 /wd4388" },
{ 0, "-W*", "" },
{ VS2005, "-march=*", "" }, // deprecated in VS2005
{ 0, "-march=pentium", "/G5" },
{ 0, "-march=pentiumpro", "/G6" },
{ 0, "-march=pentium3", "/G6" },
{ 0, "-march=pentium-m", "/G6" },
{ 0, "-march=athlon", "/G7" },
{ 0, "-march=pentium4", "/G7" },
{ 0, "-march=athlon64", "/G7" },
// TODO: the x64 compiler doesn't have the /arch:SSE*
{ VS71, "-msse", "/arch:SSE" },
{ 0, "-msse", "" },
{ VS71, "-msse2", "/arch:SSE2" },
{ 0, "-msse2", "" },
{ 0, "-msse3", "" },
{ VS2010, "-mavx", "/arch:AVX" },
// TODO: introduced in Visual Studio 2013 Update 2, version 12.0.34567.1
//{ 0, "-mavx2", "/arch:AVX2" },
{ 0, "-mwindows", "" },
{ 0, "-mno-cygwin", "" },
{ 0, "-std=gnu89", "" },
{ 0, "-std=gnu++98", "/TP" },
{ 0, "-pipe", "" },
{ 0, "-x", "" },
{ 0, "c++", "" },
{ 0, "-flto", "/GL" },
{ 0, "-fno-optimize-sibling-calls", "" },
{ VS2005, "-fopenmp", "/openmp" },
{ 0 }
};
static const translation_info ld_translate[] =
{
{ VS2008, "-lbufferoverflowu", "" },
{ 0, "-l*", "*.lib" },
{ 0, "-o*", "/out:*" },
{ 0, "-Wl,-Map,*", "/map:*" },
{ 0, "-Wl,--allow-multiple-definition", "/force:multiple" },
{ 0, "-Wl,--warn-common", "" },
{ 0, "-mno-cygwin", "" },
{ 0, "-s", "" },
{ 0, "-WO", "" },
{ 0, "-mconsole", "/subsystem:console" },
{ 0, "-mwindows", "/subsystem:windows" },
{ 0, "-municode", "" },
{ 0, "-static-libgcc", "" },
{ 0, "-static-libstdc++", "" },
{ 0, "-shared", "/dll" },
{ 0, "-flto", "/LTCG" },
{ 0 }
};
static const translation_info ar_translate[] =
{
{ 0, "-cr", "" },
{ 0, "/LTCG", "/LTCG" },
{ 0 }
};
static const translation_info windres_translate[] =
{
{ 0, "-D*", "/D*" },
{ 0, "-U*", "/U*" },
{ 0, "-I*", "/I*" },
{ 0, "--include-dir*", "/I*" },
{ 0, "-o*", "/fo*" },
{ 0, "-O*", "" },
{ 0, "-i*", "*" },
{ 0 }
};
//============================================================
// GLOBALS
//============================================================
static char command_line[32768];
//============================================================
// get_exe_version
//============================================================
static DWORD get_exe_version(const char *executable)
{
char path[MAX_PATH];
void *version_info;
DWORD version_info_size, dummy;
void *sub_buffer;
UINT sub_buffer_size;
VS_FIXEDFILEINFO *info;
DWORD product_version;
char sub_block[2] = { '\\', '\0' };
// try to locate the executable
if (!SearchPath(NULL, executable, NULL, sizeof(path) / sizeof(path[0]), path, NULL))
{
fprintf(stderr, "Cannot find %s\n", executable);
exit(-100);
}
// determine the size of the version info
version_info_size = GetFileVersionInfoSize(path, &dummy);
if (version_info_size == 0)
{
switch(GetLastError())
{
case ERROR_RESOURCE_TYPE_NOT_FOUND:
fprintf(stderr, "\"%s\" does not contain version info; this is probably not a MSVC executable\n", path);
break;
default:
fprintf(stderr, "GetFileVersionInfoSize() failed\n");
break;
}
exit(-100);
}
// allocate the memory; using GlobalAlloc() so that we do not
// unintentionally uses malloc() overrides
version_info = GlobalAlloc(GMEM_FIXED, version_info_size);
if (!version_info)
{
fprintf(stderr, "Out of memory\n");
exit(-100);
}
// retrieve the version info
if (!GetFileVersionInfo(path, 0, version_info_size, version_info))
{
GlobalFree(version_info);
fprintf(stderr, "GetFileVersionInfo() failed\n");
exit(-100);
}
// extract the VS_FIXEDFILEINFO from the version info
if (!VerQueryValue(version_info, sub_block, &sub_buffer, &sub_buffer_size))
{
GlobalFree(version_info);
fprintf(stderr, "VerQueryValue() failed\n");
exit(-100);
}
info = (VS_FIXEDFILEINFO *) sub_buffer;
product_version = info->dwProductVersionMS;
GlobalFree(version_info);
return product_version;
}
//============================================================
// build_command_line
//============================================================
// TODO: VS2012 and up enable SSE2 instructions by default for x86 - we should make older versions consistent with this
static void build_command_line(int argc, char *argv[])
{
const translation_info *transtable;
const char *executable;
const char *outstring = "";
char *dst = command_line;
int output_is_first = 0;
int icl_compile = 0;
int parampos = 2;
int param;
DWORD exe_version = 0;
// if no parameters, show usage
if (argc < 2)
{
fprintf(stderr, "Usage:\n vconv {gcc|ar|ld} [-icl] [param [...]]\n");
exit(0);
}
if (!strcmp(argv[2], "-icl"))
{
icl_compile = 1;
parampos = 3;
}
// first parameter determines the type
if (!strcmp(argv[1], "gcc"))
{
transtable = gcc_translate;
if (!icl_compile)
{
executable = "cl.exe";
dst += sprintf(dst, "cl /nologo ");
}
else
{
executable = "icl.exe";
dst += sprintf(dst, "icl /nologo");
/* ICL 14.0 generates more warnings than MSVC, for now turn them off */
dst += sprintf(dst, " /Qwd9 "); /* remark #9: nested comment is not allowed */
dst += sprintf(dst, " /Qwd82 "); /* remark #82: storage class is not first */
dst += sprintf(dst, " /Qwd111 "); /* remark #111: statement is unreachable */
dst += sprintf(dst, " /Qwd128 "); /* remark #128: loop is not reachable */
dst += sprintf(dst, " /Qwd177 "); /* remark #177: function "xxx" was declared but never referenced */
dst += sprintf(dst, " /Qwd181 "); /* remark #181: argument of type "UINT32={unsigned int}" is incompatible with format "%d", expecting argument of type "int" */
dst += sprintf(dst, " /Qwd185 "); /* remark #185: dynamic initialization in unreachable code */
dst += sprintf(dst, " /Qwd280 "); /* remark #280: selector expression is constant */
dst += sprintf(dst, " /Qwd344 "); /* remark #344: typedef name has already been declared (with same type) */
dst += sprintf(dst, " /Qwd411 "); /* remark #411: class "xxx" defines no constructor to initialize the following */
dst += sprintf(dst, " /Qwd869 "); /* remark #869: parameter "xxx" was never referenced */
dst += sprintf(dst, " /Qwd2545 "); /* remark #2545: empty dependent statement in "else" clause of if - statement */
dst += sprintf(dst, " /Qwd2553 "); /* remark #2553: nonstandard second parameter "TCHAR={WCHAR = { __wchar_t } } **" of "main", expected "char *[]" or "char **" extern "C" int _tmain(int argc, TCHAR **argv) */
dst += sprintf(dst, " /Qwd2557 "); /* remark #2557: comparison between signed and unsigned operands */
dst += sprintf(dst, " /Qwd3280 "); /* remark #3280: declaration hides member "attotime::seconds" (declared at line 126) static attotime from_seconds(INT32 seconds) { return attotime(seconds, 0); } */
dst += sprintf(dst, " /Qwd170 "); /* error #170: pointer points outside of underlying object */
dst += sprintf(dst, " /Qwd188 "); /* error #188: enumerated type mixed with another type */
dst += sprintf(dst, " /Qwd63 "); /* warning #63: shift count is too large */
dst += sprintf(dst, " /Qwd177 "); /* warning #177: label "xxx" was declared but never referenced */
dst += sprintf(dst, " /Qwd186 "); /* warning #186: pointless comparison of unsigned integer with zero */
dst += sprintf(dst, " /Qwd488 "); /* warning #488: template parameter "_FunctionClass" is not used in declaring the parameter types of function template "device_delegate<_Signature>::device_delegate<_FunctionClass>(delegate<_Signature>: */
dst += sprintf(dst, " /Qwd1478 "); /* warning #1478: function "xxx" (declared at line yyy of "zzz") was declared deprecated */
dst += sprintf(dst, " /Qwd1879 "); /* warning #1879: unimplemented pragma ignored */
dst += sprintf(dst, " /Qwd3291 "); /* warning #3291: invalid narrowing conversion from "double" to "int" */
// icl: command line warning #10120: overriding '/O2' with '/Od'
}
}
else if (!strcmp(argv[1], "windres"))
{
transtable = windres_translate;
executable = "rc.exe";
dst += sprintf(dst, "rc ");
}
else if (!strcmp(argv[1], "ld"))
{
transtable = ld_translate;
if (!icl_compile)
{
executable = "link.exe";
dst += sprintf(dst, "link /nologo /debug ");
}
else
{
executable = "xilink.exe";
dst += sprintf(dst, "xilink /nologo /debug ");
}
}
else if (!strcmp(argv[1], "ar"))
{
transtable = ar_translate;
if (!icl_compile)
{
executable = "link.exe";
dst += sprintf(dst, "link /lib /nologo ");
outstring = "/out:";
output_is_first = 1;
}
else
{
executable = "xilink.exe";
dst += sprintf(dst, "xilink /lib /nologo ");
outstring = "/out:";
output_is_first = 1;
}
}
else
{
fprintf(stderr, "Error: unknown translation type '%s'\n", argv[1]);
exit(-100);
}
// identify the version number of the EXE
if (!icl_compile)
exe_version = get_exe_version(executable);
else
exe_version = 0x00110000; // assume this for ICL
// special cases
if (!icl_compile && !strcmp(executable, "cl.exe")) {
if (exe_version >= 0x00070000)
dst += sprintf(dst, "/wd4025 ");
// fixes -j compiles with VS2013
if (exe_version >= 0x000C0000)
dst += sprintf(dst, "/FS ");
}
// iterate over parameters
for (param = parampos; param < argc; param++)
{
const char *src = argv[param];
int firstchar = src[0];
int srclen = strlen(src);
int matched = FALSE;
int i;
// find a match
for (i = 0; !matched && transtable[i].gcc_option != NULL; i++)
{
const char *compare = transtable[i].gcc_option;
const char *replace;
int j;
// check version number
if (exe_version < transtable[i].vc_version)
continue;
// find a match
for (j = 0; j < srclen; j++)
if (src[j] != compare[j])
break;
// if we hit an asterisk, we're ok
if (compare[j] == '*')
{
// if this is the end of the parameter, use the next one
if (src[j] == 0)
src = argv[++param];
else
src += j;
// copy the replacement up to the asterisk
replace = transtable[i].vc_option;
while (*replace && *replace != '*')
{
if (*replace == '~')
{
dst += sprintf(dst, "%s", outstring);
replace++;
}
else
*dst++ = *replace++;
}
// if we have an asterisk in the replacement, copy the rest of the source
if (*replace == '*')
{
int addquote = (strchr(src, ' ') != NULL);
if (addquote)
*dst++ = '"';
while (*src)
{
*dst++ = (*src == '/') ? '\\' : *src;
src++;
}
if (addquote)
*dst++ = '"';
// if there's stuff after the asterisk, copy that
replace++;
while (*replace)
*dst++ = *replace++;
}
// append a final space
*dst++ = ' ';
matched = TRUE;
}
// if we hit the end, we're also ok
else if (compare[j] == 0 && j == srclen)
{
// copy the replacement up to the tilde
replace = transtable[i].vc_option;
while (*replace && *replace != '~')
*dst++ = *replace++;
// if we hit a tilde, set the new output
if (*replace == '~')
outstring = replace + 1;
// append a final space
*dst++ = ' ';
matched = TRUE;
}
// else keep looking
}
// if we didn't match, process
if (!matched)
{
// warn if we missed a parameter
if (transtable[i].gcc_option == NULL && firstchar == '-')
fprintf(stderr, "Unable to match parameter '%s'\n", src);
// otherwise, assume it's a filename and copy translating slashes
// it can also be a Windows-specific option which is passed through unscathed
else if (firstchar != '-')
{
int dotrans = (*src != '/');
// if the output filename is implicitly first, append the out parameter
if (output_is_first)
{
dst += sprintf(dst, "%s", outstring);
output_is_first = 0;
}
// now copy the rest of the string
while (*src)
{
*dst++ = (dotrans && *src == '/') ? '\\' : *src;
src++;
}
*dst++ = ' ';
}
}
}
// trim remaining spaces and NULL terminate
while (dst > command_line && dst[-1] == ' ')
dst--;
*dst = 0;
}
//============================================================
// main
//============================================================
int main(int argc, char *argv[])
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
DWORD exitcode;
int uses_redirection, in_quotes, i;
static const char cmd_prefix[] = "cmd.exe /c ";
// build the new command line
build_command_line(argc, argv);
// do we use redirection? if so, use cmd.exe
uses_redirection = FALSE;
in_quotes = FALSE;
for (i = 0; command_line[i]; i++)
{
if (command_line[i] == '\"')
in_quotes = !in_quotes;
if (!in_quotes && strchr("|<>", command_line[i]))
uses_redirection = TRUE;
}
if (uses_redirection)
{
memmove(command_line + strlen(cmd_prefix), command_line, strlen(command_line) + 1);
memcpy(command_line, cmd_prefix, strlen(cmd_prefix));
}
if (PRINT_COMMAND_LINE)
printf("%s\n", command_line);
// create the process information structures
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
memset(&pi, 0, sizeof(pi));
// create and execute the process
if (!CreateProcess(NULL, command_line, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) ||
pi.hProcess == INVALID_HANDLE_VALUE)
return -101;
// block until done and fetch the error code
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, &exitcode);
// clean up the handles
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
// return the child's error code
return exitcode;
}