aboutsummaryrefslogblamecommitdiffstats
path: root/erts/test/utils/gccifier.c
blob: a6b8a340a1a8bd505c3ed5f2d3fc2dda195c8bf1 (plain) (tree)








































































































































































































































                                                                            


                                            


















































































                                                                           
/*
 * %CopyrightBegin%
 * 
 * Copyright Ericsson AB 2004-2009. All Rights Reserved.
 * 
 * The contents of this file are subject to the Erlang Public License,
 * Version 1.1, (the "License"); you may not use this file except in
 * compliance with the License. You should have received a copy of the
 * Erlang Public License along with this software. If not, it can be
 * retrieved online at http://www.erlang.org/.
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 * 
 * %CopyrightEnd%
 *
 */

/*
 * A compiler wrapper that translate (some) gcc command line arguments
 * to the Visual C++ compiler and (of course) the gcc compiler. It also
 * makes some changes in the command line arguments when debug compiling.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>


#if !defined(__WIN32__)
#define USE_EXEC
#include <unistd.h>
#endif


#ifdef __WIN32__
#define EOL "\r\n"
#else
#define EOL "\n"
#endif

#define ARGS_INCR 20

static char *prog;

typedef struct {
    char **vec;
    int no;
    int ix;
    int chars;
} args_t;

static void
enomem(void)
{
    fprintf(stderr, "%s: Out of memory%s", prog, EOL);
    exit(1);
}

static void
save_arg(args_t *args, char *arg1, ...)
{
    char *carg;
    va_list argp;

    va_start(argp, arg1);
    carg = arg1;
    while (carg) {
	if (args->no <= args->ix) {
	    args->vec = (char **) (args->no
				   ? realloc((void *) args->vec,
					     (sizeof(char *)
					      *(args->no + ARGS_INCR + 1)))
				   : malloc((sizeof(char *)
					     *(args->no + ARGS_INCR + 1))));
	    if (!args->vec)
		enomem();
	    args->no += ARGS_INCR;
	}
	args->vec[args->ix++] = carg;
	args->chars += strlen(carg);
	carg = va_arg(argp, char *);
    }
    args->vec[args->ix++] = " ";
    args->chars++;
    va_end(argp);
}

static int
is_prefix(char *prfx, char **str)
{
    int i;
    for (i = 0; prfx[i] && (*str)[i]; i++) {
	if (prfx[i] != (*str)[i])
	    return 0;
    }
    if (!prfx[i]) {
	*str = &(*str)[i];
	return 1;
    }
    return 0;
}

static void
cpy(char **dst, char *src)
{
    int i;
    for (i = 0; src[i]; i++)
	(*dst)[i] = src[i];
    *dst = &(*dst)[i];
}

typedef enum {
    STDLIB_NONE,
    STDLIB_MD,
    STDLIB_ML,
    STDLIB_MT
} stdlib_t;

int
main(int argc, char *argv[])
{
    int res;
    int i;
    size_t cmd_len;
    char *cmd;
    char *cmd_end;
    char *cc = NULL;
    args_t args = {0};
    int is_debug = 0;
    int is_purify = 0;
    int is_quantify = 0;
    int is_purecov = 0;
#ifdef __WIN32__
    int is_shared = 0;
    stdlib_t stdlib = STDLIB_NONE;
    char *shared_flag = "";
    char *stdlib_flag = "";
    int have_link_args = 0;
    args_t link_args = {0};

#define CHECK_FIRST_LINK_ARG						\
	if (!have_link_args) {						\
	    save_arg(&link_args, "-link", NULL);			\
	    have_link_args = 1;						\
	}
#else /* #ifdef __WIN32__ */
#define CHECK_FIRST_LINK_ARG
#endif /* #ifdef __WIN32__ */

   prog = argv[0];


    for (i = 1; i < argc; i++) {
	char *arg = argv[i];
	if (is_prefix("-CC", &arg)) {
	    cc = arg;
	}
	else if (is_prefix("-O", &arg)) {
	    if (!is_debug)
		save_arg(&args, argv[i], NULL);
	}
	else if (strcmp("-DDEBUG", arg) == 0) {
	    save_arg(&args, arg, NULL);
#ifdef __WIN32__
	set_debug:
#endif
	    if (!is_debug) {
		int j;
		is_debug = 1;
#ifdef __WIN32__
		save_arg(&args, "-Z7", NULL);
		CHECK_FIRST_LINK_ARG;
		save_arg(&link_args, "-debug", NULL);
		save_arg(&link_args, "-pdb:none", NULL);
#endif
		for (j = 0; j < args.ix; j++) {
		    char *tmp_arg = args.vec[j];
		    if (is_prefix("-O", &tmp_arg))
			args.vec[j] = "";
		}
	    }
	}
	else if (strcmp("-DPURIFY", arg) == 0) {
	    save_arg(&args, arg, NULL);
	    is_purify = 1;
	}
	else if (strcmp("-DQUANTIFY", arg) == 0) {
	    save_arg(&args, arg, NULL);
	    is_quantify = 1;
	}
	else if (strcmp("-DPURECOV", arg) == 0) {
	    save_arg(&args, arg, NULL);
	    is_purecov = 1;
	}
#ifdef __WIN32__
	else if (strcmp("-g", arg) == 0) {
	    goto set_debug;
	}
	else if (strcmp("-MD", arg) == 0)
	    stdlib = STDLIB_MD;
	else if (strcmp("-MDd", arg) == 0) {
	    stdlib = STDLIB_MD;
	    goto set_debug;
	}
	else if (strcmp("-ML", arg) == 0)
	    stdlib = STDLIB_ML;
	else if (strcmp("-MLd", arg) == 0) {
	    stdlib = STDLIB_ML;
	    goto set_debug;
	}
	else if (strcmp("-MT", arg) == 0)
	    stdlib = STDLIB_MT;
	else if (strcmp("-MTd", arg) == 0) {
	    stdlib = STDLIB_MT;
	    goto set_debug;
	}
	else if (strcmp("-shared", arg) == 0 || strcmp("-LD", arg) == 0)
	    is_shared = 1;
	else if (strcmp("-LDd", arg) == 0) {
	    is_shared = 1;
	    goto set_debug;
	}
	else if (strcmp("-Wall", arg) == 0) {
	    save_arg(&args, "-W3", NULL);
	}
	else if (is_prefix("-L", &arg)) {
	    CHECK_FIRST_LINK_ARG;
	    save_arg(&link_args, "-libpath:", arg, NULL);
	}
	else if (strcmp("-link",arg) == 0) {
	  CHECK_FIRST_LINK_ARG;
	}
#endif /* #ifdef __WIN32__ */
	else if (is_prefix("-l", &arg)) {
	    CHECK_FIRST_LINK_ARG;
	    if (is_debug && strcmp("ethread", arg) == 0)
		arg = "ethread.debug";
	    else if (is_purify && strcmp("ethread", arg) == 0)
		arg = "ethread.purify";
	    else if (is_quantify && strcmp("ethread", arg) == 0)
		arg = "ethread.quantify";
	    else if (is_purecov && strcmp("ethread", arg) == 0)
		arg = "ethread.purecov";
#ifdef __WIN32__
	    else if (strcmp("socket", arg) == 0)
		arg = "ws2_32";
	    save_arg(&link_args, arg, ".lib", NULL);
#else
	    save_arg(&args, "-l", arg, NULL);
#endif
	}
	else
	    save_arg(&args, argv[i], NULL);
    }

    if (!cc || !cc[0]) {
	fprintf(stderr, "%s: Missing compulsory -CC flag%s", prog, EOL);
	exit(1);
    }

    cmd_len = strlen(cc) + 1 + args.chars + 1;

