%
% Build a specific package, residing in dir, for target

readonly proc BootstrapPkg(dir,pkg,target,host) is
  local ret = 0

  % Create a directory for the package e.g. boot-LINUXELF/m3core

  local targetPkg = "pm3-" & target & SL & "boot-" & target & SL & pkg
  ret = exec(["mkdir", targetPkg])

  % Create a soft link to the source in the real package

  ret = exec(["ln", "-s", ".." & SL & ".." & SL & ".." & SL & dir & SL & pkg & 
      SL & "src", "."], [], targetPkg)

  % Issue the m3build command for the package

  write("---------- Building " & pkg & " ----------" & CR)
  ret = exec([BIN_USE & SL & "m3build", "-b", target,
      "-T", ".." & SL & ".." & SL & ".." & SL & 
      ".." & SL & ".." & SL & ".." & SL & 
      ".." & SL & ".." & SL & ".." & SL & 
      "m3config" & SL & "src" , 
      "-F", ".." & SL & ".." & SL & ".." & SL & "config.tmpl" ], 
      [], targetPkg)
  if not equal(ret, 0) error (BIN_USE & SL & "m3build failed for " & pkg & 
      " in " & target & CR) end

  >> "pm3-" & target & SL & "config.tmpl" in
    write("override(\"" & pkg & "\",\".." & SL & "..\")" & CR)
  end
end

%
% Remove the links to the real source directory

readonly proc CleanPkg(pkg,target) is
  local ret = 0
  ret = exec(["rm", "pm3-" & target & SL & "boot-" & target & SL & pkg & SL &
      "src"])
end

%
% Write the command to "make" one package

readonly proc WriteMakefileLine(pkg,target,options) is
  % In a makefile, only real / may work
  write("\tcd boot-" & target & "/" & pkg & "/" & target & 
      "; ${MAKE} -f make.boot " & options, CR)

end

%
% Write the global bootstrap makefile

readonly proc CreateMakefile(file,target,header,options) is
  local exportrpath = "-DEXPORTRPATH=binaries/" & target

  if equal(target,"NT386GNU") 
    exportrpath = "-DEXPORTRPATH=binaries\\\\" & target
  end

  > file in
    write(header,CR,CR)

    write("all: boot packages", CR, CR)

    write("exportall: boot exportpackages", CR, CR)

    write("packages:", CR)
    write("\tboot-" & target & "/" & "m3build" & "/" & target & "/" &
        "m3build -T ../m3config/src -DBOOTSTRAP=TRUE", 
        " ${M3OPTIONS}",CR, CR)

    write("exportpackages:", CR)
    write("\tboot-" & target & "/" & "m3build" & "/" & target & "/" &
        "m3build -T ../m3config/src -DBOOTSTRAP=TRUE " &
        "${M3OPTIONS} ",exportrpath, CR, CR)

    write("clean: pkg-clean boot-clean",CR, CR)

    write("pkg-clean:", CR)
    write("\tboot-" & target & "/" & "m3build" & "/" & target & "/" &
        "m3build -T ../m3config/src -DBOOTSTRAP=TRUE -DCLEAN_ALL", 
        " ${M3OPTIONS}",CR, CR)

    write("nothing:",CR,CR)

    write("boot:", CR)
    WriteMakefileLine("m3core",target,options)
    WriteMakefileLine("libm3",target,options)
    WriteMakefileLine("m3middle",target,options)
    WriteMakefileLine("m3front",target,options)
    WriteMakefileLine("m3linker",target,options)
    WriteMakefileLine("m3driver",target,options)
    WriteMakefileLine("m3quake",target,options)
    WriteMakefileLine("m3templates",target,options)
    WriteMakefileLine("m3config",target,options)
    WriteMakefileLine("m3build",target,options)
    WriteMakefileLine("m3ship",target,options)

    write(CR, "boot-clean:", CR)
    WriteMakefileLine("m3core",target, "clean " & options)
    WriteMakefileLine("libm3",target, "clean " & options)
    WriteMakefileLine("m3middle",target, "clean " & options)
    WriteMakefileLine("m3front",target, "clean " & options)
    WriteMakefileLine("m3linker",target, "clean " & options)
    WriteMakefileLine("m3driver",target, "clean " & options)
    WriteMakefileLine("m3quake",target, "clean " & options)
    WriteMakefileLine("m3templates",target, "clean " & options)
    WriteMakefileLine("m3config",target, "clean " & options)
    WriteMakefileLine("m3build",target, "clean " & options)
    WriteMakefileLine("m3ship",target, "clean " & options)
  end
end

