abinit/config/scripts/make-macros-options

741 lines
18 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
except ImportError:
from configparser import ConfigParser
from time import gmtime,strftime
try:
from commands import getoutput
except:
from subprocess import getoutput
import os
import re
import sys
class MyConfigParser(ConfigParser):
def optionxform(self,option):
return str(option)
# ---------------------------------------------------------------------------- #
#
# Subroutines
#
# Macro header
def macro_header(name,stamp):
return """# Generated by %s on %s
#
# Command-line options for the "configure" script
#
#
# IMPORTANT NOTE
#
# This file has been automatically generated by the %s
# script. If you try to edit it, your changes will systematically be
# overwritten.
#
""" % (name,stamp,name)
# Define macro header
def macro_define_header():
return """
# ABI_OPTIONS_DEFINE()
# --------------------
#
# Declares command-line arguments for the "configure" script.
#
AC_DEFUN([ABI_OPTIONS_DEFINE],[
# Count use of deprecated options
abi_opt_deprecated_count=0
abi_opt_deprecated_used=""
"""
# Define macro footer
def macro_define_footer():
return "]) # ABI_OPTIONS_DEFINE\n"
# Init macro header
def macro_setup_header():
return """
# ABI_OPTIONS_SETUP()
# -------------------
#
# Sets the default values of command-line arguments.
#
AC_DEFUN([ABI_OPTIONS_SETUP],[
"""
# Init macro footer
def macro_setup_footer():
return "]) # ABI_OPTIONS_SETUP\n"
# Backup macro header
def macro_backup_header():
return """
# ABI_OPTIONS_BACKUP()
# --------------------
#
# Saves all command-line arguments.
#
AC_DEFUN([ABI_OPTIONS_BACKUP],[
"""
# Backup macro footer
def macro_backup_footer():
return "]) # ABI_OPTIONS_BACKUP\n"
# Restore macro header
def macro_recall_header():
return """
# ABI_OPTIONS_RECALL()
# --------------------
#
# Restores all previously-saved command-line arguments.
#
AC_DEFUN([ABI_OPTIONS_RECALL],[
"""
# Restore macro footer
def macro_recall_footer():
return "]) # ABI_OPTIONS_RECALL\n"
# Changed options macro
def macro_changed_template():
return """
# ABI_INFO_OPTIONS_CHANGED()
# --------------------------
#
# Display changes of user interface between versions and warns about
# obsolete uses.
#
AC_DEFUN([ABI_INFO_OPTIONS_CHANGED],[
@MACRO@
]) # ABI_INFO_OPTIONS_CHANGED
"""
# Parsing macro
def macro_parse_template():
return """
# ABI_OPTIONS_PARSE()
# -------------------
#
# Parses command-line arguments.
#
AC_DEFUN([ABI_OPTIONS_PARSE],[
AC_REQUIRE([AC_PROG_EGREP])
AC_MSG_NOTICE([parsing command-line options])
@MACRO@
]) # ABI_OPTIONS_PARSE
"""
# Defines and conditionals
def macro_triggers_template():
return """
# ABI_OPTIONS_CPP_DEFINES()
# -------------------------
#
# Set switches associated to 'enable_*' options (AC_DEFINE and
# AM_CONDTIONAL).
#
AC_DEFUN([ABI_OPTIONS_CPP_DEFINES],[
AC_MSG_NOTICE([setting build switches associated to command-line options])
@MACRO@
]) # ABI_OPTIONS_CPP_DEFINES
"""
# Config file values
def macro_cfg_template():
return """
# ABI_OPTIONS_CFG_TRANSFER()
# --------------------------
#
# Transfer options from the config file to internal variables.
#
AC_DEFUN([ABI_OPTIONS_CFG_TRANSFER],[
@MACRO@
]) # ABI_OPTIONS_CFG_TRANSFER
"""
# Option parser generator
def parse_opt(opt,opt_ivar,values):
ret = " # Parse %s\n" % (opt)
if ( len(values.split()) > 1 ):
ret += """ if test "${%s}" != ""; then
for v in `echo "${%s}" | sed -e 's/+/ /g'`; do
opt_ok="no"
for r in %s; do
if test "${v}" = "${r}";then
opt_ok="yes"
break
fi
done
test "${opt_ok}" = "no" && break
done
if test "${opt_ok}" = "no"; then
AC_MSG_WARN([%s = (%s)])
AC_MSG_ERROR([invalid option: %s = ${v}])
fi
fi
""" % (opt_ivar,opt_ivar,values,opt,"|".join(values.split()),opt)
else:
if ( values == "@float" ):
ret += r""" if test "${%s}" != ""; then
opt_ok="no"
test "`echo "${%s}" | \\
${EGREP} -e '^-?[[0-9]]+\.[[0-9]]+$'`" != "" && opt_ok="yes"
test "`echo "${%s}" | \\
${EGREP} -e '^-?[[0-9]]+\.[[0-9]]+[[Ee]]-?[[0-9]]+$'`" != "" && opt_ok="yes"
if test "${opt_ok}" = "no"; then
AC_MSG_ERROR([invalid float: %s = ${%s}])
fi
fi
""" % (opt,opt,opt,opt,opt)
elif ( values == "@includes" ):
ret += """ if test "${%s}" != ""; then
opt_ok="yes"
for v in ${%s}; do
if test "`echo "${v}" | grep '^-I'`" = ""; then
opt_ok="no"
break
fi
done
if test "${opt_ok}" = "no"; then
AC_MSG_ERROR([invalid include statement in %s: ${v}])
fi
fi
""" % (opt,opt,opt)
elif ( values == "@install" ):
ret += r""" if test "${%s}" != ""; then
opt_ok="yes"
if test "${%s}" != "no" -a "${%s}" != "yes"; then
if test \! -d "${%s}" -o \! -r "${%s}"; then
opt_ok="no"
break
fi
fi
fi
""" % (opt,opt,opt,opt,opt)
elif ( values == "@integer" ):
ret += """ if test "${%s}" != ""; then
opt_ok="yes"
test "`echo "${%s}" | ${EGREP} -e '^-?[[0-9]]+$'`" = "" && opt_ok="no"
if test "${opt_ok}" = "no"; then
AC_MSG_ERROR([invalid integer: %s = ${%s}])
fi
fi
""" % (opt,opt,opt,opt)
elif ( values == "@libs" ):
ret += """ if test "${%s}" != ""; then
opt_ok="yes"
for v in ${%s}; do
if test "`echo "${v}" | grep '^-[[LloW]]'`" = ""; then
opt_ok="no"
fi
if test "${opt_ok}" = "no"; then
if test -s "${v}"; then
opt_ok="yes"
else
break
fi
fi
done
if test "${opt_ok}" = "no"; then
AC_MSG_WARN([possible invalid library statement in %s: ${v}])
fi
fi
""" % (opt,opt,opt)
elif ( re.match("@profile", values) ):
arg = " ".join(values.split()[1:])
arg = re.sub("@VALUE@", "${%s}" % opt, arg)
ret += """ if test "${%s}" != ""; then
opt_ok="no"
test -s "${%s}" && opt_ok="yes"
if test "${opt_ok}" = "no"; then
AC_MSG_ERROR([file for option %s not found:
%s])
fi
fi
""" % (opt,arg,opt,arg)
elif ( values == "@readabledir" ):
ret += r""" if test "${%s}" != ""; then
opt_ok="yes"
if test \! -d "${%s}" -o \! -r "${%s}"; then
opt_ok="no"
break
fi
fi
""" % (opt,opt,opt)
else:
ret += """ # FIXME: NOT IMPLEMENTED!\n
AC_MSG_WARN([parsing not implemented for value type '%s'])\n""" % values
return ret
# ---------------------------------------------------------------------------- #
#
# Main program
#
# Initial setup
my_name = "make-macros-options"
my_configs = {
"deps":"config/specs/dependencies.conf",
"opts":"config/specs/options.conf",
}
my_output = "config/m4/auto-options.m4"
# 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)
cnf_deps = MyConfigParser()
cnf_opts = MyConfigParser()
for cnf_file in my_configs.values():
if ( not os.path.exists(cnf_file) ):
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_deps.read(my_configs["deps"])
cnf_opts.read(my_configs["opts"])
re_en = re.compile("enable_")
re_wi = re.compile("with_")
all_args = cnf_opts.sections()
all_args.sort()
ac_args = { "enable":list(), "with":list() }
for arg in all_args:
arg_stat = cnf_opts.get(arg,"status")
if ( (arg_stat != "removed") and (arg_stat != "dropped") ):
if ( arg.startswith("enable_") ):
ac_args["enable"].append(arg)
if ( arg.startswith("with_") ):
ac_args["with"].append(arg)
ac_args["enable"].sort()
ac_args["with"].sort()
# Start writing macro
m4 = open(my_output, "wt")
m4.write(macro_header(my_name,now))
# Start writing define macro
m4.write(macro_define_header())
# Process arguments
defaults = ""
parse = ""
for arg in ("enable","with"):
m4.write("\n #\n # --%s arguments\n #\n" % (arg))
defaults += "\n #\n # --%s arguments\n #\n\n" % (arg)
for opt in ac_args[arg]:
var = re.sub(arg+"_","",opt)
opt_name = re.sub("_","-",var)
opt_desc = cnf_opts.get(opt,"description")
opt_stat = cnf_opts.get(opt,"status")
if ( arg == "enable" ):
opt_ivar = "abi_%s_enable" % var
else:
opt_ivar = "abi_%s" % var
try:
opt_dflt = cnf_opts.get(opt,"default")
except:
opt_dflt = None
try:
opt_nega = cnf_opts.get(opt,"negative")
except:
opt_nega = ""
try:
opt_vals = cnf_opts.get(opt,"values")
except:
opt_vals = None
if ( arg == "enable" ):
m4.write("\n AC_ARG_%s(%s,\n" % (arg.upper(),opt_name) \
+ " AS_HELP_STRING([--%s-%s],\n [%s (default: %s)]),\n" % \
(arg,opt_name,opt_desc,opt_dflt) \
+ " [abi_%s_enable=\"${enableval}\"; abi_%s_init=\"yon\"],\n" % (var,var) \
+ " [abi_%s_enable=\"%s\"; abi_%s_init=\"def\"])\n" % (var, opt_dflt, var))
else:
tmp_dflt = ""
if ( not opt_dflt is None ):
tmp_dflt = opt_dflt
tmp_init = "kwd"
if ( opt_vals == "@install" ):
tmp_init = "dir"
tmp_decl = """
AC_ARG_WITH({name},
AS_HELP_STRING([--with-{cmd}],
[{help} (default: '{default}')]),
[ abi_{name}="${{withval}}"
case "${{withval}}" in
no|yes)
abi_{name}_init="yon"
;;
*)
abi_{name}_init="{init}"
;;
esac],
[ abi_{name}_init="def"; abi_{name}="{default}"])
""".format(cmd=opt_name, name=var, help=opt_desc, default=tmp_dflt, init=tmp_init)
m4.write(tmp_decl)
if ( opt_dflt is not None ):
if ( arg == "enable" ):
defaults += " if test \"${%s_%s}\" = \"\"; then\n abi_%s_%s=\"%s\"\n fi\n" % \
(arg,var,var,arg,opt_dflt)
else:
defaults += " if test \"${%s_%s}\" = \"\"; then\n abi_%s=\"%s\"\n fi\n" % \
(arg,var,var,opt_dflt)
if ( arg == "with" ):
defaults += " if test \"${%s_%s}\" = \"no\"; then\n abi_%s=\"%s\"\n fi\n" % \
(arg,var,var,opt_nega)
if ( opt_vals is not None ):
parse += "\n"+parse_opt(opt,opt_ivar,opt_vals)
elif ( arg == "enable" ):
parse += "\n"+parse_opt(opt,opt_ivar,"no yes")
m4.write(" AC_SUBST(%s_%s)\n" % (arg,var))
if ( arg == "enable" ):
m4.write(" AC_SUBST(abi_%s_%s)\n" % (var,arg))
# Finish writing define macro
m4.write(macro_define_footer())
# Start writing setup macro
m4.write(macro_setup_header())
# Process arguments
m4.write(defaults)
# Finish writing setup macro
m4.write(macro_setup_footer())
# Start writing backup macro
m4.write(macro_backup_header())
# Process arguments
for arg in ("enable","with"):
m4.write("\n #\n # --%s arguments\n #\n" % (arg))
for opt in ac_args[arg]:
var = re.sub(arg+"_","",opt)
m4.write(" cmd_%s_%s=\"${%s_%s}\"\n" % (arg,var,arg,var))
for dep in sorted(cnf_deps.sections()):
if (cnf_deps.get(dep, "detector") == "steredeg" ):
m4.write(" cmd_with_%s=\"${with_%s}\"\n" % (dep,dep))
if ( cnf_deps.has_option(dep, "flavors") ):
m4.write(" cmd_with_%s_flavor=\"${with_%s_flavor}\"\n" % (dep,dep))
# Do not forget "prefix"
m4.write("""
#
# Prefix
#
if test "${prefix}" != "NONE"; then
cmd_prefix="${prefix}"
fi
""")
# Finish writing backup macro
m4.write(macro_backup_footer())
# Write transfer-from-config-file macro
transfer = ""
for arg in ("enable","with"):
transfer += "\n #\n # --%s arguments\n #\n" % (arg)
for opt in ac_args[arg]:
var = re.sub(arg+"_","",opt)
if ( arg == "enable" ):
transfer += "\n if test \"${%s_%s}\" != \"\"; then\n abi_%s_%s=\"${%s_%s}\"\n fi\n" % \
(arg,var,var,arg,arg,var)
else:
transfer += "\n if test \"${%s_%s}\" != \"\"; then\n abi_%s=\"${%s_%s}\"\n fi\n" % \
(arg,var,var,arg,var)
m4.write(re.sub("@MACRO@", transfer, macro_cfg_template()))
# Start writing recall macro
m4.write(macro_recall_header())
# Process arguments
for arg in ("enable","with"):
m4.write("\n #\n # --%s arguments\n #\n" % (arg))
for opt in ac_args[arg]:
var = re.sub(arg+"_","",opt)
if ( arg == "enable" ):
m4.write(" if test \"${cmd_%s_%s}\" != \"\"; then\n abi_%s_%s=\"${cmd_%s_%s}\"\n fi\n" % \
(arg,var,var,arg,arg,var))
else:
m4.write(" if test \"${cmd_%s_%s}\" != \"\"; then\n %s_%s=\"${cmd_%s_%s}\"\n fi\n" % \
(arg,var,arg,var,arg,var))
for dep in sorted(cnf_deps.sections()):
if (cnf_deps.get(dep, "detector") == "steredeg" ):
m4.write(" if test \"${cmd_with_%s}\" != \"\"; then\n with_%s=\"${cmd_with_%s}\"\n fi\n" % \
(dep,dep,dep))
if ( cnf_deps.has_option(dep, "flavors") ):
m4.write(" if test \"${cmd_with_%s_flavor}\" != \"\"; then\n with_%s_flavor=\"${cmd_with_%s_flavor}\"\n fi\n" % \
(dep,dep,dep))
# Do not forget "prefix"
m4.write("""
#
# Prefix
#
if test "${cmd_prefix}" != ""; then
prefix="${cmd_prefix}"
fi
""")
# Finish writing recall macro
m4.write(macro_recall_footer())
# Build changed macro
changed = ""
chg_dep = ""
chg_mod = ""
chg_new = ""
chg_rem = ""
chg_ren = ""
for arg in all_args:
# Init
arg_stat = cnf_opts.get(arg,"status")
try:
arg_repl = cnf_opts.get(arg,"use_instead")
except:
arg_repl = ""
# Removed options
if ( (arg_stat == "removed") or (arg_stat == "dropped") ):
arg1 = re.sub("_","-",arg)
chg_rem += "\n # Removed --%s option" % (arg1)
if ( arg_stat == "removed" ):
chg_rem += "\n AC_MSG_NOTICE([ * removed option --%s])" % (arg1)
if ( arg_repl != "" ):
if ( arg_repl.upper() == arg_repl ):
chg_rem += "\n AC_MSG_NOTICE([ >>> use %s instead])" % arg_repl
else:
chg_rem += "\n AC_MSG_NOTICE([ >>> use --%s instead])" % \
(re.sub("_","-",arg_repl))
chg_rem += """
if test "${%s}" != ""; then
AC_MSG_ERROR([removed option --%s has been used])
fi
""" % (re.sub("-","_",arg1),arg1)
# New options
elif ( arg_stat.startswith("new") ):
arg2 = re.sub("_","-",arg.split()[0])
chg_new += "\n # New --%s option\n" % (arg2)
chg_new += " AC_MSG_NOTICE([ * new option --%s is available])\n" % (arg2)
if ( len(arg.split()) > 1 ):
chg_new += " AC_MSG_NOTICE([ (%s)])\n" % (" ".join(arg.split()[1:]))
# Changed UIs
elif ( re.match("changed",arg_stat) ):
arg1 = re.sub("_","-",arg)
chg_mod += """
# UI change for --%s option
AC_MSG_NOTICE([ * modified option --%s])
AC_MSG_NOTICE([ (%s)])
AC_MSG_NOTICE([ please check that --%s="${%s}" is OK for you])
""" % (arg1,arg1,arg_stat,arg1,re.sub("-","_",arg1))
# Deprecated options
elif ( re.match("deprecated",arg_stat) ):
arg2 = re.sub("_","-",arg)
chg_dep += """
# --%s deprecated
AC_MSG_NOTICE([ * deprecated option --%s])
if test "${%s}" != ""; then
AC_MSG_NOTICE([ >>> --%s = '${%s}' will soon be forbidden!])
abi_opt_deprecated_count=`expr ${abi_opt_deprecated_count} + 1`
abi_opt_deprecated_used="${abi_opt_deprecated_used} %s"
fi
""" % (arg2,arg2,arg,arg2,arg,arg)
changed = chg_rem + chg_new + chg_mod + chg_ren + chg_dep
if ( changed == "" ):
changed = """\
AC_MSG_NOTICE([])
AC_MSG_NOTICE([no change in user interface to report])"""
else:
changed = """\
AC_MSG_NOTICE([])
AC_MSG_NOTICE([reporting user interface changes:])
AC_MSG_NOTICE([])\n""" + changed
# Write changed macro
m4.write(re.sub("@MACRO@",changed,macro_changed_template()))
# Write parse macro
m4.write(re.sub("@MACRO@",parse,macro_parse_template()))
# Build triggers macro
triggers = ""
for opt in ac_args["enable"]:
opt_desc = cnf_opts.get(opt,"description")
opt_desc = opt_desc[0].lower() + opt_desc[1:]
opt_ivar = "abi_" + opt.replace("enable_", "") + "_enable"
try:
opt_cnds = cnf_opts.get(opt,"conditionals").split()
except:
opt_cnds = list()
try:
opt_defs = cnf_opts.get(opt,"defines").split()
except:
opt_defs = list()
if ( len(opt_cnds) + len(opt_defs) > 0 ):
triggers += """
# Triggers for %s
AC_MSG_CHECKING([whether to %s])
AC_MSG_RESULT([${%s}])
""" % (opt,opt_desc,opt_ivar)
if ( len(opt_cnds) > 0 ):
for cnd in opt_cnds:
if ( cnd[0] == "!" ):
val = "no"
cnd = cnd[1:]
else:
val = "yes"
triggers += """
if test "${%s}" = "%s"; then
AC_MSG_NOTICE([triggering the '%s' conditional])
fi
AM_CONDITIONAL([%s],[test "${%s}" = "%s"])""" % (opt_ivar,val,cnd,cnd,opt_ivar,val)
if ( len(opt_defs) > 0 ):
for cpp in opt_defs:
if ( cpp[0] == "!" ):
val = "no"
cpp = cpp[1:]
else:
val = "yes"
triggers += """
if test "${%s}" = "%s"; then
AC_MSG_NOTICE([defining the '%s' preprocessing macro])
AC_DEFINE([%s], 1,
[Define to 1 if you want to %s.])
fi""" % (opt_ivar,val,cpp,cpp,opt_desc)
# Write triggers macro
m4.write(re.sub("@MACRO@",triggers,macro_triggers_template()))
# Finish
m4.close()
tmp = getoutput("./config/scripts/add-header-typed Autoconf %s" % (my_output))
if ( tmp != "" ):
print(tmp)
# Write option dumper (for debugging)
dumper = open("config.dump.in","a")
dumper.write("# Command-line options (script: %s)\n" % (my_name))
for arg in all_args:
arg_stat = cnf_opts.get(arg,"status")
if ( (arg_stat != "removed") and \
(arg_stat != "dropped") and \
(not re.match("group", arg)) ):
var = re.sub("-","_",opt_name)
dumper.write("%s=\"@%s@\"\n" % (arg,arg))
dumper.write("\n")
dumper.close()