#ifdef __WIN32__
    if (is_shared)
	shared_flag = is_debug ? "-LDd " : "-LD ";
    switch (stdlib) {
    case STDLIB_MD: stdlib_flag = is_debug ? "-MDd " : "-MD ";	break;
    case STDLIB_ML: stdlib_flag = is_debug ? "-MLd " : "-ML ";	break;
    case STDLIB_MT: stdlib_flag = is_debug ? "-MTd " : "-MT ";	break;
    case STDLIB_NONE:						break;
    }

    cmd_len += strlen(shared_flag) + strlen(stdlib_flag) + link_args.chars;
#endif

    cmd = (char *) malloc(sizeof(char) * cmd_len);

    if (!cmd)
	enomem();
    cmd_end = cmd;
    cpy(&cmd_end, cc);
    cpy(&cmd_end, " ");
#ifdef __WIN32__
    cpy(&cmd_end, stdlib_flag);
    cpy(&cmd_end, shared_flag);
#endif
    for (i = 0; i < args.ix; i++)
	cpy(&cmd_end, args.vec[i]);
#ifdef __WIN32__
    for (i = 0; i < link_args.ix; i++)
	cpy(&cmd_end, link_args.vec[i]);
#endif
    *cmd_end = '\0';

    printf("==> %s%s", cmd, EOL);
    fflush(stdout);

#ifdef USE_EXEC
    (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
    perror(NULL);
    res = 1;
#else
    res = system(cmd);
#endif

    free((void *) args.vec);
#ifdef __WIN32__
    free((void *) link_args.vec);
#endif
    free((void *) cmd);

    if (res < 0)
	res = 1;
    return res;
}