src/Pure/Admin/build_polyml.scala
author wenzelm
Thu, 10 Nov 2016 22:54:46 +0100
changeset 64484 784e28e4dc57
parent 64483 bba1d341bdf6
child 64485 e996c0a5eca9
permissions -rw-r--r--
proper options; simplified command-line; tuned;

/*  Title:      Pure/Admin/build_polyml.scala
    Author:     Makarius

Build Poly/ML from sources.
*/

package isabelle


object Build_PolyML
{
  sealed case class Platform_Info(
    options: List[String] = Nil,
    options_multilib: List[String] = Nil,
    shell_path: String = "",
    copy_files: List[String] = Nil)

  private val platform_info = Map(
    "x86-linux" ->
      Platform_Info(
        options_multilib =
          List("--build=i386", "CFLAGS=-m32 -O3", "CXXFLAGS=-m32 -O3", "CCASFLAGS=-m32")),
    "x86_64-linux" -> Platform_Info(),
    "x86-darwin" ->
      Platform_Info(
        options =
          List("--build=i686-darwin", "CFLAGS=-arch i686 -O3 -I../libffi/include",
            "CXXFLAGS=-arch i686 -O3 -I../libffi/include", "CCASFLAGS=-arch i686 -O3",
            "LDFLAGS=-segprot POLY rwx rwx")),
    "x86_64-darwin" ->
      Platform_Info(
        options =
          List("--build=x86_64-darwin", "CFLAGS=-arch x86_64 -O3 -I../libffi/include",
            "CXXFLAGS=-arch x86_64 -O3 -I../libffi/include", "CCASFLAGS=-arch x86_64",
            "LDFLAGS=-segprot POLY rwx rwx")),
    "x86-windows" ->
      Platform_Info(
        options =
          List("--host=i686-w32-mingw32", "CPPFLAGS=-I/mingw32/include", "--disable-windows-gui"),
        shell_path = "/mingw32/bin",
        copy_files =
          List("/mingw32/bin/libgcc_s_dw2-1.dll",
            "/mingw32/bin/libgmp-10.dll",
            "/mingw32/bin/libstdc++-6.dll")),
    "x86_64-windows" ->
      Platform_Info(
        options =
          List("--host=x86_64-w64-mingw32", "CPPFLAGS=-I/mingw64/include", "--disable-windows-gui"),
        shell_path = "/mingw64/bin",
        copy_files =
          List("/mingw64/bin/libgcc_s_seh-1.dll",
            "/mingw64/bin/libgmp-10.dll",
            "/mingw64/bin/libstdc++-6.dll")))

  lazy val default_platform = Isabelle_System.getenv_strict("ISABELLE_PLATFORM32")

  def build_polyml(
    source: Path,
    progress: Progress = Ignore_Progress,
    platform: String = default_platform,
    options: List[String] = Nil)
  {
    source.is_dir || error("Bad source directory: " + source)

    val info =
      platform_info.get(platform) getOrElse
        error("Bad platform identifier: " + quote(platform))

    val multilib =
      platform == "x86-linux" && Isabelle_System.getenv("ISABELLE_PLATFORM64") == "x86_64-linux"

    val configure_options =
      (if (multilib) info.options_multilib else info.options) :::
        List("--enable-intinf-as-int") ::: options

    Isabelle_System.bash(cwd = source.file,
      script =
        (if (info.shell_path == "") "" else "export PATH=\"" + info.shell_path + ":$PATH\"\n") +
        """
          [ -f Makefile ] && make distclean
          {
            ./configure --prefix="$PWD/target" """ + Bash.strings(configure_options) + """
            rm -rf target
            make compiler && make compiler && make install
          } || { echo "Build failed" >&2; exit 2; }
        """,
      progress_stdout = progress.echo(_),
      progress_stderr = progress.echo(_)).check


    val target = Path.explode(platform)

    if (target.file.exists) {
      if (target.backup.file.exists) Isabelle_System.rm_tree(target.backup)
      File.move(target, target.backup)
    }
    Isabelle_System.mkdirs(target)

    for {
      d <- List("target/bin", "target/lib")
      dir = source + Path.explode(d)
      entry <- File.read_dir(dir)
    } File.move(dir + Path.explode(entry), target)

    for (file <- "~~/Admin/polyml/polyi" :: info.copy_files)
      File.copy(Path.explode(file), target)
  }


  /* Isabelle tool wrapper */

  val isabelle_tool =
    Isabelle_Tool("build_polyml", "build Poly/ML from sources", args =>
    {
      Command_Line.tool0 {
        var options = List.empty[String]
        var platform = default_platform

        val getopts = Getopts("""
Usage: isabelle build_polyml [OPTIONS] [SOURCE]

  Options are:
    -O OPTS...   additional options ./configure (e.g. --with-gmp)
    -p PLATFORM  platform identifier and target directory

  Build Poly/ML in SOURCE directory (default: .) for
  given PLATFORM (default: """ + default_platform + """).
""",
          "O:" -> (arg => options = options ::: List(arg)),
          "p:" -> (arg => platform = arg))

        val more_args = getopts(args)
        val source =
          more_args match {
            case Nil => Path.current
            case List(source) => Path.explode(source)
            case _ => getopts.usage()
          }
        build_polyml(source,
          progress = new Console_Progress, platform = platform, options = options)
      }
    }, admin = true)
}