268 lines
8.5 KiB
Python
268 lines
8.5 KiB
Python
|
#!/usr/bin/python
|
||
|
|
||
|
# Copyright (C) 2013 Steven Watanabe
|
||
|
# Distributed under the Boost Software License, Version 1.0.
|
||
|
# (See accompanying file LICENSE.txt or copy at
|
||
|
# https://www.bfgroup.xyz/b2/LICENSE.txt)
|
||
|
|
||
|
import sys
|
||
|
|
||
|
def create(t):
|
||
|
t.write('''mockinfo.py''', '''
|
||
|
from __future__ import print_function
|
||
|
import re
|
||
|
import optparse
|
||
|
import os
|
||
|
|
||
|
parser = optparse.OptionParser()
|
||
|
parser.add_option('-o', dest="output_file")
|
||
|
parser.add_option('-x', dest="language")
|
||
|
parser.add_option('-c', dest="compile", action="store_true")
|
||
|
parser.add_option('-I', dest="includes", action="append")
|
||
|
parser.add_option('-D', dest="defines", action="append")
|
||
|
parser.add_option('-L', dest="library_path", action="append")
|
||
|
parser.add_option('--dll', dest="dll", action="store_true")
|
||
|
parser.add_option('--archive', dest="archive", action="store_true")
|
||
|
parser.add_option('--static-lib', dest="static_libraries", action="append")
|
||
|
parser.add_option('--shared-lib', dest="shared_libraries", action="append")
|
||
|
|
||
|
cwd = os.environ["JAM_CWD"]
|
||
|
|
||
|
class MockInfo(object):
|
||
|
def __init__(self, verbose=False):
|
||
|
self.files = dict()
|
||
|
self.commands = list()
|
||
|
self.verbose = verbose
|
||
|
def source_file(self, name, pattern):
|
||
|
self.files[name] = pattern
|
||
|
def action(self, command, status=0):
|
||
|
if isinstance(command, str):
|
||
|
command = command.split()
|
||
|
self.commands.append((command, status))
|
||
|
def check(self, command):
|
||
|
print("Testing command", command)
|
||
|
for (raw, status) in self.commands:
|
||
|
if self.matches(raw, command):
|
||
|
return status
|
||
|
def matches(self, raw, command):
|
||
|
(expected_options, expected_args) = parser.parse_args(raw)
|
||
|
options = command[0]
|
||
|
input_files = list(command[1])
|
||
|
if self.verbose:
|
||
|
print(" - matching against", (expected_options, expected_args))
|
||
|
if len(expected_args) != len(input_files):
|
||
|
if self.verbose:
|
||
|
print(" argument list sizes differ")
|
||
|
return False
|
||
|
for arg in expected_args:
|
||
|
if arg.startswith('$'):
|
||
|
fileid = arg[1:]
|
||
|
pattern = self.files[fileid] if fileid in self.files else fileid
|
||
|
matching_file = None
|
||
|
for input_file in input_files:
|
||
|
with open(input_file, 'r') as f:
|
||
|
contents = f.read()
|
||
|
if pattern == contents:
|
||
|
matching_file = input_file
|
||
|
break
|
||
|
if matching_file is not None:
|
||
|
input_files.remove(matching_file)
|
||
|
else:
|
||
|
if self.verbose:
|
||
|
print(" Failed to match input file contents: %s" % arg)
|
||
|
return False
|
||
|
else:
|
||
|
if arg in input_files:
|
||
|
input_files.remove(arg)
|
||
|
else:
|
||
|
if self.verbose:
|
||
|
print(" Failed to match input file: %s" % arg)
|
||
|
return False
|
||
|
|
||
|
if options.language != expected_options.language:
|
||
|
if self.verbose:
|
||
|
print(" Failed to match -c")
|
||
|
return False
|
||
|
|
||
|
if options.compile != expected_options.compile:
|
||
|
if self.verbose:
|
||
|
print(" Failed to match -x")
|
||
|
return False
|
||
|
|
||
|
# Normalize a path for comparison purposes
|
||
|
def adjust_path(p):
|
||
|
return os.path.normcase(os.path.normpath(os.path.join(cwd, p)))
|
||
|
|
||
|
# order matters
|
||
|
if options.includes is None:
|
||
|
options.includes = []
|
||
|
if expected_options.includes is None:
|
||
|
expected_options.includes = []
|
||
|
if list(map(adjust_path, options.includes)) != \
|
||
|
list(map(adjust_path, expected_options.includes)):
|
||
|
if self.verbose:
|
||
|
print(" Failed to match -I ", list(map(adjust_path, options.includes)), \
|
||
|
" != ", list(map(adjust_path, expected_options.includes)))
|
||
|
return False
|
||
|
|
||
|
if options.defines is None:
|
||
|
options.defines = []
|
||
|
if expected_options.defines is None:
|
||
|
expected_options.defines = []
|
||
|
if options.defines != expected_options.defines:
|
||
|
if self.verbose:
|
||
|
print(" Failed to match -I ", options.defines, \
|
||
|
" != ", expected_options.defines)
|
||
|
return False
|
||
|
|
||
|
if options.library_path is None:
|
||
|
options.library_path = []
|
||
|
if expected_options.library_path is None:
|
||
|
expected_options.library_path = []
|
||
|
if list(map(adjust_path, options.library_path)) != \
|
||
|
list(map(adjust_path, expected_options.library_path)):
|
||
|
if self.verbose:
|
||
|
print(" Failed to match -L ", list(map(adjust_path, options.library_path)), \
|
||
|
" != ", list(map(adjust_path, expected_options.library_path)))
|
||
|
return False
|
||
|
|
||
|
if options.static_libraries != expected_options.static_libraries:
|
||
|
if self.verbose:
|
||
|
print(" Failed to match --static-lib")
|
||
|
return False
|
||
|
|
||
|
if options.shared_libraries != expected_options.shared_libraries:
|
||
|
if self.verbose:
|
||
|
print(" Failed to match --shared-lib")
|
||
|
return False
|
||
|
|
||
|
if options.dll != expected_options.dll:
|
||
|
if self.verbose:
|
||
|
print(" Failed to match --dll")
|
||
|
return False
|
||
|
|
||
|
if options.archive != expected_options.archive:
|
||
|
if self.verbose:
|
||
|
print(" Failed to match --archive")
|
||
|
return False
|
||
|
|
||
|
# The output must be handled after everything else
|
||
|
# is validated
|
||
|
if expected_options.output_file is not None:
|
||
|
if options.output_file is not None:
|
||
|
if expected_options.output_file.startswith('$'):
|
||
|
fileid = expected_options.output_file[1:]
|
||
|
if fileid not in self.files:
|
||
|
self.files[fileid] = fileid
|
||
|
else:
|
||
|
assert(self.files[fileid] == fileid)
|
||
|
with open(options.output_file, 'w') as output:
|
||
|
output.write(fileid)
|
||
|
else:
|
||
|
if self.verbose:
|
||
|
print("Failed to match -o")
|
||
|
return False
|
||
|
elif options.output_file is not None:
|
||
|
if self.verbose:
|
||
|
print("Failed to match -o")
|
||
|
return False
|
||
|
|
||
|
# if we've gotten here, then everything matched
|
||
|
if self.verbose:
|
||
|
print(" Matched")
|
||
|
return True
|
||
|
''')
|
||
|
|
||
|
t.write('mock.py', '''
|
||
|
from __future__ import print_function
|
||
|
import mockinfo
|
||
|
import markup
|
||
|
import sys
|
||
|
|
||
|
status = markup.info.check(mockinfo.parser.parse_args())
|
||
|
if status is not None:
|
||
|
exit(status)
|
||
|
else:
|
||
|
print("Unrecognized command: " + ' '.join(sys.argv))
|
||
|
exit(1)
|
||
|
''')
|
||
|
|
||
|
t.write('mock.jam', '''
|
||
|
import feature ;
|
||
|
import toolset ;
|
||
|
import path ;
|
||
|
import modules ;
|
||
|
import common ;
|
||
|
import type ;
|
||
|
|
||
|
.python-cmd = "\"%s\"" ;
|
||
|
|
||
|
# Behave the same as gcc on Windows, because that's what
|
||
|
# the test system expects
|
||
|
type.set-generated-target-prefix SHARED_LIB : <toolset>mock <target-os>windows : lib ;
|
||
|
type.set-generated-target-suffix STATIC_LIB : <toolset>mock <target-os>windows : a ;
|
||
|
|
||
|
rule init ( )
|
||
|
{
|
||
|
local here = [ path.make [ modules.binding $(__name__) ] ] ;
|
||
|
here = [ path.native [ path.root [ path.parent $(here) ] [ path.pwd ] ] ] ;
|
||
|
.config-cmd = [ common.variable-setting-command JAM_CWD : $(here) ] $(.python-cmd) -B ;
|
||
|
}
|
||
|
|
||
|
feature.extend toolset : mock ;
|
||
|
|
||
|
generators.register-c-compiler mock.compile.c++ : CPP : OBJ : <toolset>mock ;
|
||
|
generators.register-c-compiler mock.compile.c : C : OBJ : <toolset>mock ;
|
||
|
|
||
|
generators.register-linker mock.link : LIB OBJ : EXE : <toolset>mock ;
|
||
|
generators.register-linker mock.link.dll : LIB OBJ : SHARED_LIB : <toolset>mock ;
|
||
|
generators.register-archiver mock.archive : OBJ : STATIC_LIB : <toolset>mock ;
|
||
|
|
||
|
toolset.flags mock.compile OPTIONS <link>shared : -fPIC ;
|
||
|
toolset.flags mock.compile INCLUDES : <include> ;
|
||
|
toolset.flags mock.compile DEFINES : <define> ;
|
||
|
|
||
|
actions compile.c
|
||
|
{
|
||
|
$(.config-cmd) mock.py -c -x c -I"$(INCLUDES)" -D"$(DEFINES)" "$(>)" -o "$(<)"
|
||
|
}
|
||
|
|
||
|
actions compile.c++
|
||
|
{
|
||
|
$(.config-cmd) mock.py -c -x c++ -I"$(INCLUDES)" -D"$(DEFINES)" "$(>)" -o "$(<)"
|
||
|
}
|
||
|
|
||
|
toolset.flags mock.link USER_OPTIONS <linkflags> ;
|
||
|
toolset.flags mock.link FINDLIBS-STATIC <find-static-library> ;
|
||
|
toolset.flags mock.link FINDLIBS-SHARED <find-shared-library> ;
|
||
|
toolset.flags mock.link LINK_PATH <library-path> ;
|
||
|
toolset.flags mock.link LIBRARIES <library-file> ;
|
||
|
|
||
|
actions link
|
||
|
{
|
||
|
$(.config-cmd) mock.py "$(>)" -o "$(<)" $(USER_OPTIONS) -L"$(LINK_PATH)" --static-lib=$(FINDLIBS-STATIC) --shared-lib=$(FINDLIBS-SHARED)
|
||
|
}
|
||
|
|
||
|
actions archive
|
||
|
{
|
||
|
$(.config-cmd) mock.py --archive "$(>)" -o "$(<)" $(USER_OPTIONS)
|
||
|
}
|
||
|
|
||
|
actions link.dll
|
||
|
{
|
||
|
$(.config-cmd) mock.py --dll "$(>)" -o "$(<)" $(USER_OPTIONS) -L"$(LINK_PATH)" --static-lib=$(FINDLIBS-STATIC) --shared-lib=$(FINDLIBS-SHARED)
|
||
|
}
|
||
|
|
||
|
''' % sys.executable.replace('\\', '\\\\'))
|
||
|
|
||
|
def set_expected(t, markup):
|
||
|
verbose = "True" if t.verbose else "False"
|
||
|
t.write('markup.py', '''
|
||
|
import mockinfo
|
||
|
info = mockinfo.MockInfo(%s)
|
||
|
def source_file(name, contents):
|
||
|
info.source_file(name, contents)
|
||
|
def action(command, status=0):
|
||
|
info.action(command, status)
|
||
|
''' % (verbose) + markup)
|