Commit 69880eb5 authored by Dimitrie O. Paun's avatar Dimitrie O. Paun Committed by Alexandre Julliard

Rewrite winegcc in preparation for merging with winewrap.

We now have comprehensive (and correct) options parsing.
parent 27c0a061
......@@ -17,6 +17,71 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* DESCRIPTION
*
* all options for gcc start with '-' and are for the most part
* single options (no parameters as separate argument).
* There are of course exceptions to this rule, so here is an
* exaustive list of options that do take parameters (potentially)
* as a separate argument:
*
* Compiler:
* -x language
* -o filename
* -aux-info filename
*
* Preprocessor:
* -D name
* -U name
* -I dir
* -MF file
* -MT target
* -MQ target
* (all -i.* arg)
* -include file
* -imacros file
* -idirafter dir
* -iwithprefix dir
* -iwithprefixbefore dir
* -isystem dir
* -A predicate=answer
*
* Linking:
* -l library
* -Xlinker option
* -u symbol
*
* Misc:
* -b machine
* -V version
* -G num (see NOTES below)
*
* NOTES
* There is -G option for compatibility with System V that
* takes no paramters. This makes "-G num" parsing ambiguous.
* This option is synonimous to -shared, and as such we will
* not support it for now.
*
* Special interest options
*
* Assembler Option
* -Wa,option
*
* Linker Options
* object-file-name -llibrary -nostartfiles -nodefaultlibs
* -nostdlib -s -static -static-libgcc -shared -shared-libgcc
* -symbolic -Wl,option -Xlinker option -u symbol
*
* Directory Options
* -Bprefix -Idir -I- -Ldir -specs=file
*
* Target Options
* -b machine -V version
*
* Please note tehat the Target Options are relevant to everything:
* compiler, linker, asssembler, preprocessor.
*
*/
#include "config.h"
......@@ -33,6 +98,25 @@
static int keep_generated = 0;
static strarray *tmp_files;
struct options
{
enum { proc_cc = 0, proc_cpp = 1, proc_pp = 2} processor;
int use_msvcrt;
int nostdinc;
int nostdlib;
int nodefaultlibs;
int gui_app;
int compile_only;
const char* output_name;
strarray* lib_names;
strarray* lib_dirs;
strarray *linker_args;
strarray *compiler_args;
strarray* files;
};
static strarray* build_compile_cmd(struct options* opts);
static int strendswith(const char *str, const char *end)
{
int l = strlen(str);
......@@ -70,180 +154,66 @@ static char *get_temp_file(const char *suffix)
return tmp;
}
static char *get_obj_file(char **argv, int n)
static int is_object_file(const char* arg)
{
char *tmpobj;
strarray* compargv;
int j;
if (strendswith(argv[n], ".o")) return argv[n];
if (strendswith(argv[n], ".a")) return argv[n];
if (strendswith(argv[n], ".res")) return argv[n];
tmpobj = get_temp_file(".o");
compargv = strarray_alloc();
strarray_add(compargv,"winegcc");
strarray_add(compargv, "-c");
strarray_add(compargv, "-o");
strarray_add(compargv, tmpobj);
for (j = 1; j <= n; j++)
if (argv[j]) strarray_add(compargv, argv[j]);
strarray_add(compargv, NULL);
return strendswith(arg, ".o")
|| strendswith(arg, ".a")
|| strendswith(arg, ".res");
}
static const char *get_obj_file(const char* file, struct options* opts)
{
strarray* compargv;
struct options copts;
if (is_object_file(file)) return file;
/* make a copy we so don't change any of the initial stuff */
/* a shallow copy is exactly what we want in this case */
copts = *opts;
copts.processor = proc_cc;
copts.output_name = get_temp_file(".o");
copts.compile_only = 1;
copts.files = strarray_alloc();
strarray_add(copts.files, file);
compargv = build_compile_cmd(&copts);
spawn(compargv);
strarray_free(copts.files);
strarray_free(compargv);
return tmpobj;
return copts.output_name;
}
int main(int argc, char **argv)
static const char* get_translator(struct options* args)
{
strarray *gcc_argv;
int i, j;
int linking = 1, cpp = 0, preprocessor = 0, use_static_linking = 0;
int use_stdinc = 1, use_stdlib = 1, use_msvcrt = 0, gui_app = 0;
tmp_files = strarray_alloc();
atexit(clean_temp_files);
if (strendswith(argv[0], "winecpp")) preprocessor = 1;
else if (strendswith(argv[0], "++")) cpp = 1;
const char* cc = proc_cc; /* keep compiler happy */
for ( i = 1 ; i < argc ; i++ )
{
if (argv[i][0] == '-') /* option */
{
switch (argv[i][1])
switch(args->processor)
{
case 'c': /* compile or assemble */
case 'S': /* generate assembler code */
case 'E': /* preprocess only */
if (argv[i][2] == 0) linking = 0;
break;
case 'M': /* map file generation */
linking = 0;
break;
case 'm':
if (strcmp("-mno-cygwin", argv[i]) == 0)
use_msvcrt = 1;
else if (strcmp("-mwindows", argv[i]) == 0)
gui_app = 1;
else if (strcmp("-mconsole", argv[i]) == 0)
gui_app = 0;
break;
case 'n':
if (strcmp("-nostdinc", argv[i]) == 0)
use_stdinc = 0;
else if (strcmp("-nodefaultlibs", argv[i]) == 0)
use_stdlib = 0;
else if (strcmp("-nostdlib", argv[i]) == 0)
use_stdlib = 0;
break;
case 's':
if (strcmp("-static", argv[i]) == 0) use_static_linking = 1;
break;
case 'v': /* verbose */
if (argv[i][2] == 0) verbose = 1;
break;
case 'W':
if (strncmp("-Wl,", argv[i], 4) == 0)
{
if (strstr(argv[i], "-static"))
use_static_linking = 1;
}
break;
case '-':
if (strcmp("-static", argv[i]+1) == 0)
use_static_linking = 1;
break;
}
}
case proc_pp: cc = "cpp"; break;
case proc_cc: cc = "gcc"; break;
case proc_cpp: cc = "g++"; break;
default: error("Unknown processor");
}
if (preprocessor) linking = 0;
if (use_static_linking) error("Static linking is not supported.");
gcc_argv = strarray_alloc();
if (linking)
{
int has_input_files = 0;
strarray *copy_argv;
/* we need a copy in case we decide to pass args straight to gcc
* and we erase some of the original parameters as we go along
*/
copy_argv = strarray_alloc();
strarray_add(copy_argv, cpp ? "g++" : "gcc");
for( j = 1; j < argc ; j++ )
strarray_add(copy_argv, argv[j]);
strarray_add(gcc_argv, "winewrap");
if (gui_app) strarray_add(gcc_argv, "-mgui");
if (cpp) strarray_add(gcc_argv, "-C");
return cc;
}
for ( j = 1 ; j < argc ; j++ )
{
if ( argv[j][0] == '-' )
{
switch (argv[j][1])
{
case 'L':
case 'o':
strarray_add(gcc_argv, argv[j]);
if (!argv[j][2] && j + 1 < argc)
{
argv[j] = 0;
strarray_add(gcc_argv, argv[++j]);
}
argv[j] = 0;
break;
case 'l':
strarray_add(gcc_argv, argv[j]);
argv[j] = 0;
break;
default:
; /* ignore the rest */
}
}
else
{
strarray_add(gcc_argv, get_obj_file(argv, j));
argv[j] = 0;
has_input_files = 1;
}
}
static strarray* build_compile_cmd(struct options* opts)
{
strarray *gcc_argv = strarray_alloc();
int j;
if (has_input_files)
{
if (use_stdlib && use_msvcrt) strarray_add(gcc_argv, "-lmsvcrt");
if (gui_app) strarray_add(gcc_argv, "-lcomdlg32");
strarray_add(gcc_argv, "-ladvapi32");
strarray_add(gcc_argv, "-lshell32");
}
else
{
/* if we have nothing to process, just forward stuff to gcc */
strarray_free(gcc_argv);
gcc_argv = copy_argv;
}
}
else
{
strarray_add(gcc_argv, preprocessor ? "cpp" : cpp ? "g++" : "gcc");
strarray_add(gcc_argv, get_translator(opts));
if (!preprocessor)
if (opts->processor != proc_pp)
{
strarray_add(gcc_argv, "-fshort-wchar");
strarray_add(gcc_argv, "-fPIC");
}
if (use_stdinc)
if (!opts->nostdinc)
{
if (use_msvcrt)
if (opts->use_msvcrt)
{
strarray_add(gcc_argv, "-I" INCLUDEDIR "/msvcrt");
strarray_add(gcc_argv, "-D__MSVCRT__");
......@@ -285,30 +255,324 @@ int main(int argc, char **argv)
strarray_add(gcc_argv, "-D__int32=int");
strarray_add(gcc_argv, "-D__int64=long long");
for ( j = 1 ; j < argc ; j++ )
{
if (strcmp("-mno-cygwin", argv[j]) == 0)
; /* ignore this option */
else if (strcmp("-mwindows", argv[j]) == 0)
; /* ignore this option */
else if (strcmp("-mconsole", argv[j]) == 0)
; /* ignore this option */
else if (strcmp("-mthreads", argv[j]) == 0)
; /* ignore this option */
else if (strncmp("-Wl,", argv[j], 4) == 0)
; /* do not pass linking options to compiler */
else if (strcmp("-s", argv[j]) == 0)
; /* ignore this option */
/* options we handle explicitly */
if (opts->compile_only)
strarray_add(gcc_argv, "-c");
if (opts->output_name)
strarray_add(gcc_argv, strmake("-o%s", opts->output_name));
/* the rest of the pass-through parameters */
for ( j = 0 ; j < opts->compiler_args->size ; j++ )
strarray_add(gcc_argv, opts->compiler_args->base[j]);
/* last, but not least, the files */
for ( j = 0; j < opts->files->size; j++ )
strarray_add(gcc_argv, opts->files->base[j]);
return gcc_argv;
}
static strarray* build_link_cmd(struct options* opts)
{
strarray *gcc_argv = strarray_alloc();
int j;
strarray_add(gcc_argv, "winewrap");
if (opts->gui_app) strarray_add(gcc_argv, "-mgui");
if (opts->processor == proc_cpp) strarray_add(gcc_argv, "-C");
if (opts->output_name)
strarray_add(gcc_argv, strmake("-o%s", opts->output_name));
else
strarray_add(gcc_argv, "-oa.out");
for ( j = 0 ; j < opts->linker_args->size ; j++ )
strarray_add(gcc_argv, opts->linker_args->base[j]);
for ( j = 0; j < opts->lib_dirs->size; j++ )
strarray_add(gcc_argv, strmake("-L%s", opts->lib_dirs->base[j]));
for ( j = 0; j < opts->lib_names->size; j++ )
strarray_add(gcc_argv, strmake("-l%s", opts->lib_names->base[j]));
if (!opts->nostdlib)
{
if (opts->use_msvcrt) strarray_add(gcc_argv, "-lmsvcrt");
}
if (!opts->nodefaultlibs)
{
if (opts->gui_app) strarray_add(gcc_argv, "-lcomdlg32");
strarray_add(gcc_argv, "-ladvapi32");
strarray_add(gcc_argv, "-lshell32");
}
for ( j = 0; j < opts->files->size; j++ )
strarray_add(gcc_argv, get_obj_file(opts->files->base[j], opts));
return gcc_argv;
}
static strarray* build_forward_cmd(int argc, char **argv, struct options* opts)
{
strarray *gcc_argv = strarray_alloc();
int j;
strarray_add(gcc_argv, get_translator(opts));
for( j = 1; j < argc; j++ )
strarray_add(gcc_argv, argv[j]);
return gcc_argv;
}
/*
* Linker Options
* object-file-name -llibrary -nostartfiles -nodefaultlibs
* -nostdlib -s -static -static-libgcc -shared -shared-libgcc
* -symbolic -Wl,option -Xlinker option -u symbol
*/
static int is_linker_arg(const char* arg)
{
static const char* link_switches[] =
{
"-nostartfiles", "-nodefaultlibs", "-nostdlib", "-s",
"-static", "-static-libgcc", "-shared", "-shared-libgcc", "-symbolic"
};
int j;
switch (arg[1])
{
case 'l':
case 'u':
return 1;
case 'W':
if (strncmp("-Wl,", arg, 4) == 0) return 1;
break;
case 'X':
if (strcmp("-Xlinker", arg) == 0) return 1;
break;
}
for (j = 0; j < sizeof(link_switches)/sizeof(link_switches[0]); j++)
if (strcmp(link_switches[j], arg) == 0) return 1;
return 0;
}
/*
* Target Options
* -b machine -V version
*/
static int is_target_arg(const char* arg)
{
return arg[1] == 'b' || arg[2] == 'V';
}
/*
* Directory Options
* -Bprefix -Idir -I- -Ldir -specs=file
*/
static int is_directory_arg(const char* arg)
{
return arg[1] == 'B' || arg[1] == 'L' || arg[1] == 'I' || strncmp("-specs=", arg, 7) == 0;
}
/*
* MinGW Options
* -mno-cygwin -mwindows -mconsole -mthreads
*/
static int is_mingw_arg(const char* arg)
{
static const char* mingw_switches[] =
{
"-mno-cygwin", "-mwindows", "-mconsole", "-mthreads"
};
int j;
for (j = 0; j < sizeof(mingw_switches)/sizeof(mingw_switches[0]); j++)
if (strcmp(mingw_switches[j], arg) == 0) return 1;
return 0;
}
int main(int argc, char **argv)
{
int i, c, next_is_arg = 0, linking = 1;
int raw_compiler_arg, raw_linker_arg;
const char* option_arg;
struct options opts;
strarray *gcc_argv;
/* setup tmp file removal at exit */
tmp_files = strarray_alloc();
atexit(clean_temp_files);
/* initialize options */
memset(&opts, 0, sizeof(opts));
opts.lib_names = strarray_alloc();
opts.lib_dirs = strarray_alloc();
opts.files = strarray_alloc();
opts.linker_args = strarray_alloc();
opts.compiler_args = strarray_alloc();
/* determine the processor type */
if (strendswith(argv[0], "winecpp")) opts.processor = proc_pp;
else if (strendswith(argv[0], "++")) opts.processor = proc_cpp;
/* parse options */
for ( i = 1 ; i < argc ; i++ )
{
if (argv[i][0] == '-') /* option */
{
/* determine if tihs switch is followed by a separate argument */
option_arg = 0;
switch(argv[i][1])
{
case 'x': case 'o': case 'D': case 'U':
case 'I': case 'A': case 'l': case 'u':
case 'b': case 'V': case 'G':
if (argv[i][2]) option_arg = argv[i] + 2;
else next_is_arg = 1;
break;
case 'i':
next_is_arg = 1;
break;
case 'a':
if (strcmp("-aux-info", argv[i]) == 0)
next_is_arg = 1;
break;
case 'X':
if (strcmp("-Xlinker", argv[i]) == 0)
next_is_arg = 1;
break;
case 'M':
c = argv[i][2];
if (c == 'F' || c == 'T' || c == 'Q')
{
if (argv[i][3]) option_arg = argv[i] + 3;
else next_is_arg = 1;
}
break;
}
if (next_is_arg) option_arg = argv[i+1];
strarray_add(gcc_argv, NULL);
/* determine what options go 'as is' to the linker & the compiler */
raw_compiler_arg = raw_linker_arg = 0;
if (is_linker_arg(argv[i]))
{
raw_linker_arg = 1;
}
else
{
if (is_directory_arg(argv[i]) || is_target_arg(argv[i]))
raw_linker_arg = 1;
raw_compiler_arg = !is_mingw_arg(argv[i]);
}
spawn(gcc_argv);
/* these things we handle explicitly so we don't pass them 'as is' */
if (argv[i][1] == 'l' || argv[i][1] == 'I' || argv[i][1] == 'L')
raw_linker_arg = 0;
if (argv[i][1] == 'c' || argv[i][1] == 'L')
raw_compiler_arg = 0;
if (argv[i][1] == 'o')
raw_compiler_arg = raw_linker_arg = 0;
/* put the arg into the appropriate bucket */
if (raw_linker_arg)
{
strarray_add(opts.linker_args, argv[i]);
if (next_is_arg && (i + 1 < argc))
strarray_add(opts.linker_args, argv[i + 1]);
}
if (raw_compiler_arg)
{
strarray_add(opts.compiler_args, argv[i]);
if (next_is_arg && (i + 1 < argc))
strarray_add(opts.compiler_args, argv[i + 1]);
}
/* do a bit of semantic analysis */
switch (argv[i][1])
{
case 'c': /* compile or assemble */
if (argv[i][2] == 0) opts.compile_only = 1;
/* fall through */
case 'S': /* generate assembler code */
case 'E': /* preprocess only */
if (argv[i][2] == 0) linking = 0;
break;
case 'l':
strarray_add(opts.lib_names, option_arg);
break;
case 'L':
strarray_add(opts.lib_dirs, option_arg);
break;
case 'M': /* map file generation */
linking = 0;
break;
case 'm':
if (strcmp("-mno-cygwin", argv[i]) == 0)
opts.use_msvcrt = 1;
else if (strcmp("-mwindows", argv[i]) == 0)
opts.gui_app = 1;
else if (strcmp("-mconsole", argv[i]) == 0)
opts.gui_app = 0;
break;
case 'n':
if (strcmp("-nostdinc", argv[i]) == 0)
opts.nostdinc = 1;
else if (strcmp("-nodefaultlibs", argv[i]) == 0)
opts.nodefaultlibs = 1;
else if (strcmp("-nostdlib", argv[i]) == 0)
opts.nostdlib = 1;
break;
case 'o':
opts.output_name = option_arg;
break;
case 's':
if (strcmp("-static", argv[i]) == 0)
linking = -1;
break;
case 'v':
if (argv[i][2] == 0) verbose = 1;
break;
case 'W':
if (strncmp("-Wl,", argv[i], 4) == 0)
{
if (strstr(argv[i], "-static"))
linking = -1;
}
break;
case '-':
if (strcmp("-static", argv[i]+1) == 0)
linking = -1;
break;
}
/* skip the next token if it's an argument */
if (next_is_arg) i++;
}
else
{
strarray_add(opts.files, argv[i]);
}
}
if (opts.processor == proc_pp) linking = 0;
if (linking == -1) error("Static linking is not supported.");
strarray_free(gcc_argv);
if (opts.files->size == 0)
gcc_argv = build_forward_cmd(argc, argv, &opts);
else if (linking)
gcc_argv = build_link_cmd(&opts);
else
gcc_argv = build_compile_cmd(&opts);
spawn(gcc_argv);
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment