build bash_process in Isabelle/Scala, with etc/platforms.prop to preserve all platform directories (e.g. for SSH upload);
authorwenzelm
Tue, 26 Mar 2024 11:15:48 +0100
changeset 80002 ee449ca91c3b
parent 80001 98384596b54b
child 80003 7e52091795e8
build bash_process in Isabelle/Scala, with etc/platforms.prop to preserve all platform directories (e.g. for SSH upload);
Admin/bash_process/bash_process.c
Admin/bash_process/build
Admin/bash_process/etc/settings
etc/build.props
src/Pure/Admin/component_bash_process.scala
src/Pure/System/isabelle_tool.scala
--- a/Admin/bash_process/bash_process.c	Tue Mar 26 10:30:41 2024 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*  Author:     Makarius
-
-Bash process with separate process group id.
-*/
-
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <time.h>
-#include <unistd.h>
-
-static void fail(const char *msg)
-{
-  fprintf(stderr, "%s\n", msg);
-  fflush(stderr);
-  exit(2);
-}
-
-static time_t now()
-{
-  struct timeval tv;
-  if (gettimeofday(&tv, NULL) == 0) {
-    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-  }
-  else {
-    return time(NULL) * 1000;
-  }
-}
-
-
-int main(int argc, char *argv[])
-{
-  /* args */
-
-  if (argc < 2) {
-    fprintf(stderr, "Bad arguments: missing TIMING_FILE\n");
-    fflush(stderr);
-    exit(1);
-  }
-  char *timing_name = argv[1];
-
-
-  /* potential fork */
-
-  time_t time_start = now();
-
-  if (strlen(timing_name) > 0 || setsid() == -1) {
-    pid_t pid = fork();
-
-    if (pid == -1) fail("Cannot set session id (failed to fork)");
-    else if (pid != 0) {
-      int status;
-
-      // ingore SIGINT
-      struct sigaction sa;
-      memset(&sa, 0, sizeof(sa));
-      sa.sa_handler = SIG_IGN;
-      sigaction(SIGINT, &sa, 0);
-
-      if (waitpid(pid, &status, 0) == -1) {
-        fail("Cannot join forked process");
-      }
-
-      /* report timing */
-
-      if (strlen(timing_name) > 0) {
-        long long timing_elapsed = now() - time_start;
-
-        struct rusage ru;
-        getrusage(RUSAGE_CHILDREN, &ru);
-
-        long long timing_cpu =
-          ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000 +
-          ru.ru_stime.tv_sec * 1000 + ru.ru_stime.tv_usec / 1000;
-
-        FILE *timing_file = fopen(timing_name, "w");
-        if (timing_file == NULL) fail("Cannot open timing file");
-        fprintf(timing_file, "%lld %lld", timing_elapsed, timing_cpu);
-        fclose(timing_file);
-      }
-
-      if (WIFEXITED(status)) {
-        exit(WEXITSTATUS(status));
-      }
-      else if (WIFSIGNALED(status)) {
-        exit(128 + WTERMSIG(status));
-      }
-      else {
-        fail("Unknown status of forked process");
-      }
-    }
-    else if (setsid() == -1) fail("Cannot set session id (after fork)");
-  }
-
-
-  /* report pid */
-
-  fprintf(stdout, "%d\n", getpid());
-  fflush(stdout);
-
-
-  /* shift command line */
-
-  int i;
-  for (i = 2; i < argc; i++) {
-    argv[i - 2] = argv[i];
-  }
-  argv[argc - 2] = NULL;
-  argv[argc - 1] = NULL;
-
-
-  /* exec */
-
-  execvp("bash", argv);
-  fail("Cannot exec process");
-}
--- a/Admin/bash_process/build	Tue Mar 26 10:30:41 2024 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-#!/usr/bin/env bash
-#
-# Multi-platform build script
-
-unset CDPATH
-THIS="$(cd "$(dirname "$0")"; pwd)"
-PRG="$(basename "$0")"
-
-
-# diagnostics
-
-function usage()
-{
-  echo
-  echo "Usage: $PRG PLATFORM"
-  echo
-  exit 1
-}
-
-function fail()
-{
-  echo "$1" >&2
-  exit 2
-}
-
-
-# command line args
-
-[ "$#" -eq 0 ] && usage
-PLATFORM="$1"; shift
-
-[ "$#" -eq 0 ] || usage
-
-
-# main
-
-PLATFORM_DIR="platform_${PLATFORM}"
-
-case "$PLATFORM" in
-  arm64-linux | arm64-darwin)
-    mkdir -p "$PLATFORM_DIR"
-    cc -Wall bash_process.c -o "$PLATFORM_DIR/bash_process"
-    ;;
-  x86_64-linux | x86_64-darwin)
-    mkdir -p "$PLATFORM_DIR"
-    cc -Wall -m64 bash_process.c -o "$PLATFORM_DIR/bash_process"
-    ;;
-  x86_64-cygwin)
-    mkdir -p "$PLATFORM_DIR"
-    cc -Wall bash_process.c -o "$PLATFORM_DIR/bash_process.exe"
-    ;;
-  *)
-    fail "Bad target platform: \"$PLATFORM\""
-    ;;
-esac
--- a/Admin/bash_process/etc/settings	Tue Mar 26 10:30:41 2024 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-# -*- shell-script -*- :mode=shellscript:
-
-ISABELLE_BASH_PROCESS_HOME="$COMPONENT"
-ISABELLE_BASH_PROCESS="$ISABELLE_BASH_PROCESS_HOME/platform_${ISABELLE_APPLE_PLATFORM64:-$ISABELLE_PLATFORM64}/bash_process"
--- a/etc/build.props	Tue Mar 26 10:30:41 2024 +0100
+++ b/etc/build.props	Tue Mar 26 11:15:48 2024 +0100
@@ -18,6 +18,7 @@
   src/Pure/Admin/build_status.scala \
   src/Pure/Admin/check_sources.scala \
   src/Pure/Admin/ci_build.scala \
