DEADSOFTWARE

cpmake: add target-specific options (compiler/processor/os/linker)
[cpc.git] / src / generic / Dsw / Mod / MakeMain.cp
index c45005e5b42fc2664bd8b7f383f189795d8a28a7..48de2a89eddc90b6cb3f46dcdc82a973ccca0f4e 100644 (file)
@@ -26,6 +26,18 @@ MODULE DswMakeMain;
     (* module state flags *)
     imported = 0; trace = 1; hasObj = 2; hasSym = 3; hasErrors = 4; library = 5;
 
+    (* procesor types *)
+    anymach = 0; cmach = 1; mach386 = 10; mach68k = 20;
+
+    (* operation system types *)
+    anyos = 0; linux = 1; freebsd = 2; openbsd = 3; win32 = 4;
+
+    (* compiler types *)
+    anycp = 0; cpnative = 1; cpfront = 2;
+
+    (* internal linker types *)
+    anyint = 0; dev2 = 1;
+
     debugImport = FALSE;
     debugOrder = FALSE;
     debugJobs = FALSE;
@@ -55,7 +67,8 @@ MODULE DswMakeMain;
     mno, rno: INTEGER; (* num modules *)
     modList, lnkList, cmpList: ARRAY maxImps OF Module;
     def: Selector; (* with head, global list of selectors *)
-    auto: INTEGER;
+    processor, compiler, os, linker: INTEGER;
+    auto: BOOLEAN;
     jobs: INTEGER;
     exe: String;
 
@@ -149,16 +162,90 @@ MODULE DswMakeMain;
     RETURN x
   END StrToInt;
 
+  PROCEDURE Help;
+  BEGIN
+    Log.String("Usage: cpmake [options] module..."); Log.Ln;
+    Log.String("Options:"); Log.Ln;
+    Log.String("  -Tm cpu      Generate code for specified processor"); Log.Ln;
+    Log.String("      none     Unknown processor (cpfront only)"); Log.Ln;
+    Log.String("      486      Intel 486"); Log.Ln;
+    Log.String("  -Ts os       Generate code for specified operation system"); Log.Ln;
+    Log.String("      none     Unknown operation system"); Log.Ln;
+    Log.String("      linux    Linux"); Log.Ln;
+    Log.String("  -Tg compiler Specify Component Pascal compiler"); Log.Ln;
+    Log.String("      native   BlackBox based native code compiler"); Log.Ln;
+    Log.String("      cpfront  BlackBox based C code translator"); Log.Ln;
+    Log.String("  -Ti linker   Specify internal linker (native only)"); Log.Ln;
+    Log.String("      dev2     Dev2 based ELF/PE linker"); Log.Ln;
+(*
+    Log.String("  -Fp path     Add path with project"); Log.Ln;
+    Log.String("  -Fx path     Add postfix for project directories"); Log.Ln;
+    Log.String("  -Xp path     Use executable file for Component Pascal compiler"); Log.Ln;
+    Log.String("  -Xi path     Use executable file for internal linker (native only)"); Log.Ln;
+    Log.String("  -Cp params   Pass parameters to Component Pasacal compiler directly"); Log.Ln;
+    Log.String("  -Ci params   Pass parameters to internal linker directly"); Log.Ln;
+    Log.String("  -a           Enable automatic dependency resolution"); Log.Ln;
+*)
+    Log.String("  -o name      Generate executable file"); Log.Ln;
+    Log.String("  -j num       Specifies the number of jobs to run simultaneously"); Log.Ln;
+    Log.String('  -D ident["+"|"-"] Add preprocessor selector'); Log.Ln;
+    Log.String('  -U ident     Remove preprocessor selector'); Log.Ln;
+    Log.String("  -h           Print help"); Log.Ln;
+    Log.String("  -v           Print version"); Log.Ln;
+    Kernel.Quit(1)
+  END Help;
+
+  PROCEDURE ParseTargetOpts;
+    VAR s: DswOpts.String;
+  BEGIN
+    CASE DswOpts.GetOpt("m:s:g:i:") OF
+    | "m":
+      s := DswOpts.str;
+      Strings.ToLower(s, s);
+      IF s$ = "none" THEN processor := anymach
+      ELSIF s$ = "486" THEN processor := mach386
+      ELSIF s$ = "68k" THEN processor := mach68k
+      ELSE Log.String("unknwon processor "); Log.String(s); Log.Ln; INC(err)
+      END
+    | "s":
+      s := DswOpts.str;
+      Strings.ToLower(s, s);
+      IF s$ = "none" THEN os := anyos
+      ELSIF s$ = "linux" THEN os := linux
+      ELSE Log.String("unknwon os "); Log.String(s); Log.Ln; INC(err)
+      END
+    | "g":
+      s := DswOpts.str;
+      Strings.ToLower(s, s);
+      IF s$ = "native" THEN compiler := cpnative
+      ELSIF s$ = "cpfront" THEN compiler := cpfront
+      ELSE Log.String("unknwon compiler "); Log.String(s); Log.Ln; INC(err)
+      END
+    | "i":
+      s := DswOpts.str;
+      Strings.ToLower(s, s);
+      IF s$ = "dev2" THEN linker := dev2
+      ELSE Log.String("unknwon linker "); Log.String(s); Log.Ln; INC(err)
+      END
+    | ":": Log.String("missing argument for option -T"); Log.String(DswOpts.str); Log.Ln; INC(err)
+    | "?": Log.String("unknown option -T"); Log.String(DswOpts.str); Log.Ln; INC(err)
+    | 0X: Log.String("unknown option -T"); Log.Ln; INC(err)
+    END
+  END ParseTargetOpts;
+
   PROCEDURE ParseArgs;
   BEGIN
