# Part of the A-A-P recipe executive: configure command handling
# Copyright (C) 2002-2003 Stichting NLnet Labs
# Permission to copy and use this file is specified in the file COPYING.
# If this file is missing you can find it here: http://www.a-a-p.org/COPYING
import Global
from Util import *
from Message import *
from Conftest import CheckFunc,CheckHeader,CheckType,CheckLib,CheckBuilder
class ConfContext:
"""
Context for configure tests. Used for the _conf scope.
"""
def __init__(self, vardict):
"""
The "_conf" scope is used for variables, so that things like $CC and
$LIBS can use the value from the _conf scope.
"""
self.vardict = vardict
self.havedict = {}
self.headerfilename = "confdefs.h"
self.headerclean = 0 # set to 1 when headerfilename has been
# cleared
self.default_lang = None
def Display(self, msg):
msg_info(Global.globals, msg, msgm_cont)
def Log(self, msg):
msg_log(Global.globals, msg, msgm_cont)
def AppendLIBS(self, lib_name_list):
from Scope import find_recdict
# Find the recdict where "LIBS" is defined and obtain the old value.
# Also obtain the old value of $_conf.LIBS.
rd = find_recdict(Global.globals, "LIBS")
if rd:
oldval = rd.get("LIBS")
else:
oldval = None
conf_oldval = Global.globals["_conf"].data.get("LIBS")
# Append library/libraries to the old value.
if oldval:
newval = oldval
else:
newval = ""
for k in lib_name_list:
if newval:
newval = newval + " "
newval = newval + ("-l%s" % k)
# Set the new value in the same scope. Also set $_conf.LIBS, so that
# ":conf write recipe" will use the new value.
if rd:
rd["LIBS"] = newval
Global.globals["_conf"].data["LIBS"] = newval
return [rd, oldval, conf_oldval]
def SetLIBS(self, newval):
# Get the recdict, and old values from the list that AppendLIBS()
# returned.
rd = newval[0]
oldval = newval[1]
conf_oldval = newval[2]
# Get the current value of $LIBS in ret_oldval and store the value from
# newval.
if rd:
ret_oldval = rd.get("LIBS")
rd["LIBS"] = oldval
else:
ret_oldval = None
# Get the current value of $_conf.LIBS in ret_conf_oldval and store
# the value from newval.
ret_conf_oldval = Global.globals["_conf"].get("LIBS")
if conf_oldval is None:
del Global.globals["_conf"].data["LIBS"]
else:
Global.globals["_conf"].data["LIBS"] = conf_oldval
return [rd, ret_oldval, ret_conf_oldval]
def BuildProg(self, text, ext):
self.Log("\n") # add a line break after "Checking..."
# source -> object
src = "conftest" + ext
trg = "conftest" + Global.globals["_no"].OBJSUF
res = self.RunAction("compile", text, src, trg)
if not res:
# object -> program
src = trg
if ext == ".cpp":
src = src + "{buildaction = cxx_build}"
trg = "conftest" + Global.globals["_no"].EXESUF
res = self.RunAction("build", None, src, trg)
try_delete(trg)
return res
def CompileProg(self, text, ext):
self.Log("\n") # add a line break after "Checking..."
# source -> object
src = "conftest" + ext
trg = "conftest" + Global.globals["_no"].OBJSUF
res = self.RunAction("compile", text, src, trg)
try_delete(trg)
return res
def RunAction(self, action, text, src, trg):
"""
Run action "action" with source "src" and target "trg".
When "text" is not None write it to "src".
Afterwards "src" is always deleted.
Returns an empty string for success, an error message for failure.
"""
save_message = Global.globals.get("MESSAGE")
Global.globals["MESSAGE"] = ""
save_sys_cmd_log = Global.sys_cmd_log
Global.sys_cmd_log = " "
try:
from Commands import aap_do
if text:
f = open(src, "w")
f.write(text)
f.close()
aap_do(0, Global.globals, "%s {target = %s} %s"
% (action, trg, src))
msg = ""
# If there is no error but there is output, log it (e.g., for a
# warning).
if Global.sys_cmd_log != " ":
msg_log(Global.globals, Global.sys_cmd_log)
except UserError:
msg = ((_("Failed to %s test program:") % action)
+ Global.sys_cmd_log)
if save_message is None:
del Global.globals["MESSAGE"]
else:
Global.globals["MESSAGE"] = save_message
Global.sys_cmd_log = save_sys_cmd_log
try_delete(src)
return msg
def init_conf_dict(confdict):
"""
Called to init a ConfContext() object and add it to the "_conf" scope
"confdict".
"""
# "confdict" is used for context.vardict, so that the variables are
# available as $_conf.VAR.
context = ConfContext(confdict)
# _conf.context is used to access the ConfContext object
confdict["context"] = context
# _conf.have is a shortcut to _conf.context.havedict
confdict["have"] = context.havedict
def doconf(line_nr, recdict, optiondict, argdictlist):
"""
Do the configure checks. Implementation of the ":conf" command.
"""
from Work import getrpstack
from Process import recipe_error
rpstack = getrpstack(recdict, line_nr)
# Get the ConfContext object from the _conf scope.
context = recdict["_conf"].context
command = argdictlist[0]["name"]
# Init the configure stuff when not done already.
# TODO: Is it possible that the file is truncated with an ":execute"
# command?
if not context.headerclean and command != "init":
_init_conf(context)
if command in [ "header", "function", "type", "lib" ]:
#
# :conf header stdlib.h ...
# :conf function snprintf ...
# :conf type size_t ...
# :conf lib iconv,iconv_open ...
#
if len(argdictlist) < 2:
recipe_error(rpstack, _('":conf %s" requires at least one more argument') % command)
found = 0
for i in range(1, len(argdictlist)):
testarg = argdictlist[i]["name"]
headerarg = argdictlist[i].get("header")
langarg = argdictlist[i].get("language")
if not langarg:
langarg = context.default_lang
if command == "header":
msg = CheckHeader(context, testarg,
header = headerarg, language = langarg)
elif command == "type":
fallbackarg = argdictlist[i].get("fallback")
msg = CheckType(context, testarg, fallback = fallbackarg,
header = headerarg, language = langarg)
elif command == "lib":
call = argdictlist[i].get("call")
comma = string.find(testarg, ",")
if comma < 0:
if not call:
recipe_error(rpstack,
_('":conf lib" requires an argument in the form libname,funcname.'))
lib_name = testarg
func_name = None
else:
lib_name = testarg[0:comma]
func_name = testarg[comma+1:]
msg = CheckLib(context, lib_name, func_name, call = call,
header = headerarg, language = langarg)
else: # command == "function"
msg = CheckFunc(context, testarg,
header = headerarg, language = langarg)
if not msg:
found = 1
if optiondict.get("oneof"):
break
elif optiondict.get("required"):
recipe_error(rpstack, _('required %s "%s" not found.')
% (command, testarg))
if not found and optiondict.get("oneof"):
from Dictlist import dictlist2str
recipe_error(rpstack,
_('None of the %ss found for ":conf {oneof} %s"')
% (command,
dictlist2str(argdictlist, Expand(0, Expand.quote_aap))))
elif command == "write":
#
# :conf write header config.h
# :conf write recipe config.aap
#
from Dictlist import dictlist_expand
dictlist_expand(argdictlist)
if len(argdictlist) != 3:
recipe_error(rpstack, _('":conf write" requires two arguments'))
what = argdictlist[1]["name"]
fname = argdictlist[2]["name"]
if what == "header":
# We copy confdefs.h to the target file. This makes sure the same
# file that was used for testing is used.
from CopyMove import remote_copy_move
remote_copy_move(rpstack, recdict, 1,
[ {"name" : context.headerfilename} ],
{ "name" : fname },
{ 'mkdir' : 1, 'force' : 1}, 0, errmsg = 1)
elif what == "recipe":
try:
f = open(fname, "w")
except StandardError, e:
recipe_error(rpstack, _('Could not create recipe "%s": %s')
% (fname, str(e)))
try:
f.write("# Generated by Aap. You are not supposed to edit this file.\n\n")
for k in context.vardict.keys():
if not k in ["have", "context"] and context.vardict[k]:
f.write("%s = %s\n" % (k, context.vardict[k]))
f.close()
except StandardError, e:
recipe_error(rpstack, _('Could not write to recipe "%s": %s')
% (fname, str(e)))
else:
msg_info(recdict, 'Written config recipe "%s"' % fname)
else:
recipe_error(rpstack, _('Unsupported argument for ":conf write": "%s"') % what)
elif command == "init":
#
# :conf init
#
if len(argdictlist) > 1:
recipe_error(rpstack, _('Too many arguments for ":conf init"'))
_init_conf(context)
elif command == "language":
#
# :conf language C++
#
if len(argdictlist) != 2:
recipe_error(rpstack, _('":conf language" requires one argument'))
context.default_lang = argdictlist[1]["name"]
# check for a valid language
msg = CheckBuilder(context, language = context.default_lang)
if msg:
msg_warning(recdict, _('Cannot compile a simple %s program: %s')
% (context.default_lang, msg))
else:
recipe_error(rpstack, _('Unsupported :conf argument: "%s"') % command)
def _init_conf(context):
"""
Init the configure stuff. This makes sure the "headerfilename" is empty.
"""
try:
f = open(context.headerfilename, "w+")
f.write("/* Generated by Aap. You are not supposed to edit this file. */\n\n")
f.close()
except StandardError, e:
msg_warning(Global.globals, _("Could not make %s empty: %s")
% (context.headerfilename, str(e)))
context.headerclean = 1
def cleanup(recdict):
"""
Cleanup after doing configure checks.
"""
# Get the ConfContext object from the _conf scope.
context = recdict["_conf"].context
try_delete(context.headerfilename)
# vim: set sw=4 et sts=4 tw=79 fo+=l:
|