+  src/Pure/Admin/component_bash_process.scala \
   src/Pure/Admin/component_csdp.scala \
   src/Pure/Admin/component_cvc5.scala \
   src/Pure/Admin/component_cygwin.scala \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/Admin/component_bash_process.scala	Tue Mar 26 11:15:48 2024 +0100
@@ -0,0 +1,226 @@
+/*  Title:      Pure/Admin/component_bash_process.scala
+    Author:     Makarius
+
+Build bash_process component from C source.
+*/
+
+package isabelle
+
+
+object Component_Bash_Process {
+  /* build bash_process */
+
+  def build_bash_process(
+    progress: Progress = new Progress,
+    target_dir: Path = Path.current,
+  ): Unit = {
+    Isabelle_System.require_command("cc")
+
+
+    /* component */
+
+    val component_date = Date.Format.alt_date(Date.now())
+    val component_name = "bash_process-" + component_date
+    val component_dir =
+      Components.Directory(target_dir + Path.basic(component_name)).create(progress = progress)
+
+
+    /* platform */
+
+    val platform_name =
+      proper_string(Isabelle_System.getenv("ISABELLE_APPLE_PLATFORM64")) orElse
+      proper_string(Isabelle_System.getenv("ISABELLE_PLATFORM64")) getOrElse
+      error("Missing ISABELLE_PLATFORM64")
+
+    val platform_dir =
+      Isabelle_System.make_directory(component_dir.path + Path.basic(platform_name))
+
+
+    /* source */
+
+    val source_file = Path.explode("bash_process.c")
+    File.write(component_dir.path + source_file,
+"""/*  Author:     Makarius
+    License:    Isabelle BSD-3
+
+Bash process with separate process group id.
+*/
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static void fail(const char *msg)
+{
+  fprintf(stderr, "%s\n", msg);
+  fflush(stderr);
+  exit(2);
+}
+
+static time_t now()
+{
+  struct timeval tv;
+  if (gettimeofday(&tv, NULL) == 0) {
+    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+  }
+  else {
+    return time(NULL) * 1000;
+  }
+}
+
+
+int main(int argc, char *argv[])
+{
+  /* args */
+
+  if (argc < 2) {
+    fprintf(stderr, "Bad arguments: missing TIMING_FILE\n");
+    fflush(stderr);
+    exit(1);
+  }
+  char *timing_name = argv[1];
+
+
+  /* potential fork */
+
+  time_t time_start = now();
+
+  if (strlen(timing_name) > 0 || setsid() == -1) {
+    pid_t pid = fork();
+
+    if (pid == -1) fail("Cannot set session id (failed to fork)");
+    else if (pid != 0) {
+      int status;
+
+      // ingore SIGINT
+      struct sigaction sa;
+      memset(&sa, 0, sizeof(sa));
+      sa.sa_handler = SIG_IGN;
+      sigaction(SIGINT, &sa, 0);
+
+      if (waitpid(pid, &status, 0) == -1) {
+        fail("Cannot join forked process");
+      }
+
+      /* report timing */
+
+      if (strlen(timing_name) > 0) {
+        long long timing_elapsed = now() - time_start;
+
+        struct rusage ru;
+        getrusage(RUSAGE_CHILDREN, &ru);
+
+        long long timing_cpu =
+          ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000 +
+          ru.ru_stime.tv_sec * 1000 + ru.ru_stime.tv_usec / 1000;
+
+        FILE *timing_file = fopen(timing_name, "w");
+        if (timing_file == NULL) fail("Cannot open timing file");
+        fprintf(timing_file, "%lld %lld", timing_elapsed, timing_cpu);
+        fclose(timing_file);
+      }
+
+      if (WIFEXITED(status)) {
+        exit(WEXITSTATUS(status));
+      }
+      else if (WIFSIGNALED(status)) {
+        exit(128 + WTERMSIG(status));
+      }
+      else {
+        fail("Unknown status of forked process");
+      }
+    }
+    else if (setsid() == -1) fail("Cannot set session id (after fork)");
+  }
+
+
+  /* report pid */
+
+  fprintf(stdout, "%d\n", getpid());
+  fflush(stdout);
+
+
+  /* shift command line */
+
+  int i;
+  for (i = 2; i < argc; i++) {
+    argv[i - 2] = argv[i];
+  }
+  argv[argc - 2] = NULL;
+  argv[argc - 1] = NULL;
+
+
+  /* exec */
+
+  execvp("bash", argv);
+  fail("Cannot exec process");
+}
+""")
+
+
+    /* build */
+
+    progress.echo("Building bash_process for " + platform_name + " ...")
+    progress.bash("cc ../bash_process.c -o bash_process", cwd = platform_dir.file).check
+
+
+    /* settings */
+
+    component_dir.write_settings("""
+ISABELLE_BASH_PROCESS_HOME="$COMPONENT"
+ISABELLE_BASH_PROCESS="$ISABELLE_BASH_PROCESS_HOME/${ISABELLE_APPLE_PLATFORM64:-$ISABELLE_PLATFORM64}/bash_process"
+""")
+
+
+    /* platform.props */
+
+    File.write(component_dir.platform_props,
+      Platform.Family.list.map(family => family.toString + " = ").mkString("", "\n", "\n"))
+
+
+    /* README */
+
+    File.write(component_dir.README,
+"""The bash_process executable has been built like this:
+
+  cc -Wall bash_process.c -o bash_process
+
+
+        Makarius
+        """ + Date.Format.date(Date.now()) + "\n")
+}
+
+
+  /* Isabelle tool wrapper */
+
+  val isabelle_tool =
+    Isabelle_Tool("component_bash_process", "build bash_process component from C source",
+      Scala_Project.here,
+      { args =>
+        var target_dir = Path.current
+
+        val getopts = Getopts("""
+Usage: isabelle component_bash_process [OPTIONS]
+
+  Options are:
+    -D DIR       target directory (default ".")
+
+  Build prover component from official download.
+""",
+          "D:" -> (arg => target_dir = Path.explode(arg)))
+
+        val more_args = getopts(args)
+        if (more_args.nonEmpty) getopts.usage()
+
+        val progress = new Console_Progress()
+
+        build_bash_process(progress = progress, target_dir = target_dir)
+      })
+}
--- a/src/Pure/System/isabelle_tool.scala	Tue Mar 26 10:30:41 2024 +0100
+++ b/src/Pure/System/isabelle_tool.scala	Tue Mar 26 11:15:48 2024 +0100
@@ -166,6 +166,7 @@
   Build_Log.isabelle_tool,
   Build_Status.isabelle_tool,
   Check_Sources.isabelle_tool,
+  Component_Bash_Process.isabelle_tool,
   Component_CSDP.isabelle_tool,
   Component_CVC5.isabelle_tool,
   Component_Cygwin.isabelle_tool,