]> git.sur5r.net Git - cc65/blob - src/cl65/main.c
Output the command line for sub-processes when -d is given
[cc65] / src / cl65 / main.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  main.c                                   */
4 /*                                                                           */
5 /*             Main module for the cl65 compile and link utility             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1999-2002 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__MINGW32__)
42 #  include <process.h>          /* DOS, OS/2 and Windows */
43 #else
44 #  include "spawn.h"            /* All others */
45 #endif
46
47 /* common */
48 #include "cmdline.h"
49 #include "fname.h"
50 #include "target.h"
51 #include "version.h"
52 #include "xmalloc.h"
53
54 /* cl65 */
55 #include "global.h"
56 #include "error.h"
57
58
59
60 /*****************************************************************************/
61 /*                                   Data                                    */
62 /*****************************************************************************/
63
64
65
66 /* Struct that describes a command */
67 typedef struct CmdDesc CmdDesc;
68 struct CmdDesc {
69     char*       Name;           /* The command name */
70
71     unsigned    ArgCount;       /* Count of arguments */
72     unsigned    ArgMax;         /* Maximum count of arguments */
73     char**      Args;           /* The arguments */
74
75     unsigned    FileCount;      /* Count of files to translate */
76     unsigned    FileMax;        /* Maximum count of files */
77     char**      Files;          /* The files */
78 };
79
80 /* Command descriptors for the different programs */
81 static CmdDesc CC65 = { 0, 0, 0, 0, 0, 0, 0 };
82 static CmdDesc CA65 = { 0, 0, 0, 0, 0, 0, 0 };
83 static CmdDesc LD65 = { 0, 0, 0, 0, 0, 0, 0 };
84 static CmdDesc GRC  = { 0, 0, 0, 0, 0, 0, 0 };
85
86 /* File types */
87 enum {
88     FILETYPE_UNKNOWN,
89     FILETYPE_C,
90     FILETYPE_ASM,
91     FILETYPE_OBJ,
92     FILETYPE_LIB,
93     FILETYPE_GR                 /* GEOS resource file */
94 };
95
96 /* Default file type, used if type unknown */
97 static unsigned DefaultFileType = FILETYPE_UNKNOWN;
98
99 /* Variables controlling the steps we're doing */
100 static int DontLink     = 0;
101 static int DontAssemble = 0;
102
103 /* The name of the output file, NULL if none given */
104 static const char* OutputName = 0;
105
106 /* The name of the linker configuration file if given */
107 static const char* LinkerConfig = 0;
108
109 /* The name of the first input file. This will be used to construct the
110  * executable file name if no explicit name is given.
111  */
112 static const char* FirstInput = 0;
113
114 /* Remember if we should link a module */
115 static int Module = 0;
116
117 /* Extension used for a module */
118 #define MODULE_EXT      ".o65"
119
120 /* Name of the crt0 object file and the runtime library */
121 static char* TargetCRT0 = 0;
122 static char* TargetLib  = 0;
123
124
125
126 /*****************************************************************************/
127 /*                           Determine a file type                           */
128 /*****************************************************************************/
129
130
131
132 static unsigned GetFileType (const char* File)
133 /* Determine the type of the given file */
134 {
135     /* Table mapping extensions to file types */
136     static const struct {
137         const char*     Ext;
138         unsigned        Type;
139     } FileTypes [] = {
140         {   ".c",       FILETYPE_C      },
141         {   ".s",       FILETYPE_ASM    },
142         {   ".asm",     FILETYPE_ASM    },
143         {   ".a65",     FILETYPE_ASM    },
144         {   ".o",       FILETYPE_OBJ    },
145         {   ".obj",     FILETYPE_OBJ    },
146         {   ".a",       FILETYPE_LIB    },
147         {   ".lib",     FILETYPE_LIB    },
148         {   ".grc",     FILETYPE_GR     },
149     };
150
151     unsigned I;
152
153     /* Determine the file type by the extension */
154     const char* Ext = FindExt (File);
155
156     /* Do we have an extension? */
157     if (Ext == 0) {
158         return DefaultFileType;
159     }
160
161     /* Check for known extensions */
162     for (I = 0; I < sizeof (FileTypes) / sizeof (FileTypes [0]); ++I) {
163         if (strcmp (FileTypes [I].Ext, Ext) == 0) {
164             /* Found */
165             return FileTypes [I].Type;
166         }
167     }
168
169     /* Not found, return the default */
170     return DefaultFileType;
171 }
172
173
174
175 /*****************************************************************************/
176 /*                        Command structure handling                         */
177 /*****************************************************************************/
178
179
180
181 static void CmdAddArg (CmdDesc* Cmd, const char* Arg)
182 /* Add a new argument to the command */
183 {
184     /* Expand the argument vector if needed */
185     if (Cmd->ArgCount == Cmd->ArgMax) {
186         unsigned NewMax  = Cmd->ArgMax + 10;
187         char**   NewArgs = xmalloc (NewMax * sizeof (char*));
188         memcpy (NewArgs, Cmd->Args, Cmd->ArgMax * sizeof (char*));
189         xfree (Cmd->Args);
190         Cmd->Args   = NewArgs;
191         Cmd->ArgMax = NewMax;
192     }
193
194     /* Add a copy of the new argument, allow a NULL pointer */
195     if (Arg) {
196         Cmd->Args [Cmd->ArgCount++] = xstrdup (Arg);
197     } else {
198         Cmd->Args [Cmd->ArgCount++] = 0;
199     }
200 }
201
202
203
204 static void CmdDelArgs (CmdDesc* Cmd, unsigned LastValid)
205 /* Remove all arguments with an index greater than LastValid */
206 {
207     while (Cmd->ArgCount > LastValid) {
208         Cmd->ArgCount--;
209         xfree (Cmd->Args [Cmd->ArgCount]);
210         Cmd->Args [Cmd->ArgCount] = 0;
211     }
212 }
213
214
215
216 static void CmdAddFile (CmdDesc* Cmd, const char* File)
217 /* Add a new file to the command */
218 {
219     /* Expand the file vector if needed */
220     if (Cmd->FileCount == Cmd->FileMax) {
221         unsigned NewMax   = Cmd->FileMax + 10;
222         char**   NewFiles = xmalloc (NewMax * sizeof (char*));
223         memcpy (NewFiles, Cmd->Files, Cmd->FileMax * sizeof (char*));
224         xfree (Cmd->Files);
225         Cmd->Files   = NewFiles;
226         Cmd->FileMax = NewMax;
227     }
228
229     /* If the file name is not NULL (which is legal and is used to terminate
230      * the file list), check if the file name does already exist in the file
231      * list and print a warning if so. Regardless of the search result, add
232      * the file.
233      */
234     if (File) {
235         unsigned I;
236         for (I = 0; I < Cmd->FileCount; ++I) {
237             if (strcmp (Cmd->Files[I], File) == 0) {
238                 /* Duplicate file */
239                 Warning ("Duplicate file in argument list: `%s'", File);
240                 /* No need to search further */
241                 break;
242             }
243         }
244
245         /* Add the file */
246         Cmd->Files [Cmd->FileCount++] = xstrdup (File);
247     } else {
248         /* Add a NULL pointer */
249         Cmd->Files [Cmd->FileCount++] = 0;
250     }
251 }
252
253
254
255 static void CmdInit (CmdDesc* Cmd, const char* Path)
256 /* Initialize the command using the given path to the executable */
257 {
258     /* Remember the command */
259     Cmd->Name = xstrdup (Path);
260
261     /* Use the command name as first argument */
262     CmdAddArg (Cmd, Path);
263 }
264
265
266
267 static void CmdSetOutput (CmdDesc* Cmd, const char* File)
268 /* Set the output file in a command desc */
269 {
270     CmdAddArg (Cmd, "-o");
271     CmdAddArg (Cmd, File);
272 }
273
274
275
276 static void CmdSetTarget (CmdDesc* Cmd, target_t Target)
277 /* Set the output file in a command desc */
278 {
279     CmdAddArg (Cmd, "-t");
280     CmdAddArg (Cmd, TargetNames[Target]);
281 }
282
283
284
285 static void CmdPrint (CmdDesc* Cmd, FILE* F)
286 /* Output the command line encoded in the command desc */
287 {
288     unsigned I;
289     for (I = 0; I < Cmd->ArgCount && Cmd->Args[I] != 0; ++I) {
290         fprintf (F, "%s ", Cmd->Args[I]);
291     }
292 }
293
294
295
296 /*****************************************************************************/
297 /*                              Target handling                              */
298 /*****************************************************************************/
299
300
301
302 static void SetTargetFiles (void)
303 /* Set the target system files */
304 {
305     /* Determine the names of the default startup and library file */
306     if (Target != TGT_NONE) {
307
308         /* Get a pointer to the system name and its length */
309         const char* TargetName = TargetNames [Target];
310         unsigned    TargetNameLen = strlen (TargetName);
311
312         /* Set the startup file */
313         TargetCRT0 = xmalloc (TargetNameLen + 2 + 1);
314         strcpy (TargetCRT0, TargetName);
315         strcat (TargetCRT0, ".o");
316
317         /* Set the library file */
318         TargetLib = xmalloc (TargetNameLen + 4 + 1);
319         strcpy (TargetLib, TargetName);
320         strcat (TargetLib, ".lib");
321
322     }
323 }
324
325
326
327 /*****************************************************************************/
328 /*                               Subprocesses                                */
329 /*****************************************************************************/
330
331
332
333 static void ExecProgram (CmdDesc* Cmd)
334 /* Execute a subprocess with the given name/parameters. Exit on errors. */
335 {
336     int Status;
337
338     /* If in debug mode, output the command line we will execute */
339     if (Debug) {
340         printf ("Executing: ");
341         CmdPrint (Cmd, stdout);
342         printf ("\n");
343     }
344
345     /* Call the program */
346     Status = spawnvp (P_WAIT, Cmd->Name, Cmd->Args);
347
348     /* Check the result code */
349     if (Status < 0) {
350         /* Error executing the program */
351         Error ("Cannot execute `%s': %s", Cmd->Name, strerror (errno));
352     } else if (Status != 0) {
353         /* Called program had an error */
354         exit (Status);
355     }
356 }
357
358
359
360 static void Link (void)
361 /* Link the resulting executable */
362 {
363     unsigned I;
364
365     /* If we have a linker config file given, add it to the command line.
366      * Otherwise pass the target to the linker if we have one.
367      */
368     if (LinkerConfig) {
369         if (Module) {
370             Error ("Cannot use -C and --module together");
371         }
372         CmdAddArg (&LD65, "-C");
373         CmdAddArg (&LD65, LinkerConfig);
374     } else if (Module) {
375         CmdSetTarget (&LD65, TGT_MODULE);
376     } else if (Target != TGT_NONE) {
377         CmdSetTarget (&LD65, Target);
378     }
379
380     /* Determine which target libraries are needed */
381     SetTargetFiles ();
382
383     /* Since linking is always the final step, if we have an output file name
384      * given, set it here. If we don't have an explicit output name given,
385      * try to build one from the name of the first input file.
386      */
387     if (OutputName) {
388
389         CmdSetOutput (&LD65, OutputName);
390
391     } else if (FirstInput && FindExt (FirstInput)) {  /* Only if ext present! */
392
393         const char* Extension = Module? MODULE_EXT : "";
394         char* Output = MakeFilename (FirstInput, Extension);
395         CmdSetOutput (&LD65, Output);
396         xfree (Output);
397
398     }
399
400     /* If we have a startup file and if we are not linking a module, add its
401      * name as a parameter
402      */
403     if (TargetCRT0 && !Module) {
404         CmdAddArg (&LD65, TargetCRT0);
405     }
406
407     /* Add all object files as parameters */
408     for (I = 0; I < LD65.FileCount; ++I) {
409         CmdAddArg (&LD65, LD65.Files [I]);
410     }
411
412     /* Add the system runtime library */
413     if (TargetLib) {
414         CmdAddArg (&LD65, TargetLib);
415     }
416
417     /* Terminate the argument list with a NULL pointer */
418     CmdAddArg (&LD65, 0);
419
420     /* Call the linker */
421     ExecProgram (&LD65);
422 }
423
424
425
426 static void Assemble (const char* File)
427 /* Assemble the given file */
428 {
429     /* Remember the current assembler argument count */
430     unsigned ArgCount = CA65.ArgCount;
431
432     /* Set the target system */
433     CmdSetTarget (&CA65, Target);
434
435     /* If we won't link, this is the final step. In this case, set the
436      * output name.
437      */
438     if (DontLink && OutputName) {
439         CmdSetOutput (&CA65, OutputName);
440     } else {
441         /* The object file name will be the name of the source file
442          * with .s replaced by ".o". Add this file to the list of
443          * linker files.
444          */
445         char* ObjName = MakeFilename (File, ".o");
446         CmdAddFile (&LD65, ObjName);
447         xfree (ObjName);
448     }
449
450     /* Add the file as argument for the assembler */
451     CmdAddArg (&CA65, File);
452
453     /* Add a NULL pointer to terminate the argument list */
454     CmdAddArg (&CA65, 0);
455
456     /* Run the assembler */
457     ExecProgram (&CA65);
458
459     /* Remove the excess arguments */
460     CmdDelArgs (&CA65, ArgCount);
461 }
462
463
464
465 static void Compile (const char* File)
466 /* Compile the given file */
467 {
468     char* AsmName = 0;
469
470     /* Remember the current assembler argument count */
471     unsigned ArgCount = CC65.ArgCount;
472
473     /* Set the target system */
474     CmdSetTarget (&CC65, Target);
475
476     /* If we won't link, this is the final step. In this case, set the
477      * output name.
478      */
479     if (DontAssemble && OutputName) {
480         CmdSetOutput (&CC65, OutputName);
481     } else {
482         /* The assembler file name will be the name of the source file
483          * with .c replaced by ".s".
484          */
485         AsmName = MakeFilename (File, ".s");
486     }
487
488     /* Add the file as argument for the compiler */
489     CmdAddArg (&CC65, File);
490
491     /* Add a NULL pointer to terminate the argument list */
492     CmdAddArg (&CC65, 0);
493
494     /* Run the compiler */
495     ExecProgram (&CC65);
496
497     /* Remove the excess arguments */
498     CmdDelArgs (&CC65, ArgCount);
499
500     /* If this is not the final step, assemble the generated file, then
501      * remove it
502      */
503     if (!DontAssemble) {
504         Assemble (AsmName);
505         if (remove (AsmName) < 0) {
506             Warning ("Cannot remove temporary file `%s': %s",
507                      AsmName, strerror (errno));
508         }
509         xfree (AsmName);
510     }
511 }
512
513
514
515 static void CompileRes (const char* File)
516 /* Compile the given geos resource file */
517 {
518     char* AsmName = 0;
519
520     /* Remember the current assembler argument count */
521     unsigned ArgCount = GRC.ArgCount;
522
523     /* The assembler file name will be the name of the source file
524      * with .grc replaced by ".s".
525      */
526     AsmName = MakeFilename (File, ".s");
527
528     /* Add the file as argument for the resource compiler */
529     CmdAddArg (&GRC, File);
530
531     /* Add a NULL pointer to terminate the argument list */
532     CmdAddArg (&GRC, 0);
533
534     /* Run the compiler */
535     ExecProgram (&GRC);
536
537     /* Remove the excess arguments */
538     CmdDelArgs (&GRC, ArgCount);
539
540     /* If this is not the final step, assemble the generated file, then
541      * remove it
542      */
543     if (!DontAssemble) {
544         Assemble (AsmName);
545         if (remove (AsmName) < 0) {
546             Warning ("Cannot remove temporary file `%s': %s",
547                      AsmName, strerror (errno));
548         }
549     }
550
551     /* Free the assembler file name which was allocated from the heap */
552     xfree (AsmName);
553 }
554
555
556
557 /*****************************************************************************/
558 /*                                   Code                                    */
559 /*****************************************************************************/
560
561
562
563 static void Usage (void)
564 /* Print usage information and exit */
565 {
566     fprintf (stderr,
567              "Usage: %s [options] file [...]\n"
568              "Short options:\n"
569              "  -c\t\t\tCompile and assemble but don't link\n"
570              "  -d\t\t\tDebug mode\n"
571              "  -g\t\t\tAdd debug info\n"
572              "  -h\t\t\tHelp (this text)\n"
573              "  -l\t\t\tCreate an assembler listing\n"
574              "  -m name\t\tCreate a map file\n"
575              "  -o name\t\tName the output file\n"
576              "  -t sys\t\tSet the target system\n"
577              "  -v\t\t\tVerbose mode\n"
578              "  -vm\t\t\tVerbose map file\n"
579              "  -A\t\t\tStrict ANSI mode\n"
580              "  -C name\t\tUse linker config file\n"
581              "  -Cl\t\t\tMake local variables static\n"
582              "  -D sym[=defn]\t\tDefine a preprocessor symbol\n"
583              "  -I dir\t\tSet a compiler include directory path\n"
584              "  -Ln name\t\tCreate a VICE label file\n"
585              "  -O\t\t\tOptimize code\n"
586              "  -Oi\t\t\tOptimize code, inline functions\n"
587              "  -Or\t\t\tOptimize code, honour the register keyword\n"
588              "  -Os\t\t\tOptimize code, inline known C funtions\n"
589              "  -S\t\t\tCompile but don't assemble and link\n"
590              "  -T\t\t\tInclude source as comment\n"
591              "  -V\t\t\tPrint the version number\n"
592              "  -W\t\t\tSuppress warnings\n"
593              "\n"
594              "Long options:\n"
595              "  --add-source\t\tInclude source as comment\n"
596              "  --ansi\t\tStrict ANSI mode\n"
597              "  --asm-include-dir dir\tSet an assembler include directory\n"
598              "  --bss-name seg\tSet the name of the BSS segment\n"
599              "  --check-stack\t\tGenerate stack overflow checks\n"
600              "  --code-name seg\tSet the name of the CODE segment\n"
601              "  --codesize x\t\tAccept larger code by factor x\n"
602              "  --cpu type\t\tSet cpu type\n"
603              "  --create-dep\t\tCreate a make dependency file\n"
604              "  --data-name seg\tSet the name of the DATA segment\n"
605              "  --debug\t\tDebug mode\n"
606              "  --debug-info\t\tAdd debug info\n"
607              "  --feature name\tSet an emulation feature\n"
608              "  --help\t\tHelp (this text)\n"
609              "  --include-dir dir\tSet a compiler include directory path\n"
610              "  --listing\t\tCreate an assembler listing\n"
611              "  --mapfile name\tCreate a map file\n"
612              "  --module\t\tLink as a module\n"
613              "  --module-id id\tSpecify a module id for the linker\n"
614              "  --rodata-name seg\tSet the name of the RODATA segment\n"
615              "  --signed-chars\tDefault characters are signed\n"
616              "  --start-addr addr\tSet the default start address\n"
617              "  --static-locals\tMake local variables static\n"
618              "  --target sys\t\tSet the target system\n"
619              "  --version\t\tPrint the version number\n"
620              "  --verbose\t\tVerbose mode\n",
621              ProgName);
622 }
623
624
625
626 static void OptAddSource (const char* Opt attribute ((unused)),
627                           const char* Arg attribute ((unused)))
628 /* Strict source code as comments to the generated asm code */
629 {
630     CmdAddArg (&CC65, "-T");
631 }
632
633
634
635 static void OptAnsi (const char* Opt attribute ((unused)),
636                      const char* Arg attribute ((unused)))
637 /* Strict ANSI mode (compiler) */
638 {
639     CmdAddArg (&CC65, "-A");
640 }
641
642
643
644 static void OptAsmIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
645 /* Include directory (assembler) */
646 {
647     CmdAddArg (&CA65, "-I");
648     CmdAddArg (&CA65, Arg);
649 }
650
651
652
653 static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
654 /* Handle the --bss-name option */
655 {
656     CmdAddArg (&CC65, "--bss-name");
657     CmdAddArg (&CC65, Arg);
658 }
659
660
661
662 static void OptCheckStack (const char* Opt attribute ((unused)),
663                            const char* Arg attribute ((unused)))
664 /* Handle the --check-stack option */
665 {
666     CmdAddArg (&CC65, "--check-stack");
667 }
668
669
670
671 static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
672 /* Handle the --code-name option */
673 {
674     CmdAddArg (&CC65, "--code-name");
675     CmdAddArg (&CC65, Arg);
676 }
677
678
679
680 static void OptCodeSize (const char* Opt attribute ((unused)), const char* Arg)
681 /* Handle the --codesize option */
682 {
683     CmdAddArg (&CC65, "--codesize");
684     CmdAddArg (&CC65, Arg);
685 }
686
687
688
689 static void OptCPU (const char* Opt attribute ((unused)), const char* Arg)
690 /* Handle the --cpu option */
691 {
692     /* Add the cpu type to the assembler and compiler */
693     CmdAddArg (&CA65, "--cpu");
694     CmdAddArg (&CA65, Arg);
695     CmdAddArg (&CC65, "--cpu");
696     CmdAddArg (&CC65, Arg);
697 }
698
699
700
701 static void OptCreateDep (const char* Opt attribute ((unused)),
702                           const char* Arg attribute ((unused)))
703 /* Handle the --create-dep option */
704 {
705     CmdAddArg (&CC65, "--create-dep");
706 }
707
708
709
710 static void OptDataName (const char* Opt attribute ((unused)), const char* Arg)
711 /* Handle the --data-name option */
712 {
713     CmdAddArg (&CC65, "--data-name");
714     CmdAddArg (&CC65, Arg);
715 }
716
717
718
719 static void OptDebug (const char* Opt attribute ((unused)),
720                       const char* Arg attribute ((unused)))
721 /* Debug mode (compiler and cl65 utility) */
722 {
723     CmdAddArg (&CC65, "-d");
724     Debug = 1;
725 }
726
727
728
729 static void OptDebugInfo (const char* Opt attribute ((unused)),
730                           const char* Arg attribute ((unused)))
731 /* Debug Info - add to compiler and assembler */
732 {
733     CmdAddArg (&CC65, "-g");
734     CmdAddArg (&CA65, "-g");
735 }
736
737
738
739 static void OptFeature (const char* Opt attribute ((unused)), const char* Arg)
740 /* Emulation features for the assembler */
741 {
742     CmdAddArg (&CA65, "--feature");
743     CmdAddArg (&CA65, Arg);
744 }
745
746
747
748 static void OptHelp (const char* Opt attribute ((unused)),
749                      const char* Arg attribute ((unused)))
750 /* Print help - cl65 */
751 {
752     Usage ();
753     exit (EXIT_SUCCESS);
754 }
755
756
757
758 static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
759 /* Include directory (compiler) */
760 {
761     CmdAddArg (&CC65, "-I");
762     CmdAddArg (&CC65, Arg);
763 }
764
765
766
767 static void OptListing (const char* Opt attribute ((unused)),
768                         const char* Arg attribute ((unused)))
769 /* Create an assembler listing */
770 {
771     CmdAddArg (&CA65, "-l");
772 }
773
774
775
776 static void OptMapFile (const char* Opt attribute ((unused)), const char* Arg)
777 /* Create a map file */
778 {
779     /* Create a map file (linker) */
780     CmdAddArg (&LD65, "-m");
781     CmdAddArg (&LD65, Arg);
782 }
783
784
785
786 static void OptModule (const char* Opt attribute ((unused)),
787                        const char* Arg attribute ((unused)))
788 /* Link as a module */
789 {
790     Module = 1;
791 }
792
793
794
795 static void OptModuleId (const char* Opt attribute ((unused)), const char* Arg)
796 /* Specify a module if for the linker */
797 {
798     /* Pass it straight to the linker */
799     CmdAddArg (&LD65, "--module-id");
800     CmdAddArg (&LD65, Arg);
801 }
802
803
804
805 static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg)
806 /* Handle the --rodata-name option */
807 {
808     CmdAddArg (&CC65, "--rodata-name");
809     CmdAddArg (&CC65, Arg);
810 }
811
812
813
814 static void OptSignedChars (const char* Opt attribute ((unused)),
815                             const char* Arg attribute ((unused)))
816 /* Make default characters signed */
817 {
818     CmdAddArg (&CC65, "-j");
819 }
820
821
822
823 static void OptStartAddr (const char* Opt attribute ((unused)), const char* Arg)
824 /* Set the default start address */
825 {
826     CmdAddArg (&LD65, "-S");
827     CmdAddArg (&LD65, Arg);
828 }
829
830
831
832 static void OptStaticLocals (const char* Opt attribute ((unused)),
833                              const char* Arg attribute ((unused)))
834 /* Place local variables in static storage */
835 {
836     CmdAddArg (&CC65, "-Cl");
837 }
838
839
840
841 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
842 /* Set the target system */
843 {
844     Target = FindTarget (Arg);
845     if (Target == TGT_UNKNOWN) {
846         Error ("No such target system: `%s'", Arg);
847     } else if (Target == TGT_MODULE) {
848         Error ("Cannot use `module' as target, use --module instead");
849     }
850 }
851
852
853
854 static void OptVerbose (const char* Opt attribute ((unused)),
855                         const char* Arg attribute ((unused)))
856 /* Verbose mode (compiler, assembler, linker) */
857 {
858     CmdAddArg (&CC65, "-v");
859     CmdAddArg (&CA65, "-v");
860     CmdAddArg (&LD65, "-v");
861 }
862
863
864
865 static void OptVersion (const char* Opt attribute ((unused)),
866                         const char* Arg attribute ((unused)))
867 /* Print version number */
868 {
869     fprintf (stderr,
870              "cl65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
871              VER_MAJOR, VER_MINOR, VER_PATCH);
872 }
873
874
875
876 int main (int argc, char* argv [])
877 /* Utility main program */
878 {
879     /* Program long options */
880     static const LongOpt OptTab[] = {
881         { "--add-source",       0,      OptAddSource            },
882         { "--ansi",             0,      OptAnsi                 },
883         { "--asm-include-dir",  1,      OptAsmIncludeDir        },
884         { "--bss-name",         1,      OptBssName              },
885         { "--check-stack",      0,      OptCheckStack           },
886         { "--code-name",        1,      OptCodeName             },
887         { "--codesize",         1,      OptCodeSize             },
888         { "--cpu",              1,      OptCPU                  },
889         { "--create-dep",       0,      OptCreateDep            },
890         { "--data-name",        1,      OptDataName             },
891         { "--debug",            0,      OptDebug                },
892         { "--debug-info",       0,      OptDebugInfo            },
893         { "--feature",          1,      OptFeature              },
894         { "--help",             0,      OptHelp                 },
895         { "--include-dir",      1,      OptIncludeDir           },
896         { "--listing",          0,      OptListing              },
897         { "--mapfile",          1,      OptMapFile              },
898         { "--module",           0,      OptModule               },
899         { "--module-id",        1,      OptModuleId             },
900         { "--rodata-name",      1,      OptRodataName           },
901         { "--signed-chars",     0,      OptSignedChars          },
902         { "--start-addr",       1,      OptStartAddr            },
903         { "--static-locals",    0,      OptStaticLocals         },
904         { "--target",           1,      OptTarget               },
905         { "--verbose",          0,      OptVerbose              },
906         { "--version",          0,      OptVersion              },
907     };
908
909     unsigned I;
910
911     /* Initialize the cmdline module */
912     InitCmdLine (&argc, &argv, "cl65");
913
914     /* Initialize the command descriptors */
915     CmdInit (&CC65, "cc65");
916     CmdInit (&CA65, "ca65");
917     CmdInit (&LD65, "ld65");
918     CmdInit (&GRC,  "grc");
919
920     /* Our default target is the C64 instead of "none" */
921     Target = TGT_C64;
922
923     /* Check the parameters */
924     I = 1;
925     while (I < ArgCount) {
926
927         /* Get the argument */
928         const char* Arg = ArgVec[I];
929
930         /* Check for an option */
931         if (Arg [0] == '-') {
932
933             switch (Arg [1]) {
934
935                 case '-':
936                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
937                     break;
938
939                 case 'A':
940                     /* Strict ANSI mode (compiler) */
941                     OptAnsi (Arg, 0);
942                     break;
943
944                 case 'C':
945                     if (Arg[2] == 'l' && Arg[3] == '\0') {
946                         /* Make local variables static */
947                         OptStaticLocals (Arg, 0);
948                     } else {
949                         /* Specify linker config file */
950                         LinkerConfig = GetArg (&I, 2);
951                     }
952                     break;
953
954                 case 'D':
955                     /* Define a preprocessor symbol (compiler) */
956                     CmdAddArg (&CC65, "-D");
957                     CmdAddArg (&CC65, GetArg (&I, 2));
958                     break;
959
960                 case 'I':
961                     /* Include directory (compiler) */
962                     OptIncludeDir (Arg, GetArg (&I, 2));
963                     break;
964
965                 case 'L':
966                     if (Arg[2] == 'n') {
967                         /* VICE label file (linker) */
968                         CmdAddArg (&LD65, "-Ln");
969                         CmdAddArg (&LD65, GetArg (&I, 3));
970                     } else {
971                         UnknownOption (Arg);
972                     }
973                     break;
974
975                 case 'O':
976                     /* Optimize code (compiler, also covers -Oi and others) */
977                     CmdAddArg (&CC65, Arg);
978                     break;
979
980                 case 'S':
981                     /* Dont assemble and link the created files */
982                     DontLink = DontAssemble = 1;
983                     break;
984
985                 case 'T':
986                     /* Include source as comment (compiler) */
987                     OptAddSource (Arg, 0);
988                     break;
989
990                 case 'V':
991                     /* Print version number */
992                     OptVersion (Arg, 0);
993                     break;
994
995                 case 'W':
996                     /* Suppress warnings - compiler and assembler */
997                     CmdAddArg (&CC65, "-W");
998                     CmdAddArg (&CA65, "-W");
999                     CmdAddArg (&CA65, "0");
1000                     break;
1001
1002                 case 'c':
1003                     /* Don't link the resulting files */
1004                     DontLink = 1;
1005                     break;
1006
1007                 case 'd':
1008                     /* Debug mode (compiler) */
1009                     OptDebug (Arg, 0);
1010                     break;
1011
1012                 case 'g':
1013                     /* Debugging - add to compiler and assembler */
1014                     OptDebugInfo (Arg, 0);
1015                     break;
1016
1017                 case 'h':
1018                 case '?':
1019                     /* Print help - cl65 */
1020                     OptHelp (Arg, 0);
1021                     break;
1022
1023                 case 'j':
1024                     /* Default characters are signed */
1025                     OptSignedChars (Arg, 0);
1026                     break;
1027
1028                 case 'l':
1029                     /* Create an assembler listing */
1030                     OptListing (Arg, 0);
1031                     break;
1032
1033                 case 'm':
1034                     /* Create a map file (linker) */
1035                     OptMapFile (Arg, GetArg (&I, 2));
1036                     break;
1037
1038                 case 'o':
1039                     /* Name the output file */
1040                     OutputName = GetArg (&I, 2);
1041                     break;
1042
1043                 case 't':
1044                     /* Set target system - compiler, assembler and linker */
1045                     OptTarget (Arg, GetArg (&I, 2));
1046                     break;
1047
1048                 case 'v':
1049                     if (Arg [2] == 'm') {
1050                         /* Verbose map file (linker) */
1051                         CmdAddArg (&LD65, "-vm");
1052                     } else {
1053                         /* Verbose mode (compiler, assembler, linker) */
1054                         OptVerbose (Arg, 0);
1055                     }
1056                     break;
1057
1058                 default:
1059                     UnknownOption (Arg);
1060             }
1061         } else {
1062
1063             /* Remember the first file name */
1064             if (FirstInput == 0) {
1065                 FirstInput = Arg;
1066             }
1067
1068             /* Determine the file type by the extension */
1069             switch (GetFileType (Arg)) {
1070
1071                 case FILETYPE_C:
1072                     /* Compile the file */
1073                     Compile (Arg);
1074                     break;
1075
1076                 case FILETYPE_ASM:
1077                     /* Assemble the file */
1078                     if (!DontAssemble) {
1079                         Assemble (Arg);
1080                     }
1081                     break;
1082
1083                 case FILETYPE_OBJ:
1084                 case FILETYPE_LIB:
1085                     /* Add to the linker files */
1086                     CmdAddFile (&LD65, Arg);
1087                     break;
1088
1089                 case FILETYPE_GR:
1090                     /* Add to the resource compiler files */
1091                     CompileRes (Arg);
1092                     break;
1093
1094                 default:
1095                     Error ("Don't know what to do with `%s'", Arg);
1096
1097             }
1098
1099         }
1100
1101         /* Next argument */
1102         ++I;
1103     }
1104
1105     /* Check if we had any input files */
1106     if (FirstInput == 0) {
1107         Warning ("No input files");
1108     }
1109
1110     /* Link the given files if requested and if we have any */
1111     if (DontLink == 0 && LD65.FileCount > 0) {
1112         Link ();
1113     }
1114
1115     /* Return an apropriate exit code */
1116     return EXIT_SUCCESS;
1117 }
1118
1119
1120
1121