#!/usr/bin/env python
#
# Copyright (c) 2005-2007 The 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)



# What to do when a library has its own Makefile
def delegated_build(name):

 return """# Delegate build to package's own Makefile
all_targets all: lib%s.a
  
lib%s.a:
	$(MAKE) -f $(top_srcdir)/lib/%s/%s.mk
	-if test -d tmp/bin ; then mv tmp/bin/* .; fi
	-if test -d tmp/lib ; then mv tmp/lib/* .; fi
	-if test -d tmp/include ; then mv tmp/include/* .; fi;

clean-local:
	$(MAKE) -f $(top_srcdir)/lib/%s/%s.mk clean
	rm -rf @%s_pkg_name@ tmp

EXTRA_DIST = @%s_pkg_name@.tar %s.mk

CLEANFILES = uncompress-stamp configure-stamp build-stamp install-stamp
""" % (name,name,name,name,name,name,name,name,name)



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

#
# Main program
#

# Initial setup
my_name    = "make-makefiles-libraries"
my_configs = ["config/specs/libraries.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())

# First generate a list of basic includes
basic_includes = ""
for lib in abilibs_specs:
 lib_specs = abilibs_specs[lib]
 if ( ((lib_specs & ABI_LIB_EXT) == 0) and ((lib_specs & ABI_LIB_INC) != 0) ):
  basic_includes += " -I../%s -I$(srcdir)/../%s" % (lib,lib)

# Process each library
for lib in abinit_libs:

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

 if ( (lib_specs & ABI_LIB_EXT) == 0 ):
  lib_dir = "src/"+lib
 else:
  lib_dir = "lib/"+lib

 # Start writing to Makefile.am
 mf = file(lib_dir+"/Makefile.am","w")
 mf.write(makefile_header(my_name,now))

 # Check whether the library has its own Makefile
 if ( (lib_specs & ABI_LIB_OWN) == 0 ):

  # Reset variables
  sources = []
  sources_par = []
  modules = []
  headers = []
  sources_specs = {}

  # Import source configuration
  cnf = lib_dir+"/abinit.src"
  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)

  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

  mf.write("AM_CPPFLAGS = @CPPFLAGS_OPT@\n\n")
  if ( (lib_specs & ABI_LIB_F77) == 0 ):
   mf.write("AM_FCFLAGS = @FCFLAGS_FREEFORM@ @fcflags_opt_%s@\n\n" % (lib))
  else:
   mf.write("AM_FFLAGS = @FCFLAGS_FIXEDFORM@ @fcflags_opt_%s@\n\n" % (lib))

  # Core-source libraries
  if ( (lib_specs & ABI_LIB_OWN) == 0 ):
   # Initialize includes
   inc = basic_includes

   # Other possible dependencies
   if ( lib in abilibs_deps ):
    for dep in abilibs_deps[lib]:
     if ( dep in abilibs_specs ):
      dep_specs = abilibs_specs[dep]
     else:
      dep_specs = ABI_LIB_NIL

     if ( (dep_specs & ABI_LIB_INC) != 0 ):
      inc += " @%s_include@" % (dep)

   if ( inc != "" ):
    mf.write("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(lib_dir+"/"+src) ):
     sys.stderr.write("Error: No such file or directory: '%s/%s'\n" % \
      (lib_dir,src))
     mf.close()
     os.remove(lib_dir+"/Makefile.am")
     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"

  mf.write("# Regular source files\n"+dd_srcs)
  if ( nds_print ):
   mf.write("# 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(lib_dir+"/"+src) ):
      sys.stderr.write("Error: No such file or directory: '%s/%s'\n" % \
       (lib_dir,src))
      mf.close()
      os.remove(lib_dir+"/Makefile.am")
      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 ):
    mf.write("# Regular source files for the MPI build\n"+dd_srcp)
   if ( ndp_print ):
    mf.write("# Source files built by scripts for the MPI build\n"+nd_srcp)

  # Library description
  mf.write("# Library description\n")

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

   if ( nds_print ):
    mf.write("nodist_lib%s_a_SOURCES = $(lib%s_srcs_built)\n" % (lib,lib))
   mf.write("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"

   mf.write("noinst_LIBRARIES = lib%ss.a\n\n" % (lib))

   # Sequential
   if ( nds_print ):
    mf.write("nodist_lib%ss_a_SOURCES = $(lib%ss_srcs_built)\n" % (lib,lib))
   mf.write("lib%ss_a_SOURCES = $(lib%ss_srcs)\n" % (lib,lib))

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

  # Write header list
  if ( len(headers) > 0 ):
   sep = " \\\n\t"
   mf.write("\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
  if ( cleans != "" ):
   mf.write("\nCLEANFILES ="+cleans)

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

  # Add "abinit.src" to the list of dist files
  mf.write("\nEXTRA_DIST = abinit.src\n")

 else:

  # Delegate the build
  mf.write(delegated_build(lib))

 # Write additional hand-made information
 add = lib_dir+"/abinit.amf"
 if ( os.path.exists(add) ):
  mf.write("\nEXTRA_DIST += abinit.amf\n")
  mf.write("\n"+file(add,"r").read())

 mf.close()
