build: allow specifying prerequisite flags when checking flags
[samba.git] / buildtools / wafsamba / samba_cross.py
1 # functions for handling cross-compilation
2
3 import os, sys, re, shlex
4 import Utils, Logs, Options
5 from Configure import conf
6
7 real_Popen = None
8
9 ANSWER_UNKNOWN = (254, "")
10 ANSWER_NO      = (1, "")
11 ANSWER_OK      = (0, "")
12
13 cross_answers_incomplete = False
14
15
16 def add_answer(ca_file, msg, answer):
17     '''add an answer to a set of cross answers'''
18     try:
19         f = open(ca_file, 'a')
20     except:
21         Logs.error("Unable to open cross-answers file %s" % ca_file)
22         sys.exit(1)
23     (retcode, retstring) = answer
24     # if retstring is more than one line then we probably
25     # don't care about its actual content (the tests should
26     # yield one-line output in order to comply with the cross-answer
27     # format)
28     retstring = retstring.strip()
29     if len(retstring.split('\n')) > 1:
30         retstring = ''
31     answer = (retcode, retstring)
32
33     if answer == ANSWER_OK:
34         f.write('%s: OK\n' % msg)
35     elif answer == ANSWER_UNKNOWN:
36         f.write('%s: UNKNOWN\n' % msg)
37     elif answer == ANSWER_NO:
38         f.write('%s: NO\n' % msg)
39     else:
40         if retcode == 0:
41             f.write('%s: "%s"\n' % (msg, retstring))
42         else:
43             f.write('%s: (%d, "%s")\n' % (msg, retcode, retstring))
44     f.close()
45
46
47 def cross_answer(ca_file, msg):
48     '''return a (retcode,retstring) tuple from a answers file'''
49     try:
50         f = open(ca_file, 'r')
51     except:
52         return ANSWER_UNKNOWN
53     for line in f:
54         line = line.strip()
55         if line == '' or line[0] == '#':
56             continue
57         if line.find(':') != -1:
58             a = line.split(':', 1)
59             thismsg = a[0].strip()
60             if thismsg != msg:
61                 continue
62             ans = a[1].strip()
63             if ans == "OK" or ans == "YES":
64                 f.close()
65                 return ANSWER_OK
66             elif ans == "UNKNOWN":
67                 f.close()
68                 return ANSWER_UNKNOWN
69             elif ans == "FAIL" or ans == "NO":
70                 f.close()
71                 return ANSWER_NO
72             elif ans[0] == '"':
73                 f.close()
74                 return (0, ans.strip('"'))
75             elif ans[0] == "'":
76                 f.close()
77                 return (0, ans.strip("'"))
78             else:
79                 m = re.match('\(\s*(-?\d+)\s*,\s*\"(.*)\"\s*\)', ans)
80                 if m:
81                     f.close()
82                     return (int(m.group(1)), m.group(2))
83                 else:
84                     raise Utils.WafError("Bad answer format '%s' in %s" % (line, ca_file))
85     f.close()
86     return ANSWER_UNKNOWN
87
88
89 class cross_Popen(Utils.pproc.Popen):
90     '''cross-compilation wrapper for Popen'''
91     def __init__(*k, **kw):
92         (obj, args) = k
93         use_answers = False
94         ans = ANSWER_UNKNOWN
95
96         # Three possibilities:
97         #   1. Only cross-answers - try the cross-answers file, and if
98         #      there's no corresponding answer, add to the file and mark
99         #      the configure process as unfinished.
100         #   2. Only cross-execute - get the answer from cross-execute
101         #   3. Both - try the cross-answers file, and if there is no
102         #      corresponding answer - use cross-execute to get an answer,
103         #       and add that answer to the file.
104         if '--cross-answers' in args:
105             # when --cross-answers is set, then change the arguments
106             # to use the cross answers if available
107             use_answers = True
108             i = args.index('--cross-answers')
109             ca_file = args[i+1]
110             msg     = args[i+2]
111             ans = cross_answer(ca_file, msg)
112
113         if '--cross-execute' in args and ans == ANSWER_UNKNOWN:
114             # when --cross-execute is set, then change the arguments
115             # to use the cross emulator
116             i = args.index('--cross-execute')
117             newargs = shlex.split(args[i+1])
118             newargs.extend(args[0:i])
119             if use_answers:
120                 p = real_Popen(newargs,
121                                stdout=Utils.pproc.PIPE,
122                                stderr=Utils.pproc.PIPE)
123                 ce_out, ce_err = p.communicate()
124                 ans = (p.returncode, ce_out)
125                 add_answer(ca_file, msg, ans)
126             else:
127                 args = newargs
128
129         if use_answers:
130             if ans == ANSWER_UNKNOWN:
131                 global cross_answers_incomplete
132                 cross_answers_incomplete = True
133                 add_answer(ca_file, msg, ans)
134             (retcode, retstring) = ans
135             args = ['/bin/sh', '-c', "echo -n '%s'; exit %d" % (retstring, retcode)]
136         real_Popen.__init__(*(obj, args), **kw)
137
138
139 @conf
140 def SAMBA_CROSS_ARGS(conf, msg=None):
141     '''get exec_args to pass when running cross compiled binaries'''
142     if not conf.env.CROSS_COMPILE:
143         return []
144
145     global real_Popen
146     if real_Popen is None:
147         real_Popen  = Utils.pproc.Popen
148         Utils.pproc.Popen = cross_Popen
149
150     ret = []
151
152     if conf.env.CROSS_EXECUTE:
153         ret.extend(['--cross-execute', conf.env.CROSS_EXECUTE])
154
155     if conf.env.CROSS_ANSWERS:
156         if msg is None:
157             raise Utils.WafError("Cannot have NULL msg in cross-answers")
158         ret.extend(['--cross-answers', os.path.join(Options.launch_dir, conf.env.CROSS_ANSWERS), msg])
159
160     if ret == []:
161         raise Utils.WafError("Cannot cross-compile without either --cross-execute or --cross-answers")
162
163     return ret
164
165 @conf
166 def SAMBA_CROSS_CHECK_COMPLETE(conf):
167     '''check if we have some unanswered questions'''
168     global cross_answers_incomplete
169     if conf.env.CROSS_COMPILE and cross_answers_incomplete:
170         raise Utils.WafError("Cross answers file %s is incomplete" % conf.env.CROSS_ANSWERS)
171     return True