Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
qcc.c
Go to the documentation of this file.
1/** @file qcc.c
2 */
3/**
4# The Basilisk C to C99 pre-processor
5
6This is the front-end for the Basilisk C to C99 translator described
7in [ast/README]().
8
9Usage:
10
11~~~
12qcc [OPTIONS] FILE.c
13~~~
14
15A summary of the options/switches:
16
17* `-grid=GRID` : specifies the grid to use (overloads any "in file" includes)
18* `-MD` : generates .d dependency file
19* `-tags` : generates .tags file
20* `-python` : generates python wrapper code
21* `-debug` : internal debugging
22* `-events` : displays a trace of events on standard error
23* `-catch` : catch floating point errors
24* `-source` : generates C99 source file (with an underscore prefix)
25* `-prepost` : as -source but before expansion of postmacros
26* `-autolink` : uses the 'autolink' pragma to link required libraries
27* `-progress` : the running code will generate a 'progress' file
28* `-cadna` : support for CADNA
29* `-nolineno` : does not generate code containing code line numbers
30* `-gpu` : computation is done on GPU by default (this is the default)
31* `-cpu` : computation is done on CPU by default
32* `-run=INT` : runs the code with the interpreter with the verbosity
33 level given by INT
34* `-dimensions[=FILE]` : outputs a summary of the dimensions in a file
35 which is the source file with a `.dims` extension if FILE == 'dims'
36 or the given FILE name. if FILE is not specified the dimensions are
37 written on stderr.
38* `-disable-dimensions` : do not check dimensional consistency
39* `-non-finite` : also outputs the dimensions of "non-finite" constants
40* `-redundant` : also outputs the dimensions of redundant constants
41* `-Wdimensions` : only warns on dimensional errors
42* `-maxcalls=VAL` : maximum number of calls for the interpreter. The default
43 is 15 millions. A negative value means no limit.
44
45All other options will be passed directly to the C compiler. */
46
47#include <stdio.h>
48#include <stdlib.h>
49#include <unistd.h>
50#include <string.h>
51#include <ctype.h>
52#include <sys/stat.h>
53#include <sys/types.h>
54#include <sys/wait.h>
55#include <assert.h>
56#include "ast/ast.h"
57
58int dimension = 2, bghosts = 0, layers = 0;
59
60int debug = 0, catch = 0, cadna = 0, nolineno = 0, events = 0, progress = 0;
61int parallel = 0, cpu = 0, gpu = 0;
62static FILE * dimensions = NULL;
63static int run = -1, finite = 1, redundant = 0, warn = 0, maxcalls = 20000000;
64char dir[] = ".qccXXXXXX";
65
66char * autolink = NULL;
67int autolinks = 0, source = 0;
68
69char * dname (const char * fname);
70FILE * dopen (const char * fname, const char * mode);
71
72void includes (int argc, char ** argv,
73 char ** grid, int * default_grid,
74 int * dimension, int * bg, int * layers, int * gpu,
75 const char * dir);
76
77FILE * writepath (char * path, const char * mode)
78{
79 char * s = path;
80 while ((s = strchr (s, '/'))) {
81 *s = '\0';
82 if (access (path, R_OK|W_OK|X_OK) && mkdir (path, 0700))
83 return NULL;
84 *s++ = '/';
85 }
86 return fopen (path, mode);
87}
88
89static void exiting (void)
90{
91 if (!debug && !strncmp (dir, ".qcc", 4)) {
92 char command[80] = "rm -r -f ";
94 if (system (command) < 0)
95 fprintf (stderr, "qcc: warning: could not cleanup\n");
96 }
97 free (autolink);
98}
99
100char * dname (const char * fname)
101{
102 char * out = malloc (strlen (dir) + strlen (fname) + 2);
103 strcpy (out, dir); strcat (out, "/"); strcat (out, fname);
104 return out;
105}
106
107FILE * dopen (const char * fname, const char * mode)
108{
109 char * out = dname (fname);
110 FILE * fout = fopen (out, mode);
111 free (out);
112 return fout;
113}
114
116 char * swigname, char * grid)
117{
118 FILE * fout1 = dopen ("_endfor.c", "w");
120 parallel, cpu, gpu, source == 2,
122 fclose (fout1);
123
124 fout1 = dopen ("_endfor.c", "r");
125 extern int postproc (FILE * fin, FILE * fout, char ** autolink, int nolineno);
126 extern int postlex_destroy (void);
129 fclose (fout1);
130 fflush (fout);
131
132 if (source && autolinks && autolink)
133 printf ("%s\n", autolink);
134
135 return ast;
136}
137
138int main (int argc, char ** argv)
139{
140 char * cc = getenv ("CC99"), command[1000], command1[1000] = "";
141 if (cc == NULL)
143 else
144 strcpy (command, cc);
145 char * file = NULL;
146 int i, dep = 0, tags = 0, swig = 0;
147 for (i = 1; i < argc; i++) {
148 if (!strncmp (argv[i], "-grid=", 6))
149 ;
150 else if (!strcmp (argv[i], "-MD"))
151 dep = 1;
152 else if (!strcmp (argv[i], "-tags"))
153 tags = 1;
154 else if (!strcmp (argv[i], "-python"))
155 swig = 1;
156 else if (!strcmp (argv[i], "-debug"))
157 debug = 1;
158 else if (!strcmp (argv[i], "-events"))
159 events = 1;
160 else if (!strcmp (argv[i], "-catch"))
161 catch = 1;
162 else if (!strcmp (argv[i], "-source"))
163 source = 1;
164 else if (!strcmp (argv[i], "-prepost"))
165 source = 2;
166 else if (!strcmp (argv[i], "-autolink"))
167 autolinks = 1;
168 else if (!strcmp (argv[i], "-progress"))
169 progress = 1;
170 else if (!strncmp (argv[i], "-run=", 5))
171 run = atoi (argv[i] + 5);
172 else if (!strcmp (argv[i], "-disable-dimensions"))
174 else if (!strncmp (argv[i], "-dimensions", 11)) {
175 if (dimensions != stdout) { // dimensions have been disabled
176 if (*(argv[i] + 11) == '=') {
177 if (!strcmp (argv[i] + 12, "dims"))
179 else {
180 dimensions = fopen (argv[i] + 12, "w");
181 if (!dimensions) {
182 perror (argv[i] + 12);
183 exit (1);
184 }
185 }
186 }
187 else
189 }
190 }
191 else if (!strcmp (argv[i], "-non-finite"))
192 finite = 0;
193 else if (!strcmp (argv[i], "-redundant"))
194 redundant = 1;
195 else if (!strcmp (argv[i], "-Wdimensions"))
196 warn = 1;
197 else if (!strncmp (argv[i], "-maxcalls", 9)) {
198 if (*(argv[i] + 9) == '=')
199 maxcalls = atoi (argv[i] + 10);
200 }
201 else if (!strcmp (argv[i], "-Wall")) {
202 char * s = strchr (command, ' ');
203 if (s) {
204 char command1[1000];
205 strcpy (command1, s);
206 *(s+1) = '\0';
207 strcat (command, argv[i]);
209 }
210 else
211 strcat (command, argv[i]);
212 }
213 else if (!strcmp (argv[i], "-cadna")) {
214 cadna = 1;
215 char * cc = getenv ("CADNACC");
216 if (cc == NULL)
218 else
219 strcpy (command, cc);
220 }
221 else if (!strncmp (argv[i], "-Ddimension=", 12))
222 dimension = 1 + argv[i][12] - '1';
223 else if (catch && !strncmp (argv[i], "-O", 2))
224 ;
225 else if (!strcmp (argv[i], "-nolineno"))
226 nolineno = 1;
227 else if (!strcmp (argv[i], "-cpu"))
228 cpu = 1;
229 else if (!strcmp (argv[i], "-gpu"))
230 cpu = 0;
231 else if (!strcmp (argv[i], "-o")) {
232 strcat (command1, " ");
233 strcat (command1, argv[i++]);
234 if (i < argc) {
235 strcat (command1, " ");
236 strcat (command1, argv[i]);
237 }
238 }
239 else if (argv[i][0] != '-' &&
240 (tags || !strcmp (argv[i] + strlen(argv[i]) - 2, ".c"))) {
241 if (file) {
242 fprintf (stderr, "usage: qcc -grid=[GRID] [OPTIONS] FILE.c\n");
243 return 1;
244 }
245 file = argv[i];
246 if (dimensions == stdin) {
247 int len = strlen (file);
248 char name[len + 4];
249 strcpy (name, file);
250 strcpy (name + len - 2, ".dims");
251 dimensions = fopen (name, "w");
252 if (!dimensions) {
253 perror (name);
254 exit (1);
255 }
256 }
257 }
258 else if (!file) {
259 strcat (command, " ");
260 strcat (command, argv[i]);
261 }
262 else {
263 strcat (command1, " ");
264 strcat (command1, argv[i]);
265 }
266 }
267 if (source && !file) {
268 fprintf (stderr, "usage: qcc -grid=[GRID] [OPTIONS] FILE.c\n");
269 return 1;
270 }
271 if (dimensions == stdin) {
272 fprintf (stderr, "qcc: error: -dimensions must be given "
273 "before the .c source file name\n");
274 exit (1);
275 }
276 if (strstr (command, "-D_MPI"))
277 parallel = 1;
278 char * openmp = strstr (command, "-fopenmp");
279 if (openmp) {
280 parallel = 1;
281 if (strstr (command, "-D_MPI")) {
283 "qcc: warning: OpenMP cannot be used with MPI (yet): "
284 "switching it off\n");
285 int i;
286 for (i = 0; i < strlen("-fopenmp"); i++)
287 openmp[i] = ' ';
288 }
289 else if (swig) {
291 "qcc: warning: OpenMP cannot be used with Python (yet): "
292 "switching it off\n");
293 int i;
294 for (i = 0; i < strlen("-fopenmp"); i++)
295 openmp[i] = ' ';
296 }
297 }
298 int status;
299 if (debug) {
300 status = system ("rm -r -f .qcc");
301 strcpy (dir, ".qcc");
302 status = mkdir (dir, 0700);
303 }
304 else
305 status = (mkdtemp (dir) == NULL);
306 if (status) {
307 perror (dir);
308 return 1;
309 }
310 atexit (exiting);
311 void * ast = NULL;
312 if (file) {
313 char * grid = NULL;
314 int default_grid;
317 dep || tags ? NULL : dir);
318 if (gpu)
319 parallel = 1;
320 FILE * swigfp = NULL;
321 char swigname[80] = "";
322 if (swig) {
324 char * dot = strchr (swigname, '.');
325 *dot = '\0'; strcat (swigname, ".i");
326 swigfp = fopen (swigname, "a");
327 if (!swigfp) {
328 fprintf (stderr, "qcc: could not open '%s': ", swigname);
329 return 1;
330 }
331 *dot = '\0';
332 }
333 if (!dep && !tags) {
334 char * basename = strdup (file), * ext = basename;
335 while (*ext != '\0' && *ext != '.') ext++;
336 char * cpp = malloc (strlen(basename) + strlen("-cpp") + strlen(ext) + 1);
337 if (*ext == '.') {
338 *ext = '\0';
340 strcat (cpp, "-cpp");
341 *ext = '.';
342 strcat (cpp, ext);
343 }
344 else {
346 strcat (cpp, "-cpp");
347 }
348 free (basename);
349 FILE * fin = dopen (file, "r");
350 if (!fin) {
351 perror (file);
352 exit (1);
353 }
354 FILE * fp = dopen ("_attributes.h", "w");
355 fputs ("typedef struct {\n", fp);
356 fclose (fp);
357 fp = dopen ("_maps.h", "w");
358 fclose (fp);
359 FILE * fout = dopen (cpp, "w");
360 if (swig)
361 fputs ("@include <Python.h>\n", fout);
362 if (gpu)
363 fputs ("@define _GPU 1\n", fout);
364 fputs ("@if _XOPEN_SOURCE < 700\n"
365 " @undef _XOPEN_SOURCE\n"
366 " @define _XOPEN_SOURCE 700\n"
367 "@endif\n"
368 "@if _GNU_SOURCE\n"
369 "@include <stdint.h>\n"
370 "@include <string.h>\n"
371 "@include <fenv.h>\n"
372 "@endif\n",
373 fout);
374 if (catch)
375 fputs ("#define TRASH 1\n"
376 "#define _CATCH last_point = point;\n",
377 fout);
378 else
379 fputs ("#define _CATCH\n", fout);
380 fprintf (fout, "#define dimension %d\n", dimension);
381 if (bghosts)
382 fprintf (fout, "#define BGHOSTS %d\n", bghosts);
383 if (layers)
384 fprintf (fout, "#define LAYERS 1\n");
385 fputs ("#include \"common.h\"\n", fout);
386 /* catch */
387 if (catch)
388 fputs ("void catch_fpe (void);\n", fout);
389 /* grid */
390 if (default_grid)
391 fprintf (fout, "#include \"grid/%s.h\"\n", grid);
392 char s[81];
393 while (fgets (s, 81, fin)) {
394 if (default_grid && strstr (s, "#include \"grid/"))
395 fputs ("\n", fout);
396 else
397 fputs (s, fout);
398 }
399 if (swigfp)
400 fputs ("#include \"python.h\"\n", fout);
401 if (progress)
402 fputs ("#include \"grid/progress.h\"\n", fout);
403 fclose (fout);
404 fclose (fin);
405 fout = dopen (file, "w");
406 if (!fout) {
407 perror (file);
408 exit (1);
409 }
410
411 char preproc[1000], * cppcommand = getenv ("CPP99");
412 strcpy (preproc, "cd ");
413 strcat (preproc, dir);
414 strcat (preproc, " && ");
415 if (!cppcommand && strcmp (CPP99, ""))
417 if (!cppcommand) {
418 if (source) {
419 /* remove -D_GNU_SOURCE flags from $CC99 */
420 char tmp[1000]; strcpy (tmp, command);
421 char * s = strtok (tmp, " \t");
422 while (s) {
423 if (strncmp (s, "-D_GNU_SOURCE", 13)) {
424 strcat (preproc, s);
425 strcat (preproc, " ");
426 }
427 s = strtok (NULL, " \t");
428 }
429 }
430 else
432 strcat (preproc, " -E");
433 }
434 else
436 // remove "-pedantic option from preprocessor
437 // This is mostly to avoid the preprocessor warning:
438 // "ISO C99 requires at least one argument in a variadic macro"
439 // note that the option is kept for the final compilation
440 char * pedantic = strstr (preproc, "-pedantic");
441 if (pedantic)
442 for (i = 0; i < strlen ("-pedantic"); i++)
443 pedantic[i] = ' ';
444 strcat (preproc, " -I");
446 strcat (preproc, "/ast/std");
447 strcat (preproc, " -I. -I");
449 strcat (preproc, " ");
450 if (events) {
451 strcat (preproc, " -DDEBUG_EVENTS=1 -DBASILISK=\"\\\"");
453 strcat (preproc, "\\\"\" ");
454 }
455 if (nolineno)
456 strcat (preproc, " -D'LINENO=0' ");
457 strcat (preproc, cpp);
458 free (cpp);
459 if (debug) {
460 fprintf (stderr, "preproc: %s\n", preproc);
461 strcat (preproc, " | tee _preproc.c");
462 }
463
464 fin = popen (preproc, "r");
465 if (!fin) {
466 fclose (fout);
467 perror (preproc);
468 exit (1);
469 }
470
472 int status = pclose (fin);
473 fclose (fout);
474 if (status == -1 ||
475 (WIFSIGNALED (status) && (WTERMSIG (status) == SIGINT ||
476 WTERMSIG (status) == SIGQUIT)))
477 exit (1);
478
479 fout = dopen ("_tmp", "w");
480 fin = dopen (file, "r");
481 char line[1024];
482 // rest of the file
483 while (fgets (line, 1024, fin)) {
484 if (!strncmp (line, "#line 0 ", 8))
485 line[6] = '1';
486 fputs (line, fout);
487 }
488 fclose (fin);
489 fclose (fout);
490
491 char src[80], dst[80];
492 strcpy (src, dir); strcat (src, "/_tmp");
493 if (source) {
494 strcpy (dst, "_");
495 }
496 else {
497 strcpy (dst, dir); strcat (dst, "/");
498 }
499 strcat (dst, file);
500 rename (src, dst);
501
502 strcat (command, " -I");
504 strcat (command, " ");
505 strcat (command, dir);
506 strcat (command, "/");
507 strcat (command, file);
509 }
510 }
511 else if (dep || tags) {
512 fprintf (stderr, "usage: qcc -grid=[GRID] [OPTIONS] FILE.c\n");
513 exit (1);
514 }
515 else
517 /* compilation */
518 status = 0;
519 if (!dep && !tags && !source) {
520 if (autolinks && autolink)
522 if (debug)
523 fprintf (stderr, "command: %s\n", command);
525 if (status == -1 ||
526 (WIFSIGNALED (status) && (WTERMSIG (status) == SIGINT ||
527 WTERMSIG (status) == SIGQUIT)))
528 exit (1);
530 }
531 int check_dimensions (void * root,
532 int nolineno,
533 int run, FILE * dimensions, int finite, int redundant,
534 int warn,
535 int maxcalls);
536 if (ast &&
537 status == 0 &&
540 !warn)
541 status = 2; // dimensional error
542 exit (status);
543 return status;
544}
#define dimension
Definition bitree.h:3
free(list1)
int x
Definition common.h:76
Grid * grid
Definition common.h:32
#define popen
Definition config.h:666
#define pclose
Definition config.h:667
define sysmalloc malloc define syscalloc calloc define sysrealloc realloc define sysfree free define systrdup strdup define file
Definition config.h:120
define sysmalloc malloc define syscalloc calloc define sysrealloc realloc define sysfree free define systrdup strdup define line line line line strdup(s) @ define tracing(...) @ define end_tracing(...) @define tid() 0 @define pid() 0 @define npe() 1 @define mpi_all_reduce(v
scalar s
Definition embed-tree.h:56
scalar int i
Definition embed.h:74
static int line
Definition errors.c:754
static char * fname
Definition errors.c:753
static FILE * swigfp
Definition include.c:951
FILE * fp
Definition mtrace.h:7
int dst
int postproc(FILE *fin, FILE *fout, char **autolink1, int _nolineno)
Definition postproc.c:2332
int postlex_destroy(void)
Definition postproc.c:2255
int source
Definition qcc.c:67
bghosts
Definition qcc.c:58
AstRoot * compdir(FILE *fin, FILE *fout, FILE *swigfp, char *swigname, char *grid)
Definition qcc.c:115
int main(int argc, char **argv)
Definition qcc.c:138
int cpu
Definition qcc.c:61
int autolinks
Definition qcc.c:67
int gpu
Definition qcc.c:61
int progress
Definition qcc.c:60
static void exiting(void)
Definition qcc.c:89
int cadna
Definition qcc.c:60
layers
Definition qcc.c:58
int nolineno
Definition qcc.c:60
static int redundant
Definition qcc.c:63
static int finite
Definition qcc.c:63
int events
Definition qcc.c:60
FILE * writepath(char *path, const char *mode)
Definition qcc.c:77
static FILE * dimensions
Definition qcc.c:62
static int maxcalls
Definition qcc.c:63
FILE * dopen(const char *fname, const char *mode)
Definition qcc.c:107
void includes(int argc, char **argv, char **grid, int *default_grid, int *2, int *bg, int *layers, int *gpu, const char *dir)
Definition include.c:2886
char dir[]
Definition qcc.c:64
static int warn
Definition qcc.c:63
char * autolink
Definition qcc.c:66
char * dname(const char *fname)
Definition qcc.c:100
int debug
Definition qcc.c:60
static int run
Definition qcc.c:63
int parallel
Definition qcc.c:61
double cc
Definition vof.h:60
src vof fflush(ferr)