-    jobs := 1;
+    exe := NIL; auto := FALSE; jobs := 1; def.next := NIL; mno := 0; rno := 0;
+    processor := anymach; os := anyos; compiler := anycp;
     LOOP
-      CASE DswOpts.GetOpt("ao:j:D:U:") OF
-      | "a": INC(auto)
+      CASE DswOpts.GetOpt("ao:j:D:U:Th") OF
+      | "a": auto := TRUE
       | "o": exe := DswOpts.str
-      | "j": IF DswOpts.str = NIL THEN jobs := maxJobs ELSE jobs := MIN(MAX(StrToInt(DswOpts.str, 0), 1), maxJobs) END
+      | "j": jobs := MIN(MAX(StrToInt(DswOpts.str, 1), 1), maxJobs)
+      | "h": Help
       | "D": Define(DswOpts.str)
       | "U": Undefine(DswOpts.str)
+      | "T": ParseTargetOpts
       | ":": Log.String("missing argument for option -"); Log.String(DswOpts.str); Log.Ln; INC(err)
       | "?": Log.String("unknown option -"); Log.String(DswOpts.str); Log.Ln; INC(err)
       | "$": AddModule(DswOpts.str, def)
@@ -167,6 +254,34 @@ MODULE DswMakeMain;
     END
   END ParseArgs;
 
