Parcourir la source

build: add pkg-config and multi-shim linking

Eric Streit il y a 2 jours
Parent
commit
988e9cb4d2

+ 2 - 1
README.md

@@ -69,7 +69,8 @@ tools/m2make/b_v3/M2make --separate --dialect iso \
 
 `M2 -c` emits one unit's QBE IR; `M2make --separate` is the transitive
 `.def` resolver and object linker.  The one-shot mode remains the default
-for the test suite and corpus.
+for the test suite and corpus.  `M2make` accepts repeated `--extra C`
+shims plus `--pkg-config pkg` and `--lib lib` for C library linking.
 
 Documentation PDFs are generated with Pandoc:
 

+ 130 - 14
tools/m2make/M2make.mod

@@ -1,7 +1,8 @@
 MODULE M2make;
 (* M2make: build-order front-end for the M2 and GNU Modula-2 compilers.
    Usage: M2make [-n] [-v] [-c m2|gm2] [-I dir] [-o out]
-                 [--m2bin path] [--shim path] main.mod
+                 [--m2bin path] [--shim path] [--extra path]...
+                 [--pkg-config pkg]... [--lib lib]... main.mod
    Follows IMPORT/FROM imports from main.mod transitively, sorts the
    modules topologically, skips the build when the output is newer
    than every source, otherwise invokes the selected compiler.
@@ -20,7 +21,8 @@ CONST
   MaxMods = 256;
   MaxDeps = 64;
   MaxDirs = 16;
-  MaxArgs = 64;
+  MaxArgs = 128;
+  MaxExtras = 16;
   StackCap = 264;
   NameStride = 64;
   PathStride = 256;
@@ -29,7 +31,7 @@ TYPE
   Name = ARRAY [0..63] OF CHAR;
   Path = ARRAY [0..255] OF CHAR;
   Line = ARRAY [0..2047] OF CHAR;
-  Cmd = ARRAY [0..2047] OF CHAR;
+  Cmd = ARRAY [0..4095] OF CHAR;
 
 VAR
   nMods: CARDINAL;
@@ -56,7 +58,10 @@ VAR
   mainPath, outName, m2bin, shimPath: Path;
   m2Flags: Cmd;
   dialect: Name;
-  extraC: Path;  (* extra C file linked in m2 mode (may be empty) *)
+  extraPool: ARRAY [0 .. MaxExtras * PathStride - 1] OF CHAR;
+  pkgPool: ARRAY [0 .. MaxExtras * PathStride - 1] OF CHAR;
+  libPool: ARRAY [0 .. MaxExtras * PathStride - 1] OF CHAR;
+  nExtras, nPkgs, nLibs: CARDINAL;
   nDirs: CARDINAL;
   progName: Name;
   wantProg: BOOLEAN;
@@ -257,6 +262,28 @@ BEGIN
   END
 END PutDir;
 
+PROCEDURE GetPool(VAR pool: ARRAY OF CHAR; idx: CARDINAL;
+                  VAR dst: Path);
+VAR k: CARDINAL;
+BEGIN
+  k := 0;
+  WHILE k <= HIGH(dst) DO
+    dst[k] := pool[idx * PathStride + k];
+    INC(k)
+  END
+END GetPool;
+
+PROCEDURE PutPool(VAR pool: ARRAY OF CHAR; idx: CARDINAL;
+                  src: ARRAY OF CHAR);
+VAR k: CARDINAL;
+BEGIN
+  k := 0;
+  WHILE k <= HIGH(src) DO
+    pool[idx * PathStride + k] := src[k];
+    INC(k)
+  END
+END PutPool;
+
 (* ---------------- console output ---------------- *)
 
 PROCEDURE Out(s: ARRAY OF CHAR);
@@ -291,8 +318,9 @@ END Die;
 PROCEDURE Usage;
 BEGIN
   Out("Usage: M2make [-n] [-v] [-c m2|gm2] [-I dir] [-o out]"); OutLn;
-  Out("       [--m2bin path] [--shim path] [--extra path]
-       [--m2flag flag] [--dialect pim|iso|gm2] [--separate] main.mod"); OutLn
+  Out("       [--m2bin path] [--shim path] [--extra path]..."); OutLn;
+  Out("       [--pkg-config pkg]... [--lib lib]..."); OutLn;
+  Out("       [--m2flag flag] [--dialect pim|iso|gm2] [--separate] main.mod"); OutLn
 END Usage;
 
 (* ---------------- module table ---------------- *)
@@ -705,6 +733,13 @@ BEGIN
     IF SrcNewer(tmpP, outT) THEN RETURN TRUE END;
     INC(k)
   END;
+  IF SrcNewer(shimPath, outT) THEN RETURN TRUE END;
+  k := 0;
+  WHILE k < nExtras DO
+    GetPool(extraPool, k, tmpP);
+    IF SrcNewer(tmpP, outT) THEN RETURN TRUE END;
+    INC(k)
+  END;
   RETURN FALSE
 END NeedBuild;
 
@@ -820,6 +855,51 @@ BEGIN
   Copy(segA, cmd)
 END AppendSeg;
 
+PROCEDURE AppendExtras(VAR cmd: ARRAY OF CHAR);
+VAR k: CARDINAL;
+BEGIN
+  k := 0;
+  WHILE k < nExtras DO
+    GetPool(extraPool, k, tmpP);
+    IF Len(tmpP) > 0 THEN AppendTok(cmd, tmpP) END;
+    INC(k)
+  END
+END AppendExtras;
+
+PROCEDURE AppendPkgConfigs(VAR cmd: ARRAY OF CHAR);
+VAR k: CARDINAL;
+BEGIN
+  k := 0;
+  WHILE k < nPkgs DO
+    GetPool(pkgPool, k, tmpP);
+    IF Len(tmpP) > 0 THEN
+      AppendSeg(cmd, " $(pkg-config --cflags --libs ");
+      AppendSeg(cmd, tmpP);
+      AppendSeg(cmd, ")")
+    END;
+    INC(k)
+  END
+END AppendPkgConfigs;
+
+PROCEDURE AppendLibs(VAR cmd: ARRAY OF CHAR);
+VAR k: CARDINAL;
+BEGIN
+  k := 0;
+  WHILE k < nLibs DO
+    GetPool(libPool, k, tmpP);
+    IF Len(tmpP) > 0 THEN
+      AppendSeg(cmd, " ");
+      IF (tmpP[0] = "-") OR (tmpP[0] = "/") THEN
+        AppendSeg(cmd, tmpP)
+      ELSE
+        AppendSeg(cmd, "-l");
+        AppendSeg(cmd, tmpP)
+      END
+    END;
+    INC(k)
+  END
+END AppendLibs;
+
 PROCEDURE BuildM2(out: ARRAY OF CHAR);
 VAR cmd: Cmd; k: CARDINAL; m: CARDINAL; rc: INTEGER;
 BEGIN
@@ -849,7 +929,9 @@ BEGIN
   AppendSeg(cmd, progName);
   AppendSeg(cmd, ".s ");
   AppendTok(cmd, shimPath);
-  IF Len(extraC) > 0 THEN AppendTok(cmd, extraC) END;
+  AppendExtras(cmd);
+  AppendPkgConfigs(cmd);
+  AppendLibs(cmd);
   AppendSeg(cmd, " -o ");
   AppendTok(cmd, out);
   AppendSeg(cmd, " -lm");
@@ -904,9 +986,10 @@ END SepObjStale;
 PROCEDURE AbiStampOK (): BOOLEAN;
 (* Content check for the object ABI/flags stamp.  This is deliberately
    a small build-system marker, not a per-object binary format. *)
-VAR h: M2makeOS.RdFile; line: Line; want: Path; ok: BOOLEAN;
+VAR h: M2makeOS.RdFile; line: Line; want, stamp: Path; ok: BOOLEAN;
 BEGIN
-  h := M2makeOS.OpenRead(AbiStampPath);
+  Copy(AbiStampPath, stamp);
+  h := M2makeOS.OpenRead(stamp);
   IF h = NIL THEN RETURN FALSE END;
   ok := M2makeOS.ReadLine(h, line, HIGH(line) + 1);
   M2makeOS.CloseRead(h);
@@ -944,7 +1027,7 @@ PROCEDURE BuildM2Separate(out: ARRAY OF CHAR);
 VAR cmd: Cmd; k, m: CARDINAL; rc: INTEGER;
     obj, src, ssafile, sfile, flags: Path;
     outT: LONGINT; compiledAny, linkNeeded, abiOK, hasGeneric: BOOLEAN;
-    gi, k2: INTEGER;
+    gi: INTEGER; k2: CARDINAL;
 BEGIN
   Zero(cmd);
   abiOK := AbiStampOK();
@@ -1067,8 +1150,11 @@ BEGIN
         INC(k)
       END;
       IF SrcNewer(shimPath, outT) THEN linkNeeded := TRUE END;
-      IF Len(extraC) > 0 THEN
-        IF SrcNewer(extraC, outT) THEN linkNeeded := TRUE END
+      k := 0;
+      WHILE k < nExtras DO
+        GetPool(extraPool, k, tmpP);
+        IF SrcNewer(tmpP, outT) THEN linkNeeded := TRUE END;
+        INC(k)
       END
     END
   END;
@@ -1093,7 +1179,9 @@ BEGIN
     INC(k)
   END;
   AppendTok(tmpCmd, shimPath);
-  IF Len(extraC) > 0 THEN AppendTok(tmpCmd, extraC) END;
+  AppendExtras(tmpCmd);
+  AppendPkgConfigs(tmpCmd);
+  AppendLibs(tmpCmd);
   AppendSeg(tmpCmd, " -o ");
   AppendTok(tmpCmd, out);
   AppendSeg(tmpCmd, " -lm");
@@ -1192,6 +1280,9 @@ BEGIN
       END;
       INC(k)
     END;
+    AppendExtras(seg);
+    AppendPkgConfigs(seg);
+    AppendLibs(seg);
     AppendCmd(cmd, seg)
   END;
   IF Len(cmd) = 0 THEN
@@ -1257,6 +1348,9 @@ BEGIN
   Zero(m2Flags);
   dialect[0] := CHR(0);
   nDirs := 0;
+  nExtras := 0;
+  nPkgs := 0;
+  nLibs := 0;
   na := 0;
   LOOP
     IF na >= MaxArgs THEN Die("M2make: too many arguments", 2) END;
@@ -1343,7 +1437,29 @@ BEGIN
         M2makeOS.ExitNow(2)
       END;
       INC(na);
-      Copy(s, extraC)
+      IF nExtras >= MaxExtras THEN Die("M2make: too many --extra files", 2) END;
+      PutPool(extraPool, nExtras, s);
+      INC(nExtras)
+    ELSIF Cmp(s, "--pkg-config") = 0 THEN
+      ok := M2makeOS.GetArg(na, s, HIGH(s) + 1);
+      IF NOT ok THEN
+        Out("M2make: --pkg-config expects a package"); OutLn;
+        M2makeOS.ExitNow(2)
+      END;
+      INC(na);
+      IF nPkgs >= MaxExtras THEN Die("M2make: too many --pkg-config packages", 2) END;
+      PutPool(pkgPool, nPkgs, s);
+      INC(nPkgs)
+    ELSIF Cmp(s, "--lib") = 0 THEN
+      ok := M2makeOS.GetArg(na, s, HIGH(s) + 1);
+      IF NOT ok THEN
+        Out("M2make: --lib expects a library"); OutLn;
+        M2makeOS.ExitNow(2)
+      END;
+      INC(na);
+      IF nLibs >= MaxExtras THEN Die("M2make: too many --lib entries", 2) END;
+      PutPool(libPool, nLibs, s);
+      INC(nLibs)
     ELSIF (Cmp(s, "-h") = 0) OR (Cmp(s, "--help") = 0) THEN
       Usage;
       M2makeOS.ExitNow(0)

+ 11 - 3
tools/m2make/README.md

@@ -9,7 +9,8 @@ to do), 1 build failure (incl. import cycles), 2 usage error.
 
 ```sh
 M2make [-n] [-v] [-c m2|gm2] [-I dir] [-o out]
-       [--m2bin path] [--shim path] [--extra path]
+       [--m2bin path] [--shim path] [--extra path]...
+       [--pkg-config pkg]... [--lib lib]...
        [--m2flag flag] [--dialect pim|iso|gm2] [--separate] main.mod
 ```
 
@@ -23,7 +24,13 @@ M2make [-n] [-v] [-c m2|gm2] [-I dir] [-o out]
 - `--m2bin path`: M2 driver binary (default `M2`).
 - `--shim path`: C runtime shim for `m2` mode (default `shim.c`).
 - `--extra path`: extra C file linked in `m2` mode (after the shim;
-  e.g. a tool's own `m2make_os.c`).
+  e.g. a tool's own `m2make_os.c`). Repeatable for multiple C shims.
+- `--pkg-config pkg`: append
+  `$(pkg-config --cflags --libs pkg)` to the link command.
+  Repeatable.
+- `--lib lib`: append one library to the link. A bare name `foo` means
+  `-lfoo`; a value beginning with `-` or `/` (for example `-L/dir` or
+  `/usr/lib/libfoo.so`) is appended unchanged. Repeatable.
 - `--m2flag flag`: pass one argument to the M2 driver before the source
   list (used by the bootstrap fixpoint for `-legacyopen1d`).
 - `--dialect pim|iso|gm2`: add `lib/<dialect>`, `lib/common`,
@@ -37,7 +44,8 @@ M2make [-n] [-v] [-c m2|gm2] [-I dir] [-o out]
   compiler ABI/flags content.
 
 `m2` mode (default, one-shot) runs one session — `<m2bin> <ordered .def/.mod files>`
-then `qbe` then `cc <image>.s <shim> [<extra>] -o <out> -lm` — and
+then `qbe` then
+`cc <image>.s <shim> [<extra>...] [<pkg-config flags>] [<libs>] -o <out> -lm` — and
 gates on M2's `Parsed correctly` verdict (M2 exits 0 even on
 failure).  Modules the session needs but that are not named on the
 command line are resolved from the `-I` directories (so

+ 15 - 0
tools/m2make/tests/LinkExtra.mod

@@ -0,0 +1,15 @@
+MODULE LinkExtra;
+(* Multiple extra C shims and a pkg-config/link test. *)
+
+PROCEDURE extra_one () : INTEGER; EXTERNAL "extra_one";
+PROCEDURE extra_two () : INTEGER; EXTERNAL "extra_two";
+
+VAR ExitCode : INTEGER;
+
+BEGIN
+  IF extra_one() + extra_two() = 42 THEN
+    ExitCode := 42
+  ELSE
+    ExitCode := 1
+  END
+END LinkExtra.

+ 1 - 0
tools/m2make/tests/extra_one.c

@@ -0,0 +1 @@
+long extra_one(void) { return 19; }

+ 1 - 0
tools/m2make/tests/extra_two.c

@@ -0,0 +1 @@
+long extra_two(void) { return 23; }

+ 10 - 0
tools/m2make/tests/m2make-test.pc

@@ -0,0 +1,10 @@
+prefix=/tmp
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: m2make-test
+Description: M2make link integration test
+Version: 1.0
+Libs: -lm
+Cflags: -I${includedir}

+ 32 - 1
tools/m2make/tests/run_tests.sh

@@ -89,6 +89,37 @@ case "$out" in
   *) no "m2-mode up-to-date skip: $out" ;;
 esac
 
+# --- multiple extra C shims, --lib and --pkg-config (one-shot) ---
+rm -rf gen_ssa LinkExtra m2make.log
+OLD_PKG_CONFIG_PATH="$PKG_CONFIG_PATH"
+PKG_CONFIG_PATH="$PWD/tests${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
+export PKG_CONFIG_PATH
+if $V3M -c m2 --m2bin ../../compiler/M2 --shim ../../runtime/syslib/shim.c \
+     --extra tests/extra_one.c --extra tests/extra_two.c \
+     --pkg-config m2make-test --lib m -o LinkExtra tests/LinkExtra.mod \
+     > /tmp/m2make_t.log 2>&1; then
+  ./LinkExtra > /dev/null 2>&1; rc=$?
+  if [ "$rc" = "42" ]; then ok "multiple --extra + --pkg-config + --lib"
+  else no "multiple --extra + --pkg-config + --lib (rc=$rc)"; fi
+else
+  no "multiple --extra + --pkg-config + --lib (build)"
+fi
+
+# --- same link integration in separate-object mode ---
+rm -rf gen_ssa LinkExtraSep m2make.log
+if $V3M --separate -c m2 --m2bin ../../compiler/M2 --shim ../../runtime/syslib/shim.c \
+     --extra tests/extra_one.c --extra tests/extra_two.c \
+     --pkg-config m2make-test --lib m -o LinkExtraSep tests/LinkExtra.mod \
+     > /tmp/m2make_t.log 2>&1; then
+  ./LinkExtraSep > /dev/null 2>&1; rc=$?
+  if [ "$rc" = "42" ]; then ok "separate --extra + --pkg-config + --lib"
+  else no "separate --extra + --pkg-config + --lib (rc=$rc)"; fi
+else
+  no "separate --extra + --pkg-config + --lib (build)"
+fi
+PKG_CONFIG_PATH="$OLD_PKG_CONFIG_PATH"
+export PKG_CONFIG_PATH
+
 # --- separate-object build, up-to-date, incremental relink ---
 rm -rf gen_ssa SepMain m2make.log
 if $V3M --separate -c m2 --m2bin ../../compiler/M2 --shim ../../runtime/syslib/shim.c \
@@ -183,7 +214,7 @@ else
   no "gm2-built M2make drives m2 build"
 fi
 
-rm -f Main MainX Main2 SepMain CDefProg GenProg GCProg *.o
+rm -f Main MainX Main2 SepMain LinkExtra LinkExtraSep CDefProg GenProg GCProg *.o
 rm -rf gen_ssa
 rm -f m2make.log