#!/usr/bin/env python
#
# Copyright (C) 2005-2009 ABINIT Group (Yann Pouillon)
# All rights reserved.
#
# This file is part of the ABINIT software package. For license information,
# please see the COPYING file in the top-level directory of the ABINIT source
# distribution.
#

from time import gmtime,strftime

import commands
import os
import re
import sys

# ---------------------------------------------------------------------------- #

#
# Subroutines
#

# Makefile header
def makefile_header(name,stamp):

 return """#
# Makefile for ABINIT                                      -*- Automake -*-
# Generated by %s on %s

#
# IMPORTANT NOTE
#
# Any manual change to this file will systematically be overwritten.
# Please modify the %s script or its config file instead.
#

""" % (name,stamp,name)



# ---------------------------------------------------------------------------- #

#
# Main program
#

# Initial setup
my_name    = "make-makefiles-corelibs"
my_configs = ["config/specs/corelibs.cf"]

# Check if we are in the top of the ABINIT source tree
if ( not os.path.exists("configure.ac") or
     not os.path.exists("src/main/abinit.F90") ):
 print "%s: You must be in the top of an ABINIT source tree." % my_name
 print "%s: Aborting now." % my_name
 sys.exit(1)

# Read config file(s)
for cnf in my_configs:
 if ( os.path.exists(cnf) ):
  execfile(cnf)
 else:
  print "%s: Could not find config file (%s)." % (my_name,cnf)
  print "%s: Aborting now." % my_name
  sys.exit(2)

# What time is it?
now = strftime("%Y/%m/%d %H:%M:%S +0000",gmtime())

