ZDS-II Object file relocations
tools/zds/zdsgen.c: Remove this program. It should have been a simpler way to manage ZDS-II compiler and assember differences. However, the compiler arguments needed to pass through too many layers of bash command line modifications and, as a result, it was not possible to retain quotes on critical strings. This approch was abandoned for an alternative approach. boards/z80/ez80/scripts/eZ80_Config.mk: Add definitions to move the object files as necessary. This seems to work well and is implemented for both native and Cygwin Windows build -- but only for the Z20x.
This commit is contained in:
parent
d74ca3ab82
commit
75be4c5677
5 changed files with 51 additions and 736 deletions
|
|
@ -47,57 +47,63 @@ endef
|
|||
# lie in a lower directory, but lies in the current directory and is
|
||||
# handled within COMPILE and ASSEMBLE.
|
||||
|
||||
define RMOBJS
|
||||
$(call DELFILE, $(1))
|
||||
$(call DELFILE, $(subst .obj,.lst,$(1)))
|
||||
$(call DELFILE, $(subst .obj,.src,$(1)))
|
||||
endef
|
||||
|
||||
ifeq ($(CONFIG_WINDOWS_NATIVE),y)
|
||||
|
||||
define CONDMOVE
|
||||
$(Q) if not exist $1 (move /Y $2 $3)
|
||||
endef
|
||||
|
||||
define MVOBJS
|
||||
$(call CONDMOVE, $(1),$(subst .obj,.src,$(2)),$(subst .obj,.src,$(3)))
|
||||
$(call CONDMOVE, $(1),$(subst .obj,.lst,$(2)),$(subst .obj,.lst,$(3)))
|
||||
$(call CONDMOVE, $(1),$(2),$(3))
|
||||
endef
|
||||
|
||||
define COMPILE
|
||||
$(call DELFILE, $(2))
|
||||
$(call RMOBJS, $(2))
|
||||
$(Q) $(CC) $(CFLAGS) $($(strip $(1))_CFLAGS) ${shell echo $(1) | sed -e "s/\//\\/g"}
|
||||
if not exist $(2) $(call MOVEFILE, $(subst .c,.obj,$(1)), $(2))
|
||||
$(call MVOBJS, $(2), $(subst .c,.obj,$(notdir $(1))), $(2))
|
||||
endef
|
||||
|
||||
define ASSEMBLE
|
||||
$(call DELFILE, $(2))
|
||||
$(call RMOBJS, $(2))
|
||||
$(Q) $(AS) $(AFLAGS) $($(strip $(1))_AFLAGS) ${shell echo $(1) | sed -e "s/\//\\/g"}
|
||||
if not exist $(2) $(call MOVEFILE, $(subst .asm,.obj,$(1)), $(2))
|
||||
$(call MVOBJS, $(2), $(subst .asm,.obj,$(notdir $(1))), $(2))
|
||||
endef
|
||||
|
||||
else
|
||||
|
||||
define CONDMOVE
|
||||
$(Q) if [ ! -e $(1) ]; then mv -f $(2) $(3) ; fi
|
||||
endef
|
||||
|
||||
define MVOBJS
|
||||
$(call CONDMOVE, $(1),$(subst .obj,.src,$(2)),$(subst .obj,.src,$(3)))
|
||||
$(call CONDMOVE, $(1),$(subst .obj,.lst,$(2)),$(subst .obj,.lst,$(3)))
|
||||
$(call CONDMOVE, $(1),$(2),$(3))
|
||||
endef
|
||||
|
||||
define COMPILE
|
||||
$(call DELFILE, $(2))
|
||||
$(call RMOBJS, $(2))
|
||||
$(Q) $(CC) $(CFLAGS) $($(strip $(1))_CFLAGS) `cygpath -w "$(1)"`
|
||||
$(Q) ( \
|
||||
__rename=`basename $(2)` ;\
|
||||
if [ ! -e $${__rename} ] ; then \
|
||||
__src=`basename $(1) | cut -d'.' -f1` ; \
|
||||
__dest=`echo $(2) | sed -e "s/.obj//g"` ; \
|
||||
mv -f $${__src}.obj $(2) ; \
|
||||
mv -f $${__src}.lst $${__dest}.lst ; \
|
||||
mv -f $${__src}.src $${__dest}.src ; \
|
||||
fi ; \
|
||||
)
|
||||
$(call MVOBJS, $(2), $(subst .c,.obj,$(notdir $(1))), $(2))
|
||||
endef
|
||||
|
||||
define ASSEMBLE
|
||||
$(call DELFILE, $(2))
|
||||
$(call RMOBJS, $(2))
|
||||
$(Q) $(AS) $(AFLAGS) $($(strip $(1))_AFLAGS) `cygpath -w "$(1)"`
|
||||
$(Q) ( \
|
||||
__rename=`basename $(2)` ; \
|
||||
if [ ! -e $${__rename} ] ; then \
|
||||
__src=`basename $(1) | cut -d'.' -f1` ; \
|
||||
__dest=`echo $(2) | sed -e "s/.obj//g"` ; \
|
||||
mv -f $${__src}.obj $(2) ; \
|
||||
mv -f $${__src}.lst $${__dest}.lst ; \
|
||||
mv -f $${__src}.src $${__dest}.src ; \
|
||||
fi ; \
|
||||
)
|
||||
$(call MVOBJS, $(2), $(subst .asm,.obj,$(notdir $(1))), $(2))
|
||||
endef
|
||||
|
||||
endif
|
||||
|
||||
define MOVEOBJ
|
||||
$(call MOVEFILE, "$(1).obj", "$(2)$(DELIM)$(1).obj")
|
||||
$(call MOVEFILE, "$(1).lst", "$(2)$(DELIM)$(1).lst")
|
||||
$(call MOVEFILE, "$(1).src", "$(2)$(DELIM)$(1).src")
|
||||
endef
|
||||
|
||||
# ARCHIVE will move a list of object files into the library. This is
|
||||
|
|
@ -142,4 +148,5 @@ endef
|
|||
define CLEAN
|
||||
$(Q) rm -f *.obj *.src *.lib *.hex *.lod *.lst
|
||||
endef
|
||||
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ endif
|
|||
|
||||
# Targets
|
||||
|
||||
all: zdsar.exe zdsgen.exe
|
||||
all: zdsar.exe
|
||||
default: all
|
||||
.PHONY: clean
|
||||
|
||||
|
|
@ -64,11 +64,6 @@ CFLAGS += -DHAVE_STRTOK_C=1
|
|||
zdsar.exe: zdsar.c
|
||||
$(Q) $(HOSTCC) $(HOSTCFLAGS) -o zdsar.exe zdsar.c
|
||||
|
||||
# zdsgen - Wrapper for the ZDS-II compiler and assembler
|
||||
|
||||
zdsgen.exe: zdsgen.c
|
||||
$(Q) $(HOSTCC) $(HOSTCFLAGS) -o zdsgen.exe zdsgen.c
|
||||
|
||||
clean:
|
||||
@rm -f *.o *.a *.dSYM *~ .*.swp
|
||||
@rm -f zdsar zdsar.exe
|
||||
|
|
|
|||
|
|
@ -7,5 +7,6 @@ tools/zds/zdsar.c: This is a wrapper around the ZDS_II librarian. It
|
|||
the build files but it also improves performance and, more importantly,i
|
||||
provides a common solution for the Windows native build case.
|
||||
|
||||
This tool should work with all ZDS-II based platforms including z8, zNeo, and ez80.
|
||||
These tools should work with all ZDS-II based platforms including z8, zNeo,
|
||||
and ez80.
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ static char g_initial_wd[MAX_PATH]; /* Initial working directory */
|
|||
static char g_path[MAX_PATH]; /* Buffer for expanding paths */
|
||||
static char g_objpath[MAX_PATH]; /* Temporary for path generation */
|
||||
#ifdef HOST_CYGWIN
|
||||
static char g_expand[MAX_EXPAND]; /* Temporary for expanded path */
|
||||
static char g_expand[MAX_EXPAND]; /* Temporary for quoted path */
|
||||
static char g_dequoted[MAX_PATH]; /* Temporary for de-quoted path */
|
||||
static char g_hostpath[MAX_PATH]; /* Temporary for host path conversions */
|
||||
#endif
|
||||
|
|
@ -231,7 +231,7 @@ static void append(char **base, char *str)
|
|||
*base = newbase;
|
||||
}
|
||||
|
||||
static const char *do_expand(const char *argument)
|
||||
static const char *quote_backslash(const char *argument)
|
||||
{
|
||||
#ifdef HOST_CYGWIN
|
||||
const char *src;
|
||||
|
|
@ -254,7 +254,7 @@ static const char *do_expand(const char *argument)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Already expanded? */
|
||||
/* Already quoted? */
|
||||
|
||||
if (*src == '\\')
|
||||
{
|
||||
|
|
@ -767,10 +767,10 @@ static void do_archive(void)
|
|||
|
||||
if (g_arflags != NULL)
|
||||
{
|
||||
const char *expanded;
|
||||
const char *quoted;
|
||||
|
||||
expanded = do_expand(g_arflags);
|
||||
cmdlen += strlen(expanded);
|
||||
quoted = quote_backslash(g_arflags);
|
||||
cmdlen += strlen(quoted);
|
||||
|
||||
if (cmdlen >= MAX_BUFFER)
|
||||
{
|
||||
|
|
@ -779,7 +779,7 @@ static void do_archive(void)
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
strcat(g_command, expanded);
|
||||
strcat(g_command, quoted);
|
||||
}
|
||||
|
||||
/* Add each object file. This loop will continue until each path has been
|
||||
|
|
@ -789,7 +789,7 @@ static void do_archive(void)
|
|||
nobjects = 0;
|
||||
while ((object = strtok_r(objects, " ", &lasts)) != NULL)
|
||||
{
|
||||
const char *expanded;
|
||||
const char *quoted;
|
||||
const char *converted;
|
||||
|
||||
/* Set objects to NULL. This will force strtok_r to move from the
|
||||
|
|
@ -887,8 +887,8 @@ static void do_archive(void)
|
|||
|
||||
pathlen = 4; /* For =-+ and terminator */
|
||||
|
||||
expanded = do_expand(g_path);
|
||||
pathlen += strlen(expanded);
|
||||
quoted = quote_backslash(g_path);
|
||||
pathlen += strlen(quoted);
|
||||
|
||||
/* Get the full length */
|
||||
|
||||
|
|
@ -899,14 +899,14 @@ static void do_archive(void)
|
|||
{
|
||||
fprintf(stderr, "ERROR: object argument is too long [%d/%d]: "
|
||||
"%s=-+%s\n",
|
||||
totallen, MAX_BUFFER, g_libname, expanded);
|
||||
totallen, MAX_BUFFER, g_libname, quoted);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Append the next librarian command */
|
||||
|
||||
pathlen = snprintf(&g_command[cmdlen], MAX_BUFFER - cmdlen, "%s=-+%s",
|
||||
g_libname, expanded);
|
||||
g_libname, quoted);
|
||||
cmdlen += pathlen;
|
||||
|
||||
/* Terminate early if we have a LOT files in the command line */
|
||||
|
|
|
|||
|
|
@ -1,688 +0,0 @@
|
|||
/****************************************************************************
|
||||
* tools/zds/zdsgen.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <libgen.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HOST_CYGWIN
|
||||
# include <sys/cygwin.h>
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define MAX_BUFFER (4096)
|
||||
#define MAX_EXPAND (2048)
|
||||
|
||||
/* MAX_PATH might be defined in stdlib.h */
|
||||
|
||||
#if !defined(MAX_PATH)
|
||||
# define MAX_PATH (512)
|
||||
#endif
|
||||
|
||||
/* NAME_MAX is typically defined in limits.h */
|
||||
|
||||
#if !defined(NAME_MAX)
|
||||
|
||||
/* FILENAME_MAX might be defined in stdio.h */
|
||||
|
||||
# if defined(FILENAME_MAX)
|
||||
# define NAME_MAX FILENAME_MAX
|
||||
# else
|
||||
|
||||
/* MAXNAMELEN might be defined in dirent.h */
|
||||
|
||||
# include <dirent.h>
|
||||
# if defined(MAXNAMLEN)
|
||||
# define NAME_MAX MAXNAMLEN
|
||||
# else
|
||||
|
||||
/* Lets not let a silly think like this stop us... just make something up */
|
||||
|
||||
# define NAME_MAX 256
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Name of the host. The ZDS-II toolchain runs only on Windows. Therefore,
|
||||
* the only options are (1) Windows native, or (2) Cygwin or environments
|
||||
* that derive for Cygwin (like MSYS2).
|
||||
*/
|
||||
|
||||
#define WINSEPARATOR '\\'
|
||||
|
||||
#if defined(HOST_NATIVE)
|
||||
# define SEPARATOR '\\'
|
||||
# define HOSTNAME "Native" /* Windows native */
|
||||
#elif defined(HOST_CYGWIN)
|
||||
# define SEPARATOR '/'
|
||||
# define HOSTNAME "Cywgin" /* Cygwin or MSYS under Windows */
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
enum slashmode_e
|
||||
{
|
||||
MODE_FSLASH = 0,
|
||||
MODE_BSLASH = 1,
|
||||
MODE_DBLBACK = 2
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static char *g_exe = NULL; /* Executable, either compiler or assembler */
|
||||
static char *g_flags = NULL; /* Assembler or compiler flags */
|
||||
static char *g_infile = NULL; /* The input source file */
|
||||
static char *g_outfile = NULL; /* The output object file */
|
||||
static int g_debug = 0;
|
||||
|
||||
static char g_command[MAX_BUFFER]; /* The command to be executed */
|
||||
static char g_path[MAX_PATH]; /* Temporary for path generation */
|
||||
#ifdef HOST_CYGWIN
|
||||
static char g_expand[MAX_EXPAND]; /* Temporary for path expansion */
|
||||
static char g_dequoted[MAX_PATH]; /* Temporary for dequoting paths */
|
||||
static char g_hostpath[MAX_PATH]; /* Temporary for host path conversions */
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/* MinGW does not seem to provide strtok_r */
|
||||
|
||||
#ifndef HAVE_STRTOK_R
|
||||
static char *my_strtok_r(char *str, const char *delim, char **saveptr)
|
||||
{
|
||||
char *pbegin;
|
||||
char *pend = NULL;
|
||||
|
||||
/* Decide if we are starting a new string or continuing from
|
||||
* the point we left off.
|
||||
*/
|
||||
|
||||
if (str)
|
||||
{
|
||||
pbegin = str;
|
||||
}
|
||||
else if (saveptr && *saveptr)
|
||||
{
|
||||
pbegin = *saveptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find the beginning of the next token */
|
||||
|
||||
for (;
|
||||
*pbegin && strchr(delim, *pbegin) != NULL;
|
||||
pbegin++);
|
||||
|
||||
/* If we are at the end of the string with nothing
|
||||
* but delimiters found, then return NULL.
|
||||
*/
|
||||
|
||||
if (!*pbegin)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find the end of the token */
|
||||
|
||||
for (pend = pbegin + 1;
|
||||
*pend && strchr(delim, *pend) == NULL;
|
||||
pend++);
|
||||
|
||||
/* pend either points to the end of the string or to
|
||||
* the first delimiter after the string.
|
||||
*/
|
||||
|
||||
if (*pend)
|
||||
{
|
||||
/* Turn the delimiter into a null terminator */
|
||||
|
||||
*pend++ = '\0';
|
||||
}
|
||||
|
||||
/* Save the pointer where we left off and return the
|
||||
* beginning of the token.
|
||||
*/
|
||||
|
||||
if (saveptr)
|
||||
{
|
||||
*saveptr = pend;
|
||||
}
|
||||
|
||||
return pbegin;
|
||||
}
|
||||
|
||||
#undef strtok_r
|
||||
#define strtok_r my_strtok_r
|
||||
#endif
|
||||
|
||||
static void append(char **base, char *str)
|
||||
{
|
||||
char *oldbase;
|
||||
char *newbase;
|
||||
int alloclen;
|
||||
|
||||
oldbase = *base;
|
||||
if (!oldbase)
|
||||
{
|
||||
newbase = strdup(str);
|
||||
if (!newbase)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Failed to strdup %s\n", str);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
alloclen = strlen(oldbase) + strlen(str) + sizeof((char) ' ') +
|
||||
sizeof((char) '\0');
|
||||
newbase = (char *)malloc(alloclen);
|
||||
if (!newbase)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Failed to allocate %d bytes\n", alloclen);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
snprintf(newbase, alloclen, "%s %s", oldbase, str);
|
||||
free(oldbase);
|
||||
}
|
||||
|
||||
*base = newbase;
|
||||
}
|
||||
|
||||
static void show_usage(const char *progname, const char *msg, int exitcode)
|
||||
{
|
||||
if (msg)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "%s:\n", msg);
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "%s [--debug] <EXE> -- <FLAGS> -- <infile> <outfile>\n",
|
||||
progname);
|
||||
fprintf(stderr, "%s [--help]\n\n", progname);
|
||||
fprintf(stderr, "Where:\n");
|
||||
fprintf(stderr, " <EXE>\n");
|
||||
fprintf(stderr, " A variable number of arguments that define how to"
|
||||
" execute the code\n");
|
||||
fprintf(stderr, " generation tool (either the compiler or the "
|
||||
"assembler)\n");
|
||||
fprintf(stderr, " <FLAGS>\n");
|
||||
fprintf(stderr, " The compiler compilation flags\n");
|
||||
fprintf(stderr, " <inile>\n");
|
||||
fprintf(stderr, " One or more C files whose dependencies will be "
|
||||
"checked. Each file is expected\n");
|
||||
fprintf(stderr, " to reside in the current directory\n");
|
||||
fprintf(stderr, " <outfile>\n");
|
||||
fprintf(stderr, " The name of the binary output file to be "
|
||||
"generated\n");
|
||||
fprintf(stderr, " --debug\n");
|
||||
fprintf(stderr, " Enable script debug\n");
|
||||
fprintf(stderr, " --help\n");
|
||||
fprintf(stderr, " Shows this message and exits\n");
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
static void parse_args(int argc, char **argv)
|
||||
{
|
||||
char *args = NULL;
|
||||
int argidx;
|
||||
|
||||
/* Parse arguments */
|
||||
|
||||
for (argidx = 1; argidx < argc; argidx++)
|
||||
{
|
||||
if (strcmp(argv[argidx], "--") == 0)
|
||||
{
|
||||
g_exe = g_flags;
|
||||
g_flags = args;
|
||||
args = NULL;
|
||||
}
|
||||
else if (strcmp(argv[argidx], "--debug") == 0)
|
||||
{
|
||||
g_debug++;
|
||||
}
|
||||
else if (strcmp(argv[argidx], "--help") == 0)
|
||||
{
|
||||
show_usage(argv[0], NULL, EXIT_SUCCESS);
|
||||
}
|
||||
else if (g_exe == NULL)
|
||||
{
|
||||
append(&args, argv[argidx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The penultimate argument should be the input source file */
|
||||
|
||||
if (argidx < argc)
|
||||
{
|
||||
g_infile = argv[argidx];
|
||||
argidx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
show_usage(argv[0], "ERROR: Missing input source file",
|
||||
EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* The last argument should be the output object file */
|
||||
|
||||
if (argidx < argc)
|
||||
{
|
||||
g_outfile = argv[argidx];
|
||||
argidx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
show_usage(argv[0], "ERROR: Missing output object file",
|
||||
EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (g_debug)
|
||||
{
|
||||
fprintf(stderr, "SELECTIONS\n");
|
||||
fprintf(stderr, " Host Environ : [%s]\n",
|
||||
HOSTNAME);
|
||||
fprintf(stderr, " Tool : [%s]\n",
|
||||
g_exe ? g_exe : "(None)");
|
||||
fprintf(stderr, " Tool flags : [%s]\n",
|
||||
g_flags ? g_flags : "(None)");
|
||||
fprintf(stderr, " Source file : [%s]\n",
|
||||
g_infile ? g_infile : "(None)");
|
||||
fprintf(stderr, " Object file : [%s]\n",
|
||||
g_outfile ? g_outfile : "(None)");
|
||||
}
|
||||
|
||||
/* Check for required parameters */
|
||||
|
||||
if (g_exe == NULL)
|
||||
{
|
||||
show_usage(argv[0], "ERROR: No compiler specified", EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (g_infile == NULL)
|
||||
{
|
||||
/* Don't report an error -- this happens normally in some configurations */
|
||||
|
||||
printf("# No source files specified\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *do_expand(const char *argument)
|
||||
{
|
||||
#ifdef HOST_CYGWIN
|
||||
const char *src;
|
||||
char *dest;
|
||||
int len;
|
||||
|
||||
src = argument;
|
||||
dest = g_expand;
|
||||
len = 0;
|
||||
|
||||
while (*src && len < MAX_EXPAND)
|
||||
{
|
||||
if (*src == '\\')
|
||||
{
|
||||
/* Copy backslash */
|
||||
|
||||
*dest++ = *src++;
|
||||
if (++len >= MAX_EXPAND)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Already expanded? */
|
||||
|
||||
if (*src == '\\')
|
||||
{
|
||||
/* Yes... just copy all consecutive backslashes */
|
||||
|
||||
do
|
||||
{
|
||||
*dest++ = *src++;
|
||||
if (++len >= MAX_EXPAND)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (*src == '\\');
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. expeand */
|
||||
|
||||
*dest++ = '\\';
|
||||
if (++len >= MAX_EXPAND)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest++ = *src++;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*src)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Truncated during expansion string is "
|
||||
"too long [%lu/%u]\n",
|
||||
(unsigned long)strlen(argument), MAX_EXPAND);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
*dest = '\0';
|
||||
return g_expand;
|
||||
#else
|
||||
return argument;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HOST_CYGWIN
|
||||
static bool dequote_path(const char *winpath)
|
||||
{
|
||||
char *dest = g_dequoted;
|
||||
const char *src = winpath;
|
||||
int len = 0;
|
||||
bool quoted = false;
|
||||
|
||||
while (*src && len < MAX_PATH)
|
||||
{
|
||||
if (src[0] != '\\' || (src[1] != ' ' && src[1] != '(' && src[1] != ')'))
|
||||
{
|
||||
*dest++ = *src;
|
||||
len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
quoted = true;
|
||||
}
|
||||
|
||||
src++;
|
||||
}
|
||||
|
||||
if (*src || len >= MAX_PATH)
|
||||
{
|
||||
fprintf(stderr, "# ERROR: Path truncated\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
*dest = '\0';
|
||||
return quoted;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If using Cygwin with a Window's Toolchain, then we have to convert the
|
||||
* POSIX path to a Windows or POSIX path.
|
||||
*/
|
||||
|
||||
#ifdef HOST_CYGWIN
|
||||
static const char *convert_path(const char *path, cygwin_conv_path_t what)
|
||||
{
|
||||
const char *retptr;
|
||||
ssize_t size;
|
||||
ssize_t ret;
|
||||
bool quoted;
|
||||
|
||||
quoted = dequote_path(path);
|
||||
if (quoted)
|
||||
{
|
||||
retptr = g_hostpath;
|
||||
}
|
||||
else
|
||||
{
|
||||
retptr = &g_hostpath[1];
|
||||
}
|
||||
|
||||
size = cygwin_conv_path(what | CCP_RELATIVE, g_dequoted, NULL, 0);
|
||||
if (size > (MAX_PATH - 3))
|
||||
{
|
||||
fprintf(stderr, "# ERROR: POSIX path too long: %lu\n",
|
||||
(unsigned long)size);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = cygwin_conv_path(what | CCP_RELATIVE, g_dequoted,
|
||||
&g_hostpath[1], MAX_PATH - 3);
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf(stderr, "# ERROR: cygwin_conv_path '%s' failed: %s\n",
|
||||
g_dequoted, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (quoted)
|
||||
{
|
||||
size++;
|
||||
g_hostpath[0] = '"';
|
||||
g_hostpath[size] = '"';
|
||||
}
|
||||
|
||||
g_hostpath[size + 1] = '\0';
|
||||
return retptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *convert_path_windows(const char *path)
|
||||
{
|
||||
#ifdef HOST_CYGWIN
|
||||
return convert_path(path, CCP_POSIX_TO_WIN_A);
|
||||
#else
|
||||
return path;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *convert_path_posix(const char *path)
|
||||
{
|
||||
#ifdef HOST_CYGWIN
|
||||
return convert_path(path, CCP_WIN_A_TO_POSIX);
|
||||
#else
|
||||
return path;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void do_generate(void)
|
||||
{
|
||||
const char *hostpath;
|
||||
const char *toolpath;
|
||||
const char *expanded;
|
||||
int cmdlen;
|
||||
int ret;
|
||||
|
||||
/* First remove any existing .obj, lst, and .src files at the path of the
|
||||
* new output object file.
|
||||
*/
|
||||
|
||||
#warning Missing logic
|
||||
|
||||
/* Copy the tool path into the command buffer. NOTE that
|
||||
* convert_path_posix() is a no-op in Windows native mode.
|
||||
*/
|
||||
|
||||
hostpath = convert_path_posix(g_exe);
|
||||
cmdlen = strlen(hostpath);
|
||||
if (cmdlen + 1 >= MAX_BUFFER)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Tool string is too long [%d/%d]: %s\n",
|
||||
cmdlen, MAX_BUFFER, hostpath);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
strcpy(g_command, hostpath);
|
||||
|
||||
/* Followed by a space */
|
||||
|
||||
if (cmdlen + 2 >= MAX_BUFFER)
|
||||
{
|
||||
fprintf(stderr, "ERROR: No room for whitespace [%d/%d]: %d\n",
|
||||
cmdlen, MAX_BUFFER, 2);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
g_command[cmdlen] = ' ';
|
||||
g_command[cmdlen + 1] = '\0';
|
||||
cmdlen++;
|
||||
|
||||
/* Copy the tool flags into the command buffer */
|
||||
|
||||
if (g_flags)
|
||||
{
|
||||
expanded = do_expand(g_flags);
|
||||
cmdlen += strlen(expanded);
|
||||
|
||||
if (cmdlen + 1 >= MAX_BUFFER)
|
||||
{
|
||||
fprintf(stderr, "ERROR: CFLAG string is too long [%d/%d]: %s\n",
|
||||
cmdlen, MAX_BUFFER, g_flags);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
strcat(g_command, expanded);
|
||||
}
|
||||
|
||||
/* Add a space */
|
||||
|
||||
if (cmdlen + 2 >= MAX_BUFFER)
|
||||
{
|
||||
fprintf(stderr, "ERROR: No room for whitespace [%d/%d]: %d\n",
|
||||
cmdlen, MAX_BUFFER, 2);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
g_command[cmdlen] = ' ';
|
||||
g_command[cmdlen + 1] = '\0';
|
||||
cmdlen++;
|
||||
|
||||
/* Add the input source file.NOTE that convert_path_windows() is a no-op
|
||||
* in Windows native mode.
|
||||
*/
|
||||
|
||||
toolpath = convert_path_windows(g_infile);
|
||||
expanded = do_expand(toolpath);
|
||||
cmdlen += strlen(expanded);
|
||||
|
||||
if (cmdlen + 1 >= MAX_BUFFER)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Input source file name is too long [%d/%d]: %s\n",
|
||||
cmdlen, MAX_BUFFER, expanded);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
strcat(g_command, expanded);
|
||||
|
||||
/* Generate the output object file */
|
||||
|
||||
if (g_debug)
|
||||
{
|
||||
fprintf(stderr, "Executing: %s\n", g_command);
|
||||
}
|
||||
|
||||
ret = system(g_command);
|
||||
#ifdef WEXITSTATUS
|
||||
if (ret < 0 || WEXITSTATUS(ret) != 0)
|
||||
{
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR: system failed: %s\n", strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: %s failed: %d\n", g_exe, WEXITSTATUS(ret));
|
||||
}
|
||||
|
||||
fprintf(stderr, " command: %s\n", g_command);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR: system failed: %s\n", strerror(errno));
|
||||
fprintf(stderr, " command: %s\n", g_command);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We don't really know that the command succeeded... Let's
|
||||
* assume that it did
|
||||
*/
|
||||
|
||||
/* Now, check if we have to move or rename the output gerated by the
|
||||
* compiler/assembly. We can determine this by the just checking if
|
||||
* the selected object file now exists after we deleted it above. In
|
||||
* that case we need to do nothing.
|
||||
*
|
||||
* In the case where we are moving the object file to sub-directory
|
||||
* (like bin/), then we don't need to do that either. That will be
|
||||
* handled by the MOVEOBJ define.
|
||||
*
|
||||
* REVISIT: Do we want to remove the MOVEOBJ macro? We should do
|
||||
* that.
|
||||
*
|
||||
* Otherwise, rename the output object file.
|
||||
*/
|
||||
|
||||
#warning Missing logic
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
/* Parse command line parameters */
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
/* Generate the object file from the source. */
|
||||
|
||||
do_generate();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue