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
|
---|