abinit/config/scripts/make-makefiles-corelibs

356 lines
10 KiB
Python
Executable File

#!/usr/bin/env python
#
# Copyright (C) 2005-2025 ABINIT Group (Yann Pouillon)
#
# 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 __future__ import print_function, division, absolute_import #, unicode_literals
try:
from ConfigParser import ConfigParser,NoOptionError
except ImportError:
from configparser import ConfigParser,NoOptionError
from time import gmtime,strftime
import os
import re
import sys
class MyConfigParser(ConfigParser):
def optionxform(self,option):
return str(option)
# ---------------------------------------------------------------------------- #
#
# 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.conf", "config/specs/dependencies.conf"]
# 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/98_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_file in my_configs:
if ( os.path.exists(cnf_file) ):
if ( re.search(r"\.cf$",cnf_file) ):
exec(compile(open(cnf_file).read(), cnf_file, 'exec'))
else:
print("%s: Could not find config file (%s)." % (my_name,cnf_file))
print("%s: Aborting now." % my_name)
sys.exit(2)
# What time is it?
now = strftime("%Y/%m/%d %H:%M:%S +0000",gmtime())
# Init
cnf = MyConfigParser()
cnf.read(my_configs[0])
abinit_corelibs = cnf.sections()
abinit_corelibs.sort()
dep_cnf = MyConfigParser()
dep_cnf.read(my_configs[1])
# Hard-coded libraries for check programs
hard_chklibs = [
"16_hideleave",
"14_hidewrite",
"12_hide_mpi",
"11_memory_mpi",
"10_defs",
"02_clib",
]
# Prepare recognition of extensions
re_src = dict()
re_src["c"] = re.compile(r"\.c$")
re_src["cu"] = re.compile(r"\.cu$")
re_src["F90"] = re.compile(r"\.F90$")
# Process each library
for lib in abinit_corelibs:
# Init
lib_opt = cnf.get(lib,"optional")
lib_rul = cnf.get(lib,"abirules")
lib_par = cnf.get(lib,"parent")
try:
lib_deps = cnf.get(lib,"dependencies").split()
except NoOptionError:
lib_deps = None
# Reset variables
makefile = makefile_header(my_name,now)
sources = list()
optional_sources = list()
modules = list()
headers = list()
cudas = list()
sources_specs = dict()
checkers = None
# Select parent dir
if ( lib_par == "common" ):
par_dir = os.path.join("shared", "common", "src", lib)
elif ( lib_par == "libpaw" ):
par_dir = os.path.join("shared", "libpaw", "src")
else:
par_dir = os.path.join("src", lib)
# Import source configuration
src_cnf = os.path.join(par_dir, "abinit.src")
if ( os.path.exists(src_cnf) ):
exec(compile(open(src_cnf).read(), src_cnf, 'exec'))
else:
print("%s: Could not find config file (%s)." % (my_name,src_cnf))
print("%s: Aborting now." % my_name)
sys.exit(3)
# Import inter-directory dependency configuration
dir_cnf = os.path.join(par_dir, "abinit.dir")
if ( os.path.exists(dir_cnf) ):
exec(compile(open(dir_cnf).read(), dir_cnf, 'exec'))
else:
include_dirs = []
# FIXME: abisrc.py glitches
if ( lib in ["57_iovars", "66_nonlocal", "70_gw"] ):
include_dirs.append("33_xc_lowlevel")
# Add special dirs to include list
include_dirs += ["common", "core", "libpaw"]
# Initialize internal variables
dd_srcs = "lib%s_srcs =" % (lib)
nd_srcs = "lib%s_srcs_built =" % (lib)
ed_srcs = ""
ob_srcs = ""
cleans = ""
distcleans = ""
nds_print = False
obs_print = False
# Initialize build flags
# FIXME: hard-coded TRIQS C++ flags
makefile += "AM_CFLAGS = @ABI_CPPFLAGS@\n"
makefile += "AM_CXXFLAGS = $(sd_triqs_cxxflags)\n"
makefile += "AM_FCFLAGS = @FPPFLAGS@ @FCFLAGS_FREEFORM@ @FCFLAGS_MODDIR@ @sd_sys_fcflags@ @fcflags_opt_%s@\n\n" % (lib)
# Initialize includes
inc = ""
for dep in include_dirs:
inc += " \\\n\t@src_%s_fcflags@" % (dep)
# Dependencies
if ( cnf.has_option(lib,"dependencies") ):
for dep in cnf.get(lib,"dependencies").split():
if ( dep in dep_cnf.sections() ):
if ( dep_cnf.get(dep, "detector") == "steredeg" ):
dep_pfx = "sd"
else:
dep_pfx = "abi"
dep_lngs = dep_cnf.get(dep, "languages").split()
if ( ("c" in dep_lngs) or ("c++" in dep_lngs) ):
inc += " \\\n\t@%s_%s_cppflags@" % (dep_pfx, dep)
if ( "fortran" in dep_lngs ):
inc += " \\\n\t@%s_%s_fcflags@" % (dep_pfx, dep)
else:
raise ValueError("invalid external dependency: '%s'" % dep)
# Required basic Fortran includes (must be last!)
inc += " \\\n\t@fc_mod_fcflags@"
if ( inc != "" ):
makefile += "AM_CPPFLAGS =%s\n\n" % (inc)
# Generate lists of source files
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)
ed_srcs += " \\\n\t%s.in" % (src)
nds_print = True
else:
dd_srcs += " \\\n\t%s" % (src)
if ( not os.path.exists("%s/%s" % (par_dir,src)) ):
sys.stderr.write("Error: No such file or directory: '%s/%s'\n" % (par_dir,src))
sys.exit(4)
# Check whether to clean the preprocessed source file
for (ext,reg) in re_src.items():
if ( reg.search(src) ):
cleans += " \\\n\t%s" % (re.sub(r"\.%s" % (ext), \
"_cpp.%s" % (ext.lower()),src))
# Find CUDA source files
if ( re_src["cu"].search(src) ):
cudas.append(src)
# Optional source files
try:
for cnd in optional_sources:
ob_srcs += "if DO_BUILD_%s\n lib%s_srcs += \\\n %s\nendif" % \
(cnd,lib," \\\n ".join(optional_sources[cnd]))
obs_print = True
except NameError:
pass
dd_srcs += "\n\n"
nd_srcs += "\n\n"
ob_srcs += "\n\n"
makefile += "# Regular source files\n"+dd_srcs
if ( obs_print ):
makefile += "# Source files depending on conditionals\n"+ob_srcs
if ( nds_print ):
makefile += "# Source files built by scripts\n"+nd_srcs
# Library description
makefile += "# Library description\n"
makefile += "noinst_LIBRARIES = lib%s.a\n\n" % (lib)
makefile += "lib%s_a_SOURCES= $(lib%s_srcs)\n" % (lib,lib)
if ( nds_print ):
makefile += "nodist_lib%s_a_SOURCES = $(lib%s_srcs_built)\n" % (lib,lib)
# 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 = os.path.join(par_dir, "abinit.dep")
if ( os.path.exists(dep) ):
makefile += "\nEXTRA_DIST += abinit.dep\n"
makefile += "\n"+ open(dep,"rt").read()
# Write targets for checkers
try:
tmp_chk = "\ncheck_PROGRAMS ="
tmp_chk_cln = "\nCLEANFILES +="
for chk in checkers:
tmp_chk += " \\\n\t%s" % (chk)
tmp_chk_cln += " \\\n\t%s.log" % (chk)
tmp_chk_cln += " \\\n\t%s.tmp" % (chk)
makefile += tmp_chk + "\n"
for chk in checkers:
# FIXME: hard-coded for now
makefile += "\n%s_SOURCES = %s.F90" % (chk,chk)
makefile += "\n%s_CPPFLAGS = @sd_netcdf_cppflags@ @sd_linalg_cppflags@ -I$(top_srcdir)/shared/common/src/incs -I$(top_srcdir)/src/incs -I$(top_builddir)/shared/common/src/mods -I$(top_builddir)/src/mods" % \
(chk)
makefile += "\n%s_LDADD = \\\n\tlib%s.a" % (chk,lib)
for elc in checkers[chk] + hard_chklibs:
makefile += " \\\n\t../%s/lib%s.a" % (elc,elc)
makefile += " \\\n\t@%s@\n" % \
("@ \\\n\t@".join(["sd_netcdf_libs","sd_linalg_libs"]))
makefile += "\ncheck-local:\n"
for chk in checkers:
makefile += "\t./%s >%s.log 2>&1; grep '^TEST FAILED' %s.log && echo 'Unit test %s FAILED' || echo 'Unit test %s OK'\n" % \
(chk,chk,chk,chk,chk)
makefile += tmp_chk_cln + "\n"
except:
pass
# Write CUDA rules
if ( len(cudas) > 0 ):
makefile += "\nSUFFIXES = .o .cu\n\n.cu.o:\n\t$(NVCC) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(NVCC_CPPFLAGS) $(NVCC_CFLAGS) -c $<\n"
for src in cudas:
makefile += "\n%s.$(OBJEXT): %s\n" % (re.sub(r"\.cu","",src),src)
# Write optional source files
# Note: useless because Automake already takes care of it
#try:
# ob_xtra = "\nEXTRA_DIST +="
# for cnd in optional_sources:
# ob_xtra += " \\\n " + " \\\n ".join(optional_sources[cnd])
# ob_xtra += "\n"
# makefile += ob_xtra
#except NameError:
# pass
# Write source file templates
if ( len(ed_srcs) > 0 ):
makefile += "\n\nEXTRA_DIST +=" + ed_srcs + "\n"
# Write additional hand-made information
add = os.path.join(par_dir, "abinit.amf")
if ( os.path.exists(add) ):
makefile += "\nEXTRA_DIST += abinit.amf\n"
makefile += "\n" + open(add, "rt").read()
# Include RoboDOC header
hdr = "%s/_%s_" % (par_dir,lib)
if ( os.path.exists(hdr) ):
makefile += "\n\nEXTRA_DIST += _%s_\n" % (lib)
# Write additional cmake information
cml = os.path.join(par_dir, "CMakeLists.txt")
if ( os.path.exists(cml) ):
makefile += "\nEXTRA_DIST += CMakeLists.txt\n"
# Output to Makefile.am
mf = open(os.path.join(par_dir, "Makefile.am"), "wt")
mf.write(makefile)
mf.close()