src/Pure/Admin/component_polyml.scala
changeset 82463 3125fd1ee69c
parent 82142 508a673c87ac
child 82464 7c9fcf2d6706
equal deleted inserted replaced
82457:5a0d1075911c 82463:3125fd1ee69c
    32         options =
    32         options =
    33           List("--host=x86_64-w64-mingw32", "CPPFLAGS=-I/mingw64/include", "--disable-windows-gui"),
    33           List("--host=x86_64-w64-mingw32", "CPPFLAGS=-I/mingw64/include", "--disable-windows-gui"),
    34         setup = MinGW.environment_export,
    34         setup = MinGW.environment_export,
    35         libs = Set("libgcc_s_seh", "libgmp", "libstdc++", "libwinpthread")))
    35         libs = Set("libgcc_s_seh", "libgmp", "libstdc++", "libwinpthread")))
    36 
    36 
       
    37   def bash(
       
    38     cwd: Path,
       
    39     platform: Isabelle_Platform,
       
    40     mingw: MinGW,
       
    41     script: String,
       
    42     redirect: Boolean = false,
       
    43     progress: Progress = new Progress
       
    44   ): Process_Result = {
       
    45     val script1 =
       
    46       if (platform.is_arm && platform.is_macos) {
       
    47         "arch -arch arm64 bash -c " + Bash.string(script)
       
    48       }
       
    49       else mingw.bash_script(script)
       
    50     progress.bash(script1, cwd = cwd, redirect = redirect, echo = progress.verbose)
       
    51   }
       
    52 
    37   def polyml_platform(arch_64: Boolean): String = {
    53   def polyml_platform(arch_64: Boolean): String = {
    38     val platform = Isabelle_Platform.self
    54     val platform = Isabelle_Platform.self
    39     (if (arch_64) platform.arch_64 else platform.arch_64_32) + "-" + platform.os_name
    55     (if (arch_64) platform.arch_64 else platform.arch_64_32) + "-" + platform.os_name
    40   }
    56   }
    41 
    57 
    42   def make_polyml(
    58   def make_polyml(
    43     root: Path,
    59     root: Path,
       
    60     gmp_root: Option[Path] = None,
    44     sha1_root: Option[Path] = None,
    61     sha1_root: Option[Path] = None,
    45     target_dir: Path = Path.current,
    62     target_dir: Path = Path.current,
    46     arch_64: Boolean = false,
    63     arch_64: Boolean = false,
    47     options: List[String] = Nil,
    64     options: List[String] = Nil,
    48     mingw: MinGW = MinGW.none,
    65     mingw: MinGW = MinGW.none,
    60         error("Bad OS platform: " + quote(platform.os_name)))
    77         error("Bad OS platform: " + quote(platform.os_name)))
    61 
    78 
    62     if (platform.is_linux) Isabelle_System.require_command("patchelf")
    79     if (platform.is_linux) Isabelle_System.require_command("patchelf")
    63 
    80 
    64 
    81 
    65     /* bash */
    82     /* configure and make */
    66 
    83 
    67     def bash(
    84     val configure_options = {
    68       cwd: Path, script: String,
    85       val options1 = if (gmp_root.nonEmpty) List("--with-gmp") else List("--without-gmp")
    69       redirect: Boolean = false,
    86 
    70       echo: Boolean = false
    87       val options2 =
    71     ): Process_Result = {
    88         for (opt <- info.options) yield {
    72       val script1 =
    89           if (opt.startsWith("CFLAGS=") && gmp_root.nonEmpty) {
    73         if (platform.is_arm && platform.is_macos) {
    90             val root0 = gmp_root.get.absolute
    74           "arch -arch arm64 bash -c " + Bash.string(script)
    91             val root1 = mingw.standard_path(root0)
       
    92             require(root0.implode == File.bash_path(root0), "Bad directory name " + root0)
       
    93             opt + " " + "-I" + root1 + "/include -L" + root1 + "/lib"
       
    94           }
       
    95           else opt
    75         }
    96         }
    76         else mingw.bash_script(script)
    97 
    77       progress.bash(script1, cwd = cwd, redirect = redirect, echo = echo)
    98       val options3 = if (arch_64) Nil else List("--enable-compact32bit")
       
    99 
       
   100       List("--disable-shared", "--enable-intinf-as-int") :::
       
   101         options1 ::: options2 ::: options ::: options3
    78     }
   102     }
    79 
   103 
    80 
   104     bash(root, platform, mingw,
    81     /* configure and make */
       
    82 
       
    83     val configure_options =
       
    84       List("--disable-shared", "--enable-intinf-as-int", "--with-gmp") :::
       
    85         info.options ::: options ::: (if (arch_64) Nil else List("--enable-compact32bit"))
       
    86 
       
    87     bash(root,
       
    88       info.setup + "\n" +
   105       info.setup + "\n" +
    89       """
   106       """
    90         [ -f Makefile ] && make distclean
   107         [ -f Makefile ] && make distclean
    91         {
   108         {
    92           ./configure --prefix="$PWD/target" """ + Bash.strings(configure_options) + """
   109           ./configure --prefix="$PWD/target" """ + Bash.strings(configure_options) + """
    93           rm -rf target
   110           rm -rf target
    94           make && make install
   111           make && make install
    95         } || { echo "Build failed" >&2; exit 2; }
   112         } || { echo "Build failed" >&2; exit 2; }
    96       """, redirect = true, echo = true).check
   113       """, redirect = true, progress = progress).check
    97 
   114 
    98 
   115 
    99     /* sha1 library */
   116     /* sha1 library */
   100 
   117 
   101     val sha1_files =
   118     val sha1_files =
   102       if (sha1_root.isDefined) {
   119       if (sha1_root.isDefined) {
   103         val dir1 = sha1_root.get
   120         val dir1 = sha1_root.get
   104         bash(dir1, "./build " + sha1_platform, redirect = true, echo = true).check
   121         bash(dir1, platform, mingw, "./build " + sha1_platform, redirect = true,
       
   122           progress = progress).check
   105 
   123 
   106         val dir2 = dir1 + Path.explode(sha1_platform)
   124         val dir2 = dir1 + Path.explode(sha1_platform)
   107         File.read_dir(dir2).map(entry => dir2 + Path.basic(entry))
   125         File.read_dir(dir2).map(entry => dir2 + Path.basic(entry))
   108       }
   126       }
   109       else Nil
   127       else Nil
   150 
   168 
   151 
   169 
   152 
   170 
   153   /** skeleton for component **/
   171   /** skeleton for component **/
   154 
   172 
       
   173   val standard_gmp_url = "https://gmplib.org/download/gmp/gmp-6.3.0.tar.bz2"
       
   174 
   155   val default_polyml_url = "https://github.com/polyml/polyml/archive"
   175   val default_polyml_url = "https://github.com/polyml/polyml/archive"
   156   val default_polyml_version = "90c0dbb2514e"
   176   val default_polyml_version = "90c0dbb2514e"
   157   val default_polyml_name = "polyml-5.9.1"
   177   val default_polyml_name = "polyml-5.9.1"
   158 
   178 
   159   val default_sha1_url = "https://isabelle.sketis.net/repos/sha1/archive"
   179   val default_sha1_url = "https://isabelle.sketis.net/repos/sha1/archive"
   179 
   199 
   180   def build_polyml(
   200   def build_polyml(
   181     options: List[String] = Nil,
   201     options: List[String] = Nil,
   182     mingw: MinGW = MinGW.none,
   202     mingw: MinGW = MinGW.none,
   183     component_name: String = "",
   203     component_name: String = "",
       
   204     gmp_url: String = "",
   184     polyml_url: String = default_polyml_url,
   205     polyml_url: String = default_polyml_url,
   185     polyml_version: String = default_polyml_version,
   206     polyml_version: String = default_polyml_version,
   186     polyml_name: String = default_polyml_name,
   207     polyml_name: String = default_polyml_name,
   187     sha1_url: String = default_sha1_url,
   208     sha1_url: String = default_sha1_url,
   188     sha1_version: String = default_sha1_version,
   209     sha1_version: String = default_sha1_version,
   189     target_dir: Path = Path.current,
   210     target_dir: Path = Path.current,
   190     progress: Progress = new Progress
   211     progress: Progress = new Progress
   191   ): Unit = {
   212   ): Unit = {
       
   213     val platform = Isabelle_Platform.self
       
   214 
       
   215 
   192     /* component */
   216     /* component */
   193 
   217 
   194     val component_name1 = if (component_name.isEmpty) "polyml-" + polyml_version else component_name
   218     val component_name1 = if (component_name.isEmpty) "polyml-" + polyml_version else component_name
   195     val component_dir =
   219     val component_dir =
   196       Components.Directory(target_dir + Path.basic(component_name1)).create(progress = progress)
   220       Components.Directory(target_dir + Path.basic(component_name1)).create(progress = progress)
   197 
   221 
   198 
   222 
   199     /* download and build */
   223     /* download and build */
   200 
   224 
   201     Isabelle_System.with_tmp_dir("download") { download_dir =>
   225     Isabelle_System.with_tmp_dir("download") { download_dir =>
       
   226       /* GMP library */
       
   227 
       
   228       val gmp_root: Option[Path] =
       
   229         if (gmp_url.isEmpty) None
       
   230         else {
       
   231           val gmp_dir = Isabelle_System.make_directory(download_dir + Path.basic("gmp"))
       
   232 
       
   233           val archive_name =
       
   234             Url.get_base_name(gmp_url).getOrElse(error("No base name in " + quote(gmp_url)))
       
   235           val archive = download_dir + Path.basic(archive_name)
       
   236           Isabelle_System.download_file(gmp_url, archive, progress = progress)
       
   237           Isabelle_System.extract(archive, gmp_dir, strip = true)
       
   238 
       
   239           val platform_arch = if (platform.is_arm) "aarch64" else "x86_64"
       
   240           val platform_os =
       
   241             if (platform.is_linux) "unknown-linux-gnu"
       
   242             else if (platform.is_windows) "w64-mingw32"
       
   243             else if (platform.is_macos) """apple-darwin"$(uname -r)""""
       
   244             else error("Bad platform " + platform)
       
   245 
       
   246           progress.echo("Building GMP library ...")
       
   247           bash(gmp_dir, platform, mingw, progress = progress,
       
   248             script = Library.make_lines(
       
   249               "set -e",
       
   250               "./configure --enable-cxx --build=" + platform_arch + "-" + platform_os +
       
   251                 """ --prefix="$PWD/target"""",
       
   252               "make",
       
   253               "make check",
       
   254               "make install"
       
   255             )).check
       
   256 
       
   257           Some(gmp_dir + Path.explode("target"))
       
   258         }
       
   259 
       
   260 
       
   261       /* Poly/ML */
       
   262 
   202       val List(polyml_download, sha1_download) =
   263       val List(polyml_download, sha1_download) =
   203         for {
   264         for {
   204           (url, version, target) <-
   265           (url, version, target) <-
   205             List((polyml_url, polyml_version, "src"), (sha1_url, sha1_version, "sha1"))
   266             List((polyml_url, polyml_version, "src"), (sha1_url, sha1_version, "sha1"))
   206         } yield {
   267         } yield {
   218 
   279 
   219       for (arch_64 <- List(false, true)) {
   280       for (arch_64 <- List(false, true)) {
   220         progress.echo("Building " + polyml_platform(arch_64))
   281         progress.echo("Building " + polyml_platform(arch_64))
   221         make_polyml(
   282         make_polyml(
   222           root = polyml_download,
   283           root = polyml_download,
       
   284           gmp_root = gmp_root,
   223           sha1_root = Some(sha1_download),
   285           sha1_root = Some(sha1_download),
   224           target_dir = component_dir.path,
   286           target_dir = component_dir.path,
   225           arch_64 = arch_64,
   287           arch_64 = arch_64,
   226           options = options,
   288           options = options,
   227           mingw = mingw,
   289           mingw = mingw,
   288 component_polyml", which can be used in the polyml component directory as
   350 component_polyml", which can be used in the polyml component directory as
   289 follows:
   351 follows:
   290 
   352 
   291 * Linux and macOS
   353 * Linux and macOS
   292 
   354 
   293   $ isabelle component_polyml
   355   $ isabelle component_polyml -G:
   294 
   356 
   295 * Windows (Cygwin shell)
   357 * Windows (Cygwin shell)
   296 
   358 
   297   $ isabelle component_polyml -M /cygdrive/c/msys64
   359   $ isabelle component_polyml -G: -M /cygdrive/c/msys64
   298 
       
   299 
       
   300 Building libgmp on macOS
       
   301 ========================
       
   302 
       
   303 The build_polyml invocations above implicitly use the GNU Multiple Precision
       
   304 Arithmetic Library (libgmp), but that is not available on macOS by default.
       
   305 Appending "--without-gmp" to the command-line omits this library. Building
       
   306 libgmp properly from sources works as follows (library headers and binaries
       
   307 will be placed in /usr/local).
       
   308 
       
   309 * Download:
       
   310 
       
   311   $ curl https://gmplib.org/download/gmp/gmp-6.3.0.tar.bz2 | tar xjf -
       
   312   $ cd gmp-6.3.0
       
   313 
       
   314 * build:
       
   315 
       
   316   $ make distclean
       
   317 
       
   318   #Intel
       
   319   $ ./configure --enable-cxx --build=core2-apple-darwin"$(uname -r)"
       
   320 
       
   321   #ARM
       
   322   $ ./configure --enable-cxx --build=aarch64-apple-darwin"$(uname -r)"
       
   323 
       
   324   $ make && make check
       
   325   $ sudo make install
       
   326 
   360 
   327 
   361 
   328         Makarius
   362         Makarius
   329         """ + Date.Format.date(Date.now()) + "\n")
   363         """ + Date.Format.date(Date.now()) + "\n")
   330   }
   364   }
   334   /** Isabelle tool wrappers **/
   368   /** Isabelle tool wrappers **/
   335 
   369 
   336   val isabelle_tool1 =
   370   val isabelle_tool1 =
   337     Isabelle_Tool("make_polyml", "make Poly/ML from existing sources", Scala_Project.here,
   371     Isabelle_Tool("make_polyml", "make Poly/ML from existing sources", Scala_Project.here,
   338       { args =>
   372       { args =>
       
   373         var gmp_root: Option[Path] = None
   339         var mingw = MinGW.none
   374         var mingw = MinGW.none
   340         var arch_64 = false
   375         var arch_64 = false
   341         var sha1_root: Option[Path] = None
   376         var sha1_root: Option[Path] = None
   342 
   377 
   343         val getopts = Getopts("""
   378         val getopts = Getopts("""
   344 Usage: isabelle make_polyml [OPTIONS] ROOT [CONFIGURE_OPTIONS]
   379 Usage: isabelle make_polyml [OPTIONS] ROOT [CONFIGURE_OPTIONS]
   345 
   380 
   346   Options are:
   381   Options are:
       
   382     -G DIR       GMP library root
   347     -M DIR       msys/mingw root specification for Windows
   383     -M DIR       msys/mingw root specification for Windows
   348     -m ARCH      processor architecture (32 or 64, default: """ +
   384     -m ARCH      processor architecture (32 or 64, default: """ +
   349         (if (arch_64) "64" else "32") + """)
   385         (if (arch_64) "64" else "32") + """)
   350     -s DIR       sha1 sources, see https://isabelle.sketis.net/repos/sha1
   386     -s DIR       sha1 sources, see https://isabelle.sketis.net/repos/sha1
   351 
   387 
   352   Make Poly/ML in the ROOT directory of its sources, with additional
   388   Make Poly/ML in the ROOT directory of its sources, with additional
   353   CONFIGURE_OPTIONS (e.g. --without-gmp).
   389   CONFIGURE_OPTIONS.
   354 """,
   390 """,
       
   391           "G:" -> (arg => gmp_root = Some(Path.explode(arg))),
   355           "M:" -> (arg => mingw = MinGW(Path.explode(arg))),
   392           "M:" -> (arg => mingw = MinGW(Path.explode(arg))),
   356           "m:" ->
   393           "m:" ->
   357             {
   394             {
   358               case "32" => arch_64 = false
   395               case "32" => arch_64 = false
   359               case "64" => arch_64 = true
   396               case "64" => arch_64 = true
   365         val (root, options) =
   402         val (root, options) =
   366           more_args match {
   403           more_args match {
   367             case root :: options => (Path.explode(root), options)
   404             case root :: options => (Path.explode(root), options)
   368             case Nil => getopts.usage()
   405             case Nil => getopts.usage()
   369           }
   406           }
   370         make_polyml(root, sha1_root = sha1_root, progress = new Console_Progress,
   407         make_polyml(root, gmp_root = gmp_root, sha1_root = sha1_root,
   371           arch_64 = arch_64, options = options, mingw = mingw)
   408           progress = new Console_Progress, arch_64 = arch_64, options = options, mingw = mingw)
   372       })
   409       })
   373 
   410 
   374   val isabelle_tool2 =
   411   val isabelle_tool2 =
   375     Isabelle_Tool("component_polyml", "build Poly/ML component from official repository",
   412     Isabelle_Tool("component_polyml", "build Poly/ML component from official repository",
   376       Scala_Project.here,
   413       Scala_Project.here,
   377       { args =>
   414       { args =>
   378         var target_dir = Path.current
   415         var target_dir = Path.current
       
   416         var gmp_url = ""
   379         var mingw = MinGW.none
   417         var mingw = MinGW.none
   380         var component_name = ""
   418         var component_name = ""
   381         var sha1_url = default_sha1_url
   419         var sha1_url = default_sha1_url
   382         var sha1_version = default_sha1_version
   420         var sha1_version = default_sha1_version
   383         var polyml_url = default_polyml_url
   421         var polyml_url = default_polyml_url
   384         var polyml_version = default_polyml_version
   422         var polyml_version = default_polyml_version
   385         var polyml_name = default_polyml_name
   423         var polyml_name = default_polyml_name
   386         var verbose = false
   424         var verbose = false
   387   
   425 
   388         val getopts = Getopts("""
   426         val getopts = Getopts("""
   389 Usage: isabelle component_polyml [OPTIONS] [CONFIGURE_OPTIONS]
   427 Usage: isabelle component_polyml [OPTIONS] [CONFIGURE_OPTIONS]
   390 
   428 
   391   Options are:
   429   Options are:
   392     -D DIR       target directory (default ".")
   430     -D DIR       target directory (default ".")
       
   431     -G URL       build GMP library from source: explicit URL or ":" for
       
   432                  """ + standard_gmp_url + """
   393     -M DIR       msys/mingw root specification for Windows
   433     -M DIR       msys/mingw root specification for Windows
   394     -N NAME      component name (default: derived from Poly/ML version)
   434     -N NAME      component name (default: derived from Poly/ML version)
   395     -S URL       SHA1 repository archive area
   435     -S URL       SHA1 repository archive area
   396                  (default: """ + quote(default_sha1_url) + """)
   436                  (default: """ + quote(default_sha1_url) + """)
   397     -T VERSION   SHA1 version (default: """ + quote(default_sha1_version) + """)
   437     -T VERSION   SHA1 version (default: """ + quote(default_sha1_version) + """)
   400     -V VERSION   Poly/ML version (default: """ + quote(default_polyml_version) + """)
   440     -V VERSION   Poly/ML version (default: """ + quote(default_polyml_version) + """)
   401     -W NAME      Poly/ML name (default: """ + quote(default_polyml_name) + """)
   441     -W NAME      Poly/ML name (default: """ + quote(default_polyml_name) + """)
   402     -v           verbose
   442     -v           verbose
   403 
   443 
   404   Download and build Poly/ML component from source repositories, with additional
   444   Download and build Poly/ML component from source repositories, with additional
   405   CONFIGURE_OPTIONS (e.g. --without-gmp).
   445   CONFIGURE_OPTIONS.
   406 """,
   446 """,
   407           "D:" -> (arg => target_dir = Path.explode(arg)),
   447           "D:" -> (arg => target_dir = Path.explode(arg)),
       
   448           "G:" -> (arg => gmp_url = if (arg == ":") standard_gmp_url else arg),
   408           "M:" -> (arg => mingw = MinGW(Path.explode(arg))),
   449           "M:" -> (arg => mingw = MinGW(Path.explode(arg))),
   409           "N:" -> (arg => component_name = arg),
   450           "N:" -> (arg => component_name = arg),
   410           "S:" -> (arg => sha1_url = arg),
   451           "S:" -> (arg => sha1_url = arg),
   411           "T:" -> (arg => sha1_version = arg),
   452           "T:" -> (arg => sha1_version = arg),
   412           "U:" -> (arg => polyml_url = arg),
   453           "U:" -> (arg => polyml_url = arg),
   417         val options = getopts(args)
   458         val options = getopts(args)
   418 
   459 
   419         val progress = new Console_Progress(verbose = verbose)
   460         val progress = new Console_Progress(verbose = verbose)
   420 
   461 
   421         build_polyml(options = options, mingw = mingw, component_name = component_name,
   462         build_polyml(options = options, mingw = mingw, component_name = component_name,
   422           polyml_url = polyml_url, polyml_version = polyml_version, polyml_name = polyml_name,
   463           gmp_url = gmp_url, polyml_url = polyml_url, polyml_version = polyml_version,
   423           sha1_url = sha1_url, sha1_version = sha1_version, target_dir = target_dir,
   464           polyml_name = polyml_name, sha1_url = sha1_url, sha1_version = sha1_version,
   424           progress = progress)
   465           target_dir = target_dir, progress = progress)
   425       })
   466       })
   426 }
   467 }