%
% Compile m3cc as a cross compiler for the specified target

readonly proc CompileCrossCompiler(target,host) is
  local ret = 0
  local m3ccdir = "pm3-" & target & SL & "m3cc"

  % Create a subdirectory for m3cc and make links to the source code.
  % Then build it as a cross compiler.

  write("---------- Creating cross compiler " & host & " to " & target)
  write(" ----------" & CR)

  ret = exec(["mkdir", m3ccdir])
  ret = exec(["ln", "-s", ".." & SL & ".." & SL & ".." & SL & ".." & SL &
      "m3cc" & SL & "src", "."], [], m3ccdir)
  ret = exec(["ln", "-s", ".." & SL & ".." & SL & ".." & SL & ".." & SL &
      "m3cc" & SL & "gcc", "."], [], m3ccdir)

  %
  % C compilation is slow, as compared to M3, cache the cross-compiler
  %

  if CACHE_CROSS_COMPILERS and not(stale(CACHE_CROSS_COMPILERS & SL & 
      "m3cgc1-" & target,m3ccdir & SL & "gcc" & SL & "m3.c"))
    ret = exec(["ln","-s",CACHE_CROSS_COMPILERS & SL & "m3cgc1-" & target,
        "pm3-" & target])
    ret = exec(["rm", "src", "gcc"], [], m3ccdir)
    ret = exec(["rmdir", m3ccdir])
    return
  end

  ret = exec([BIN_USE & SL & "m3build",  "-b", host, 
      "-T", ".." & SL & ".." & SL & 
      ".." & SL & ".." & SL & ".." & SL & 
      ".." & SL & ".." & SL & ".." & SL & 
      "m3config" & SL & "src" , 
      "-DM3CC_TARGET=" & target], [], m3ccdir)
  if not equal(ret, 0) error ("m3build failed for m3cc in " & target & CR) end

  % Keep the cross compiler under target-m3cgc1 and remove everything else.

  if equal(host,target)
    ret = exec(["mv", host & SL & "m3cgc1", ".." & SL & "m3cgc1-" & target], 
        [], m3ccdir)
  else
    ret = exec(["mv", host & "-" & target & SL & "m3cgc1", ".." & SL & 
        "m3cgc1-" & target], [], m3ccdir)
    ret = exec(["rm", "-r", host & "-" & target], [], m3ccdir)
  end
  ret = exec(["rm", "-r", host], [], m3ccdir)
  ret = exec(["rm", "src", "gcc"], [], m3ccdir)
  ret = exec(["rmdir", m3ccdir])

  if CACHE_CROSS_COMPILERS
    ret = exec(["mv","pm3-" & target & SL & "m3cgc1-" & target,
        CACHE_CROSS_COMPILERS])
    ret = exec(["ln","-s",CACHE_CROSS_COMPILERS & SL & "m3cgc1-" & target,
        "pm3-" & target])
  end

  write("---------- Finished cross compiler ----------")
end

%
% Create everything needed for bootstrapping on platform "target"

