2 * Copyright (c) 2002 Gus Baldauf (gus@picturel.com)
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
23 * this program provides the functionality of iverilog-vpi.sh under Win32
30 #include <sys/types.h>
35 /* Macros used for compiling and linking */
37 #define IVERILOG_VPI_CC "gcc" /* no .exe extension */
38 #define IVERILOG_VPI_CXX "gcc" /* no .exe extension */
39 #define IVERILOG_VPI_CFLAGS "-O" /* -I appended later */
40 #define IVERILOG_VPI_LD "gcc" /* no .exe extension */
41 #define IVERILOG_VPI_LDFLAGS "-shared -Wl,--enable-auto-image-base"
42 #define IVERILOG_VPI_LDLIBS "-lveriuser -lvpi" /* -L prepended later */
44 /* pointers to global strings */
46 static struct global_strings
{
47 char *pCCSRC
; /* list of C source files */
48 char *pCXSRC
; /* list of C++ source files */
49 char *pOBJ
; /* list of object files */
50 char *pLIB
; /* list of library files */
51 char *pOUT
; /* output file name (.vpi extension), if 0 length then no source files specified */
52 char *pMINGW
; /* path to MinGW directory */
53 char *pIVL
; /* path to IVL directory */
54 char *pCFLAGS
; /* CFLAGS option */
55 char *pLDLIBS
; /* LDLIBS option */
56 char *pNewPath
; /* new PATH environment variable setting */
60 static void deInitDynString(char *str
)
65 /* when finished, free allocated memory and return error code */
67 static void myExit(int exitVal
)
69 deInitDynString(gstr
.pCCSRC
);
70 deInitDynString(gstr
.pCXSRC
);
71 deInitDynString(gstr
.pOBJ
);
72 deInitDynString(gstr
.pLIB
);
73 deInitDynString(gstr
.pOUT
);
74 deInitDynString(gstr
.pMINGW
);
75 deInitDynString(gstr
.pIVL
);
76 deInitDynString(gstr
.pCFLAGS
);
77 deInitDynString(gstr
.pLDLIBS
);
78 deInitDynString(gstr
.pNewPath
);
83 /* display usage summary and exit */
87 fprintf(stderr
,"usage: iverilog-vpi [--name=name] [-llibrary] [-mingw=dir] [-ivl=dir] sourcefile...\n");
88 fprintf(stderr
," or iverilog-vpi -mingw=dir\n");
89 fprintf(stderr
," or iverilog-vpi -ivl=dir\n");
93 static void initDynString(char **str
)
95 *str
= (char *) malloc(1);
98 fprintf(stderr
,"error: out of memory\n");
105 /* initialize dynamic memory buffers */
109 initDynString(&gstr
.pCCSRC
);
110 initDynString(&gstr
.pCXSRC
);
111 initDynString(&gstr
.pOBJ
);
112 initDynString(&gstr
.pLIB
);
113 initDynString(&gstr
.pOUT
);
114 initDynString(&gstr
.pMINGW
);
115 initDynString(&gstr
.pIVL
);
116 initDynString(&gstr
.pCFLAGS
);
117 initDynString(&gstr
.pLDLIBS
);
118 initDynString(&gstr
.pNewPath
);
121 /* return true if "str" is terminated with with "end", case insensitive */
123 static int endsIn (char *end
, char *str
)
127 if (strlen(end
) >= strlen(str
))
130 ext
= str
+ (strlen(str
) - strlen(end
));
132 return stricmp(end
,ext
) ? 0 : 1;
135 /* return true if "str" begins with "prefix", case insensitive */
137 static int startsWith (char *prefix
, char *str
)
139 if (strlen(prefix
) >= strlen(str
))
142 return strnicmp(prefix
,str
,strlen(prefix
)) ? 0 : 1;
145 /* append "app" to "ptr", allocating memory as needed */
146 /* if count is zero, then copy all characters of "app" */
148 static void appendn (char **ptr
, char *app
, int count
)
150 *ptr
= (char *) realloc(*ptr
,strlen(*ptr
)+(count
?count
:strlen(app
))+1);
153 fprintf(stderr
,"error: out of memory\n");
158 strncat(*ptr
,app
,count
);
163 /* append "app" to "ptr", allocating memory as needed */
165 static void append (char **ptr
, char *app
)
170 /* if the string does not end with a backslash, add one */
172 static void appendBackSlash(char **str
)
174 if ((*str
)[strlen(*str
)-1] != '\\')
178 /* copy count characters of "str" to "ptr", allocating memory as needed */
179 /* if count is zero, then copy all characters of "str" */
181 static void assignn (char **ptr
, char *str
, int count
)
183 *ptr
= (char *) realloc(*ptr
,(count
?count
:strlen(str
))+1);
186 fprintf(stderr
,"error: out of memory\n");
191 strncpy(*ptr
,str
,count
);
198 /* copy count characters of "str" to "ptr", allocating memory as needed */
200 static void assign (char **ptr
, char *str
)
205 /* get a copy of a Icarus Verilog registry string key */
207 static int GetRegistryKey(char *key
, char **value
)
212 DWORD regKeyType
, regKeySize
;
214 lrv
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
,"Software\\Icarus Verilog",0,KEY_QUERY_VALUE
,&hkKey
);
215 if (lrv
!= ERROR_SUCCESS
)
218 lrv
= RegQueryValueEx(hkKey
,key
,NULL
,®KeyType
,NULL
,®KeySize
);
219 if ((lrv
!= ERROR_SUCCESS
) || (regKeyType
!= REG_SZ
) || (!regKeySize
)) {
220 lrv
= RegCloseKey(hkKey
);
224 regKeyBuffer
= (char *) malloc(regKeySize
+1);
226 lrv
= RegCloseKey(hkKey
);
227 fprintf(stderr
,"error: out of memory\n");
230 regKeyBuffer
[regKeySize
] = 0; /* makes sure there is a trailing NULL */
232 lrv
= RegQueryValueEx(hkKey
,key
,NULL
,®KeyType
,regKeyBuffer
,®KeySize
);
233 if ((lrv
!= ERROR_SUCCESS
) || (regKeyType
!= REG_SZ
) || (!regKeySize
)) {
234 lrv
= RegCloseKey(hkKey
);
241 assign(value
,regKeyBuffer
);
247 /* store a copy of a Icarus Verilog registry string key */
249 static void SetRegistryKey(char *key
, char *value
)
256 "Software\\Icarus Verilog",
259 REG_OPTION_NON_VOLATILE
,
262 &res
) != ERROR_SUCCESS
)
265 RegSetValueEx(hkKey
,key
,0,REG_SZ
,value
,strlen(value
)+1);
268 printf("info: storing %s in Windows' registry entry\n",value
);
269 printf(" HKEY_LOCAL_MACHINE\\Software\\Icarus Verilog\\%s\n",key
);
272 /* parse the command line, assign results to global variable strings */
274 static int parse(int argc
, char *argv
[])
276 int idx
, srcFileCnt
=0;
278 char dot_c_ext
[] = ".c";
279 char dot_cc_ext
[] = ".cc";
280 char dot_cpp_ext
[] = ".cpp";
281 char dot_o_ext
[] = ".o";
282 char name_option
[] = "--name=";
283 char lib_option
[] = "-l";
284 char mingw_option
[] = "-mingw=";
285 char ivl_option
[] = "-ivl=";
290 for (idx
=1; idx
<argc
; ++idx
) {
291 if (endsIn(dot_c_ext
,argv
[idx
])) { /* check for C source files */
293 append(&gstr
.pCCSRC
,argv
[idx
]);
294 append(&gstr
.pCCSRC
," ");
296 assignn(&gstr
.pOUT
,argv
[idx
],strlen(argv
[idx
])-strlen(dot_c_ext
));
298 else if (endsIn(dot_cc_ext
,argv
[idx
])) { /* check for C++ source files */
300 append(&gstr
.pCXSRC
,argv
[idx
]);
301 append(&gstr
.pCXSRC
," ");
303 assignn(&gstr
.pOUT
,argv
[idx
],strlen(argv
[idx
])-strlen(dot_cc_ext
));
305 else if (endsIn(dot_cpp_ext
,argv
[idx
])) { /* check for C++ source files */
307 append(&gstr
.pCXSRC
,argv
[idx
]);
308 append(&gstr
.pCXSRC
," ");
310 assignn(&gstr
.pOUT
,argv
[idx
],strlen(argv
[idx
])-strlen(dot_cpp_ext
));
312 else if (endsIn(dot_o_ext
,argv
[idx
])) { /* check for compiled object files */
314 append(&gstr
.pOBJ
,argv
[idx
]);
315 append(&gstr
.pOBJ
," ");
317 assignn(&gstr
.pOUT
,argv
[idx
],strlen(argv
[idx
])-strlen(dot_o_ext
));
319 else if (startsWith(name_option
,argv
[idx
])) { /* check for --name option */
320 assignn(&gstr
.pOUT
,argv
[idx
]+sizeof(name_option
)-1,strlen(argv
[idx
])-(sizeof(name_option
)-1));
322 else if (startsWith(lib_option
,argv
[idx
])) { /* check for -l option */
323 append(&gstr
.pLIB
,argv
[idx
]);
324 append(&gstr
.pLIB
," ");
326 else if (startsWith(mingw_option
,argv
[idx
])) /* check for -mingw option */
327 assignn(&gstr
.pMINGW
,argv
[idx
]+sizeof(mingw_option
)-1,strlen(argv
[idx
])-(sizeof(mingw_option
)-1));
328 else if (startsWith(ivl_option
,argv
[idx
])) /* check for -ivl option */
329 assignn(&gstr
.pIVL
,argv
[idx
]+sizeof(ivl_option
)-1,strlen(argv
[idx
])-(sizeof(ivl_option
)-1));
331 return 0; /* different from iverilog-vpi.sh, we don't ignore accept arguments */
335 assign(&gstr
.pOUT
,""); /* in case they used --name with no source files */
337 if (!*gstr
.pOUT
) { /* normally it's an error if there are no *.c,*.cc,*.o files */
338 if (!*gstr
.pMINGW
&& !*gstr
.pIVL
) /* unless they are just setting the IVL or MinGW registry entries */
342 append(&gstr
.pOUT
,".vpi"); /* the result file should have a .vpi extension */
343 append(&gstr
.pOUT
," ");
349 /* do minimal check that the MinGW root directory looks valid */
351 static void checkMingwDir(char *root
)
354 struct _stat stat_buf
;
357 initDynString(&path
);
358 assign(&path
,gstr
.pMINGW
);
359 appendBackSlash(&path
);
360 append(&path
,"bin\\" IVERILOG_VPI_CC
".exe");
362 irv
= _stat(path
,&stat_buf
);
363 deInitDynString(path
);
366 fprintf(stderr
,"error: %s does not appear to be the valid root directory\n",root
);
367 fprintf(stderr
," of MinGW. Use the -mingw option of iverilog-vpi.exe to\n");
368 fprintf(stderr
," point to the MinGW root directory. For a Windows command\n");
369 fprintf(stderr
," shell the option would be something like -mingw=c:\\mingw\n");
370 fprintf(stderr
," For a Cygwin shell the option would be something like\n");
371 fprintf(stderr
," -mingw=c:\\\\mingw\n");
376 /* do minimal check that the Icarus Verilog root directory looks valid */
378 static void checkIvlDir(char *root
)
381 struct _stat stat_buf
;
384 initDynString(&path
);
385 assign(&path
,gstr
.pIVL
);
386 appendBackSlash(&path
);
387 append(&path
,"bin\\vvp.exe");
389 irv
= _stat(path
,&stat_buf
);
390 deInitDynString(path
);
393 fprintf(stderr
,"error: %s does not appear to be the valid root directory of\n",root
);
394 fprintf(stderr
," Icarus Verilog. Use the -ivl option of iverilog-vpi.exe to\n");
395 fprintf(stderr
," point to the Icarus Verilog root directory. For a Windows\n");
396 fprintf(stderr
," command shell the option would be something like -ivl=c:\\iverilog\n");
397 fprintf(stderr
," For a Cygwin shell the option would be something like\n");
398 fprintf(stderr
," -ivl=c:\\\\iverilog\n");
403 /* see if we can find mingw root */
405 #define IVL_REGKEY_MINGW "MingwDir"
407 static void setup_mingw_environment()
409 char *pOldPATH
= getenv("PATH"); /* get current path */
412 checkMingwDir(gstr
.pMINGW
);
413 SetRegistryKey(IVL_REGKEY_MINGW
,gstr
.pMINGW
);
416 if (!GetRegistryKey(IVL_REGKEY_MINGW
,&gstr
.pMINGW
)) {
417 fprintf(stderr
,"error: can not locate the MinGW root directory, use the -mingw option of\n");
418 fprintf(stderr
," iverilog-vpi.exe to point to the MinGW root directory. For\n");
419 fprintf(stderr
," a Windows command shell the option would be something like\n");
420 fprintf(stderr
," -mingw=c:\\mingw For a Cygwin shell the option would be\n");
421 fprintf(stderr
," something like -mingw=c:\\\\mingw\n");
425 assign(&gstr
.pNewPath
,"PATH="); /* create new path */
426 append(&gstr
.pNewPath
,gstr
.pMINGW
);
427 appendBackSlash(&gstr
.pNewPath
);
428 append(&gstr
.pNewPath
,"bin;");
429 append(&gstr
.pNewPath
,pOldPATH
);
431 _putenv(gstr
.pNewPath
); /* place new path in environment variable */
434 /* see if we can find iverilog root */
436 #define IVL_REGKEY_IVL "InstallDir"
438 static void setup_ivl_environment()
441 checkIvlDir(gstr
.pIVL
);
442 SetRegistryKey(IVL_REGKEY_IVL
,gstr
.pIVL
);
445 if (!GetRegistryKey(IVL_REGKEY_IVL
,&gstr
.pIVL
)) {
446 fprintf(stderr
,"error: can not locate the Icarus Verilog root directory, use the -ivl option\n");
447 fprintf(stderr
," of iverilog-vpi.exe to point to the Icarus Verilog root directory.\n");
448 fprintf(stderr
," For a Windows command shell the option would be something like\n");
449 fprintf(stderr
," -ivl=c:\\iverilog For a Cygwin shell the option would be something\n");
450 fprintf(stderr
," like -ivl=c:\\\\iverilog\n");
454 /* build up the CFLAGS option string */
456 assign(&gstr
.pCFLAGS
,IVERILOG_VPI_CFLAGS
);
457 append(&gstr
.pCFLAGS
," -I");
458 append(&gstr
.pCFLAGS
,gstr
.pIVL
);
459 appendBackSlash(&gstr
.pCFLAGS
);
460 append(&gstr
.pCFLAGS
,"include");
462 /* build up the LDFLAGS option string */
464 assign(&gstr
.pLDLIBS
,"-L");
465 append(&gstr
.pLDLIBS
,gstr
.pIVL
);
466 appendBackSlash(&gstr
.pLDLIBS
);
467 append(&gstr
.pLDLIBS
,"lib ");
468 append(&gstr
.pLDLIBS
,IVERILOG_VPI_LDLIBS
);
471 /* compile source modules */
473 static void compile(char *pSource
, char **pObject
, char *ext
, int *compile_errors
, char *compiler
)
475 char *ptr1
= pSource
;
476 char *ptr2
= strchr(pSource
,' ');
477 char *buf
=0,*src
=0,*obj
=0;
480 int len
= ptr2
- ptr1
;
481 assignn(&src
,ptr1
,len
);
483 assignn(&obj
,ptr1
,len
-strlen(ext
)); /* strip off the extension */
486 assign (&buf
,compiler
);
487 append (&buf
," -c -o ");
490 append (&buf
,gstr
.pCFLAGS
);
494 append (pObject
,obj
);
495 append (pObject
," ");
502 ptr1
= ptr2
+ 1; /* advance to next token */
503 ptr2
= strchr(ptr1
,' ');
511 /* using the global strings, compile and link */
513 static void compile_and_link()
516 int iRet
, compile_errors
= 0;
518 /* print out the mingw and ivl directories to help the user debug problems */
520 printf("info: %s will be used as the MinGW root directory.\n",gstr
.pMINGW
);
521 checkMingwDir(gstr
.pMINGW
);
523 printf("info: %s will be used as the Icarus Verilog root directory.\n",gstr
.pIVL
);
524 checkIvlDir(gstr
.pIVL
);
528 compile(gstr
.pCCSRC
,&gstr
.pOBJ
,".c" ,&compile_errors
,IVERILOG_VPI_CC
); /* compile the C source files */
529 compile(gstr
.pCXSRC
,&gstr
.pOBJ
,".cc",&compile_errors
,IVERILOG_VPI_CXX
); /* compile the C++ source files */
531 if (compile_errors
) {
532 fprintf(stderr
,"iverilog-vpi: Some %d files failed to compile.\n",compile_errors
);
538 assign(&buf
,IVERILOG_VPI_LD
);
540 append(&buf
,gstr
.pOUT
); /* has a trailing space */
541 append(&buf
,IVERILOG_VPI_LDFLAGS
);
543 append(&buf
,gstr
.pOBJ
) /* has a trailing space */;
544 append(&buf
,gstr
.pLIB
); /* has a trailing space */
545 append(&buf
,gstr
.pLDLIBS
);
557 /* program execution starts here */
559 int main(int argc
, char *argv
[])
563 if (!parse(argc
,argv
))
566 setup_mingw_environment();
567 setup_ivl_environment();
569 if (*gstr
.pOUT
) /* are there any *.c,*.cc,*.o files specified */