You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
FreeRTOS/FreeRTOS-Plus/Test/CBMC/proofs/ninja.py

220 lines
6.3 KiB
Python

#!/usr/bin/env python3
"""
Write a ninja build file to generate reports for cbmc proofs.
Given a list of folders containing cbmc proofs, write a ninja build
file the generate reports for these proofs. The list of folders may
be given on the command line, in a json file, or found in the file
system.
"""
# Add task pool
import sys
import os
import platform
import argparse
import json
################################################################
# The command line parser
def argument_parser():
"""Return the command line parser."""
parser = argparse.ArgumentParser(
description='Generate ninja build file for cbmc proofs.',
epilog="""
Given a list of folders containing cbmc proofs, write a ninja build
file the generate reports for these proofs. The list of folders may
be given on the command line, in a json file, or found in the file
system.
In the json file, there should be a dict mapping the key "proofs"
to a list of folders containing proofs.
The file system, all folders folders under the current directory
containing a file named 'cbmc-batch.yaml' is considered a
proof folder.
This script assumes that the proof is driven by a Makefile
with targets goto, cbmc, coverage, property, and report.
This script does not work with Windows and Visual Studio.
"""
)
parser.add_argument('folders', metavar='PROOF', nargs='*',
help='Folder containing a cbmc proof')
parser.add_argument('--proofs', metavar='JSON',
help='Json file listing folders containing cbmc proofs')
return parser
################################################################
# The list of folders containing proofs
#
# The list of folders will be taken from
# 1. the list PROOFS defined here or
# 2. the command line
# 3. the json file specified on the command line containing a
# dict mapping the key JSON_KEY to a list of folders
# 4. the folders below the current directory containing
# a file named FS_KEY
#
PROOFS = [
]
JSON_KEY = 'proofs'
FS_KEY = 'cbmc-batch.yaml'
def find_proofs_in_json_file(filename):
"""Read the list of folders containing proofs from a json file."""
if not filename:
return []
try:
with open(filename) as proofs:
return json.load(proofs)[JSON_KEY]
except (FileNotFoundError, KeyError):
raise UserWarning("Can't find key {} in json file {}".format(JSON_KEY, filename))
except json.decoder.JSONDecodeError:
raise UserWarning("Can't parse json file {}".format(filename))
def find_proofs_in_filesystem():
"""Locate the folders containing proofs in the filesystem."""
proofs = []
for root, _, files in os.walk('.'):
if FS_KEY in files:
proofs.append(os.path.normpath(root))
return proofs
################################################################
# The strings used to write sections of the ninja file
NINJA_RULES = """
################################################################
# task pool to force sequential builds of goto binaries
pool goto_pool
depth = 1
################################################################
# proof target rules
rule build_goto
command = make -C ${folder} goto
pool = goto_pool
rule build_cbmc
command = make -C ${folder} cbmc
rule build_coverage
command = make -C ${folder} coverage
rule build_property
command = make -C ${folder} property
rule build_report
command = make -C ${folder} report
rule clean_folder
command = make -C ${folder} clean
rule veryclean_folder
command = make -C ${folder} veryclean
rule open_proof
command = open ${folder}/html/index.html
"""
NINJA_BUILDS = """
################################################################
# {folder} proof targets
build {folder}/{entry}.goto: build_goto
folder={folder}
build {folder}/cbmc.txt: build_cbmc {folder}/{entry}.goto
folder={folder}
build {folder}/coverage.xml: build_coverage {folder}/{entry}.goto
folder={folder}
build {folder}/property.xml: build_property {folder}/{entry}.goto
folder={folder}
build {folder}/html/index.html: build_report {folder}/{entry}.goto {folder}/cbmc.txt {folder}/coverage.xml {folder}/property.xml
folder={folder}
build clean_{folder}: clean_folder
folder={folder}
build veryclean_{folder}: veryclean_folder
folder={folder}
build open_{folder}: open_proof
folder={folder}
build {folder}: phony {folder}/html/index.html
default {folder}
"""
NINJA_GLOBALS = """
################################################################
# global targets
build clean: phony {clean_targets}
build veryclean: phony {veryclean_targets}
build open: phony {open_targets}
"""
################################################################
# The main function
def get_entry(folder):
"""Find the name of the proof in the proof Makefile."""
with open('{}/Makefile'.format(folder)) as makefile:
for line in makefile:
if line.strip().lower().startswith('entry'):
return line[line.find('=')+1:].strip()
if line.strip().lower().startswith('h_entry'):
return line[line.find('=')+1:].strip()
raise UserWarning("Can't find ENTRY in {}/Makefile".format(folder))
def write_ninja_build_file():
"""Write a ninja build file to generate proof results."""
if platform.system().lower() == 'windows':
print("This script does not run on Windows.")
sys.exit()
args = argument_parser().parse_args()
proofs = (PROOFS or
args.folders or
find_proofs_in_json_file(args.proofs) or
find_proofs_in_filesystem())
with open('build.ninja', 'w') as ninja:
ninja.write(NINJA_RULES)
for proof in proofs:
entry = get_entry(proof)
ninja.write(NINJA_BUILDS.format(folder=proof, entry=entry))
targets = lambda kind, folders: ' '.join(
['{}_{}'.format(kind, folder) for folder in folders]
)
ninja.write(NINJA_GLOBALS.format(
clean_targets=targets('clean', proofs),
veryclean_targets=targets('veryclean', proofs),
open_targets=targets('open', proofs)
))
################################################################
if __name__ == "__main__":
write_ninja_build_file()