+  PROCEDURE CheckParams;
+  BEGIN
+    IF compiler = anycp THEN
+      Log.String("compiler not selected"); Log.Ln; INC(err)
+    ELSIF compiler = cpnative THEN
+      IF processor = anymach THEN
+        Log.String("processor not selected"); Log.Ln; INC(err)
+      ELSIF processor # mach386 THEN
+        Log.String("processor not supported by native compiler"); Log.Ln; INC(err)
+      END
+    END;
+    IF (compiler = cpfront) & (linker # anyint) THEN
+      Log.String("internal linker not required for cpfront"); Log.Ln; INC(err)
+    END;
+    IF (compiler = cpfront) & (exe # NIL) THEN
+      Log.String("cpfront can't out executable file"); Log.Ln; INC(err)
+    END;
+    IF (exe # NIL) & (compiler = cpnative) & (linker = anyint) THEN
+      Log.String("linker not selected"); Log.Ln; INC(err)
+    END;
+    IF (linker = dev2) & (os = anyos) THEN
+      Log.String("os not selected"); Log.Ln; INC(err)
+    END;
+    IF (exe # NIL) & (exe^ = "") THEN
+      Log.String("output file name can't be empty"); Log.Ln; INC(err)
+    END
+  END CheckParams;
+
   (* --------- loader --------- *)
 
   PROCEDURE Import (m: Module; IN name: DevCPT.Name);
@@ -428,7 +543,10 @@ MODULE DswMakeMain;
     ASSERT(m.path # "", 21);
     ASSERT(m.worker = NIL, 22);
     w := DswProcs.dir.New();
-    w.Program("cpc486");
+    CASE compiler OF
+    | cpnative: w.Program("cpc486")
+    | cpfront: w.Program("cpfront")
+    END;
     w.PutParam("-legacy");
     w.PutParam(m.path);
     w.Execute(ok);
@@ -489,15 +607,24 @@ MODULE DswMakeMain;
     END
   END Compile;
 
-  PROCEDURE Link;
-    VAR p: DswProcs.Process; i: INTEGER; ok: BOOLEAN;
+  PROCEDURE LinkDev2;
+    VAR p: DswProcs.Process; i, res: INTEGER; ok: BOOLEAN;
   BEGIN
-    ASSERT(exe # NIL, 20);
-    ASSERT(exe^ # "", 21);
+    ASSERT((exe # NIL) & (exe^ # ""), 20);
+    ASSERT(processor = mach386, 21);
+    ASSERT(compiler = cpnative, 22);
+    ASSERT(os IN {linux, freebsd, openbsd, win32}, 23);
     p := DswProcs.dir.New();
     p.Program("cpl486");
-    p.PutParam("-os");
-    p.PutParam("linux");
+    IF os # anyos THEN
+      p.PutParam("-os");
+      CASE os OF
+      | linux: p.PutParam("linux")
+      | freebsd: p.PutParam("freebsd")
+      | openbsd: p.PutParam("openbsd")
+      | win32: p.PutParam("win32")
+      END
+    END;
     p.PutParam("-kernel");
     p.PutParam("Kernel");
     p.PutParam("-main");
@@ -515,30 +642,46 @@ MODULE DswMakeMain;
     END;
     p.Execute(ok);
     IF ok THEN
-      i := p.Result();
-      IF i # 0 THEN
-        Log.String("linker terminated with error"); Log.Int(i); Log.Ln;
+      Log.String("Link "); Log.String(exe); Log.Ln;
+      res := p.Result();
+      IF res # 0 THEN
+        Log.String("linker terminated with error"); Log.Int(res); Log.Ln;
         INC(err)
       END
     ELSE
       Log.String("unable to execute linker"); Log.Int(i); Log.Ln;
       INC(err)
     END
+  END LinkDev2;
+
+  PROCEDURE Link;
+  BEGIN
+    IF exe # NIL THEN
+      CASE linker OF
+      | anyint: (* do not link *)
+      | dev2: LinkDev2
+      END
+    END
   END Link;
 
   PROCEDURE Main;
     VAR m: Module; s: Selector; p: DswProcs.Process; ok: BOOLEAN; i, res: INTEGER;
   BEGIN
-    IF Kernel.trapCount # 0 THEN Kernel.Quit(1) END;
-    ParseArgs;
-    IF err = 0 THEN
-      CheckDeps;
+    IF Kernel.trapCount = 0 THEN
+      ParseArgs;
       IF err = 0 THEN
-        Compile;
+        CheckParams;
         IF err = 0 THEN
-          IF exe # NIL THEN Link END;
+          CheckDeps;
+          IF err = 0 THEN
+            Compile;
+            IF err = 0 THEN
+              Link
+            END
+          END
         END
-      END
+     END
+    ELSE INC(err)
     END;
     IF err = 0 THEN Kernel.Quit(0)
     ELSE Kernel.Quit(1)