2 # Check header contents against the given standard.
3 # Copyright (C) 2018-2023 Free Software Foundation, Inc.
4 # This file is part of the GNU C Library.
6 # The GNU C Library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # The GNU C Library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with the GNU C Library; if not, see
18 # <https://www.gnu.org/licenses/>.
31 class CompileSubTest(object):
32 """A compilation subtest."""
34 def __init__(self
, name
, text
):
35 """Initialize a CompileSubTest object."""
36 self
.run_early
= False
40 def run(self
, header_tests
):
41 """Run a compilation subtest."""
42 header_tests
.compile_test(self
.name
, self
.text
)
45 class ExecuteSubTest(object):
46 """An execution subtest."""
48 def __init__(self
, name
, text
):
49 """Initialize an ExecuteSubTest object."""
50 self
.run_early
= False
54 def run(self
, header_tests
):
55 """Run an execution subtest."""
56 header_tests
.execute_test(self
.name
, self
.text
)
59 class ElementTest(object):
60 """Test for an element of a structure or union type."""
62 def __init__(self
, dummy
, type_name
, member_type
, member_name
, *rest
):
63 """Initialize an ElementTest object."""
64 self
.type_name
= type_name
65 self
.member_type
= member_type
66 self
.member_name
= member_name
67 self
.rest
= ' '.join(rest
)
68 self
.allow_name
= self
.member_name
70 def gen_subtests(self
):
71 """Generate subtests for an ElementTest."""
72 text
= ('%(type_name)s a_%(num)d;\n'
73 '%(type_name)s b_%(num)d;\n'
74 'extern void xyzzy_%(num)d '
75 '(__typeof__ (&b_%(num)d.%(member_name)s), '
76 '__typeof__ (&a_%(num)d.%(member_name)s), unsigned);\n'
77 'void foobarbaz_%(num)d (void) {\n'
78 'xyzzy_%(num)d (&a_%(num)d.%(member_name)s, '
79 '&b_%(num)d.%(member_name)s, '
80 'sizeof (a_%(num)d.%(member_name)s));\n'
83 self
.subtests
.append(CompileSubTest(
84 'Availability of member %s' % self
.member_name
,
86 text
= ('%(type_name)s a2_%(num)d;\n'
87 'extern %(member_type)s b2_%(num)d%(rest)s;\n'
88 'extern __typeof__ (a2_%(num)d.%(member_name)s) b2_%(num)d;\n'
90 self
.subtests
.append(CompileSubTest(
91 'Type of member %s' % self
.member_name
,
95 class ConstantTest(object):
96 """Test for a macro or constant."""
98 def __init__(self
, symbol_type
, symbol
, extra1
=None, extra2
=None,
100 """Initialize a ConstantTest object."""
101 self
.symbol_type
= symbol_type
103 # A comparison operation may be specified without a type.
104 if extra2
is not None and extra3
is None:
112 self
.allow_name
= self
.symbol
114 def gen_subtests(self
):
115 """Generate subtests for a ConstantTest."""
116 if 'macro' in self
.symbol_type
:
117 text
= ('#ifndef %(symbol)s\n'
118 '# error "Macro %(symbol)s not defined"\n'
121 self
.subtests
.append(CompileSubTest(
122 'Availability of macro %s' % self
.symbol
,
124 if 'constant' in self
.symbol_type
:
125 text
= ('__typeof__ (%(symbol)s) a_%(num)d = %(symbol)s;\n'
127 self
.subtests
.append(CompileSubTest(
128 'Availability of constant %s' % self
.symbol
,
130 if self
.symbol_type
== 'macro-int-constant':
131 sym_bits_def_neg
= ''.join(
132 '# if %s & (1LL << %d)\n'
133 '# define conformtest_%d_bit_%d 0LL\n'
135 '# define conformtest_%d_bit_%d (1LL << %d)\n'
137 % (self
.symbol
, i
, self
.num
, i
, self
.num
, i
, i
)
139 sym_bits_or_neg
= '|'.join('conformtest_%d_bit_%d' % (self
.num
, i
)
141 sym_bits_def_pos
= ''.join(
142 '# if %s & (1ULL << %d)\n'
143 '# define conformtest_%d_bit_%d (1ULL << %d)\n'
145 '# define conformtest_%d_bit_%d 0ULL\n'
147 % (self
.symbol
, i
, self
.num
, i
, i
, self
.num
, i
)
149 sym_bits_or_pos
= '|'.join('conformtest_%d_bit_%d' % (self
.num
, i
)
151 text
= ('#if %s < 0\n'
152 '# define conformtest_%d_negative 1\n'
154 '# define conformtest_%d_value ~(%s)\n'
156 '# define conformtest_%d_negative 0\n'
158 '# define conformtest_%d_value (%s)\n'
160 '_Static_assert (((%s < 0) == conformtest_%d_negative) '
161 '&& (%s == conformtest_%d_value), '
162 '"value match inside and outside #if");\n'
163 % (self
.symbol
, self
.num
, sym_bits_def_neg
, self
.num
,
164 sym_bits_or_neg
, self
.num
, sym_bits_def_pos
, self
.num
,
165 sym_bits_or_pos
, self
.symbol
, self
.num
, self
.symbol
,
167 self
.subtests
.append(CompileSubTest(
168 '#if usability of symbol %s'% self
.symbol
,
170 if self
.c_type
is not None:
171 if self
.c_type
.startswith('promoted:'):
172 c_type
= self
.c_type
[len('promoted:'):]
173 text
= ('__typeof__ ((%s) 0 + (%s) 0) a2_%d;\n'
174 % (c_type
, c_type
, self
.num
))
176 text
= '__typeof__ ((%s) 0) a2_%d;\n' % (self
.c_type
, self
.num
)
177 text
+= 'extern __typeof__ (%s) a2_%d;\n' % (self
.symbol
, self
.num
)
178 self
.subtests
.append(CompileSubTest(
179 'Type of symbol %s' % self
.symbol
,
181 if self
.op
is not None:
182 text
= ('_Static_assert (%(symbol)s %(op)s %(value)s, '
183 '"value constraint");\n'
185 self
.subtests
.append(CompileSubTest(
186 'Value of symbol %s' % self
.symbol
,
190 class SymbolTest(object):
191 """Test for a symbol (not a compile-time constant)."""
193 def __init__(self
, dummy
, symbol
, value
=None):
194 """Initialize a SymbolTest object."""
197 self
.allow_name
= self
.symbol
199 def gen_subtests(self
):
200 """Generate subtests for a SymbolTest."""
201 text
= ('void foobarbaz_%(num)d (void) {\n'
202 '__typeof__ (%(symbol)s) a_%(num)d = %(symbol)s;\n'
205 self
.subtests
.append(CompileSubTest(
206 'Availability of symbol %s' % self
.symbol
,
208 if self
.value
is not None:
209 text
= ('int main (void) { return %(symbol)s != %(symbol)s; }\n'
211 self
.subtests
.append(ExecuteSubTest(
212 'Value of symbol %s' % self
.symbol
,
216 class TypeTest(object):
217 """Test for a type name."""
219 def __init__(self
, dummy
, type_name
):
220 """Initialize a TypeTest object."""
221 self
.type_name
= type_name
222 if type_name
.startswith('struct '):
223 self
.allow_name
= type_name
[len('struct '):]
224 self
.maybe_opaque
= False
225 elif type_name
.startswith('union '):
226 self
.allow_name
= type_name
[len('union '):]
227 self
.maybe_opaque
= False
229 self
.allow_name
= type_name
230 self
.maybe_opaque
= True
232 def gen_subtests(self
):
233 """Generate subtests for a TypeTest."""
234 text
= ('%s %sa_%d;\n'
235 % (self
.type_name
, '*' if self
.maybe_opaque
else '', self
.num
))
236 self
.subtests
.append(CompileSubTest(
237 'Availability of type %s' % self
.type_name
,
241 class TagTest(object):
242 """Test for a tag name."""
244 def __init__(self
, dummy
, type_name
):
245 """Initialize a TagTest object."""
246 self
.type_name
= type_name
247 if type_name
.startswith('struct '):
248 self
.allow_name
= type_name
[len('struct '):]
249 elif type_name
.startswith('union '):
250 self
.allow_name
= type_name
[len('union '):]
252 raise ValueError('unexpected kind of tag: %s' % type_name
)
254 def gen_subtests(self
):
255 """Generate subtests for a TagTest."""
256 # If the tag is not declared, these function prototypes have
257 # incompatible types.
258 text
= ('void foo_%(num)d (%(type_name)s *);\n'
259 'void foo_%(num)d (%(type_name)s *);\n'
261 self
.subtests
.append(CompileSubTest(
262 'Availability of tag %s' % self
.type_name
,
266 class FunctionTest(object):
267 """Test for a function."""
269 def __init__(self
, dummy
, return_type
, function_name
, *args
):
270 """Initialize a FunctionTest object."""
271 self
.function_name_full
= function_name
272 self
.args
= ' '.join(args
)
273 if function_name
.startswith('(*'):
274 # Function returning a pointer to function.
275 self
.return_type
= '%s (*' % return_type
276 self
.function_name
= function_name
[len('(*'):]
278 self
.return_type
= return_type
279 self
.function_name
= function_name
280 self
.allow_name
= self
.function_name
282 def gen_subtests(self
):
283 """Generate subtests for a FunctionTest."""
284 text
= ('%(return_type)s (*foobarbaz_%(num)d) %(args)s '
285 '= %(function_name)s;\n'
287 self
.subtests
.append(CompileSubTest(
288 'Availability of function %s' % self
.function_name
,
290 text
= ('extern %(return_type)s (*foobarbaz2_%(num)d) %(args)s;\n'
291 'extern __typeof__ (&%(function_name)s) foobarbaz2_%(num)d;\n'
293 self
.subtests
.append(CompileSubTest(
294 'Type of function %s' % self
.function_name
,
298 class VariableTest(object):
299 """Test for a variable."""
301 def __init__(self
, dummy
, var_type
, var_name
, *rest
):
302 """Initialize a VariableTest object."""
303 self
.var_type
= var_type
304 self
.var_name
= var_name
305 self
.rest
= ' '.join(rest
)
306 self
.allow_name
= var_name
308 def gen_subtests(self
):
309 """Generate subtests for a VariableTest."""
310 text
= ('typedef %(var_type)s xyzzy_%(num)d%(rest)s;\n'
311 'xyzzy_%(num)d *foobarbaz_%(num)d = &%(var_name)s;\n'
313 self
.subtests
.append(CompileSubTest(
314 'Availability of variable %s' % self
.var_name
,
316 text
= ('extern %(var_type)s %(var_name)s%(rest)s;\n'
318 self
.subtests
.append(CompileSubTest(
319 'Type of variable %s' % self
.var_name
,
323 class MacroFunctionTest(object):
324 """Test for a possibly macro-only function."""
326 def __init__(self
, dummy
, return_type
, function_name
, *args
):
327 """Initialize a MacroFunctionTest object."""
328 self
.return_type
= return_type
329 self
.function_name
= function_name
330 self
.args
= ' '.join(args
)
331 self
.allow_name
= function_name
333 def gen_subtests(self
):
334 """Generate subtests for a MacroFunctionTest."""
335 text
= ('#ifndef %(function_name)s\n'
336 '%(return_type)s (*foobarbaz_%(num)d) %(args)s '
337 '= %(function_name)s;\n'
340 self
.subtests
.append(CompileSubTest(
341 'Availability of macro %s' % self
.function_name
,
343 text
= ('#ifndef %(function_name)s\n'
344 'extern %(return_type)s (*foobarbaz2_%(num)d) %(args)s;\n'
345 'extern __typeof__ (&%(function_name)s) foobarbaz2_%(num)d;\n'
348 self
.subtests
.append(CompileSubTest(
349 'Type of macro %s' % self
.function_name
,
353 class MacroStrTest(object):
354 """Test for a string-valued macro."""
356 def __init__(self
, dummy
, macro_name
, value
):
357 """Initialize a MacroStrTest object."""
358 self
.macro_name
= macro_name
360 self
.allow_name
= macro_name
362 def gen_subtests(self
):
363 """Generate subtests for a MacroStrTest."""
364 text
= ('#ifndef %(macro_name)s\n'
365 '# error "Macro %(macro_name)s not defined"\n'
368 self
.subtests
.append(CompileSubTest(
369 'Availability of macro %s' % self
.macro_name
,
371 # We can't include <string.h> here.
372 text
= ('extern int (strcmp)(const char *, const char *);\n'
373 'int main (void) { return (strcmp) (%(macro_name)s, '
374 '%(value)s) != 0; }\n'
376 self
.subtests
.append(ExecuteSubTest(
377 'Value of macro %s' % self
.macro_name
,
381 class HeaderTests(object):
382 """The set of tests run for a header."""
384 def __init__(self
, header
, standard
, cc
, flags
, ldflags
, libs
,
385 run_program_prefix
, cross
, xfail
):
386 """Initialize a HeaderTests object."""
388 self
.standard
= standard
391 self
.ldflags
= ldflags
393 self
.run_program_prefix
= run_program_prefix
395 self
.xfail_str
= xfail
396 self
.cflags_namespace
= ('%s -fno-builtin %s -D_ISOMAC'
397 % (flags
, glibcconform
.CFLAGS
[standard
]))
398 # When compiling the conformance test programs, use of
399 # __attribute__ in headers is disabled because of attributes
400 # that affect the types of functions as seen by typeof.
401 self
.cflags
= "%s '-D__attribute__(x)='" % self
.cflags_namespace
404 self
.allow_fnmatch
= set()
405 self
.headers_handled
= set()
412 def add_allow(self
, name
, pattern_ok
):
413 """Add an identifier as an allowed token for this header.
415 If pattern_ok, fnmatch patterns are OK as well as
419 if re
.fullmatch(r
'[A-Za-z_][A-Za-z0-9_]*', name
):
422 self
.allow_fnmatch
.add(name
)
424 raise ValueError('bad identifier: %s' % name
)
426 def check_token(self
, bad_tokens
, token
):
427 """Check whether an identifier token is allowed, and record it in
431 if token
.startswith('_'):
433 if token
in glibcconform
.KEYWORDS
[self
.standard
]:
435 if token
in self
.allow
:
437 for pattern
in self
.allow_fnmatch
:
438 if fnmatch
.fnmatch(token
, pattern
):
440 bad_tokens
.add(token
)
442 def handle_test_line(self
, line
, allow
):
443 """Handle a single line in the test data.
445 If allow is true, the header is one specified in allow-header
446 and so tests are marked as allowed for namespace purposes but
452 if line
.startswith('xfail-'):
454 line
= line
[len('xfail-'):]
456 match
= re
.match(r
'xfail\[(.*?)\]-(.*)', line
)
458 xfail_cond
= match
.group(1)
459 line
= match
.group(2)
460 # "xfail[cond]-" or "xfail[cond1|cond2|...]-" means a
461 # failure of the test is allowed if any of the listed
462 # conditions are in the --xfail command-line option
464 if self
.xfail_str
and re
.search(r
'\b(%s)\b' % xfail_cond
,
468 if line
.startswith('optional-'):
470 line
= line
[len('optional-'):]
471 # Tokens in test data are space-separated, except for {...}
472 # tokens that may contain spaces.
475 match
= re
.match(r
'\{(.*?)\}(.*)', line
)
477 tokens
.append(match
.group(1))
478 line
= match
.group(2)
480 match
= re
.match(r
'([^ ]*)(.*)', line
)
481 tokens
.append(match
.group(1))
482 line
= match
.group(2)
484 if tokens
[0] == 'allow-header':
485 if len(tokens
) != 2 or xfail
or optional
:
486 raise ValueError('bad allow-header line: %s' % orig_line
)
487 if tokens
[1] not in self
.headers_handled
:
488 self
.load_tests(tokens
[1], True)
490 if tokens
[0] == 'allow':
491 if len(tokens
) != 2 or xfail
or optional
:
492 raise ValueError('bad allow line: %s' % orig_line
)
493 self
.add_allow(tokens
[1], True)
495 test_classes
= {'element': ElementTest
,
496 'macro': ConstantTest
,
497 'constant': ConstantTest
,
498 'macro-constant': ConstantTest
,
499 'macro-int-constant': ConstantTest
,
500 'symbol': SymbolTest
,
503 'function': FunctionTest
,
504 'variable': VariableTest
,
505 'macro-function': MacroFunctionTest
,
506 'macro-str': MacroStrTest
}
507 test
= test_classes
[tokens
[0]](*tokens
)
509 test
.optional
= optional
510 test
.num
= self
.num_tests
513 self
.add_allow(test
.allow_name
, False)
516 self
.tests
.append(test
)
518 def load_tests(self
, header
, allow
):
519 """Load tests of a header.
521 If allow is true, the header is one specified in allow-header
522 and so tests are marked as allowed for namespace purposes but
526 self
.headers_handled
.add(header
)
527 header_s
= header
.replace('/', '_')
528 temp_file
= os
.path
.join(self
.temp_dir
, 'header-data-%s' % header_s
)
529 cmd
= ('%s -E -D%s -std=c99 -x c data/%s-data > %s'
530 % (self
.cc
, self
.standard
, header
, temp_file
))
531 subprocess
.check_call(cmd
, shell
=True)
532 with
open(temp_file
, 'r') as tests
:
535 if line
== '' or line
.startswith('#'):
537 self
.handle_test_line(line
, allow
)
539 def note_error(self
, name
, xfail
):
540 """Note a failing test."""
542 print('XFAIL: %s' % name
)
545 print('FAIL: %s' % name
)
549 def note_skip(self
, name
):
550 """Note a skipped test."""
551 print('SKIP: %s' % name
)
555 def compile_test(self
, name
, text
):
556 """Run a compilation test; return True if it passes."""
558 if self
.group_ignore
:
560 optional
= self
.group_optional
561 self
.group_optional
= False
565 c_file
= os
.path
.join(self
.temp_dir
, 'test.c')
566 o_file
= os
.path
.join(self
.temp_dir
, 'test.o')
567 with
open(c_file
, 'w') as c_file_out
:
568 c_file_out
.write('#include <%s>\n%s' % (self
.header
, text
))
569 cmd
= ('%s %s -c %s -o %s' % (self
.cc
, self
.cflags
, c_file
, o_file
))
571 subprocess
.check_call(cmd
, shell
=True)
572 except subprocess
.CalledProcessError
:
574 print('MISSING: %s' % name
)
576 self
.group_ignore
= True
578 self
.note_error(name
, self
.group_xfail
)
579 self
.group_skip
= True
581 print('PASS: %s' % name
)
585 def execute_test(self
, name
, text
):
586 """Run an execution test."""
588 if self
.group_ignore
:
593 c_file
= os
.path
.join(self
.temp_dir
, 'test.c')
594 exe_file
= os
.path
.join(self
.temp_dir
, 'test')
595 with
open(c_file
, 'w') as c_file_out
:
596 c_file_out
.write('#include <%s>\n%s' % (self
.header
, text
))
597 cmd
= ('%s %s %s %s %s -o %s' % (self
.cc
, self
.cflags
, self
.ldflags
,
598 c_file
, self
.libs
, exe_file
))
600 subprocess
.check_call(cmd
, shell
=True)
601 except subprocess
.CalledProcessError
:
602 self
.note_error(name
, self
.group_xfail
)
608 subprocess
.check_call('%s %s' % (self
.run_program_prefix
,
611 except subprocess
.CalledProcessError
:
612 self
.note_error(name
, self
.group_xfail
)
614 print('PASS: %s' % name
)
617 def check_namespace(self
, name
):
618 """Check the namespace of a header."""
619 c_file
= os
.path
.join(self
.temp_dir
, 'namespace.c')
620 out_file
= os
.path
.join(self
.temp_dir
, 'namespace-out')
621 with
open(c_file
, 'w') as c_file_out
:
622 c_file_out
.write('#include <%s>\n' % self
.header
)
623 cmd
= ('%s %s -E %s -P -Wp,-dN > %s'
624 % (self
.cc
, self
.cflags_namespace
, c_file
, out_file
))
625 subprocess
.check_call(cmd
, shell
=True)
627 with
open(out_file
, 'r') as content
:
632 if re
.match(r
'# [1-9]', line
):
634 if line
.startswith('#pragma GCC '):
635 # No GCC pragma uses macro expansion, so no
636 # namespace issues arise from such pragmas. (Some
637 # pragmas not in the GCC namespace do macro-expand
638 # their arguments and so could be affected by
639 # macros defined by user code including the
642 match
= re
.match(r
'#define (.*)', line
)
644 self
.check_token(bad_tokens
, match
.group(1))
646 match
= re
.match(r
'#undef (.*)', line
)
648 bad_tokens
.discard(match
.group(1))
650 # Tokenize the line and check identifiers found. The
651 # handling of strings and character constants does not
652 # allow for escaped quotes, and hex floats may be
653 # wrongly split into tokens including identifiers, but
654 # this is sufficient in practice.
655 line
= re
.sub(r
'(?:\bL)?(?:"[^"]*"|\'[^
\']*\')', '', line)
657 for token in re.split(r'[^A
-Za
-z0
-9_]+', line):
658 if re.match(r'[A
-Za
-z_
]', token):
659 self.check_token(bad_tokens, token)
661 for token in sorted(bad_tokens):
662 print(' Namespace violation
: "%s"' % token)
663 self.note_error(name, False)
665 print('PASS
: %s' % name)
669 """Load and run tests of a header."""
670 with tempfile.TemporaryDirectory() as self.temp_dir:
671 self.load_tests(self.header, False)
672 self.group_optional = False
673 self.group_xfail = False
674 self.group_ignore = False
675 self.group_skip = False
676 available = self.compile_test('Availability of
<%s>' % self.header,
679 # As an optimization, try running all non-optional,
680 # non-XFAILed compilation tests in a single execution
683 for test in self.tests:
684 if not test.optional and not test.xfail:
685 for subtest in test.subtests:
686 if isinstance(subtest, CompileSubTest):
687 combined_list.append(subtest.text)
688 subtest.run_early = True
689 combined_ok = self.compile_test('Combined
<%s> test
'
691 '\n'.join(combined_list))
692 # Now run the other tests, or all tests if the
693 # combined test failed.
694 for test in self.tests:
695 # A test may run more than one subtest. If the
696 # initial subtest for an optional symbol fails,
697 # others are not run at all; if the initial
698 # subtest for an optional symbol succeeds, others
699 # are run and are not considered optional; if the
700 # initial subtest for a required symbol fails,
701 # others are skipped.
702 self.group_optional = test.optional
703 self.group_xfail = test.xfail
704 self.group_ignore = False
705 self.group_skip = False
706 for subtest in test.subtests:
707 if combined_ok and subtest.run_early:
709 print('PASSCOMBINED
: %s' % subtest.name)
713 namespace_name = 'Namespace of
<%s>' % self.header
715 self.check_namespace(namespace_name)
717 self.note_skip(namespace_name)
719 print(' Total number of tests
: %4d
' % self.total)
720 print(' Number of failed tests
: %4d
' % self.errors)
721 print(' Number of xfailed tests
: %4d
' % self.xerrors)
722 print(' Number of skipped tests
: %4d
' % self.skipped)
723 sys.exit(1 if self.errors else 0)
727 """The main entry point."""
728 parser = argparse.ArgumentParser(description='Check header contents
.')
729 parser.add_argument('--header
', metavar='HEADER
',
730 help='name of header
')
731 parser.add_argument('--standard
', metavar='STD
',
732 help='standard to use when processing header
')
733 parser.add_argument('--cc
', metavar='CC
',
734 help='C compiler to use
')
735 parser.add_argument('--flags
', metavar='CFLAGS
',
736 help='Compiler flags to use with CC
')
737 parser.add_argument('--ldflags
', metavar='LDFLAGS
',
738 help='Compiler arguments
for linking before inputs
')
739 parser.add_argument('--libs
', metavar='LIBS
',
740 help='Compiler arguments
for linking after inputs
')
741 parser.add_argument('--run
-program
-prefix
', metavar='RUN
-PROGRAM
-PREFIX
',
742 help='Wrapper
for running newly built program
')
743 parser.add_argument('--cross
', action='store_true
',
744 help='Do
not run compiled test programs
')
745 parser.add_argument('--xfail
', metavar='COND
',
746 help='Name of condition
for XFAILs
')
747 args = parser.parse_args()
748 tests = HeaderTests(args.header, args.standard, args.cc, args.flags,
749 args.ldflags, args.libs, args.run_program_prefix,
750 args.cross, args.xfail)
754 if __name__ == '__main__
':