# vim: set filetype=python: import re # Testsuite configuration setup for GHC # # This file is Python source # config.compiler_always_flags = ghc_compiler_always_flags.split() # By default, the 'normal' way is enabled. In addition, certain # ways are enabled automatically if this GHC supports them. Ways that fall in # this group are 'hpc', 'optasm', 'optllvm', 'profasm', 'threaded1', 'threaded2', # 'profthreaded', 'ghci', and whichever of 'static/dyn' is not this GHC's # default mode. Other ways should be set explicitly from .T files. config.compile_ways = ['normal'] config.run_ways = ['normal'] # ways that are not enabled by default, but can always be invoked explicitly config.other_ways = ['hpc', 'prof', 'normal_h', 'prof_hc_hb','prof_hb', 'prof_hd','prof_hy','prof_hr', 'sanity', 'threaded1_ls', 'threaded2_hT', 'threaded2_sanity', 'debug_numa', 'llvm', 'debugllvm', 'profllvm', 'profoptllvm', 'profthreadedllvm', 'debug', 'ghci-ext', 'ghci-ext-prof', 'ext-interp', 'nonmoving', 'nonmoving_thr', 'nonmoving_thr_sanity', 'nonmoving_thr_ghc', 'compacting_gc', ] if ghc_with_native_codegen: config.compile_ways.append('optasm') config.run_ways.append('optasm') if config.have_interp: config.run_ways.append('ghci') # we read the 'Support SMP' setting from the ghcconfig file. This dictates # whether the target supports smp if config.ghc_with_threaded_rts: config.run_ways.append('threaded1') if target_with_smp: config.target_has_smp = True config.run_ways.append('threaded2') if config.speed == 0: config.run_ways.append('nonmoving_thr') config.run_ways.append('nonmoving_thr_sanity') if ghc_with_dynamic_rts: config.supports_dynamic_libs = True config.run_ways.append('dyn') if windows: config.supports_dynamic_hs = False # WinIO I/O manager for Windows if windows: winio_ways = ['winio', 'winio_threaded'] if config.speed == 0: config.run_ways += winio_ways else: config.other_ways += winio_ways # LLVM if not config.unregisterised and not config.arch in {"wasm32", "javascript"} and config.have_llvm: config.compile_ways.append('optllvm') config.run_ways.append('optllvm') # HPC if not config.arch == "javascript": config.compile_ways.append('hpc') config.run_ways.append('hpc') if config.arch == "wasm32": config.have_process = False config.supports_dynamic_libs = False config.way_flags = { 'normal' : [], 'normal_h' : [], 'g1' : [], 'nursery_chunks' : [], 'debug_numa' : ['-threaded', '-debug'], 'optasm' : ['-O', '-fasm'], 'llvm' : ['-fllvm'], 'optllvm' : ['-O', '-fllvm'], 'debugllvm' : ['-fllvm', '-keep-llvm-files'], 'prof' : ['-prof', '-static', '-fprof-auto', '-fasm'], 'prof_no_auto' : ['-prof', '-static', '-fasm'], 'profasm' : ['-O', '-prof', '-static', '-fprof-auto'], 'profthreaded' : ['-O', '-prof', '-static', '-fprof-auto', '-threaded'], 'ghci' : ['--interactive', '-v0', '-ignore-dot-ghci', '-fno-ghci-history', '+RTS', '-I0.1', '-RTS'] + (['-fghci-leak-check'] if not config.compiler_debugged else []), 'sanity' : ['-debug'], 'threaded1' : ['-threaded', '-debug'], 'threaded1_ls' : ['-threaded', '-debug'], 'threaded2' : ['-O', '-threaded'], 'threaded2_hT' : ['-O', '-threaded'], 'threaded2_sanity': ['-O', '-threaded', '-debug'], 'hpc' : ['-O', '-fhpc'], 'prof_hc_hb' : ['-O', '-prof', '-static', '-fprof-auto'], 'prof_hb' : ['-O', '-prof', '-static', '-fprof-auto'], 'prof_hd' : ['-O', '-prof', '-static', '-fprof-auto'], 'prof_hy' : ['-O', '-prof', '-static', '-fprof-auto'], 'prof_hr' : ['-O', '-prof', '-static', '-fprof-auto'], 'dyn' : ['-O', '-dynamic'], 'static' : ['-O', '-static'], 'debug' : ['-O', '-g', '-dannot-lint'], # llvm variants... 'profllvm' : ['-prof', '-static', '-fprof-auto', '-fllvm'], 'profoptllvm' : ['-O', '-prof', '-static', '-fprof-auto', '-fllvm'], 'profthreadedllvm' : ['-O', '-prof', '-static', '-fprof-auto', '-threaded', '-fllvm'], 'ghci-ext' : ['--interactive', '-v0', '-ignore-dot-ghci', '-fno-ghci-history', '-fexternal-interpreter', '+RTS', '-I0.1', '-RTS'], 'ghci-ext-prof' : ['--interactive', '-v0', '-ignore-dot-ghci', '-fno-ghci-history', '-fexternal-interpreter', '-prof', '+RTS', '-I0.1', '-RTS'], 'ext-interp' : ['-fexternal-interpreter'], 'nonmoving' : [], 'nonmoving_thr': ['-threaded'], 'nonmoving_thr_sanity': ['-threaded', '-debug'], 'nonmoving_thr_ghc': ['+RTS', '-xn', '-N2', '-RTS', '-threaded'], 'compacting_gc': [], 'winio': [], 'winio_threaded': ['-threaded'], } config.way_rts_flags = { 'normal' : [], 'normal_h' : ['-hT'], # works without -prof 'g1' : ['-G1'], 'nursery_chunks' : ['-n32k'], 'debug_numa' : ['-N2', '--debug-numa=2'], 'optasm' : [], 'llvm' : [], 'optllvm' : [], 'debugllvm' : [], 'prof' : ['-p'], 'prof_no_auto' : ['-p'], 'profasm' : ['-hc', '-p'], # test heap profiling too 'profthreaded' : ['-p'], 'ghci' : [], 'sanity' : ['-DS'], 'threaded1' : [], 'threaded1_ls' : ['-ls'], 'threaded2' : ['-N2', '-ls'], 'threaded2_hT' : ['-N2', '-hT'], 'threaded2_sanity' : ['-N2', '-DS'], 'hpc' : [], 'prof_hc_hb' : ['-hc', '-hbvoid'], 'prof_hb' : ['-hb'], 'prof_hd' : ['-hd'], 'prof_hy' : ['-hy'], 'prof_hr' : ['-hr'], 'dyn' : [], 'static' : [], 'debug' : [], # llvm variants... 'profllvm' : ['-p'], 'profoptllvm' : ['-hc', '-p'], 'profthreadedllvm' : ['-p'], 'ghci-ext' : [], 'ghci-ext-prof' : [], 'ext-interp' : [], 'nonmoving' : ['-xn'], 'nonmoving_thr' : ['-xn', '-N2'], 'nonmoving_thr_sanity' : ['-xn', '-N2', '-DS'], 'nonmoving_thr_ghc': ['-xn', '-N2'], 'compacting_gc': ['-c'], 'winio': ['--io-manager=native'], 'winio_threaded': ['--io-manager=native'], } # Useful classes of ways that can be used with only_ways(), omit_ways() and # expect_broken_for(). prof_ways = [x[0] for x in config.way_flags.items() if '-prof' in x[1]] debug_ways = [x[0] for x in config.way_flags.items() if '-debug' in x[1]] threaded_ways = [x[0] for x in config.way_flags.items() if '-threaded' in x[1] or 'ghci' == x[0]] # Ways which run with multiple capabilities concurrent_ways = [name for name, flags in config.way_flags.items() if '-threaded' in flags or 'ghci' == name if '-N2' in config.way_rts_flags.get(name, [])] opt_ways = [x[0] for x in config.way_flags.items() if '-O' in x[1]] llvm_ways = [x[0] for x in config.way_flags.items() if '-fllvm' in x[1]] def get_compiler_info(): # Whether GHC itself was built using the LLVM backend. We need to know this # since some tests in ext-interp fail when stage2 ghc is built using # LLVM. See #16087. # # The condition here is a bit approximate: we assume that if stage2 doesn't # have the NCG and isn't unregisterised then it must be using the LLVM # backend by default. config.ghc_built_by_llvm = not config.have_ncg and not config.unregisterised # external interpreter needs RTS linker support # If the field is not present (GHC 8.0 and earlier), assume we don't # have -fexternal-interpreter (though GHC 8.0 actually does) # so we can still run most tests. config.have_ext_interp = config.have_RTS_linker # See Note [Replacing backward slashes in config.libdir]. config.libdir = config.libdir.replace('\\', '/') def test_compile(flags): """ Check whether GHC can compile in the given way. This is used as a proxy to determine, e.g., whether profiled libraries were built, or whether the host RTS supports smp. """ import tempfile import textwrap res = False with tempfile.TemporaryDirectory() as d: src = Path(d) / 'test.hs' src.write_text(textwrap.dedent(''' module Main where main = putStrLn "Hello World!" ''')) try: p = subprocess.run( '{} -v0 {} -o test '.format(config.compiler, src) + ' '.join(flags), shell=True, cwd=d, stderr=None if config.verbose >= 3 else subprocess.DEVNULL ) except Exception as err: print("Exception thrown in testsuite/config/ghc.get_compiler_info: %s", err) else: res = p.returncode == 0 return res def compiler_supports_way(flags): return test_compile(flags) # Test the Host RTS to determine if it supports SMP. For cross compilers the # Host /= Target, so we cannot determine from the ghcconfig file if the host # itself supports smp. To support smp the host must be linked with an RTS # built with 'defined(THREADED_RTS) && !defined(NO_SMP)'. Thus we directly # query the RTS the host is linked with. config.ghc_has_smp = test_compile(["+RTS", "-N"]) config.have_vanilla = compiler_supports_way([]) config.have_dynamic = compiler_supports_way(['-dynamic']) config.have_profiling = compiler_supports_way(['-prof']) if config.have_profiling: config.compile_ways.append('profasm') config.run_ways.append('profasm') if config.have_profiling and config.ghc_with_threaded_rts: config.run_ways.append('profthreaded') ghc_env['HAVE_PROFILING'] = 'YES' # See Note [WayFlags] if config.ghc_dynamic: config.ghc_th_way_flags = "-dynamic" config.ghci_way_flags = "-dynamic" config.plugin_way_flags = "-dynamic" config.ghc_th_way = "dyn" elif config.compiler_profiled: config.ghc_th_way_flags = "-prof" config.ghci_way_flags = "-prof" config.plugin_way_flags = "-prof" config.ghc_th_way = "prof" else: config.ghc_th_way_flags = "-static" config.ghci_way_flags = "-static" config.plugin_way_flags = "-static" config.ghc_th_way = "normal" # Note [Replacing backward slashes in config.libdir] # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # We *do* need to replace backslashes in config.libdir, for the following # reason: # # * Tests use config.libdir as follows: # # extra_run_opts('"' + config.libdir + '"') # # The double quotes are there because config.libdir might contain # spaces. # # * This string is then written /as is/ to .genscript in # testlib.interpreter_run: # # script.write(':set args ' + opts.extra_run_opts + '\n') # # * But GHCi expects the arguments to ':set args' to be proper Haskell # strings (when they are quoted), with backslashes escaped. Since # config.libdir contains single backslash characters, tests such as T5313 # will fail for WAY=ghci with "Pattern match failure in do expression". # # Arguably the above code for writing `:set args` should be smarter. This # is tricky to get right though, because in GHCI `:set args foo\bar` (no # double quotes) works perfectly fine, and is interpreted as the Haskell # string "foo\\bar". Therefore, simply escaping all backward slashes in # opts.extra_run_opts before concatenating it with ':set args' is not right # either. # # Replacing backslashes to forward slashes in config.libdir works around the # problem.