/* * Copyright (c) 2002 Gus Baldauf (gus@picturel.com) * Copyright (c) 2015 Martin Whitaker * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * iverilog-vpi.c * * this program provides the functionality of iverilog-vpi.sh under Windows */ #include #include #include #include #include #include static void setup_ivl_environment(void); static void assign(char **ptr, char *str); /* The compile options: compiler, flags, etc. are in here */ #include "config.h" /* pointers to global strings */ static struct global_strings { char *pCCSRC; /* list of C source files (*.c) */ char *pCXSRC; /* list of C++ source files (*.cc, *.cpp) */ char *pOBJ; /* list of object files */ char *pLIB; /* list of library files */ char *pINCS; /* list of include directories */ char *pDEFS; /* list of definitions */ char *pOUT; /* output file name (.vpi extension), if 0 length then no source files specified */ char *pMINGW; /* path to MinGW directory */ char *pIVL; /* path to IVL directory */ char *pCCFLAGS; /* compiler flags for compiling C source files */ char *pCXFLAGS; /* compiler flags for compiling C++ source files */ char *pLDLIBS; /* linker flags for final linking stage */ char *pCCNAME; /* base name of compiler */ char *pLD; /* what to use for a linker */ } gstr; static void deInitDynString(char *str) { free(str); } /* when finished, free allocated memory and return error code */ static void myExit(int exitVal) { deInitDynString(gstr.pCCSRC); deInitDynString(gstr.pCXSRC); deInitDynString(gstr.pOBJ); deInitDynString(gstr.pLIB); deInitDynString(gstr.pINCS); deInitDynString(gstr.pDEFS); deInitDynString(gstr.pOUT); deInitDynString(gstr.pMINGW); deInitDynString(gstr.pIVL); deInitDynString(gstr.pCCFLAGS); deInitDynString(gstr.pCXFLAGS); deInitDynString(gstr.pLDLIBS); deInitDynString(gstr.pCCNAME); deInitDynString(gstr.pLD); exit(exitVal); } /* display usage summary and exit */ static void usage(void) { fprintf(stderr, "usage: iverilog-vpi" IVERILOG_SUFFIX " [options] [src and obj files]...\n"); fprintf(stderr, " or iverilog-vpi" IVERILOG_SUFFIX " -mingw=dir\n"); myExit(1); } static void initDynString(char **str) { *str = (char *) malloc(1); if (!*str) { fprintf(stderr, "error: out of memory\n"); myExit(4); } *str[0] = 0; } /* initialize dynamic memory buffers */ static void init(void) { char *ptr; initDynString(&gstr.pCCSRC); initDynString(&gstr.pCXSRC); initDynString(&gstr.pOBJ); initDynString(&gstr.pLIB); initDynString(&gstr.pINCS); initDynString(&gstr.pDEFS); initDynString(&gstr.pOUT); initDynString(&gstr.pMINGW); initDynString(&gstr.pIVL); initDynString(&gstr.pCCFLAGS); initDynString(&gstr.pCXFLAGS); initDynString(&gstr.pLDLIBS); initDynString(&gstr.pCCNAME); initDynString(&gstr.pLD); /* Get the base name of the C compiler. */ assign(&gstr.pCCNAME, IVERILOG_VPI_CC); ptr = strchr(gstr.pCCNAME, ' '); if (ptr != NULL) *ptr = '\0'; /* By default use the C compiler to link the programs. */ assign(&gstr.pLD, IVERILOG_VPI_CC); } /* return true if "str" is terminated with with "end", case insensitive */ static int endsIn (char *end, char *str) { char *ext; if (strlen(end) >= strlen(str)) return 0; ext = str + (strlen(str) - strlen(end)); return stricmp(end, ext) ? 0 : 1; } /* return true if "str" begins with "prefix", case insensitive */ static int startsWith (char *prefix, char *str) { if (strlen(prefix) >= strlen(str)) return 0; return strnicmp(prefix, str, strlen(prefix)) ? 0 : 1; } /* append "app" to "ptr", allocating memory as needed */ /* if count is zero, then copy all characters of "app" */ static void appendn (char **ptr, char *app, size_t count) { char *nptr = (char *) realloc(*ptr, strlen(*ptr) + (count ? count : strlen(app)) + 1); if (nptr == NULL) { fprintf(stderr, "error: out of memory\n"); free(*ptr); myExit(4); } *ptr = nptr; if (count) strncat(*ptr, app, count); else strcat(*ptr, app); } /* append "app" to "ptr", allocating memory as needed */ static void append (char **ptr, char *app) { appendn(ptr, app, 0); } /* if the string does not end with a backslash, add one */ static void appendBackSlash(char **str) { if ((*str)[strlen(*str)-1] != '\\') append(str, "\\"); } /* copy count characters of "str" to "ptr", allocating memory as needed */ /* if count is zero, then copy all characters of "str" */ static void assignn (char **ptr, char *str, size_t count) { char *nptr = (char *) realloc(*ptr, (count ? count : strlen(str)) + 1); if (nptr == NULL) { fprintf(stderr, "error: out of memory\n"); free(*ptr); myExit(4); } *ptr = nptr; if (count) { strncpy(*ptr, str, count); (*ptr)[count] = 0; } else strcpy(*ptr, str); } /* copy count characters of "str" to "ptr", allocating memory as needed */ static void assign (char **ptr, char *str) { assignn(ptr, str, 0); } /* get a copy of a Icarus Verilog registry string key */ static int GetRegistryKey(char *key, char **value) { long lrv; HKEY hkKey; char *regKeyBuffer; DWORD regKeyType, regKeySize; lrv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Icarus Verilog", 0, KEY_QUERY_VALUE, &hkKey); if (lrv != ERROR_SUCCESS) return 0; lrv = RegQueryValueEx(hkKey, key, NULL, ®KeyType, NULL, ®KeySize); if ((lrv != ERROR_SUCCESS) || (regKeyType != REG_SZ) || (!regKeySize)) { lrv = RegCloseKey(hkKey); return 0; } regKeyBuffer = (char *) malloc(regKeySize+1); if (!regKeyBuffer) { lrv = RegCloseKey(hkKey); fprintf(stderr, "error: out of memory\n"); myExit(4); } regKeyBuffer[regKeySize] = 0; /* makes sure there is a trailing NULL */ /* This needs an unsigned char *, but for MinGW the char is signed. */ lrv = RegQueryValueEx(hkKey, key, NULL, ®KeyType, (unsigned char *) regKeyBuffer, ®KeySize); if ((lrv != ERROR_SUCCESS) || (regKeyType != REG_SZ) || (!regKeySize)) { lrv = RegCloseKey(hkKey); free(regKeyBuffer); return 0; } RegCloseKey(hkKey); assign(value, regKeyBuffer); free(regKeyBuffer); return 1; } /* store a copy of a Icarus Verilog registry string key */ static void SetRegistryKey(char *key, char *value) { long lrv; HKEY hkKey; DWORD res; lrv = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\Icarus Verilog", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkKey, &res); if (lrv != ERROR_SUCCESS) { char message[1024]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, lrv, LANG_USER_DEFAULT, message, sizeof(message), NULL); fprintf(stderr, "error: couldn't write to registry - %s\n", message); if (lrv == ERROR_ACCESS_DENIED) { fprintf(stderr, " try running as administrator\n"); } return; } /* This needs an unsigned char *, but for MinGW the char is signed. */ RegSetValueEx(hkKey, key, 0, REG_SZ, (unsigned char *) value, strlen(value)+1); RegCloseKey(hkKey); printf("info: storing %s in Windows' registry entry\n", value); printf(" HKEY_LOCAL_MACHINE\\Software\\Icarus Verilog\\%s\n", key); } /* parse the command line, assign results to global variable strings */ static int parse(int argc, char *argv[]) { int idx, srcFileCnt=0; char dot_c_ext[] = ".c"; char dot_cc_ext[] = ".cc"; char dot_cpp_ext[] = ".cpp"; char dot_o_ext[] = ".o"; char name_option[] = "--name="; char lib_option[] = "-l"; char inc_option[] = "-I"; char mingw_option[] = "-mingw="; char def_option[] = "-D"; if (argc == 1) return 0; for (idx=1; idx