readonly proc BootstrapTarget(target) is
  local ret = 0
  local host = TARGET

  ret = exec(["mkdir", "pm3-" & target])

  CompileCrossCompiler(target,host)

  % Prepare a config file with bootstrap specific overrides
  % The -O option should prevent using the integrated backend
  % which does not produce assembly; moreover, it may reduce the
  % bootstrap code size.

  > "pm3-" & target & SL & "config.tmpl" in
    write("option(\"bootstrap\",\"T\")",CR)
    write("option(\"shared_lib\",\"\")",CR)
    if equal(target,"HPPA") or equal(target,"DS3100") or equal(target,"IRIX5")
        or equal(target,"NT386GNU") or equal(target,"IBMR2")
      write("option(\"optimization\",\"\")",CR)
    else 
      write("option(\"optimization\",\"T\")",CR)
    end
    if equal(target,"ALPHA_OSF") or equal(target, "Tru64v5")
      % m3cgc1 generates bad code when -g flag is not used
      write("option(\"debuginfo\",\"T\")",CR)
    else	
      write("option(\"debuginfo\",\"" & BOOTDEBUG & "\")",CR)
    end
    write("HOST=\"" & host & "\"",CR)
    write("USE_M3DOC=\"\"",CR)
    write("IBACK=\"\"",CR)
    write("setDefault(\"\",\"\")",CR)
    write("BACKEND=[\"" & path() & SL & ".." & SL & host & SL & "pm3-" & 
        target & SL & "m3cgc1-" & target & 
        "\",\"-fno-strength-reduce\",\"-quiet\"]", CR)
  end

  write("---------- Config file ----------", CR)
  ret = exec(["cat", "pm3-" & target & SL & "config.tmpl"])

  ret = exec(["mkdir", "pm3-" & target & SL & "boot-" & target])

  % Build all the packages required for m3build and m3ship
  % to obtain a bootstrap m3build and m3ship.

  BootstrapPkg("../../../../../text/sgmltools","m3doc",target,host)
  BootstrapPkg("../../../../../libs","m3core",target,host)
  BootstrapPkg("../../../../../libs","libm3",target,host)
  BootstrapPkg("../..","m3middle",target,host)
  BootstrapPkg("../..","m3front",target,host)
  BootstrapPkg("../..","m3linker",target,host)
  BootstrapPkg("../..","m3driver",target,host)
  BootstrapPkg("../../../..","m3quake",target,host)
  BootstrapPkg("../..","m3templates",target,host)
  BootstrapPkg("../../../../..","m3config",target,host)
  BootstrapPkg("../..","m3build",target,host)
  BootstrapPkg("../..","m3ship",target,host)
  CleanPkg("m3doc",target)
  CleanPkg("m3core",target)
  CleanPkg("libm3",target)
  CleanPkg("m3middle",target)
  CleanPkg("m3front",target)
  CleanPkg("m3linker",target)
  CleanPkg("m3driver",target)
  CleanPkg("m3quake",target)
  CleanPkg("m3templates",target)
  CleanPkg("m3config",target)
  CleanPkg("m3build",target)
  CleanPkg("m3ship",target)

  local header = "M3OPTIONS=" & CR
  local options = "\"CC=${CC}\" \"CFLAGS=${CFLAGS}\"" &
      " \"AS=${AS}\" \"ASFLAGS=${ASFLAGS}\"" &
      " \"AR=${AR}\" \"ARFLAGS=${ARFLAGS}\"" &
      " \"RANLIB=${RANLIB}\" \"EXTRALIBS=${EXTRALIBS}\"" & 
      " \"LDFLAGS=${LDFLAGS}\""

  if equal(target,"NT386GNU")
    header = header & "EXTRALIBS=-ladvapi32" & CR
  else if equal(target,"SOLsun")
    header = header & "EXTRALIBS=-lsunmath -lm" & CR
  else if equal(target,"HPPA")
    header = header & "EXTRALIBS=-lm -lBSD" & CR
  else
    header = header & "EXTRALIBS=-lm" & CR
  end
  end
  end

  if equal(target,"SOLgnu") or equal(target,"SOLsun")
    header = header & "ASFLAGS=-s -P" & CR
  end

  if equal(target,"HPPA")
    header = header & "AS=gas" & CR
    header = header & "CC=gcc" & CR
  end

  if equal(target,"LINUXLIBC6")
    include("../../../../../m3config/src/GCWRAP")
    header = header & "LDFLAGS=" & GCWRAPFLAGS & CR
  end
    
  if equal(target,"ALPHA_OSF")
    header = header & "CFLAGS=-ieee_with_no_inexact -g3" & CR
    header = header & "LDFLAGS=-ieee_with_no_inexact" & CR
    header = header & "ASFLAGS=-g3" & CR
  end     
    
  if equal(target,"Tru64v5")
    header = header & "CFLAGS=-ieee_with_no_inexact -g" & CR
    header = header & "LDFLAGS=-ieee_with_no_inexact" & CR
    header = header & "ASFLAGS=-g" & CR
  end     

  if equal(target,"FreeBSD2")
    header = header & "RANLIB=ranlib" & CR
  else
    header = header & "RANLIB=touch" & CR
  end

  if equal(target, "FBSD_ALPHA")
    header = header & "CFLAGS=-mieee" & CR
  end

  CreateMakefile("pm3-" & target & SL & "Makefile." & target,target,
      header, options)
  CreateMakefile("pm3-" & target & SL & "Makefile",target,
      header, options)

  ret = exec(["rm", "pm3-" & target & SL & "config.tmpl"])
  ret = exec(["rm", "pm3-" & target & SL & "m3cgc1-" & target])
  write("---------- bootstrap finished for " & target & " ----------", CR)
end

% Create a bootstrap for each of these "target" in boot-target
%

CACHE_CROSS_COMPILERS = lookup("CACHE_CROSS_COMPILERS","")
BOOTDEBUG = lookup("BOOTDEBUG","")

if defined("BOOTTARGET")
  BootstrapTarget(BOOTTARGET)
else
  foreach platform in Platforms
    if Platforms{platform}[3] BootstrapTarget(platform) end
  end
end