# Process each library
for lib in abinit_corelibs:

 # Init
 if ( lib in corelibs_specs ):
  lib_specs = corelibs_specs[lib]
 else:
  lib_specs = ABI_LIB_NIL

 # Reset variables
 makefile = makefile_header(my_name,now)
 sources = []
 sources_par = []
 modules = []
 headers = []
 sources_specs = {}

 # Import source configuration
 cnf = "src/%s/abinit.src" % (lib)
 if ( os.path.exists(cnf) ):
  execfile(cnf)
 else:
  print "%s: Could not find config file (%s)." % (my_name,cnf)
  print "%s: Aborting now." % my_name
  sys.exit(3)

 # Import inter-directory dependency configuration
 cnf = "src/%s/abinit.dir" % (lib)
 if ( os.path.exists(cnf) ):
  execfile(cnf)
 else:
  include_dirs = []

 # Import interfaces
 if ( os.path.exists("src/%s/interfaces_%s.F90" % (lib,lib)) ):
  sources.append("interfaces_%s.F90" % (lib))

 if ( (lib_specs & ABI_LIB_MPI) == 0 ):
  dd_srcs  = "lib%s_srcs =" % (lib)
  nd_srcs  = "lib%s_srcs_built =" % (lib)
 else:
  dd_srcs = "lib%ss_srcs =" % (lib)
  nd_srcs = "lib%ss_srcs_built =" % (lib)
  dd_srcp = "lib%sp_srcs =" % (lib)
  nd_srcp = "lib%sp_srcs_built =" % (lib)

 cleans = ""
 distcleans = ""

 nds_print = False
 ndp_print = False
 ddp_print = False

 # Initialize build flags
 makefile += "AM_CPPFLAGS = @CPPFLAGS_OPT@\n\n"
 if ( (lib_specs & ABI_LIB_F77) == 0 ):
  makefile += "AM_FCFLAGS = @FCFLAGS_FREEFORM@ @fcflags_opt_%s@\n\n" % (lib)
 else:
  makefile += "AM_FFLAGS = @FCFLAGS_FIXEDFORM@ @fcflags_opt_%s@\n\n" % (lib)

 # FIXME: workaround for missing deps in 15rsprc
 if ( lib == "15rsprc" ):
  if ( not "11util" in include_dirs ):
   include_dirs.append("11util")
   sys.stderr.write("FIXME: adding missing dependencies for 15rsprc\n")

 # Initialize includes
 inc = ""
 for dep in include_dirs:
  inc += " \\\n\t@src_%s_includes@" % (dep)

 # Other possible dependencies
 if ( lib in corelibs_deps ):
  for dep in corelibs_deps[lib]:
   inc += " \\\n\t@lib_%s_includes@" % (dep)

 if ( inc != "" ):
  makefile += "INCLUDES =%s\n\n" % (inc)

 # Source files for sequential build
 for src in sources:
  if ( src in sources_specs ):
   src_specs = sources_specs[src]
  else:
   src_specs = ABI_SRC_NIL

  # Check whether the file is built by the configure script
  if ( (src_specs & ABI_SRC_BLT) != 0 ):
   distcleans += " \\\n\t%s" % (src)
   nd_srcs += " \\\n\t%s" % (src)
   nds_print = True
  else:
   dd_srcs += " \\\n\t%s" % (src)
   if ( not os.path.exists("src/%s/%s" % (lib,src)) ):
    sys.stderr.write("Error: No such file or directory: 'src/%s/%s'\n" % (lib,src))
    sys.exit(4)

  # Check whether to clean the preprocessed source file
  if ( ((lib_specs & ABI_LIB_NPP) == 0) and 
       ((lib_specs & ABI_LIB_C89) == 0) ):
   cleans += " \\\n\t%s" % (re.sub("\.F","_cpp.f",src))

 dd_srcs += "\n\n"
 nd_srcs += "\n\n"

 makefile += "# Regular source files\n"+dd_srcs
 if ( nds_print ):
  makefile += "# Source files built by scripts\n"+nd_srcs

 # Source files for parallel build
 if ( (lib_specs & ABI_LIB_MPI) != 0 ):
  for src in sources_par:
   if ( src in sources_specs ):
    src_specs = sources_specs[src]
   else:
    src_specs = ABI_SRC_NIL

   # Check whether the file is built by the configure script
   if ( (src_specs & ABI_SRC_BLT) != 0 ):
    distcleans += " \\\n\t%s" % (src)
    nd_srcp += " \\\n\t%s" % (src)
    ndp_print = True
   else:
    dd_srcp += " \\\n\t%s" % (src)
    ddp_print = True
    if ( not os.path.exists("src/%s/%s" % (lib,src)) ):
     sys.stderr.write("Error: No such file or directory: 'src/%s/%s'\n" % \
      (lib,src))
     sys.exit(4)

   # Check whether to clean the preprocessed source file
   if ( ((lib_specs & ABI_LIB_NPP) == 0) and 
        ((lib_specs & ABI_LIB_C89) == 0) ):
    cleans += " \\\n\t%s" % (re.sub("\.F","_cpp.f",src))

  dd_srcp += "\n\n"
  nd_srcp += "\n\n"

  if ( ddp_print ):
   makefile += "# Regular source files for the MPI build\n"+dd_srcp
  if ( ndp_print ):
   makefile += "# Source files built by scripts for the MPI build\n"+nd_srcp

 # Library description
 makefile += "# Library description\n"

 if ( (lib_specs & ABI_LIB_MPI) == 0 ):
  # Sequential-only
  makefile += "noinst_LIBRARIES = lib%s.a\n\n" % (lib)

  if ( nds_print ):
   makefile += "nodist_lib%s_a_SOURCES = $(lib%s_srcs_built)\n" % (lib,lib)
  makefile += "lib%s_a_SOURCES= $(lib%s_srcs)\n" % (lib,lib)
 else:
  # Sequential + parallel
  if ( (lib_specs & ABI_LIB_F77) == 0 ):
   lib_form = "FREE"
  else:
   lib_form = "FIXED"

  makefile += "noinst_LIBRARIES = lib%ss.a\n\n" % (lib)

  # Sequential
  if ( nds_print ):
   makefile += "nodist_lib%ss_a_SOURCES = $(lib%ss_srcs_built)\n" % (lib,lib)
  makefile += "lib%ss_a_SOURCES = $(lib%ss_srcs)\n" % (lib,lib)

  # Parallel
  makefile += "\nif DO_BUILD_PARALLEL\n"
  makefile += " noinst_LIBRARIES += lib%sp.a\n" % (lib)
  if ( nds_print ):
   makefile += " nodist_lib%sp_a_SOURCES = $(lib%sp_srcs_built) $(lib%ss_srcs_built)\n" % (lib,lib,lib)
  makefile += " lib%sp_a_SOURCES  = $(lib%sp_srcs) $(lib%ss_srcs)\n" % (lib,lib,lib)
  makefile += " lib%sp_a_CPPFLAGS = @MPI_CPPFLAGS@\n" % (lib)
  makefile += " lib%sp_a_FCFLAGS  = @FCFLAGS_%sFORM@ @fcflags_opt_%s@ @MPI_FCFLAGS@\n" % (lib,lib_form,lib)
  makefile += "endif\n"

 # Write header list
 if ( len(headers) > 0 ):
  sep = " \\\n\t"
  makefile += "\nnoinst_HEADERS = \\\n\t%s\n" % (sep.join(headers))

 # Fix list of files to clean
 if ( len(modules) > 0 ):
  sep = ".mod \\\n\t"
  cleans += " \\\n\t%s.mod\n" % (sep.join(modules))
 elif ( cleans != "" ):
  cleans += "\n"

 # Write list of files to clean (must be set before adding abilint output)
 if ( cleans == "" ):
  cleans = "\n"
 makefile += "\nCLEANFILES ="+cleans

 # Write list of files to distclean
 if ( distcleans != "" ):
  makefile += "\nDISTCLEANFILES =%s\n" % (distcleans)

 # Add "abinit.src" to the list of dist files
 makefile += "\nEXTRA_DIST = abinit.src\n"

 # Write internal library dependencies
 dep = "src/%s/abinit.dep" % (lib)
 if ( os.path.exists(dep) ):
  makefile += "\nEXTRA_DIST += abinit.dep\n"
  makefile += "\n"+file(dep,"r").read()

 # Write additional hand-made information
 add = "src/%s/abinit.amf" % (lib)
 if ( os.path.exists(add) ):
  makefile += "\nEXTRA_DIST += abinit.amf\n"
  makefile += "\n"+file(add,"r").read()

 # Include RoboDOC header
 hdr = "src/%s/_%s_" % (lib,lib)
 if ( os.path.exists(hdr) ):
  makefile += "\nEXTRA_DIST += _%s_\n" % (lib)

 # Output to Makefile.am
 mf = file("src/%s/Makefile.am" % (lib),"w")
 mf.write(makefile)
 mf.close()
