diff --git a/data/Makefile.in b/data/Makefile.in index fb724e35..a11e1ce5 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -462,11 +462,16 @@ R_DEP := $(R_OBJ:%.o=%.d) recursion-target: $(R_TARGET) +# By giving "phony-%" as the value to R_TARGET, we only create the object files +ifeq ($(patsubst phony-%,phony,$(R_TARGET)),phony) +$(R_TARGET): $(R_OBJ) +else $(R_TARGET): $(R_OBJ) @$(call color_out,BLUE, Creating $(R_TARGET)) @+mkdir -p $(dir $@) $(R_COMPILER) -o $@ $(R_OPTL) $(R_SWITCHES) $(R_CXXFLAGS) $(CXXFLAGS) \ $(R_OBJ) $(LDFLAGS) $(R_LDFLAGS) $(LDLIBS) +endif $(R_OBJ_DIR): +$(MKDIR) $@ diff --git a/data/Makefile_bisect_binary.in b/data/Makefile_bisect_binary.in index 7a24858a..f726a4fa 100644 --- a/data/Makefile_bisect_binary.in +++ b/data/Makefile_bisect_binary.in @@ -101,7 +101,7 @@ TROUBLE_CXX := {trouble_cxx} TROUBLE_OPTL := {trouble_optl} TROUBLE_SWITCHES := {trouble_switches} TROUBLE_CXX_TYPE := {trouble_type} -BISECT_LINK := $(GT_CXX) +BISECT_LINK := {bisect_linker} RM := rm -f RMDIR := rm -rf @@ -140,6 +140,7 @@ SPLIT_SRC := TROUBLE_CXXFLAGS := {trouble_cxxflags} TROUBLE_LDFLAGS := {trouble_ldflags} +BISECT_LDFLAGS := {bisect_ldflags} TROUBLE_TARGET_OUT := $(TROUBLE_TARGET:%=%-out) TROUBLE_TARGET_RESULT := $(TROUBLE_TARGET_OUT:%=%-comparison.csv) @@ -161,34 +162,6 @@ else GT_TARGET_TO_USE := $(GT_TARGET) endif -# Similar to REC_COMPILE_RULE but has an extra param -# @param 8: directory where a copy may reside. If this directory has the -# desired object file, then copy it instead of compiling one -define REC_COMPILE_OR_COPY_RULE -ifneq ($$(R_TARGET),$1) -.PHONY: $1 -$1: Makefile custom.mk $$(MAKEFILE) - +$$(REC_MAKE) R_TYPE=compile-or-copy \ - R_TARGET="$1" \ - R_COMPILER="$2" \ - R_OPTL="$3" \ - R_SWITCHES="$4" \ - R_CXXFLAGS="$5" \ - R_LDFLAGS="$6" \ - R_OBJ_DIR="$7" \ - R_COPY_DIR="$8" -endif -endef - -# Note: trouble-fpic is to create the fpic version of the executable -# it is used to precompile fpic object files if requested for speedier search -# This target is not reentrant, do not have multiple of them running at the -# same time -.PHONY: trouble trouble-out trouble-fpic -trouble: $(TROUBLE_TARGET) -trouble-out: $(TROUBLE_TARGET_RESULT) $(TROUBLE_TARGET_OUT) -trouble-fpic: $(TROUBLE_TARGET)-fpic - .PHONY: bisect bisect: $(BISECT_TARGET) $(BISECT_RESULT) @@ -199,10 +172,6 @@ bisect-smallclean: $(RM) $(BISECT_TARGET) $(RM) $(BISECT_OUT) $(RM) $(addsuffix *.dat,$(BISECT_OUT)) - $(RM) $(TROUBLE_TARGET) - $(RM) $(TROUBLE_TARGET)-fpic - $(RM) $(TROUBLE_TARGET_OUT) - $(RM) $(addsuffix *.dat,$(TROUBLE_TARGET_OUT)) $(RMDIR) $(SPLIT_DIR) bisect-clean: bisect-smallclean @@ -215,15 +184,17 @@ bisect-clean: bisect-smallclean bisect-distclean: bisect-clean $(RM) bisect.log - $(RM) $(TROUBLE_TARGET_RESULT) $(RM) $(BISECT_RESULT) $(RM) $(MAKEFILE) $(RMDIR) $(SYMBOLS_DIR) $(RMDIR) $(LOCAL_OBJ_DIR) -rmdir --ignore-fail-on-non-empty $(BISECT_DIR) +.PHONY: trouble phony-trouble +trouble: phony-trouble +# Note: phony-target here causes no executable to be created $(eval $(call REC_COMPILE_RULE,\ - $(TROUBLE_TARGET),\ + phony-trouble,\ $(TROUBLE_CXX),\ $(TROUBLE_OPTL),\ $(TROUBLE_SWITCHES),\ @@ -231,8 +202,12 @@ $(eval $(call REC_COMPILE_RULE,\ $(TROUBLE_LDFLAGS),\ $(BISECT_OBJ_DIR))) +# to create the fpic version of the object files +.PHONY: trouble-fpic phony-trouble-fpic +trouble-fpic: phony-trouble-fpic +# Note: phony-target here causes no executable to be created $(eval $(call REC_COMPILE_RULE,\ - $(TROUBLE_TARGET)-fpic,\ + phony-trouble-fpic,\ $(TROUBLE_CXX),\ $(TROUBLE_OPTL),\ $(TROUBLE_SWITCHES),\ @@ -275,16 +250,6 @@ $(BISECT_RESULT): $(BISECT_OUT) $(GT_RESULT_TO_USE) $(GT_TARGET_TO_USE) $(RUNWRAP) ./$(GT_TARGET_TO_USE) --compare-mode --compare-gt $(GT_RESULT_TO_USE) \ --suffix "-comparison.csv" $< -o /dev/null -$(TROUBLE_TARGET_OUT): $(TROUBLE_TARGET) - @$(call color_out,CYAN, $< -> $@) - $(RUNWRAP) ./$(TROUBLE_TARGET) --output $(TROUBLE_TARGET_OUT) --no-timing \ - --precision "$(PRECISION)" $(TEST_CASE) - -$(TROUBLE_TARGET_RESULT): $(TROUBLE_TARGET_OUT) $(GT_RESULT_TO_USE) $(GT_TARGET_TO_USE) - @$(call color_out,CYAN, $< -> $@) - $(RUNWRAP) ./$(GT_TARGET_TO_USE) --compare-mode --compare-gt $(GT_RESULT_TO_USE) \ - --suffix "-comparison.csv" $< -o /dev/null - ################################# # *** R_TYPE=bisect-compile *** # ################################# @@ -313,8 +278,8 @@ recursion-target: $(BISECT_TARGET) $(BISECT_TARGET): $(BISECT_OBJ) Makefile custom.mk | $(BISECT_DIR) @$(call color_out,BLUE, Creating $@) - $(GT_CXX) $(CXXFLAGS) $(GT_CXXFLAGS) -o $@ $(BISECT_OBJ) $(LDFLAGS) \ - $(GT_LDFLAGS) $(LDLIBS) + $(BISECT_LINK) $(CXXFLAGS) $(GT_CXXFLAGS) -o $@ $(BISECT_OBJ) $(LDFLAGS) \ + $(BISECT_LDFLAGS) $(LDLIBS) # compile BISECT_GT_OBJ $(foreach s,$(BISECT_GT_SRC),\ diff --git a/documentation/flit-command-line.md b/documentation/flit-command-line.md index 4a0c6b07..0ab2a047 100644 --- a/documentation/flit-command-line.md +++ b/documentation/flit-command-line.md @@ -193,7 +193,8 @@ Note: if the compiler given (e.g., `g++`) is found in the `compiler` section of `flit-config.toml`, then the `fixed_compile_flags` specified there will be used when compiling object files from this compilation under test. However, the `fixed_link_flags` will not be used since the link step is performed by default -with the baseline compilation's compiler. +with the baseline compilation's compiler. This behavior can be overridden with +the `--ldflags`, `--use-linker`, and `--add-ldflags` options. And here is an example of giving a full SQLite3 database diff --git a/scripts/bash-completion/flit b/scripts/bash-completion/flit index 5d002196..b636d4b3 100644 --- a/scripts/bash-completion/flit +++ b/scripts/bash-completion/flit @@ -46,7 +46,10 @@ _flit_bisect() --compile-only --precompile-fpic --skip-verification - -t --compiler-type" + -t --compiler-type + --ldflags + --add-ldflags + --use-linker" case "${prev}" in diff --git a/scripts/flitcli/experimental/flit_ninja.py b/scripts/flitcli/experimental/flit_ninja.py index 0a5fc755..f45b2e0e 100755 --- a/scripts/flitcli/experimental/flit_ninja.py +++ b/scripts/flitcli/experimental/flit_ninja.py @@ -671,18 +671,19 @@ def main(arguments, prog=None): args = parser.parse_args(arguments) arguments = [x for x in arguments if x not in ('-q', '--quiet')] - if not args.quiet: - if os.path.exists(BUILD_FILENAME): - print('Updating', BUILD_FILENAME) - else: - print('Creating', BUILD_FILENAME) - - with open(BUILD_FILENAME, 'w') as build_file: - writer = NinjaWriter(build_file, prog, arguments) - writer.load_project_config('flit-config.toml') - if os.path.isfile('custom.mk'): - writer.load_makefile('custom.mk') - writer.write() + with util.pushd(args.directory): + if not args.quiet: + if os.path.exists(BUILD_FILENAME): + print('Updating', BUILD_FILENAME) + else: + print('Creating', BUILD_FILENAME) + + with open(BUILD_FILENAME, 'w') as build_file: + writer = NinjaWriter(build_file, prog, arguments) + writer.load_project_config('flit-config.toml') + if os.path.isfile('custom.mk'): + writer.load_makefile('custom.mk') + writer.write() return 0 diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index c5440df0..02c6a4dc 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -296,37 +296,60 @@ def create_bisect_makefile(directory, replacements, gt_src, baseline and differing symbols for each file. Within replacements, there are some optional fields: - - link_flags: (list) (optional) List of linker flags to give to the + - added_link_flags: (list) (optional) List of linker flags to give to the ground-truth compiler when performing linking. @return the bisect makefile name without directory prepended to it ''' + # TODO: refactor this function. it is too complicated if split_symbol_map is None: split_symbol_map = {} # default to an empty dictionary repl_copy = dict(replacements) projdir = os.path.join(directory, '..') projconf = util.load_projconf(projdir) - cxxflags, ldflags = try_get_compiler_flags(repl_copy['trouble_cxx'], projconf) + cxxflags, tbl_ldflags = try_get_compiler_flags(repl_copy['trouble_cxx'], + projconf) try: with util.pushd(projdir): - ldflags += ' {}'.format(flit_update._additional_ldflags( + tbl_ldflags += ' {}'.format(flit_update._additional_ldflags( {'type': repl_copy['trouble_type'], 'binary': repl_copy['trouble_cxx']})) except NotImplementedError: pass # skip over unsupported compiler types repl_copy['trouble_cxxflags'] = cxxflags - repl_copy['trouble_ldflags'] = ldflags + repl_copy['trouble_ldflags'] = tbl_ldflags + if repl_copy['bisect_ldflags'] is None: + # TODO: have this be linker flags for $(BISECT_LINK) executable + # (similar to ldflags and cxxflags) + if repl_copy['bisect_linker'] is not None: + _, bisect_ldflags = try_get_compiler_flags( + repl_copy['bisect_linker'], projconf) + bisect_c_type = try_resolve_compiler_type( + repl_copy['bisect_linker'], projconf) + try: + with util.pushd(projdir): + bisect_ldflags += ' {}'.format( + flit_update._additional_ldflags( + {'type': bisect_c_type, + 'binary': repl_copy['bisect_linker']})) + except NotImplementedError: + pass # skip over unsupported compiler types + repl_copy['bisect_ldflags'] = bisect_ldflags + else: + repl_copy['bisect_ldflags'] = '$(GT_LDFLAGS)' + if repl_copy['bisect_linker'] is None: + repl_copy['bisect_linker'] = '$(GT_CXX)' repl_copy['TROUBLE_SRC'] = '\n'.join(['TROUBLE_SRC += {0}'.format(x) for x in trouble_src]) repl_copy['BISECT_GT_SRC'] = '\n'.join(['BISECT_GT_SRC += {0}'.format(x) for x in gt_src]) repl_copy['SPLIT_SRC'] = '\n'.join(['SPLIT_SRC += {0}'.format(x) for x in split_symbol_map]) - if 'link_flags' in repl_copy: + if 'added_link_flags' in repl_copy: repl_copy['EXTRA_LDFLAGS'] = '\n'.join([ 'LDFLAGS += {0}'.format(x) - for x in repl_copy['link_flags']]) - del repl_copy['link_flags'] + for x in repl_copy['added_link_flags']]) + del repl_copy['added_link_flags'] @@ -1236,6 +1259,37 @@ def populate_parser(parser=None): given compiler is the same as that used by the ground-truth compilation. ''') + parser.add_argument('--ldflags', + help=''' + Replace the linker flags that would be used by the + linker program (pulled from 'fixed_link_flags' from + flit_config.toml). If you want to add linker flags + instead of replacing them, use '--add-ldflags' + instead. + + Note: since flags start with a '-', to not confuse + this argument parser, use the '=' syntax. For + example: '--ldflags="-Wl,-rpath=/usr + -Wl,-rpath=/usr/lib64"' + ''') + parser.add_argument('--add-ldflags', default='', + help=''' + Add linker flags on top of the default that would be used. + + Note: since flags start with a '-', to not confuse + this argument parser, use the '=' syntax. For + example: '--add-ldflags="-Wl,-rpath=/usr + -Wl,-rpath=/usr/lib64"' + ''') + parser.add_argument('--use-linker', + help=''' + Specify a different linker to use. This should + probably be a C++ compiler, like 'g++'. If this + program is found in 'flit-config.toml', then the + linker flags used will be from the + 'fixed_link_flags' specified there, unless + '--ldflags' is also specified. + ''') return parser def parse_args(arguments, prog=None): @@ -1315,8 +1369,8 @@ def builder_and_checker(libs): full baseline compilation. ''' repl_copy = dict(replacements) - repl_copy['link_flags'] = list(repl_copy['link_flags']) - repl_copy['link_flags'].extend(libs) + repl_copy['added_link_flags'] = list(repl_copy['added_link_flags']) + repl_copy['added_link_flags'].extend(libs) makefile = create_bisect_makefile(bisect_path, repl_copy, sources, [], dict()) makepath = os.path.join(bisect_path, makefile) @@ -1609,18 +1663,34 @@ def differing_source_callback(filename, score): return differing_sources, differing_symbols -def compile_trouble(directory, compiler, optl, switches, compiler_type, - verbose=False, jobs=mp.cpu_count(), delete=True, - fpic=False): +def gen_replacements(args, bisect_dir): + 'Build the replacements dictionary from parsed command-line arguments' + hashval = hash_compilation(args.compiler, args.optl, args.switches) + return { + 'bisect_dir': bisect_dir, + 'datetime': datetime.date.today().strftime("%B %d, %Y"), + 'flit_version': conf.version, + 'precision': args.precision, + 'test_case': args.testcase, + 'trouble_cxx': args.compiler, + 'trouble_optl': args.optl, + 'trouble_switches': args.switches, + 'trouble_type': args.compiler_type, + 'trouble_id': hashval, + 'bisect_ldflags': args.ldflags, + 'bisect_linker': args.use_linker, + 'added_link_flags': [args.add_ldflags], + 'build_gt_local': 'false', + } + +def compile_trouble(directory, replacements, verbose=False, + jobs=mp.cpu_count(), delete=True, fpic=False): ''' Compiles the trouble executable for the given arguments. This is useful to compile the trouble executable as it will force the creation of all needed object files for bisect. This can be used to precompile all object files needed for bisect. ''' - # TODO: much of this was copied from run_bisect(). Refactor code. - trouble_hash = hash_compilation(compiler, optl, switches) - # see if the Makefile needs to be regenerated # we use the Makefile to check for itself, sweet run_make( @@ -1636,20 +1706,6 @@ def compile_trouble(directory, compiler, optl, switches, compiler_type, except FileExistsError: pass # not a problem if it already exists - replacements = { - 'bisect_dir': 'bisect-precompile', - 'datetime': datetime.date.today().strftime("%B %d, %Y"), - 'flit_version': conf.version, - 'precision': '', - 'test_case': '', - 'trouble_cxx': compiler, - 'trouble_optl': optl, - 'trouble_switches': switches, - 'trouble_type': compiler_type, - 'trouble_id': trouble_hash, - 'link_flags': [], - 'build_gt_local': 'false', - } makefile = create_bisect_makefile(trouble_path, replacements, []) makepath = os.path.join(trouble_path, makefile) @@ -1687,8 +1743,6 @@ def run_bisect(arguments, prog=None): projconf = util.load_projconf(args.directory) args.compiler_type = try_resolve_compiler_type(args.compiler, projconf) - trouble_hash = hash_compilation(args.compiler, args.optl, args.switches) - # see if the Makefile needs to be regenerated # we use the Makefile to check for itself, sweet run_make(directory=args.directory, verbose=args.verbose, jobs=1, @@ -1711,12 +1765,15 @@ def run_bisect(arguments, prog=None): #level=logging.INFO) level=logging.DEBUG) + replacements = gen_replacements(args, bisect_dir) + logging.info('Starting the bisect procedure') logging.debug(' trouble compiler: "%s"', args.compiler) logging.debug(' trouble optimization level: "%s"', args.optl) logging.debug(' trouble switches: "%s"', args.switches) logging.debug(' trouble testcase: "%s"', args.testcase) - logging.debug(' trouble hash: "%s"', trouble_hash) + logging.debug(' trouble hash: "%s"', + replacements['trouble_id']) # get the list of source files from the Makefile sources = util.extract_make_var('SOURCE', directory=args.directory) @@ -1724,21 +1781,6 @@ def run_bisect(arguments, prog=None): for source in sources: logging.debug(' %s', source) - replacements = { - 'bisect_dir': bisect_dir, - 'datetime': datetime.date.today().strftime("%B %d, %Y"), - 'flit_version': conf.version, - 'precision': args.precision, - 'test_case': args.testcase, - 'trouble_cxx': args.compiler, - 'trouble_optl': args.optl, - 'trouble_switches': args.switches, - 'trouble_type': args.compiler_type, - 'trouble_id': trouble_hash, - 'link_flags': [], - 'build_gt_local': 'false', - } - update_gt_results(args.directory, verbose=args.verbose, jobs=args.jobs) # Find out if the linker is to blame (e.g. intel linker linking mkl libs) @@ -1800,7 +1842,7 @@ def run_bisect(arguments, prog=None): # Compile all following executables with these static libraries # regardless of their effect - replacements['link_flags'].extend(libs) + replacements['added_link_flags'].extend(libs) # If the libraries were a problem, then reset what the baseline # ground-truth is, especially since we updated the LINK_FLAGS in the @@ -2058,14 +2100,14 @@ def parallel_auto_bisect(arguments, prog=None): print('Before parallel bisect run, compile all object files') for i, compilation in enumerate(sorted(compilation_set)): - compiler, optl, switches = compilation + args.compiler, args.optl, args.switches = compilation print(' ({0} of {1})'.format(i + 1, len(compilation_set)), - ' '.join((compiler, optl, switches)) + ':', + ' '.join((args.compiler, args.optl, args.switches)) + ':', end='', flush=True) - compiler_type = try_resolve_compiler_type(compiler, projconf) - compile_trouble(args.directory, compiler, optl, switches, - compiler_type, verbose=args.verbose, + args.compiler_type = try_resolve_compiler_type(args.compiler, projconf) + replacements = gen_replacements(args, 'bisect-precompile') + compile_trouble(args.directory, replacements, verbose=args.verbose, jobs=args.jobs, delete=args.delete, fpic=args.precompile_fpic) print(' done', flush=True) diff --git a/src/flit/ALL-FLIT.cpp b/src/flit/ALL-FLIT.cpp index 23ba9943..63d37767 100644 --- a/src/flit/ALL-FLIT.cpp +++ b/src/flit/ALL-FLIT.cpp @@ -82,8 +82,6 @@ */ // This file includes all of the source files within FLiT to be compiled in one go -// -// For now, this is an experiment to see how it affects compile-time #include "flit.cpp" #include "FlitCsv.cpp" diff --git a/tests/flit_cli/flit_bisect/common.py b/tests/flit_cli/flit_bisect/common.py new file mode 100644 index 00000000..a6579311 --- /dev/null +++ b/tests/flit_cli/flit_bisect/common.py @@ -0,0 +1,90 @@ +from io import StringIO +import os +import sys + +before_path = sys.path[:] +sys.path.append('../..') +import test_harness as th +sys.path = before_path + +class BisectTestError(RuntimeError): pass + +def flit_init(directory): + 'Creates a new FLiT directory returning the standard output' + with StringIO() as ostream: + retval = th.flit.main(['init', '-C', directory], outstream=ostream) + if retval != 0: + raise BisectTestError( + 'Could not initialize (retval={0}):\n'.format(retval) + + ostream.getvalue()) + init_out = ostream.getvalue().splitlines() + return init_out + +def flit_update(directory): + 'Calls flit update in the given directory' + with StringIO() as ostream: + retval = th.flit.main(['update', '-C', directory], + outstream=ostream) + if retval != 0: + raise BisectTestError('Could not update Makefile\n' + + ostream.getvalue()) + +def bisect_compile(compiler, directory=None, linker=None, ldflags=None, + add_ldflags=None): + ''' + Runs bisect with the given compiler and returns makefile variables + + @param compiler (str): name or path to invoke the compiler under test + @param directory (str): directory path to flit test directory + If None is given, use the current working directory + @param linker (str): Linker program to use + If None is given, use baseline compiler + @param ldflags (str): Linker flags to use + If None is given, use value from flit-config.toml for the linker + executable (if given) + @param add_ldflags (str): Linker flags to add to the base linker flags + (either from the ldflags given or the ones from the baseline compiler) + If None is given, no linker flags are added + + @return Dictionary of Makefile variables for first bisect Makefile + ''' + + # create static variable i for how many times this function is called + if not hasattr(bisect_compile, 'i'): + bisect_compile.i = 0 # initialize only once + bisect_compile.i += 1 + + # Note: we give a bad flag to cause bisect to error out early + # we just need it to get far enough to create the first makefile + args = ['bisect'] + + if directory is not None: + args.extend(['-C', directory]) + if linker is not None: + args.extend(['--use-linker', linker]) + if ldflags is not None: + args.extend(['--ldflags={}'.format(ldflags)]) + if add_ldflags is not None: + args.extend(['--add-ldflags={}'.format(add_ldflags)]) + + args.extend([ + '--precision', 'double', + compiler + ' -bad-flag', + 'EmptyTest' + ]) + + with StringIO() as ostream: + retval = th.flit.main(args, outstream=ostream) + if retval == 0: + raise BisectTestError('Expected bisect to fail\n' + + ostream.getvalue()) + + # Since each call creates a separate bisect dir, we use our counter + makepath = os.path.join(directory, + 'bisect-{0:02d}'.format(bisect_compile.i), + 'bisect-make-01.mk') + makevars = th.util.extract_make_vars( + makefile=os.path.relpath(makepath, directory), + directory=directory) + return makevars + diff --git a/tests/flit_cli/flit_bisect/tst_bisect.py b/tests/flit_cli/flit_bisect/tst_bisect.py index 37e357a3..723001f5 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect.py +++ b/tests/flit_cli/flit_bisect/tst_bisect.py @@ -95,17 +95,12 @@ >>> import subprocess as subp >>> from io import StringIO >>> import flitutil as util +>>> from common import BisectTestError, flit_init >>> class BisectTestError(RuntimeError): pass >>> with th.tempdir() as temp_dir: -... with StringIO() as ostream: -... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) -... if retval != 0: -... raise BisectTestError( -... 'Could not initialize (retval={0}):\\n'.format(retval) + -... ostream.getvalue()) -... init_out = ostream.getvalue().splitlines() +... init_out = flit_init(temp_dir) ... shutil.rmtree(os.path.join(temp_dir, 'tests')) ... _ = shutil.copytree(os.path.join('data', 'tests'), ... os.path.join(temp_dir, 'tests')) diff --git a/tests/flit_cli/flit_bisect/tst_bisect_autosqlite_clang.py b/tests/flit_cli/flit_bisect/tst_bisect_autosqlite_clang.py index 5a24787b..b0d2fbb0 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect_autosqlite_clang.py +++ b/tests/flit_cli/flit_bisect/tst_bisect_autosqlite_clang.py @@ -89,23 +89,14 @@ Let's now make a temporary directory and test that we can successfully compile and run FLiT bisect ->>> import glob >>> import os >>> import shutil >>> import subprocess as subp >>> from io import StringIO ->>> import flitutil as util - ->>> class BisectTestError(RuntimeError): pass +>>> from common import BisectTestError, flit_init >>> with th.tempdir() as temp_dir: -... with StringIO() as ostream: -... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) -... if retval != 0: -... raise BisectTestError( -... 'Could not initialize (retval={0}):\\n'.format(retval) + -... ostream.getvalue()) -... init_out = ostream.getvalue().splitlines() +... init_out = flit_init(temp_dir) ... shutil.rmtree(os.path.join(temp_dir, 'tests')) ... _ = shutil.copytree(os.path.join('data', 'tests'), ... os.path.join(temp_dir, 'tests')) @@ -152,11 +143,11 @@ ... '--no-print-directory', '--always-make', ... '-f', os.path.join('bisect-precompile', 'bisect-make-01.mk')]) ... makeout3 = makeout3.strip().decode('utf-8').splitlines() -... troublecxx = util.extract_make_var( +... troublecxx = th.util.extract_make_var( ... 'TROUBLE_CXX', ... os.path.join('bisect-precompile', 'bisect-make-01.mk'), ... directory=temp_dir) -... troublecxx_type = util.extract_make_var( +... troublecxx_type = th.util.extract_make_var( ... 'TROUBLE_CXX_TYPE', ... os.path.join('bisect-precompile', 'bisect-make-01.mk'), ... directory=temp_dir) @@ -173,7 +164,7 @@ >>> fakeclang_lines = [line for line in makeout1 ... if line.startswith('./fake_clang34.py')] >>> len(fakeclang_lines) -9 +8 >>> any('--gcc-toolchain' in line for line in fakeclang_lines) False diff --git a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py index e8fb9d86..8745d6a8 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py @@ -89,11 +89,10 @@ Let's now make a temporary directory and test that we can successfully compile and run FLiT bisect ->>> import glob >>> import os >>> import shutil ->>> import subprocess as subp >>> from io import StringIO +>>> from common import flit_init let's stub out some functions that actually confer with the compiler. These make the test take way too long and that interaction has already been tested in @@ -195,9 +194,7 @@ Now for the test after we stubbed a single file >>> with th.tempdir() as temp_dir: -... with StringIO() as ostream: -... _ = th.flit.main(['init', '-C', temp_dir], outstream=ostream) -... init_out = ostream.getvalue().splitlines() +... init_out = flit_init(temp_dir) ... shutil.rmtree(os.path.join(temp_dir, 'tests')) ... _ = shutil.copytree(os.path.join('data', 'tests'), ... os.path.join(temp_dir, 'tests')) diff --git a/tests/flit_cli/flit_bisect/tst_bisect_compilerspecificflags.py b/tests/flit_cli/flit_bisect/tst_bisect_compilerspecificflags.py index e115459a..5653a094 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect_compilerspecificflags.py +++ b/tests/flit_cli/flit_bisect/tst_bisect_compilerspecificflags.py @@ -84,49 +84,13 @@ Tests the use of the compiler-specific flags in flit-config.toml for both the compilation under test and for the link step (to use the baseline compilation) ->>> import glob >>> import os >>> import shutil ->>> import subprocess as subp >>> from io import StringIO ->>> import flitutil as util - ->>> class BisectTestError(RuntimeError): pass - ->>> def bisect_compile(compiler, directory): -... 'Runs bisect with the given compiler and returns makefile variables' -... -... # create static variable i for how many times this function is called -... if not hasattr(bisect_compile, 'i'): -... bisect_compile.i = 0 # initialize only once -... bisect_compile.i += 1 -... -... # Note: we give a bad flag to cause bisect to error out early -... # we just need it to get far enough to create the first makefile -... with StringIO() as ostream: -... retval = th.flit.main(['bisect', '-C', directory, -... '--precision', 'double', -... compiler + ' -bad-flag', 'EmptyTest'], -... outstream=ostream) -... if retval == 0: -... raise BisectTestError('Expected bisect to fail\\n' + -... ostream.getvalue()) -... -... # Since each call creates a separate bisect dir, we use our counter -... makevars = util.extract_make_vars( -... makefile=os.path.join(directory, -... 'bisect-{0:02d}'.format(bisect_compile.i), -... 'bisect-make-01.mk'), -... directory=directory) -... return makevars +>>> from common import bisect_compile, flit_init, flit_update, BisectTestError >>> with th.tempdir() as temp_dir: -... with StringIO() as ostream: -... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) -... if retval != 0: -... raise BisectTestError( -... 'Could not initialize (retval={0}):\\n'.format(retval) + -... ostream.getvalue()) +... _ = flit_init(temp_dir) ... _ = shutil.copy( ... os.path.join('data', 'flit-config-compilerspecificflags.toml'), ... os.path.join(temp_dir, 'flit-config.toml')) @@ -134,13 +98,9 @@ ... _ = shutil.copy(os.path.join('data', 'fake_gcc9.py'), temp_dir) ... _ = shutil.copy(os.path.join('data', 'fake_clang34.py'), temp_dir) ... _ = shutil.copy(os.path.join('data', 'fake_intel19.py'), temp_dir) -... with StringIO() as ostream: -... retval = th.flit.main(['update', '-C', temp_dir], -... outstream=ostream) -... if retval != 0: -... raise BisectTestError('Could not update Makefile\\n' + -... ostream.getvalue()) +... flit_update(temp_dir) ... +... # Note: ./fake_gcc9.py is not in flit-config.toml ... bisect_makevars_gcc4 = bisect_compile('./fake_gcc4.py', temp_dir) ... bisect_makevars_gcc9 = bisect_compile('./fake_gcc9.py', temp_dir) ... bisect_makevars_clang = bisect_compile('./fake_clang34.py', temp_dir) @@ -185,6 +145,15 @@ ['-l-intel-link1', '-l-intel-link2', '-no-pie'] >>> sorted(bisect_makevars_gcc9['TROUBLE_LDFLAGS']) [] + +>>> sorted(bisect_makevars_gcc4['BISECT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(bisect_makevars_clang['BISECT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(bisect_makevars_intel['BISECT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(bisect_makevars_gcc9['BISECT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] ''' # Test setup before the docstring is run. diff --git a/tests/flit_cli/flit_bisect/tst_bisect_linkstep.py b/tests/flit_cli/flit_bisect/tst_bisect_linkstep.py new file mode 100644 index 00000000..9dc71a5e --- /dev/null +++ b/tests/flit_cli/flit_bisect/tst_bisect_linkstep.py @@ -0,0 +1,307 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Tests FLiT Bisect, specifically the command-line options related to linking. + +>>> import os +>>> import shutil +>>> from common import bisect_compile, flit_init, flit_update + +>>> def dual_bisect_compile(*args, add_ldflags=None, **kwargs): +... without = bisect_compile(*args, **kwargs) +... added = bisect_compile(*args, add_ldflags=add_ldflags, **kwargs) +... return without, added + +>>> with th.tempdir() as temp_dir: +... _ = flit_init(temp_dir) +... _ = shutil.copy( +... os.path.join('data', 'flit-config-compilerspecificflags.toml'), +... os.path.join(temp_dir, 'flit-config.toml')) +... _ = shutil.copy(os.path.join('data', 'fake_gcc4.py'), temp_dir) +... _ = shutil.copy(os.path.join('data', 'fake_gcc9.py'), temp_dir) +... _ = shutil.copy(os.path.join('data', 'fake_clang34.py'), temp_dir) +... _ = shutil.copy(os.path.join('data', 'fake_intel19.py'), temp_dir) +... flit_update(temp_dir) +... +... # Note: ./fake_gcc9.py is not in flit-config.toml +... vars_ldflags, vars_ldflags_added = dual_bisect_compile( +... './fake_gcc4.py', temp_dir, ldflags='-other -ldflags', +... add_ldflags='-add1 -add2') +... vars_clanglink, vars_clanglink_added = dual_bisect_compile( +... './fake_intel19.py', temp_dir, linker='./fake_clang34.py', +... add_ldflags='-add3') +... vars_both, vars_both_added = dual_bisect_compile( +... './fake_clang34.py', temp_dir, linker='./fake_intel19.py', +... ldflags='-more -still', add_ldflags='-add4 -add5') +... vars_unknown_linker, vars_unknown_linker_added = dual_bisect_compile( +... './fake_clang34.py', temp_dir, linker='./fake_gcc9.py', +... add_ldflags='-add6 -add7 -add8') +... vars_unknown_linker_ld, vars_unknown_linker_ld_added = dual_bisect_compile( +... './fake_gcc4.py', temp_dir, linker='./fake_gcc9.py', +... ldflags='-ld-for-unknown', add_ldflags='') + +Test that BISECT_LDFLAGS is populated correctly +----------------------------------------------- + +Uses the ld flags that were given +>>> sorted(vars_ldflags['BISECT_LDFLAGS']) +['-ldflags', '-other'] +>>> sorted(vars_ldflags['LDFLAGS']) +[] +>>> sorted(vars_ldflags_added['BISECT_LDFLAGS']) +['-ldflags', '-other'] +>>> sorted(vars_ldflags_added['LDFLAGS']) +['-add1', '-add2'] + +Use flags from ./fake_clang34.py +>>> sorted(vars_clanglink['BISECT_LDFLAGS']) +['-l-clang-link1', '-l-clang-link2', '-nopie'] +>>> sorted(vars_clanglink['LDFLAGS']) +[] +>>> sorted(vars_clanglink_added['BISECT_LDFLAGS']) +['-l-clang-link1', '-l-clang-link2', '-nopie'] +>>> sorted(vars_clanglink_added['LDFLAGS']) +['-add3'] + +Use the ld flags that were given +>>> sorted(vars_both['BISECT_LDFLAGS']) +['-more', '-still'] +>>> sorted(vars_both['LDFLAGS']) +[] +>>> sorted(vars_both_added['BISECT_LDFLAGS']) +['-more', '-still'] +>>> sorted(vars_both_added['LDFLAGS']) +['-add4', '-add5'] + +Empty because linker is not found in flit-config.toml +>>> sorted(vars_unknown_linker['BISECT_LDFLAGS']) +[] +>>> sorted(vars_unknown_linker['LDFLAGS']) +[] +>>> sorted(vars_unknown_linker_added['BISECT_LDFLAGS']) +[] +>>> sorted(vars_unknown_linker_added['LDFLAGS']) +['-add6', '-add7', '-add8'] + +Use the ld flags that were given +>>> sorted(vars_unknown_linker_ld['BISECT_LDFLAGS']) +['-ld-for-unknown'] +>>> sorted(vars_unknown_linker_ld['LDFLAGS']) +[] +>>> sorted(vars_unknown_linker_ld_added['BISECT_LDFLAGS']) +['-ld-for-unknown'] +>>> sorted(vars_unknown_linker_ld_added['LDFLAGS']) +[] + +Test that the BISECT_LINK is set appropriately +-------------------------------------------- + +>>> sorted(vars_ldflags['BISECT_LINK']) +['./fake_gcc4.py'] +>>> sorted(vars_ldflags_added['BISECT_LINK']) +['./fake_gcc4.py'] +>>> sorted(vars_clanglink['BISECT_LINK']) +['./fake_clang34.py'] +>>> sorted(vars_clanglink_added['BISECT_LINK']) +['./fake_clang34.py'] +>>> sorted(vars_both['BISECT_LINK']) +['./fake_intel19.py'] +>>> sorted(vars_both_added['BISECT_LINK']) +['./fake_intel19.py'] +>>> sorted(vars_unknown_linker['BISECT_LINK']) +['./fake_gcc9.py'] +>>> sorted(vars_unknown_linker_added['BISECT_LINK']) +['./fake_gcc9.py'] +>>> sorted(vars_unknown_linker_ld['BISECT_LINK']) +['./fake_gcc9.py'] +>>> sorted(vars_unknown_linker_ld_added['BISECT_LINK']) +['./fake_gcc9.py'] + +Test GT_CXXFLAGS is unaffected by extra flags +--------------------------------------------- + +>>> sorted(vars_ldflags['GT_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2', '-g'] +>>> sorted(vars_ldflags_added['GT_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2', '-g'] +>>> sorted(vars_clanglink['GT_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2', '-g'] +>>> sorted(vars_clanglink_added['GT_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2', '-g'] +>>> sorted(vars_both['GT_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2', '-g'] +>>> sorted(vars_both_added['GT_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2', '-g'] +>>> sorted(vars_unknown_linker['GT_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2', '-g'] +>>> sorted(vars_unknown_linker_added['GT_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2', '-g'] +>>> sorted(vars_unknown_linker_ld['GT_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2', '-g'] +>>> sorted(vars_unknown_linker_ld_added['GT_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2', '-g'] + +Test GT_LDFLAGS is unaffected by extra flags +-------------------------------------------- + +>>> sorted(vars_ldflags['GT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_ldflags_added['GT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_clanglink['GT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_clanglink_added['GT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_both['GT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_both_added['GT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_unknown_linker['GT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_unknown_linker_added['GT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_unknown_linker_ld['GT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_unknown_linker_ld_added['GT_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] + +Test TROUBLE_CXXFLAGS is unaffected by extra flags +-------------------------------------------------- + +>>> sorted(vars_ldflags['TROUBLE_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2'] +>>> sorted(vars_ldflags_added['TROUBLE_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2'] +>>> sorted(vars_clanglink['TROUBLE_CXXFLAGS']) +['-W-intel-flag1', '-W-intel-flag2'] +>>> sorted(vars_clanglink_added['TROUBLE_CXXFLAGS']) +['-W-intel-flag1', '-W-intel-flag2'] +>>> sorted(vars_both['TROUBLE_CXXFLAGS']) +['-W-clang-flag1', '-W-clang-flag2'] +>>> sorted(vars_both_added['TROUBLE_CXXFLAGS']) +['-W-clang-flag1', '-W-clang-flag2'] +>>> sorted(vars_unknown_linker['TROUBLE_CXXFLAGS']) +['-W-clang-flag1', '-W-clang-flag2'] +>>> sorted(vars_unknown_linker_added['TROUBLE_CXXFLAGS']) +['-W-clang-flag1', '-W-clang-flag2'] +>>> sorted(vars_unknown_linker_ld['TROUBLE_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2'] +>>> sorted(vars_unknown_linker_ld_added['TROUBLE_CXXFLAGS']) +['-W-gcc-flag1', '-W-gcc-flag2'] + +Test TROUBLE_LDFLAGS is unaffected by extra flags +------------------------------------------------- + +>>> sorted(vars_ldflags['TROUBLE_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_ldflags_added['TROUBLE_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_clanglink['TROUBLE_LDFLAGS']) +['-l-intel-link1', '-l-intel-link2', '-no-pie'] +>>> sorted(vars_clanglink_added['TROUBLE_LDFLAGS']) +['-l-intel-link1', '-l-intel-link2', '-no-pie'] +>>> sorted(vars_both['TROUBLE_LDFLAGS']) +['-l-clang-link1', '-l-clang-link2', '-nopie'] +>>> sorted(vars_both_added['TROUBLE_LDFLAGS']) +['-l-clang-link1', '-l-clang-link2', '-nopie'] +>>> sorted(vars_unknown_linker['TROUBLE_LDFLAGS']) +['-l-clang-link1', '-l-clang-link2', '-nopie'] +>>> sorted(vars_unknown_linker_added['TROUBLE_LDFLAGS']) +['-l-clang-link1', '-l-clang-link2', '-nopie'] +>>> sorted(vars_unknown_linker_ld['TROUBLE_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +>>> sorted(vars_unknown_linker_ld_added['TROUBLE_LDFLAGS']) +['-l-gcc-link1', '-l-gcc-link2'] +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('../..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures)