Bluegene testsuite fixes
[dyninst.git] / testsuite / src / specification / makemake.py
1 import os
2 import tuples
3
4 ######################################################################
5 # Utility functions
6 ######################################################################
7 #
8
9 def uniq(lst):
10    return reduce(lambda l, i: ((i not in l) and l.append(i)) or l, lst, [])
11
12 info = {}
13 def read_tuples(tuplefile):
14    f = open(tuplefile)
15    info['platforms'] = tuples.parse_platforms(f.readline())
16    info['languages'] = tuples.parse_languages(f.readline())
17    info['compilers'] = tuples.parse_compilers(f.readline())
18    info['mutators'] = tuples.parse_mutators(f.readline())
19    info['mutatees'] = tuples.parse_mutatees(f.readline())
20    info['tests'] = tuples.parse_tests(f.readline())
21    info['rungroups'] = tuples.parse_rungroups(f.readline())
22 #  info['exception_types'] = tuples.parse_exception_types(f.readline())
23    info['exception_types'] = None
24 #  info['exceptions'] = tuples.parse_exceptions(f.readline())
25    info['exceptions'] = None
26    info['objects'] = tuples.parse_object_files(f.readline())
27    f.close()
28
29
30 def extension(filename):
31    ext_ndx = filename.rfind('.')
32    return filename[ext_ndx:]
33
34 def replace_extension(name, ext):
35    dot_ndx = name.rfind('.')
36    return name[:dot_ndx] + ext
37
38 # Get the name of the language for the given file.  If more than one
39 # is possible, I don't really know what to do...  Return a list of all
40 # the possibilities with compilers on the current platform?
41 # We should not ever get more than one language for a given extension.  We're
42 # enforcing that in the tuple generator.
43 def get_file_lang(filename):
44    ext = extension(filename)
45    langs = filter(lambda x: ext in x['extensions'], info['languages'])
46    # We have a list of all languages which match the extension of the file
47    # Filter out all of those languages for which there is no compiler on this
48    # platform:
49    #  Find the compilers available on this platform
50    platform = os.environ.get('PLATFORM')
51    comps = filter(lambda x: platform in info['compilers'][x]['platforms'],
52                info['compilers'])
53    #  Get a list of all the languages supported by those compilers
54    supported_langs = map(lambda x: info['compilers'][x]['languages'],
55                     comps)
56    supported_langs = reduce(lambda x,y:x+y, supported_langs)
57    supported_langs = uniq(supported_langs)
58    #  Remove all languages from langs that aren't in supported_langs
59    langs = filter(lambda x: x['name'] in supported_langs, langs)
60    if len(langs) > 1:
61       return langs
62    else:
63       return langs[0]
64
65 def compiler_count(lang):
66    plat = os.environ.get('PLATFORM')
67    return len(filter(lambda x: lang in info['compilers'][x]['languages']
68                        and plat in info['compilers'][x]['platforms']
69                  , info['compilers']))
70
71 def find_platform(pname):
72    plist = filter(lambda p: p['name'] == pname, info['platforms'])
73    if len(plist) == 0:
74       return None
75    else:
76       return plist[0]
77
78 def find_language(lname):
79    llist = filter(lambda l: l['name'] == lname, info['languages'])
80    if len(llist) == 0:
81       return None
82    else:
83       return llist[0]
84
85 # Returns a string containing the mutatee's compile-time options filename
86 # component: a string of the form _<compiler>_<ABI>_<optimization>
87 def mutatee_cto_component(mutatee):
88    compiler = info['compilers'][mutatee['compiler']]
89    return fullspec_cto_component(compiler,
90                           mutatee['abi'],
91                           mutatee['optimization'], mutatee['pic'])
92
93 # Returns a string containing the mutatee's compile-time options filename
94 # component for mutatees compiled with an auxilliary compiler
95 def auxcomp_cto_component(compiler, mutatee):
96    return fullspec_cto_component(compiler,
97                           mutatee['abi'],
98                           mutatee['optimization'],
99                           mutatee['pic'])
100
101 # Returns a string containing the mutatee's compile-time options filename
102 # component for a fully specified set of build-time options
103 def fullspec_cto_component(compiler, abi, optimization, pic):
104    retval = "_%s_%s_%s_%s" % (compiler['executable'],
105                      abi,
106                      pic,
107                      optimization)
108    return retval
109
110 # Returns a string containing the link-time options component for a fully-
111 # specified set of link-time options
112 # NOTE: There are currently no link-time options specified
113 def fullspec_lto_component():
114    return ""
115
116 # Returns a string containing the link-time options component for a mutatee's
117 # filename
118 # NOTE: There are currently no link-time options specified
119 def mutatee_lto_component(mutatee):
120    return fullspec_lto_component()
121
122 # Returns a string containing the link-time options component for a mutatee's
123 # filename when the mutatee is compiled using an auxilliary compiler
124 # NOTE: I think this function is pointless
125 def auxcomp_lto_component(compiler, mutatee):
126    return fullspec_lto_component()
127
128 # Returns a string containing the build-time options component for a fully-
129 # specified set of build-time options
130 def fullspec_bto_component(compiler, abi, optimization, pic):
131    return "%s%s" % (fullspec_cto_component(compiler, abi, optimization, pic),
132                 fullspec_lto_component())
133
134 # Returns a string containing the build-time options component for a mutatee's
135 # filename
136 def mutatee_bto_component(mutatee):
137    return "%s%s" % (mutatee_cto_component(mutatee),
138                 mutatee_lto_component(mutatee))
139
140 # Returns a string containing the build-time options component for a mutatee's
141 # filename, when the mutatee is built using an auxilliary compiler
142 # NOTE: I don't think this ever happens.
143 def auxcomp_bto_component(compiler, mutatee):
144    return "%s%s" % (auxcomp_cto_component(compiler, mutatee),
145                 auxcomp_lto_component(compiler, mutatee))
146
147 def mutatee_binary(mutatee):
148    # Returns standard name for the solo mutatee binary for this mutatee
149    platform = find_platform(os.environ.get('PLATFORM'))
150    es = platform['filename_conventions']['executable_suffix']
151    format = mutatee_format(mutatee['format'])
152    return "%s.mutatee_solo%s%s%s" % (mutatee['name'], format,
153                            mutatee_bto_component(mutatee),
154                            es)
155
156 #
157 ######################################################################
158
159
160 ######################################################################
161 # make.mutators.gen
162 ######################################################################
163 #
164
165 def print_mutators_list(out, mutator_dict, test_dict):
166         platform = find_platform(os.environ.get('PLATFORM'))
167         LibSuffix = platform['filename_conventions']['library_suffix']
168         ObjSuffix = platform['filename_conventions']['object_suffix']
169
170         out.write("######################################################################\n")
171         out.write("# A list of all the mutators to be compiled\n")
172         out.write("######################################################################\n\n")
173
174         module_list = []
175         for t in test_dict:
176                 module_list.append(t['module'])
177         module_set = set(module_list)
178
179         for m in module_set:
180                 out.write("\n")
181                 out.write("%s_MUTATORS = " % (m))
182                 module_tests = filter(lambda t: m == t['module'], test_dict)
183                 module_mutators = map(lambda t: t['mutator'], module_tests)
184                 for t in uniq(module_mutators):
185                         out.write("%s " % (t))
186                 out.write("\n\n")
187                 out.write("%s_OBJS_ALL_MUTATORS = " % (m))
188                 for t in uniq(module_mutators):
189                         out.write("%s%s " % (t, ObjSuffix))
190                 out.write("\n\n")
191
192
193         # Now we'll print out a rule for each mutator..
194         for m in mutator_dict:
195                 tests = filter(lambda t: t['mutator'] == m['name'], test_dict)
196                 modules = map(lambda t: t['module'], tests)
197                 if(len(uniq(modules)) != 1):
198                          print "ERROR: multiple modules for test " + m['name']
199                          raise
200                 module = modules.pop()
201                 # FIXME Don't hardcode $(LIBTESTSUITE)
202                 out.write("%s%s: " % (m['name'], LibSuffix))
203                 # Loop through the files listed in this mutator's source list and
204                 # add object files corresponding to each to the list of dependencies
205                 try:
206                         for s in m['sources']:
207                                 # Print out the object file for this source file
208                                 out.write("%s%s " % (s[0:-len(extension(s))], ObjSuffix))
209                         out.write("$(OBJS_FORALL_MUTATORS) $(DEPENDDIR)/%s.dep $(LIBTESTSUITE) $(%s_COMPONENT_LIB)\n" % (m['name'], module))
210                 except KeyError:
211                         print "Couldn't find sources for mutator " + m['name']
212                         raise
213                 # FIXME Make this one better too.  Right now it's copied straight from
214                 # make.module.tmpl
215                 libstr = ""
216                 try:
217                         for l in m['libraries']:
218                                 libstr += ("-l%s " % l)
219                 except KeyError:
220                         print "Couldn't find libs for mutator " + m['name']
221                         raise
222                 out.write("\t$(CXX) -o $@ -shared $(filter %%%s,$^) $(%s_MUTATOR_FLAGS) $(MUTATOR_SO_LDFLAGS) $(LIBDIR) $(LIBS) $(LDFLAGS) %s\n" % (ObjSuffix, module, libstr))
223                 out.write("ifndef NO_OPT_FLAG\n")
224                 out.write("ifdef STRIP_SO\n")
225                 out.write("\t$(STRIP_SO) $@\n")
226                 out.write("endif\n")
227                 out.write("endif\n\n")
228
229         for m in module_set:
230                 rest = """
231
232 # Create shared library names from the mutator test names
233 %s_MUTATORS_SO += $(addsuffix %s,$(%s_MUTATORS))
234
235 """ % (m, LibSuffix, m)
236                 out.write(rest)
237
238        
239
240
241
242 def write_make_mutators_gen(filename, tuplefile):
243    read_tuples(tuplefile)
244    mutator_dict = info['mutators']
245    test_dict = info['tests']
246    platform = find_platform(os.environ.get('PLATFORM'))
247    LibSuffix = platform['filename_conventions']['library_suffix']
248    header = """
249 # This file is automatically generated by the Dyninst testing system.
250 # For more information, see core/testsuite/src/specification/makemake.py
251
252 """
253    out = open(filename, "w")
254    out.write(header)
255    print_mutators_list(out, mutator_dict, test_dict)
256    out.close()
257
258 #
259 ######################################################################
260
261 ######################################################################
262 # test_info_new.gen.C
263 ######################################################################
264 #
265
266 def write_test_info_new_gen(filename, tuplefile):
267    header = """/* This file automatically generated from test specifications.  See
268  * specification/spec.pl and specification/makemake.py
269  */
270
271 #include "test_info_new.h"
272
273
274 """
275    read_tuples(tuplefile)
276    compilers = info['compilers']
277    rungroups = info['rungroups']
278    out = open(filename, "w")
279    out.write(header)
280    print_initialize_mutatees(out, rungroups, compilers)
281    out.close()
282
283 # Return the name of the mutatee executable for this rungroup
284 def mutatee_filename(rungroup, compilers):
285    if rungroup['mutatee'] == 'none':
286       retval = ""
287    else:
288       compiler = compilers[rungroup['compiler']]
289       mutatee = rungroup['mutatee']
290       bto = fullspec_bto_component(compiler,
291                             rungroup['abi'],
292                             rungroup['optimization'],
293                             rungroup['pic'])
294       platform = find_platform(os.environ.get('PLATFORM'))
295       format = mutatee_format(rungroup['format'])
296       es = platform['filename_conventions']['executable_suffix']
297       retval = "%s.mutatee_solo%s%s%s" % (mutatee, format, bto, es)
298    return retval
299
300 def mutatee_format(formatSpec):
301     if formatSpec == 'staticMutatee':
302         format = '_static'
303     else:
304         format = '_dynamic'
305     return format
306
307 # Return the name of the mutator for this test
308 def test_mutator(testname):
309    testobj = filter(lambda t: t['name'] == testname, info['tests'])
310    if len(testobj) >= 1:
311       testobj = testobj[0]
312    else:
313       # TODO Handle this case better
314       testobj = None
315    if testobj != None:
316       mrname = testobj['mutator']
317    else:
318       mrname = None
319    return mrname
320
321 # Builds a text label for a test based on the run group's information
322 # FIXME This is hardcoded to set grouped to false.  It needs to be fixed to
323 # support the group mutatee optimization
324 def build_label(test, mutator, rungroup):
325    label = "{test: %s, mutator: %s, grouped: false" % (test, mutator)
326    for n in rungroup:
327       # We've already dealt with tests and we don't handle groupable yet
328       if n not in ['tests', 'groupable']:
329          label = label + ", " + n + ": " + rungroup[n]
330    label = label + "}"
331    return label
332
333
334 def print_initialize_mutatees(out, rungroups, compilers):
335         header = """
336 // Now we insert the test lists into the run groups
337 void initialize_mutatees(std::vector<RunGroup *> &tests) {
338         unsigned int group_count = 0;
339         // Keep track of which element each test is, for later use with the resumelog
340         unsigned int test_count;
341         RunGroup *rg;
342 """
343         out.write(header)
344
345         platform = find_platform(os.environ.get('PLATFORM'))
346         LibSuffix = platform['filename_conventions']['library_suffix']
347
348         # TODO Change these to get the string conversions from a tuple output
349         for group in rungroups:
350                 compiler = info['compilers'][group['compiler']]
351                 if compiler['presencevar'] != 'true':
352                         out.write("#ifdef %s\n" % (compiler['presencevar']))
353                 mutateename = mutatee_filename(group, compilers)
354                 out.write('  test_count = 0;\n')
355                 out.write('  rg = new RunGroup("%s", ' % (mutateename))
356                 if group['start_state'] == 'stopped':
357                         out.write('STOPPED, ')
358                 elif group['start_state'] == 'running':
359                         out.write('RUNNING, ')
360                 else: # Assuming 'selfstart'
361                         out.write('SELFSTART, ')
362                 if group['run_mode'] == 'createProcess':
363                         out.write('CREATE, ')
364                 elif group['run_mode'] == 'useAttach':
365                         out.write('USEATTACH, ')
366                 elif group['run_mode'] == 'deserialize':
367                         out.write('DESERIALIZE, ')
368                 else:
369                         out.write('DISK, ')
370                 if group['thread_mode'] == 'None':
371                         out.write('TNone, ')
372                 elif group['thread_mode'] == 'SingleThreaded':
373                         out.write('SingleThreaded, ')
374                 elif group['thread_mode'] == 'MultiThreaded':
375                         out.write('MultiThreaded, ')
376                 if group['process_mode'] == 'None':
377                         out.write('PNone, ')
378                 elif group['process_mode'] == 'SingleProcess':
379                         out.write('SingleProcess, ')
380                 elif group['process_mode'] == 'MultiProcess':
381                         out.write('MultiProcess, ')
382                 if group['format'] == 'staticMutatee':
383                         out.write('StaticLink, ')
384                 else:
385                         out.write('DynamicLink, ')
386                 if group['groupable'] == 'true':
387                         out.write('false, ') # !groupable
388                 else:
389                         out.write('true, ') # !groupable
390                 if group['pic'] == 'pic':
391                         out.write('PIC')
392                 else:
393                         out.write('nonPIC')
394                 try:
395                         testobj = filter(lambda t: t['name'] == group['tests'][0], info['tests'])
396                         if len(testobj) < 1:
397                                 raise TestNotFound, 'Test not found: ' + test
398                         else:
399                                 module = testobj[0]['module']
400                 except KeyError:
401                         print "No module found! Test object: " 
402                         print testobj[0]
403                         raise
404                 out.write(', "%s", "%s", "%s", "%s"' % (module, group['compiler'], group['optimization'], group['abi']))
405                 out.write(');\n')
406                 for test in group['tests']:
407                         # Set the tuple string for this test
408                         # (<test>, <mutatee compiler>, <mutatee optimization>, <create mode>)
409                         # I need to get the mutator that this test maps to..
410                         mutator = test_mutator(test)
411                         ts = build_label(test, mutator, group)
412                         if test in ['test_serializable']:
413                                 serialize_enable = 'true'
414                         else:
415                                 serialize_enable = 'false'
416                         out.write('  rg->tests.push_back(new TestInfo(test_count++, "%s", "%s", "%s%s", %s, "%s"));\n' % (test, mutator, mutator, LibSuffix, serialize_enable, ts))
417                 out.write('  rg->index = group_count++;\n')
418                 out.write('  tests.push_back(rg);\n')
419                 # Close compiler presence #ifdef
420                 if compiler['presencevar'] != 'true':
421                         out.write("#endif // defined(%s)\n" % (compiler['presencevar']))
422         out.write('}\n')
423
424 #
425 ##########
426
427 ######################################################################
428 # make.solo_mutatee.gen
429 ######################################################################
430 #
431
432 def collect_mutatee_comps(mutatees):
433    comps = []
434    for m in mutatees:
435       if m['compiler'] != '' and m['compiler'] not in comps:
436          comps.append(m['compiler'])
437    return comps
438
439 # Print makefile variable initializations for all the compilers used for
440 # makefiles on this platform
441 def print_mutatee_comp_defs(out):
442    out.write("# Define variables for our compilers, if they aren't already defined\n")
443    pname = os.environ.get('PLATFORM')
444    # TODO Check that we got a string
445    comps = filter(lambda c: c != ''
446                          and pname in info['compilers'][c]['platforms'],
447                info['compilers'])
448    for c in comps:
449       if info['compilers'][c]['presencevar'] != 'true':
450          out.write("ifdef %s\n" % (info['compilers'][c]['presencevar']))
451       out.write('M_%s ?= %s\n' % (info['compilers'][c]['defstring'], info['compilers'][c]['executable']))
452       if info['compilers'][c]['presencevar'] != 'true':
453          out.write("endif\n")
454    out.write('\n')
455
456 def get_module(mutatee):
457    return mutatee["module"]
458
459 def group_uses_module(group, module):
460    mutatee_name = group['mutatee']
461    mutatees = filter(lambda t: t['name'] == group['mutatee'], info['mutatees'])
462    return get_module(mutatees[0]) == module
463
464 def has_multiple_tests(testgroup):
465    try:
466       t = testgroup['tests']
467       return len(t) > 1
468    except TypeError:
469       print "Test group's test list was not a list"
470       print t
471       raise
472
473 def print_mutatee_rules(out, mutatees, compiler, module):
474         if(len(mutatees) == 0):
475                 return
476         mut_names = map(lambda x: mutatee_binary(x), mutatees)
477         out.write("######################################################################\n")
478         out.write("# Mutatees compiled with %s for %s\n" % (mutatees[0]['compiler'], module))
479         out.write("######################################################################\n\n")
480         if compiler['presencevar'] != 'true':
481                 out.write("ifdef %s\n" % (compiler['presencevar']))
482                 out.write("# We only want to build these targets if the compiler exists\n")
483         out.write("%s_SOLO_MUTATEES_%s = " % (module, compiler['defstring']))
484         for m in mut_names:
485                 out.write("%s " % (m))
486         out.write('\n')
487         if compiler['presencevar'] != 'true':
488                 out.write("endif\n")
489         out.write("\n")
490         out.write("# Now a list of rules for compiling the mutatees with %s\n\n"
491                           % (mutatees[0]['compiler']))
492
493         pname = os.environ.get('PLATFORM')
494         platform = find_platform(pname)
495         ObjSuffix = platform['filename_conventions']['object_suffix']
496         groups = info['rungroups']
497
498         # Write rules for building the mutatee executables from the object files
499         for (m, n) in zip(mutatees, mut_names):
500                 out.write("%s: " % (n))
501
502                 group_mutatee_list = filter(has_multiple_tests, groups)
503                 group_mutatee_list = filter(lambda g: g['mutatee'] == m['name'], group_mutatee_list)
504                 group_boilerplates = uniq(map(lambda g: g['mutatee'] + '_group.c', group_mutatee_list))
505                 for bp in group_boilerplates:
506                         cto = mutatee_cto_component(m)
507                         out.write("%s " % (replace_extension(bp, "%s%s"
508                                                          % (cto, ObjSuffix))))
509
510                 for f in m['preprocessed_sources']:
511                         # List all the compiled transformed source files
512                         # I need to futz with the compiler here to make sure it's correct..
513                         # FIXME This next line may end up arbitrarily picking the first
514                         # language from a list of more than one for an extension
515                         lang = filter(lambda l: extension(f) in l['extensions'],
516                                                   info['languages'])[0]['name']
517                         if (lang in compiler['languages']):
518                                 cto = mutatee_cto_component(m)
519                                 out.write("%s " % (replace_extension(f, "_solo%s%s"
520                                                                                                          % (cto, ObjSuffix))))
521                         else: # Preprocessed file compiled with auxilliary compiler
522                                 pname = os.environ.get('PLATFORM')
523                                 # TODO Check that we got a string..
524                                 platform = find_platform(pname)
525                                 # TODO Check that we retrieved a platform object
526                                 try:
527                                         aux_comp = platform['auxilliary_compilers'][lang]
528                                 except KeyError:
529                                         print "Working on mutatee: " + n + ", file: " + f + ", no language for " + lang + ", platform object:"
530                                         print platform
531                                         raise
532                                 # TODO Verify that we got a compiler
533                                 cto = auxcomp_cto_component(info['compilers'][aux_comp], m)
534                                 out.write("%s " % (replace_extension(f, "_solo%s%s"
535                                                                                                          % (cto, ObjSuffix))))
536                 # TODO Let's grab the languages used in the preprocessed sources, and
537                 # save them for later.  We use this to determine which raw sources get
538                 # compiled with the same options as the preprocessed ones, in the case
539                 # of a compiler that is used for more than one language (e.g. GCC in
540                 # tests test1_35 or test_mem)
541
542                 # FIXME I'm doing this wrong: the compiler for preprocessed files might
543                 # not be the compiler that we're testing..
544                 # Get the compiler..
545                 maincomp_langs = uniq(info['compilers'][m['compiler']]['languages'])
546                 pp_langs = uniq(map(lambda x: get_file_lang(x)['name'], m['preprocessed_sources']))
547                 # So we want to print out a list of object files that go into this
548                 # mutatee.  For files that can be compiled with m['compiler'], we'll
549                 # use it, and compile at optimization level m['optimization'].  For
550                 # other files, we'll just use the appropriate compiler and not worry
551                 # about optimization levels?
552                 for f in m['raw_sources']:
553                         # Figure out whether or not this file can be compiled with
554                         # m['compiler']
555                         lang = get_file_lang(f)
556                         if type(lang) == type([]):
557                                 lang = lang[0] # BUG This may cause unexpected behavior if more
558                                                # than one language was returned, but more than
559                                                            # one language should never be returned
560                         if lang['name'] in maincomp_langs:
561                                 # This file is compiled with the main compiler for this mutatee
562                                 cto = mutatee_cto_component(m)
563                                 out.write("%s " % (replace_extension(f, "%s%s"
564                                                                                                          % (cto, ObjSuffix))))
565                         else:
566                                 # This file is compiled with an auxilliary compiler
567                                 # Find the auxilliary compiler for this language on this
568                                 # platform
569                                 # This assumes that there is only one possible auxilliary
570                                 # compiler for a language ending with the extension of interest
571                                 # on the platform.  This condition is enforced by sanity checks
572                                 # in the specification file.
573                                 aux_comp = platform['auxilliary_compilers'][lang['name']]
574                                 cto = fullspec_cto_component(info['compilers'][aux_comp],
575                                                                                          m['abi'], 'none', 'none')
576                                 out.write("%s " % (replace_extension(f, '%s%s'
577                                                                                                          % (cto, ObjSuffix))))
578                 # FIXME Check whether the current compiler compiles C files and if not
579                 # then use the aux compiler for this platform for the mutatee driver
580                 # object.
581                 if 'c' in info['compilers'][m['compiler']]['languages']:
582                         out.write("mutatee_driver_solo_%s_%s%s\n"
583                                           % (info['compilers'][m['compiler']]['executable'],
584                                                  m['abi'], ObjSuffix))
585                 else:
586                         # Get the aux compiler for C on this platform and use it
587                         aux_c = find_platform(os.environ.get('PLATFORM'))['auxilliary_compilers']['c']
588                         aux_c = info['compilers'][aux_c]['executable']
589                         out.write("mutatee_driver_solo_%s_%s%s\n"
590                                           % (aux_c, m['abi'], ObjSuffix))
591                 # Print the actions used to link the mutatee executable
592                 out.write("\t%s %s -o $@ $(filter %%%s,$^) %s %s"
593                                   % (platform['linker'] or "$(M_%s)" % compiler['defstring'],
594                                     compiler['flags']['std'],
595                                          ObjSuffix,
596                                          compiler['flags']['link'],
597                                          compiler['abiflags'][platform['name']][m['abi']]))
598                 if m['format'] == 'staticMutatee':
599                     linkage = compiler['staticlink']
600                 else:
601                     linkage = compiler['dynamiclink']
602                 out.write("%s " % linkage)
603                 for l in m['libraries']:
604                         # Need to include the required libraries on the command line
605                         # FIXME Use a compiler-specific command-line flag instead of '-l'
606                         out.write("-l%s" % (l))
607                         if os.environ.get('PLATFORM') == 'x86_64-unknown-linux2.4':
608                                 if m['abi'] == '32':
609                                         if l == 'testA':
610                                                 out.write('_m32')
611                         out.write(" ")
612                 out.write('\n')
613
614                 # ***ADD NEW BUILD-TIME ACTIONS HERE***
615
616
617 # Prints all the special object file compile rules for a given compiler
618 # FIXME This doesn't deal with preprocessed files!
619 def print_special_object_rules(compiler, out):
620         out.write("\n# Exceptional rules for mutatees compiled with %s\n\n"
621                           % (compiler))
622         objects = filter(lambda o: o['compiler'] == compiler, info['objects'])
623         for o in objects:
624                 # Print a rule to build this object file
625                 # TODO Convert the main source file name to an object name
626                 #  * Crap!  I don't know if this is a preprocessed file or not!
627                 #  * This should be okay soon; I'm removing the proprocessing stage..
628                 platform = os.environ.get("PLATFORM")
629                 ofileext = find_platform(platform)['filename_conventions']['object_suffix']
630                 ofilename = o['object'] + ofileext
631                 out.write("%s: " % (ofilename))
632                 for s in o['sources']:
633                         out.write("../src/%s " % (s))
634                 for i in o['intermediate_sources']:
635                         out.write("%s " % (i))
636                 for d in o['dependencies']:
637                         out.write("%s " % (d))
638                 out.write("\n")
639                 out.write("\t$(M_%s) $(SOLO_MUTATEE_DEFS) " % (info['compilers'][compiler]['defstring']))
640                 for f in o['flags']:
641                         out.write("%s " % (f))
642                 out.write("-o $@ %s " % info['compilers'][compiler]['parameters']['partial_compile'])
643                 for s in o['sources']:
644                         out.write("../src/%s " % (s))
645                 for i in o['intermediate_sources']:
646                         out.write("%s " % (i))
647                 out.write("\n")
648         out.write("\n")
649
650 # Produces a string of compiler flags for compiling mutatee object files with
651 # the specified build-time options
652 def object_flag_string(platform, compiler, abi, optimization, pic):
653    return "%s %s %s %s %s %s" % (compiler['flags']['std'],
654                         compiler['flags']['mutatee'],
655                         compiler['parameters']['partial_compile'],
656                         compiler['abiflags'][platform['name']][abi],
657                         compiler['optimization'][optimization],
658                         compiler['pic'][pic])
659
660
661 def print_patterns_wildcards(c, out, module):
662    compiler = info['compilers'][c]
663    platform = find_platform(os.environ.get('PLATFORM'))
664    ObjSuffix = platform['filename_conventions']['object_suffix']
665    
666    for abi in platform['abis']:
667       for o in compiler['optimization']:
668         for p in compiler['pic']:
669             cto = fullspec_cto_component(compiler, abi, o, p)
670             for l in compiler['languages']:
671                 lang = find_language(l) # Get language dictionary from name
672                 for e in lang['extensions']:
673                     if (module == None):
674                         out.write("%%%s%s: ../src/%%%s\n"
675                                     % (cto, ObjSuffix, e))
676                     else:
677                         out.write("%%%s%s: ../src/%s/%%%s\n"
678                                     % (cto, ObjSuffix, module, e))
679                     out.write("\t$(M_%s) $(SOLO_MUTATEE_DEFS) %s -o $@ $<\n"
680                                 % (compiler['defstring'],
681                                     object_flag_string(platform, compiler,
682                                                     abi, o, p)))
683 def is_valid_test(mutatee):
684          if(mutatee['groupable'] == 'false'):
685                   return 'true'
686          groups = info['rungroups']
687          mutatee_tests = filter(lambda g: g['mutatee'] == mutatee['name'], groups)
688          if not mutatee_tests:
689                   return 'false'
690          else:
691                   return 'true'
692
693 def is_groupable(mutatee):
694          if(mutatee['groupable'] == 'false'):
695                   return 'false'
696          groups = info['rungroups']
697          mutatee_tests = filter(lambda g: g['mutatee'] == mutatee['name'], groups)
698          if(max(map(lambda g: len(g['tests']), mutatee_tests)) > 1):
699                   return 'true'
700          else:
701                   return 'false'
702
703 def get_all_mutatee_sources(groupable, module):
704         return uniq(reduce(lambda a, b: set(a) | set(b),
705                 (map(lambda m: m['preprocessed_sources'],
706                 filter(lambda m: m['name'] != 'none'
707                         and is_valid_test(m) == 'true' and is_groupable(m) == groupable and get_module(m) == module,
708                         info['mutatees']))),
709                 []))
710          
711    
712 # Prints generic rules for compiling from mutatee boilerplate
713 def print_patterns(c, out, module):
714         out.write("\n# Generic rules for %s's mutatees and varying optimization levels for %s\n" % (c, module))
715
716         compiler = info['compilers'][c]
717         platform = find_platform(os.environ.get('PLATFORM'))
718         ObjSuffix = platform['filename_conventions']['object_suffix']
719
720         ng_sources = get_all_mutatee_sources('false', module)
721         g_sources = get_all_mutatee_sources('true', module)
722
723         for abi in platform['abis']:
724                 for o in compiler['optimization']:
725                     for p in compiler['pic']:
726                         # Rules for compiling source files to .o files
727                         cto = fullspec_cto_component(compiler, abi, o, p)
728
729                         #FIXME this prints out one rule for every mutatee preprocessed source for EVERY optimization
730                         #      I don't know whether the previous targets require every combination of source/opt
731                         #      i.e. printing ALL of them may be superfluous
732                         for sourcefile in ng_sources:
733                                 ext = extension(sourcefile)
734                                 boilerplate = "solo_mutatee_boilerplate" + ext
735                                 basename = sourcefile[0:-len('_mutatee') - len(ext)]
736
737                                 out.write("%s_mutatee_solo%s%s: ../src/%s ../src/%s/%s\n"
738                                                 % (basename, cto, ObjSuffix, boilerplate, module, sourcefile))
739                                 out.write("\t$(M_%s) $(%s_SOLO_MUTATEE_DEFS) %s -I../src/%s -DTEST_NAME=%s -DGROUPABLE=0 -DMUTATEE_SRC=../src/%s/%s -o $@ $<\n"
740                                                 % (compiler['defstring'], module,
741                                                    object_flag_string(platform, compiler, abi, o, p),
742                                                    module,
743                                                    basename, module, sourcefile))
744                         for sourcefile in g_sources:
745                                 ext = extension(sourcefile)
746                                 boilerplate = "solo_mutatee_boilerplate" + ext
747                                 basename = sourcefile[0:-len('_mutatee') - len(ext)]
748
749                                 out.write("%s_mutatee_solo%s%s: ../src/%s ../src/%s/%s\n"
750                                                 % (basename, cto, ObjSuffix, boilerplate, module, sourcefile))
751                                 out.write("\t$(M_%s) $(%s_SOLO_MUTATEE_DEFS) %s -I../src/%s -DTEST_NAME=%s -DGROUPABLE=1 -DMUTATEE_SRC=../src/%s/%s -o $@ $<\n"
752                                                 % (compiler['defstring'], module,
753                                                    object_flag_string(platform, compiler, abi, o, p),
754
755                                                    module,
756                                                    basename, module, sourcefile))
757         groups = info['rungroups']
758         group_mutatee_list = filter(has_multiple_tests, groups)
759         groups_for_module = filter(lambda g: group_ok_for_module(g, module) == 'true', group_mutatee_list)
760         group_boilerplates = uniq(map(lambda g: g['mutatee'] + '_group.c', groups_for_module))
761         for abi in platform['abis']:
762                 for o in compiler['optimization']:
763                     for p in compiler['pic']:
764                         cto = fullspec_cto_component(compiler, abi, o, p)
765                         for sourcefile in group_boilerplates:
766                                     ext = extension(sourcefile)
767                                     basename = sourcefile[0:-len(ext)]
768                                     out.write("%s%s%s: %s\n" % (basename, cto, ObjSuffix, sourcefile))
769                                     out.write("\t$(M_%s) $(%s_SOLO_MUTATEE_DEFS) %s -DGROUPABLE=1 -o $@ $<\n"
770                                                             % (compiler['defstring'], module,
771                                                                     object_flag_string(platform, compiler, abi, o, p)))
772
773         out.write("\n")
774
775
776
777 # Prints pattern rules for this platform's auxilliary compilers
778 def print_aux_patterns(out, platform, comps, module):
779         # Pattern rules for auxilliary compilers supported on this platform
780         out.write("\n# Generic rules for this platform's auxilliary compilers\n\n")
781         aux_comps = platform['auxilliary_compilers']
782         for ac_lang in aux_comps:
783                 compname = aux_comps[ac_lang]
784                 comp = info['compilers'][compname]
785                 # Print pattern rule(s) for this compiler
786                 # ac should be a map from a language to a compiler..
787                 lang = filter(lambda l: l['name'] == ac_lang, info['languages'])[0]
788                 for ext in lang['extensions']:
789                         for abi in platform['abis']:
790                                 for o in comp['optimization']:
791                                     for p in comp['pic']:
792                                         cto = fullspec_cto_component(comp, abi, o, p)
793                                         out.write("%%%s%s: ../src/%%%s\n"
794                                                           % (cto,
795                                                                  platform['filename_conventions']['object_suffix'],
796                                                                  ext))
797                                         # FIXME Make this read the parameter flags from the
798                                         # compiler tuple (output file parameter flag)
799                                         out.write("\t$(M_%s) %s -o $@ $<\n\n"
800                                                           % (comp['defstring'],
801                                                                  object_flag_string(platform, comp, abi, o, p)))
802
803                                         if (module != None):
804                                                  out.write("%%%s%s: ../src/%s/%%%s\n"
805                                                                           % (cto, platform['filename_conventions']['object_suffix'],
806                                                                                   module, ext))
807                                         else:
808                                                  out.write("%%%s%s: ../src/%%%s\n"
809                                                                           % (cto, platform['filename_conventions']['object_suffix'],
810                                                                                   ext))
811                                         # FIXME Make this read the parameter flags from the
812                                         # compiler tuple (output file parameter flag)
813                                         out.write("\t$(M_%s) %s -o $@ $<\n\n"
814                                                           % (comp['defstring'],
815                                                                  object_flag_string(platform, comp, abi, o, p)))
816
817
818 # Prints the footer for make.solo_mutatee.gen
819 def print_make_solo_mutatee_gen_footer(out, comps, platform, module):
820    compilers = info['compilers']
821    out.write("# And a rule to build all of the mutatees\n")
822    out.write(".PHONY: %s_solo_mutatees\n" % (module))
823    out.write("%s_solo_mutatees: " % (module))
824    for c in comps:
825       out.write("$(%sSOLO_MUTATEES_%s) " % (module, compilers[c]['defstring']))
826    out.write("\n\n")
827    out.write(".PHONY: clean_solo_mutatees\n")
828    out.write("%s_clean_solo_mutatees:\n" % (module))
829    for c in comps:
830       out.write("\t-$(RM) $(%s_SOLO_MUTATEES_%s)\n"
831               % (module, compilers[c]['defstring']))
832    # Get a list of optimization levels we're using and delete the mutatee
833    # objects for each of them individually
834    objExt = platform['filename_conventions']['object_suffix']
835    # FIXME Get the actual list of optimization levels we support
836    for o in ['none', 'low', 'high', 'max']:
837       out.write("\t-$(RM) *_%s%s\n" % (o, objExt))
838    out.write("\n\n")
839    out.write("%s_SOLO_MUTATEES =" % (module))
840    for c in comps:
841       out.write(" $(%s_SOLO_MUTATEES_%s)" % (module, compilers[c]['defstring']))
842    out.write("\n\n")
843
844    out.write("### COMPILER_CONTROL_DEFS is used to determine which compilers are present\n")
845    out.write("### when compiling the list of mutatees to test against\n")
846    out.write("COMPILER_CONTROL_DEFS =\n")
847    for c in comps:
848       if info['compilers'][c]['presencevar'] != 'true':
849          out.write("ifdef %s # Is %s present?\n" % (info['compilers'][c]['presencevar'], c))
850          out.write("COMPILER_CONTROL_DEFS += -D%s\n" % (info['compilers'][c]['presencevar']))
851          out.write("endif\n")
852    out.write('\n')
853
854 def format_test_info(test):
855    line = '  {"' + test + '", ' + test + '_mutatee, GROUPED, "' + test + '"}'
856    return line
857
858 def format_test_defines(test):
859    line = 'extern int ' + test + '_mutatee();\n'
860    return line
861
862 def write_group_mutatee_boilerplate_file(filename, tests):
863    out = open(filename, "w")
864    out.write("#ifdef __cplusplus\n")
865    out.write('extern "C" {\n')
866    out.write("#endif\n")
867    out.write('#include "../src/mutatee_call_info.h"\n\n')
868    map(lambda t: out.write(format_test_defines(t)), tests)
869    out.write("\n")
870    out.write("mutatee_call_info_t mutatee_funcs[] = {\n")
871    out.write(reduce(lambda s, t: s + ',\n' + t, map(format_test_info, tests)))
872    out.write("\n")
873    out.write("};\n")
874    out.write("\n")
875    out.write("int max_tests = %d;\n" % (len(tests)))
876    out.write("int runTest[%d];\n" % (len(tests)))
877    out.write("int passedTest[%d];\n" % (len(tests)))
878    out.write("#ifdef __cplusplus\n")
879    out.write("}\n")
880    out.write("#endif\n")
881    out.close()
882
883
884 def accumulate_tests_by_mutatee(acc, g):
885    if g['mutatee'] in acc:
886       acc[g['mutatee']] = acc[g['mutatee']] | set(g['tests']);
887    else:
888       acc.update([(g['mutatee'], set(g['tests']))])
889    return acc
890
891
892 def write_group_mutatee_boilerplate(filename_pre, filename_post, tuplefile):
893    read_tuples(tuplefile)
894    groups = filter(lambda g: len(g['tests']) > 25, info['rungroups'])
895    tests_by_group = reduce(accumulate_tests_by_mutatee, groups, {})
896    for mutatee, tests in tests_by_group.iteritems():
897       write_group_mutatee_boilerplate_file(filename_pre + mutatee + filename_post, tests)
898
899
900 # Main function for generating make.solo_mutatee.gen
901 def write_make_solo_mutatee_gen(filename, tuplefile):
902         read_tuples(tuplefile)
903         compilers = info['compilers']
904         mutatees = info['mutatees']
905         out = open(filename, "w")
906         print_mutatee_comp_defs(out)
907         comps = collect_mutatee_comps(mutatees)
908         pname = os.environ.get('PLATFORM')
909         platform = find_platform(pname)
910         ObjSuffix = platform['filename_conventions']['object_suffix']
911         modules = uniq(map(lambda t: t['module'], info['tests']))
912         for c in comps:
913                 # Generate a block of rules for mutatees produced by each compiler
914                 for m in modules:
915                         muts = filter(lambda x: x['compiler'] == c and is_valid_test(x) == 'true' and get_module(x) == m, mutatees)
916                         if(len(muts) != 0):
917                                 print_mutatee_rules(out, muts, compilers[c], m)
918                 # Print rules for exceptional object files
919                 print_special_object_rules(c, out)
920
921                 for m in modules:
922                         print_patterns(c, out, m)
923                         print_patterns_wildcards(c, out, m)
924                 print_patterns_wildcards(c, out, None)
925
926                 out.write("# Rules for building the driver and utility objects\n")
927                 # TODO Replace this code generation with language neutral code
928                 # generation
929                 if 'c' in info['compilers'][c]['languages']:
930                         for abi in platform['abis']:
931                                 out.write("mutatee_driver_solo_%s_%s%s: ../src/mutatee_driver.c\n" % (info['compilers'][c]['executable'], abi, ObjSuffix))
932                                 out.write("\t$(M_%s) %s %s %s -o $@ -c $<\n"
933                                                   % (compilers[c]['defstring'],
934                                                          compilers[c]['flags']['std'],
935                                                          compilers[c]['flags']['mutatee'],
936                                                          compilers[c]['abiflags'][platform['name']][abi]))
937                                 out.write("mutatee_util_%s_%s%s: ../src/mutatee_util.c\n"
938                                                   % (info['compilers'][c]['executable'],
939                                                          abi, ObjSuffix))
940                                 out.write("\t$(M_%s) %s %s %s -o $@ -c $<\n\n"
941                                                   % (compilers[c]['defstring'],
942                                                          compilers[c]['flags']['std'],
943                                                          compilers[c]['flags']['mutatee'],
944                                                          compilers[c]['abiflags'][platform['name']][abi]))
945                 else:
946                         out.write("# (Skipped: driver and utility objects cannot be compiled with this compiler\n")
947
948         # Print pattern rules for this platform's auxilliary compilers
949
950         for m in modules:
951                 print_aux_patterns(out, platform, comps, m)
952         print_aux_patterns(out, platform, comps, None)
953         # Print footer (list of targets, clean rules, compiler presence #defines)
954         for m in modules:
955                 print_make_solo_mutatee_gen_footer(out, comps, platform, m)
956
957
958         out.close()
959
960 #
961 ##########
962
963 # --------------------------------------------------------
964 # --------------------------------------------------------
965 # BEGIN NT SPECIFIC PROCEDURES
966 # --------------------------------------------------------
967 # --------------------------------------------------------
968
969 # Return the name of the mutatee executable for this rungroup
970 # (Based on compiler name, NOT compiler executable name
971 def mutatee_filename_nt(rungroup, compilers):
972         if rungroup['mutatee'] == 'none':
973                 retval = ""
974         else:
975                 compiler = compilers[rungroup['compiler']]
976                 mutatee = rungroup['mutatee']
977                 bto = fullspec_cto_component_nt(compiler,
978                                                                          rungroup['abi'],
979                                                                          rungroup['optimization'])
980                 platform = find_platform(os.environ.get('PLATFORM'))
981                 es = platform['filename_conventions']['executable_suffix']
982                 retval = "%s_mutatee_solo%s%s" % (mutatee, bto, es)
983         return retval
984
985
986
987 # These functions are duplicated because the compiler NAME, not executable name,
988 # needs to be used for windows, since the exec. name is the same for both c and c++
989 def mutatee_cto_component_nt(mutatee):
990    compiler = info['compilers'][mutatee['compiler']]
991    return fullspec_cto_component_nt(compiler,
992                           mutatee['abi'],
993                           mutatee['optimization'])
994
995 def auxcomp_cto_component_nt(compiler, mutatee):
996    return fullspec_cto_component_nt(compiler,
997                           mutatee['abi'],
998                           mutatee['optimization'])
999
1000 def fullspec_cto_component_nt(compiler, abi, optimization):
1001    def reverse_lookup(dict, value):
1002       for key in dict:
1003          if dict[key] == value:
1004             return key
1005       raise ValueError
1006
1007    retval = "_%s_%s_%s" % (reverse_lookup(info['compilers'], compiler),
1008                      abi,
1009                      optimization)
1010    return retval
1011
1012 def mutatee_binary_nt(mutatee):
1013         # Returns standard name for the solo mutatee binary for this mutatee
1014         # (for windows)
1015         platform = find_platform(os.environ.get('PLATFORM'))
1016         es = platform['filename_conventions']['executable_suffix']
1017         return "%s_mutatee_solo%s%s" % (mutatee['name'],
1018                 mutatee_cto_component_nt(mutatee),
1019                 es)
1020
1021
1022 def group_ok_for_module(g, m):
1023         tests_in_group = filter(lambda t: t['mutatee'] == g['mutatee'], info['tests'])
1024         if(filter(lambda t: m == t['module'], tests_in_group) == []):
1025                 return 'false'
1026         else:
1027                 return 'true'
1028
1029 #TODO this function has literally one line differnet from the non _nt version.
1030 #     merge?
1031 def write_test_info_new_gen_nt(filename, tuplefile):
1032         header = """/* This file automatically generated from test specifications.  See
1033  * specification/spec.pl and specification/makemake.py
1034  */
1035
1036 #include "test_info_new.h"
1037 """
1038         read_tuples(tuplefile)
1039         compilers = info['compilers']
1040         rungroups = info['rungroups']
1041         out = open(filename, "w")
1042         out.write(header)
1043         modules = uniq(map(lambda t: t['module'], info['tests']))
1044         for m in modules:
1045                 out.write("void initialize_mutatees_%s(std::vector<RunGroup *> &tests);\n" % m)
1046         out.write("void initialize_mutatees(std::vector<RunGroup *> &tests) {")
1047         for m in modules:
1048                 out.write("  initialize_mutatees_%s(tests);" % m)
1049         out.write("}")
1050         for m in modules:
1051                 print_initialize_mutatees_nt(out, filter(lambda g: group_ok_for_module(g, m) == 'true', rungroups), compilers, m)
1052         out.close()
1053
1054 def test_ok_for_module(test, module):
1055         tests = info['tests']
1056         if(len(filter (lambda t: t['name'] == test and t['module'] == module, tests)) > 0):
1057                 return 'true'
1058         return 'false'
1059
1060 def print_initialize_mutatees_nt(out, rungroups, compilers, module):
1061 # in visual studio 2003, exceeding 1920 'exception states' causes the compiler to crash.
1062 # from what I can tell, each instantation of an object creates an 'exception case,' so
1063 # the workaround is to instantiate dynamically
1064         header = """
1065 // Now we insert the test lists into the run groups
1066 void initialize_mutatees_%s(std::vector<RunGroup *> &tests) {
1067         unsigned int group_count = 0;
1068         // Keep track of which element each test is, for later use with the resumelog
1069         unsigned int test_count;
1070         RunGroup *rg;
1071 """ % module
1072         out.write(header)
1073         platform = find_platform(os.environ.get('PLATFORM'))
1074         LibSuffix = platform['filename_conventions']['library_suffix']
1075
1076         rungroup_params = []
1077         test_params = []
1078         tests = info['tests']
1079         # TODO Change these to get the string conversions from a tuple output
1080         for group in rungroups:
1081                 compiler = info['compilers'][group['compiler']]
1082                 if compiler['presencevar'] == 'true':
1083                         presencevar = 'true'
1084                 else:
1085                         presencevar = 'false'
1086                 mutatee_name = mutatee_filename_nt(group, compilers)
1087                 if group['start_state'] == 'stopped':
1088                         state_init = 'STOPPED'
1089                 elif group['start_state'] == 'running':
1090                         state_init = 'RUNNING'
1091                 else: # Assuming 'selfstart'
1092                         state_init = 'SELFSTART'
1093                 if group['run_mode'] == 'createProcess':
1094                         attach_init = 'CREATE'
1095                 else: # Assuming 'useAttach'
1096                         attach_init = 'USEATTACH'
1097                 if group['groupable'] == 'true':
1098                         ex = 'false'
1099                 else:
1100                         ex = 'true'
1101                 if group['pic'] == 'pic':
1102                         pic = 'PIC'
1103                 else:
1104                         pic = 'nonPIC'
1105
1106                 group_empty = 'true'
1107                 for test in group['tests']:
1108                         if(test_ok_for_module(test, module) == 'false'):
1109                                 continue
1110                         group_empty = 'false'
1111                         # Set the tuple string for this test
1112                         # (<test>, <mutatee compiler>, <mutatee optimization>, <create mode>)
1113                         # I need to get the mutator that this test maps to..
1114                         mutator = test_mutator(test)
1115                         ts = build_label(test, mutator, group)
1116                         if test in ['test_serializable']:
1117                                 serialize_enable = 'true'
1118                         else:
1119                                 serialize_enable = 'false'
1120                         test_params.append({'test': test, 'mutator': mutator, 'LibSuffix': LibSuffix, 'serialize_enable' : serialize_enable, 'ts': ts, 'endrungroup': 'false'})
1121                 test_params[-1]['endrungroup'] = 'true'
1122                 if(group_empty == 'false'):
1123                         rungroup_params.append({'presencevar': presencevar, 'mutatee_name': mutatee_name, 'state_init': state_init, 
1124                                 'attach_init': attach_init, 'ex': ex, 'compiler': group['compiler'], 'optimization': group['optimization'],
1125                                 'abi': group['abi'], 'pic': pic})
1126
1127         body = """struct {
1128
1129     char * mutatee_name;
1130     start_state_t state_init;
1131     create_mode_t attach_init;
1132     bool ex;
1133     bool presencevar;
1134     char* module;
1135     char* compiler;
1136     char* optimization;
1137     char* abi;
1138     test_pictype_t pic;
1139   } rungroup_params[] = {"""
1140         out.write(body)
1141
1142         out.write(' {"%s", %s, %s, %s, %s, "%s", "%s", "%s", "%s", %s}' % (rungroup_params[0]['mutatee_name'], \
1143                 rungroup_params[0]['state_init'], rungroup_params[0]['attach_init'], rungroup_params[0]['ex'], \
1144                 rungroup_params[0]['presencevar'], module, rungroup_params[0]['compiler'], \
1145                 rungroup_params[0]['optimization'], rungroup_params[0]['abi'], rungroup_params[0]['pic']))
1146         for i in range(1, len(rungroup_params)):
1147                 out.write(',\n {"%s", %s, %s, %s, %s, "%s", "%s", "%s", "%s", %s}' % (rungroup_params[i]['mutatee_name'], \
1148                         rungroup_params[i]['state_init'], rungroup_params[i]['attach_init'], rungroup_params[i]['ex'], \
1149                         rungroup_params[i]['presencevar'], module, rungroup_params[i]['compiler'], \
1150                         rungroup_params[i]['optimization'], rungroup_params[i]['abi'], rungroup_params[i]['pic']))
1151         body = """ };
1152
1153   struct {
1154     bool endrungroup;
1155     const char * iname;
1156     const char * mrname;
1157     const char * isoname;
1158         bool serialize_enable;
1159     const char * ilabel;
1160   } test_params[] = {"""
1161
1162         out.write(body)
1163
1164         out.write(' {%s, "%s", "%s", "%s%s", %s, "%s"}' % (test_params[0]['endrungroup'], test_params[0]['test'], test_params[0]['mutator'], test_params[0]['mutator'], test_params[0]['LibSuffix'], test_params[i]['serialize_enable'], test_params[0]['ts']))
1165         for i in range(1, len(test_params)):
1166                 out.write(',\n {%s, "%s", "%s", "%s%s", %s, "%s"}' % (test_params[i]['endrungroup'], test_params[i]['test'], test_params[i]['mutator'], test_params[i]['mutator'], test_params[i]['LibSuffix'], test_params[i]['serialize_enable'], test_params[i]['ts']))
1167
1168 #TODO presencevar
1169         body = """ };
1170
1171   int tp_index = -1;
1172   for (int i = 0; i < %d; i++) {
1173     test_count = 0;
1174     rg = new RunGroup(rungroup_params[i].mutatee_name, rungroup_params[i].state_init, rungroup_params[i].attach_init, 
1175                         rungroup_params[i].ex, rungroup_params[i].pic, rungroup_params[i].module, rungroup_params[i].compiler,
1176                         rungroup_params[i].optimization, rungroup_params[i].abi);
1177     
1178     do {
1179       tp_index++;
1180       rg->tests.push_back(new TestInfo(test_count++, test_params[tp_index].iname, test_params[tp_index].mrname, test_params[tp_index].isoname, test_params[tp_index].serialize_enable, test_params[tp_index].ilabel));
1181     } while (tp_index < %d && test_params[tp_index].endrungroup == false);
1182
1183     rg->index = group_count++;
1184     tests.push_back(rg);
1185   }
1186 }
1187 """
1188
1189         out.write(body % (len(rungroup_params), len(test_params)))
1190
1191 # ----------------------------
1192 # nmake.mutators.gen (windows)
1193 # ----------------------------
1194 def print_mutators_list_nt(out, mutator_dict, test_dict):
1195         platform = find_platform(os.environ.get('PLATFORM'))
1196         LibSuffix = platform['filename_conventions']['library_suffix']
1197         ObjSuffix = platform['filename_conventions']['object_suffix']
1198         module_list = []
1199         for t in test_dict:
1200                 module_list.append(t['module'])
1201         module_set = set(module_list)
1202
1203         out.write("######################################################################\n")
1204         out.write("# A list of all the mutators to be compiled\n")
1205         out.write("######################################################################\n\n")
1206         mutator_string = "mutators:"
1207         for mod in module_set:  
1208                 module_tests = filter(lambda t: mod == t['module'], test_dict)
1209                 out.write("%s_MUTATORS = " % (mod))
1210                 mutator_string = "%s $(%s_MUTATORS_SO)" % (mutator_string, mod)
1211                 for t in module_tests:
1212                         out.write("%s " % (t['mutator']))
1213                 out.write("\n\n")
1214                 out.write("%s_MUTATORS_SO = " % (mod))
1215                 for t in module_tests:
1216                         out.write("%s%s " % (t['mutator'], LibSuffix))
1217                 out.write("\n\n")
1218                 out.write("%s_OBJS_ALL_MUTATORS = " % (mod))
1219                 for t in module_tests:
1220                         out.write("%s%s " % (t['mutator'], ObjSuffix))
1221                 out.write("\n\n")
1222         out.write("%s\n\n" % mutator_string)
1223
1224         # Now we'll print out a rule for each mutator..
1225         for mod in module_set:
1226                 module_tests = filter(lambda t: t['module'] == mod, test_dict)
1227                 module_mutators = map(lambda t: t['mutator'], module_tests)
1228                 mutators_for_module = filter(lambda m: m['name'] in module_mutators, mutator_dict)
1229                 for m in mutators_for_module:
1230                         # FIXME Don't hardcode $(LIBTESTSUITE)
1231                         out.write("%s%s: " % (m['name'], LibSuffix))
1232                         # Loop through the files listed in this mutator's source list and
1233                         # add object files corresponding to each to the list of dependencies
1234                         objs = []
1235                         sourcefiles = []
1236                         for s in m['sources']:
1237                                 # Print out the object file for this source file
1238                                 objs.append('%s%s' % (s[0:-len(extension(s))], ObjSuffix))
1239                                 sourcefiles.append('../src/%s/%s' % (mod, s))
1240                                 # TODO proper dependencies
1241                                 out.write("%s $(LIBTESTSUITE)\n" % (reduce(lambda x, y: x + " " + y, objs)))
1242                                 # FIXME Make this one better too.  Right now it's copied straight from
1243                                 # make.module.tmpl
1244                                 out.write("\t$(LINK) $(LDFLAGS) -DLL -out:$@ %s $(MUTATOR_LIBS)\n\n" % (reduce(lambda x, y: x + " " + y, objs)))
1245                         for s, o in zip(sourcefiles, objs):
1246                                 out.write("%s: %s\n" % (o, s))
1247                                 out.write("\t$(CXX) $(CXXFLAGS_NORM) -DDLL_BUILD -c -Fo$@ $**\n\n")
1248
1249
1250
1251 def write_make_mutators_gen_nt(filename, tuplefile):
1252         read_tuples(tuplefile)
1253         mutator_dict = info['mutators']
1254         test_dict = info['tests']
1255         platform = find_platform(os.environ.get('PLATFORM'))
1256         LibSuffix = platform['filename_conventions']['library_suffix']
1257         header = """
1258 # This file is automatically generated by the Dyninst testing system.
1259 # For more information, see core/testsuite/src/specification/makemake.py
1260
1261 """
1262
1263         out = open(filename, "w")
1264         out.write(header)
1265         print_mutators_list_nt(out, mutator_dict, test_dict)
1266         out.close()
1267
1268 # --------------------------------
1269 # --------------------------------
1270 # nmake.solo_mutatee.gen (windows)
1271 # --------------------------------
1272 # --------------------------------
1273
1274 # Print makefile variable initializations for all the compilers used for
1275 # makefiles on this platform
1276 def print_mutatee_comp_defs_nt(out):
1277    out.write("# Define variables for our compilers\n")
1278    pname = os.environ.get('PLATFORM')
1279    # TODO Check that we got a string
1280    comps = filter(lambda c: c != ''
1281                          and pname in info['compilers'][c]['platforms'],
1282                info['compilers'])
1283    for c in comps:
1284       if info['compilers'][c]['presencevar'] != 'true':
1285          out.write("!ifdef %s\n" % (info['compilers'][c]['presencevar']))
1286       out.write('M_%s = %s\n' % (info['compilers'][c]['defstring'], info['compilers'][c]['executable']))
1287       if info['compilers'][c]['presencevar'] != 'true':
1288          out.write("!endif\n")
1289    out.write('\n')
1290
1291 def print_mutatee_rules_nt(out, mutatees, compiler, unique_target_dict, module):
1292         mutatees_for_module = filter(lambda x: get_module(x) == module, mutatees)
1293         mut_names = map(lambda x: mutatee_binary_nt(x), mutatees_for_module)
1294
1295         out.write("######################################################################\n")
1296         out.write("# Mutatees compiled with %s for %s\n" % (mutatees[0]['compiler'], module))
1297         out.write("######################################################################\n\n")
1298         if compiler['presencevar'] != 'true':
1299                 out.write("!ifdef %s\n" % (compiler['presencevar']))
1300                 out.write("# We only want to build these targets if the compiler exists\n")
1301         out.write("%s_SOLO_MUTATEES_%s = " % (module, compiler['defstring']))
1302         for m in mut_names:
1303                 out.write("%s " % (m))
1304         out.write('\n')
1305         if compiler['presencevar'] != 'true':
1306                 out.write("!endif\n")
1307         out.write("\n")
1308         out.write("# Now a list of rules for compiling the mutatees with %s\n\n"
1309                           % (mutatees[0]['compiler']))
1310
1311         pname = os.environ.get('PLATFORM')
1312         platform = find_platform(pname)
1313         ObjSuffix = platform['filename_conventions']['object_suffix']
1314
1315         # this variable is used to keep track of dependency targets. this must
1316         # be done for windows because nmake doesn't have % wildcard support.
1317         # note: this excludes a mutattee's ['preprocessed_sources'][0], since
1318         # this is a special case accounted for in print_patterns_nt
1319         dependency_sources = {}
1320
1321         groups = info['rungroups']
1322
1323         # Write rules for building the mutatee executables from the object files
1324         for (m, n) in zip(mutatees_for_module, mut_names):
1325                 out.write("%s: " % (n))
1326
1327                 group_mutatee_list = filter(has_multiple_tests, groups)
1328                 group_mutatee_list = filter(lambda g: g['mutatee'] == m['name'], group_mutatee_list)
1329                 group_boilerplates = uniq(map(lambda g: g['mutatee'] + '_group.c', group_mutatee_list))
1330                 for bp in group_boilerplates:
1331                         cto = mutatee_cto_component_nt(m)
1332                         out.write("%s " % (replace_extension(bp, "%s%s"
1333                                                          % (cto, ObjSuffix))))
1334
1335                 for f in m['preprocessed_sources']:
1336                         # List all the compiled transformed source files
1337                         # I need to futz with the compiler here to make sure it's correct..
1338                         # FIXME This next line may end up arbitrarily picking the first
1339                         # language from a list of more than one for an extension
1340                         lang = filter(lambda l: extension(f) in l['extensions'],
1341                                                   info['languages'])[0]['name']
1342                         if (lang in compiler['languages']):
1343                                 cto = mutatee_cto_component_nt(m)
1344                                 pps_name = replace_extension(f, "_solo%s%s"
1345                                                                                                         % (cto, ObjSuffix))
1346                                 out.write("%s " % (pps_name))
1347                                 # only add unique elements to the sources dictionary,
1348                                 # and don't add the first one, since it's rule is printed
1349                                 # in print_patterns_nt
1350 #                               if f != m['preprocessed_sources'][0]:
1351                                         # only insert this if it hasn't been accounted for in a
1352                                         # previous invocation of this procedure
1353 #                               try:
1354 #                                       unique_target_dict[pps_name]
1355 #                               except KeyError:
1356 #                                       # only insert it if it's not already in the list
1357 #                                       try:
1358 #                                               dependency_sources[pps_name]
1359 #                                       except KeyError:
1360 #                                               dependency_sources[pps_name] = {'src': f, 'abi': m['abi'],
1361 #                                                       'optimization': m['optimization'], 'suffix': ObjSuffix, 'compiler': compiler}
1362                         else: # Preprocessed file compiled with auxilliary compiler
1363                                 pname = os.environ.get('PLATFORM')
1364                                 # TODO Check that we got a string..
1365                                 platform = find_platform(pname)
1366                                 # TODO Check that we retrieved a platform object
1367                                 aux_comp = platform['auxilliary_compilers'][lang]
1368                                 # TODO Verify that we got a compiler
1369                                 cto = auxcomp_cto_component_nt(info['compilers'][aux_comp], m)
1370                                 out.write("%s " % (replace_extension(f, "_solo%s%s"
1371                                                                                                          % (cto, ObjSuffix))))
1372                                 # TODO
1373                                 # the same try/except block can be duplicated as above, but
1374                                 # I don't think windows ever has preprocessed files compiled
1375                                 # with auxilliary compiler. if it does though, the script
1376                                 # will die here
1377                                 makeshift_die
1378                 # TODO Let's grab the languages used in the preprocessed sources, and
1379                 # save them for later.  We use this to determine which raw sources get
1380                 # compiled with the same options as the preprocessed ones, in the case
1381                 # of a compiler that is used for more than one language (e.g. GCC in
1382                 # tests test1_35 or test_mem)
1383
1384                 # FIXME I'm doing this wrong: the compiler for preprocessed files might
1385                 # not be the compiler that we're testing..
1386                 # Get the compiler..
1387                 maincomp_langs = uniq(info['compilers'][m['compiler']]['languages'])
1388                 pp_langs = uniq(map(lambda x: get_file_lang(x)['name'], m['preprocessed_sources']))
1389                 # So we want to print out a list of object files that go into this
1390                 # mutatee.  For files that can be compiled with m['compiler'], we'll
1391                 # use it, and compile at optimization level m['optimization'].  For
1392                 # other files, we'll just use the appropriate compiler and not worry
1393                 # about optimization levels?
1394                 for f in m['raw_sources']:
1395                         # Figure out whether or not this file can be compiled with
1396                         # m['compiler']
1397                         lang = get_file_lang(f)
1398                         if type(lang) == type([]):
1399                                 lang = lang[0] # BUG This may cause unexpected behavior if more
1400                                                # than one language was returned, but more than
1401                                                            # one language should never be returned
1402                         if lang['name'] in maincomp_langs:
1403                                 # This file is compiled with the main compiler for this mutatee
1404                                 cto = mutatee_cto_component_nt(m)
1405                                 comp = compiler
1406                                 opt = m['optimization']
1407                                 rs_name = replace_extension(f, "%s%s"
1408                                                                                                         % (cto, ObjSuffix))
1409                         else:
1410                                 # This file is compiled with an auxilliary compiler
1411                                 # Find the auxilliary compiler for this language on this
1412                                 # platform
1413                                 # This assumes that there is only one possible auxilliary
1414                                 # compiler for a language ending with the extension of interest
1415                                 # on the platform.  This condition is enforced by sanity checks
1416                                 # in the specification file.
1417                                 aux_comp = platform['auxilliary_compilers'][lang['name']]
1418                                 comp = info['compilers'][aux_comp]
1419                                 opt = 'none'
1420                                 cto = fullspec_cto_component_nt(info['compilers'][aux_comp],
1421                                                                                          m['abi'], 'none')
1422                                 rs_name = replace_extension(f, '%s%s'
1423                                                                                                         % (cto, ObjSuffix))
1424                         out.write("%s " % (rs_name))
1425
1426                         # only insert if it hasn't been accounted for in a previous
1427                         # invocation of this function
1428                         try:
1429                                 unique_target_dict[rs_name]
1430                         except KeyError:
1431                                 try:
1432                                         dependency_sources[rs_name]
1433                                 except KeyError:
1434                                         dependency_sources[rs_name] = {'src': f, 'abi': m['abi'],
1435                                                         'optimization': opt, 'suffix': ObjSuffix, 'compiler': comp,
1436                                                         'groupable': m['groupable'], 'pic': 'none'}
1437                 # FIXME Check whether the current compiler compiles C files and if not
1438                 # then use the aux compiler for this platform for the mutatee driver
1439                 # object.
1440                 if 'c' in info['compilers'][m['compiler']]['languages']:
1441                         out.write("mutatee_driver_solo_%s_%s_%s%s\n"
1442                                           % (m['compiler'],
1443                                                  m['abi'], m['optimization'], ObjSuffix))
1444                 else:
1445                         # Get the aux compiler for C on this platform and use it
1446                         aux_c = find_platform(os.environ.get('PLATFORM'))['auxilliary_compilers']['c']
1447                         aux_c = info['compilers'][aux_c]['executable']
1448                         out.write("mutatee_driver_solo_%s_%s_%s%s\n"
1449                                           % (aux_c, m['abi'], m['optimization'], ObjSuffix))
1450                 # Print the actions used to link the mutatee executable
1451                 out.write("\t%s %s -out:$@ $** %s "
1452                                   % (platform['linker'] or "$(M_%s)" % compiler['defstring'],
1453                                          compiler['flags']['link'],
1454                                          compiler['abiflags'][platform['name']][m['abi']]))
1455                 # TODO: libraries
1456                 #for l in m['libraries']:
1457                 # Need to include the required libraries on the command line
1458                 # FIXME Use a compiler-specific command-line flag instead of '-l'
1459                 #       out.write("-l%s " % (l))
1460                 out.write('\n')
1461
1462                 # ***ADD NEW BUILD-TIME ACTIONS HERE***
1463
1464         # now write the individual preprocessed source targets
1465         for object, options in dependency_sources.iteritems():
1466                 ObjSuffix = options['suffix']
1467                 src = options['src']
1468                 abi = options['abi']
1469                 o = options['optimization']
1470                 comp = options['compiler']
1471                 pic = options['pic']
1472
1473                 if src.startswith("mutatee_util"):
1474                         out.write("%s: ../src/%s\n" % (object, src))
1475                 else:
1476                         out.write("%s: ../src/%s/%s\n" % (object, module, src))
1477                 # FIXME -Dsnprintf=_snprintf is needed for c files that contain snprintf,
1478                 #       but not for .asm files. the masm compiler accepts the -D parameter,
1479                 #       but it's unnecessary
1480                 out.write("\t$(M_%s) %s -Dsnprintf=_snprintf -Fo$@ $**\n"
1481                                         % (comp['defstring'], object_flag_string(platform, comp, abi, o, pic)))
1482
1483                 # now add the object to the unique target list. this prevents the same
1484                 # target from being specified in a different invocation of this function
1485                 unique_target_dict[object] = 1
1486
1487
1488 # Prints generic rules for compiling from mutatee boilerplate
1489 def print_patterns_nt(c, out, module):
1490         out.write("\n# Generic rules for %s's mutatees and varying optimization levels\n" % (c))
1491
1492         compiler = info['compilers'][c]
1493         platform = find_platform(os.environ.get('PLATFORM'))
1494         ObjSuffix = platform['filename_conventions']['object_suffix']
1495
1496         
1497         ng_sources = get_all_mutatee_sources('false', module)
1498
1499         g_sources = get_all_mutatee_sources('true', module)
1500
1501         groups = filter(lambda g: group_ok_for_module(g, module) == 'true', info['rungroups'])
1502         group_mutatee_list = filter(has_multiple_tests, groups)
1503         group_boilerplates = uniq(map(lambda g: g['mutatee'] + '_group.c', group_mutatee_list))
1504         for abi in platform['abis']:
1505                 for o in compiler['optimization']:
1506                         # Rules for compiling source files to .o files
1507                         cto = fullspec_cto_component_nt(compiler, abi, o)
1508
1509                         #FIXME this prints out one rule for every mutatee preprocessed source for EVERY optimization
1510                         #      I don't know whether the previous targets require every combination of source/opt
1511                         #      i.e. printing ALL of them may be superfluous
1512                         for sourcefile in ng_sources:
1513                                 ext = extension(sourcefile)
1514                                 boilerplate = "solo_mutatee_boilerplate" + ext
1515                                 basename = sourcefile[0:-len('_mutatee') - len(ext)]
1516
1517                                 out.write("%s_mutatee_solo%s%s: ../src/%s\n"
1518                                                 % (basename, cto, ObjSuffix, boilerplate))
1519                                 out.write("\t$(M_%s) %s -DTEST_NAME=%s -DGROUPABLE=0 -DMUTATEE_SRC=../src/%s/%s -Fo$@ $**\n"
1520                                                 % (compiler['defstring'],
1521                                                    object_flag_string(platform, compiler, abi, o, "none"),
1522                                                    basename, module, sourcefile))
1523
1524                         for sourcefile in g_sources:
1525                                 ext = extension(sourcefile)
1526                                 boilerplate = "solo_mutatee_boilerplate" + ext
1527                                 basename = sourcefile[0:-len('_mutatee') - len(ext)]
1528
1529                                 out.write("%s_mutatee_solo%s%s: ../src/%s\n"
1530                                                 % (basename, cto, ObjSuffix, boilerplate))
1531                                 out.write("\t$(M_%s) %s -DTEST_NAME=%s -DGROUPABLE=1 -DMUTATEE_SRC=../src/%s/%s -Fo$@ $**\n"
1532                                                 % (compiler['defstring'],
1533                                                    object_flag_string(platform, compiler, abi, o, "none"),
1534                                                    basename, module, sourcefile))
1535
1536
1537                         for sourcefile in group_boilerplates:
1538                                 ext = extension(sourcefile)
1539                                 basename = sourcefile[0:-len(ext)]
1540                                 out.write("%s%s%s: ../%s/%s\n" % (basename, cto, ObjSuffix, os.environ.get('PLATFORM'), sourcefile))
1541                                 out.write("\t$(M_%s) $(%s_SOLO_MUTATEE_DEFS) %s -DGROUPABLE=1 -Fo$@ $**\n" 
1542                                         % (compiler['defstring'], module, 
1543                                         object_flag_string(platform, compiler, abi, o, "none")))
1544                         for l in compiler['languages']: 
1545                                 lang = find_language(l) # Get language dictionary from name
1546                                 for e in lang['extensions']:
1547                                         # FIXME This generates spurious lines for compilers that
1548                                         # aren't used for this part of the mutatee build system
1549                                         # like .s and .S files for gcc and Fortran files.
1550                                         out.write("%%%s%s: {../src/%s/}%%%s\n"
1551                                                           % (cto, ObjSuffix, module, e))
1552                                         out.write("\t$(M_%s) %s -Fo$@ $**\n"
1553                                                 % (compiler['defstring'], object_flag_string(platform, compiler, abi, o, "none")))
1554         out.write("\n")
1555
1556 # Main function for generating nmake.solo_mutatee.gen
1557 def write_make_solo_mutatee_gen_nt(filename, tuplefile):
1558         read_tuples(tuplefile)
1559         compilers = info['compilers']
1560         mutatees = info['mutatees']
1561         out = open(filename, "w")
1562         print_mutatee_comp_defs_nt(out)
1563         # vvvvv This one isn't nt specific vvvvv
1564         comps = collect_mutatee_comps(mutatees)
1565         pname = os.environ.get('PLATFORM')
1566         platform = find_platform(pname)
1567         ObjSuffix = platform['filename_conventions']['object_suffix']
1568         unique_target_dict = {}
1569         modules = uniq(map(lambda t: t['module'], info['tests']))
1570         for c in comps:
1571                 # Generate a block of rules for mutatees produced by each compiler
1572                 muts = filter(lambda x: x['compiler'] == c, mutatees)
1573                 for m in modules:
1574                         print_mutatee_rules_nt(out, muts, compilers[c], unique_target_dict, m)
1575                 # Print rules for exceptional object files
1576                 # TODO: don't know if this needs to be done for windows
1577                 #print_special_object_rules(c, out)
1578 # TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO 
1579                 for m in modules:
1580                         print_patterns_nt(c, out, m)
1581                 out.write("# Rules for building the driver and utility objects\n")
1582                 # TODO Replace this code generation with language neutral code
1583                 # generation
1584                 if 'c' in info['compilers'][c]['languages']:
1585                         for abi in platform['abis']:
1586                                 for (opt_level, opt_flag) in compilers[c]['optimization'].items():
1587                                         out.write("mutatee_driver_solo_%s_%s_%s%s: ../src/mutatee_driver.c\n" % (c, abi, opt_level, ObjSuffix))
1588                                         out.write("\t$(M_%s) %s %s %s %s -Dsnprintf=_snprintf -Fo$@ -c $**\n"
1589                                                           % (compilers[c]['defstring'],
1590                                                                  compilers[c]['flags']['std'],
1591                                                                  compilers[c]['flags']['mutatee'],
1592                                                                  opt_flag,
1593                                                                  compilers[c]['abiflags'][platform['name']][abi]))
1594                                         # TODO: find where these files live in our data structures
1595                                         # and remove the hardcoding!
1596
1597                 else:
1598                         out.write("# (Skipped: driver and utility objects cannot be compiled with this compiler\n")
1599
1600         # Print pattern rules for this platform's auxilliary compilers
1601         #print_aux_patterns(out, platform, comps)
1602
1603         # Print footer (list of targets, clean rules, compiler presence #defines)
1604         for m in modules:
1605                 print_make_solo_mutatee_gen_footer(out, comps, platform, m)
1606         out.write("mutatees: ");
1607         for m in modules:
1608                 out.write("$(%s_SOLO_MUTATEES) " %(m));
1609         out.write("\n");
1610         out.close()