diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c4b65f3c273..6da30bfba00e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,30 +1,45 @@ -name: CI +name: Nix CI -# Trigger the workflow on push or pull request, but only for the master branch on: pull_request: - types: - - opened - - synchronize + types: [opened, synchronize] push: - branches: [master] - + branches: [stable-ghc-9.14, stable-master] workflow_dispatch: jobs: cabal: - name: ${{ matrix.plat }} / ghc ${{ matrix.ghc }} - runs-on: "${{ fromJSON('{\"x86_64-linux\": \"ubuntu-24.04\", \"aarch64-linux\": \"ubuntu-24.04-arm\", \"x86_64-darwin\": \"macos-latest\", \"aarch64-darwin\": \"macos-latest\"}')[matrix.plat] }}" - strategy: fail-fast: false matrix: - plat: - - x86_64-linux - # - aarch64-linux # disabled: waiting for devx images to be fixed - # - x86_64-darwin # disabled: waiting for devx images to be fixed - - aarch64-darwin - ghc: ['98'] # bootstrapping compiler + include: + - plat: x86_64-linux + runner: ubuntu-24.04 + ghc: '98' + dynamic: 0 + - plat: x86_64-linux + runner: ubuntu-24.04 + ghc: '98' + dynamic: 1 + # - plat: aarch64-linux # disabled: waiting for devx images to be fixed + # runner: ubuntu-24.04-arm + # ghc: '98' + # dynamic: 0 + # - plat: aarch64-linux + # runner: ubuntu-24.04-arm + # ghc: '98' + # dynamic: 1 + - plat: aarch64-darwin + runner: macos-latest + ghc: '98' + dynamic: 0 + - plat: aarch64-darwin + runner: macos-latest + ghc: '98' + dynamic: 1 + + name: "${{ matrix.plat }} / ghc ${{ matrix.ghc }} / dynamic=${{ matrix.dynamic }}" + runs-on: ${{ matrix.runner }} steps: - uses: actions/checkout@v4 @@ -50,25 +65,25 @@ jobs: # shell: devx {0} # run: ./configure - - name: Build the bindist + - name: Build the bindist (dynamic=${{ matrix.dynamic }}) shell: devx {0} - run: make CABAL=$PWD/_build/stage0/bin/cabal + run: make CABAL=$PWD/_build/stage0/bin/cabal DYNAMIC=${{ matrix.dynamic }} - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: ${{ matrix.plat }}-bindist + name: ${{ matrix.plat }}-dynamic${{ matrix.dynamic }}-bindist path: _build/bindist - - name: Run the testsuite + - name: Run the testsuite (dynamic=${{ matrix.dynamic }}) shell: devx {0} - run: make test CABAL=$PWD/_build/stage0/bin/cabal + run: make test CABAL=$PWD/_build/stage0/bin/cabal DYNAMIC=${{ matrix.dynamic }} - name: Upload test results uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} # upload test results even if the testsuite failed to pass with: - name: ${{ matrix.plat }}-testsuite-results + name: ${{ matrix.plat }}-dynamic${{ matrix.dynamic }}-testsuite-results path: | _build/test-perf.csv _build/test-summary.txt diff --git a/.gitignore b/.gitignore index f6d6b0bc9006..3393551070cf 100644 --- a/.gitignore +++ b/.gitignore @@ -259,3 +259,4 @@ ghc.nix/ # clangd .clangd dist-newstyle/ +cabal.project.stage2.settings diff --git a/Makefile b/Makefile index 20837cbea965..4fa39da95af8 100644 --- a/Makefile +++ b/Makefile @@ -879,6 +879,16 @@ _build/bindist: stage2 driver/ghc-usage.txt driver/ghci-usage.txt $@/bin/ghc-pkg recache # Copy headers @$(call copy_all_stage2_h,$@/bin/ghc-pkg) + # Add basename symlinks for nested shared libs (.dylib, .so) in lib/$(HOST_PLATFORM) + @if [ -d "$@/lib/$(HOST_PLATFORM)" ]; then \ + cd "$@/lib/$(HOST_PLATFORM)" ; \ + for lib in $$(find . -mindepth 2 \( -name "*.dylib" -o -name "*.so" \) -type f) ; do \ + ln -sf "$$lib" "$$(basename "$$lib")" ; \ + done ; \ + fi + # Create -dyn iserv executable. #FIXME: THIS IS IDIOTIC! + @cd "$@/bin" + @ln -sf ghc-iserv ghc-iserv-dyn @echo "::endgroup::" _build/bindist/ghc.tar.gz: _build/bindist @@ -903,6 +913,13 @@ _build/bindist/lib/targets/%: _build/bindist driver/ghc-usage.txt driver/ghci-us # Copy libraries and settings @if [ -e $(CURDIR)/_build/bindist/lib/targets/$(@F)/lib/$(@F) ] ; then find $(CURDIR)/_build/bindist/lib/targets/$(@F)/lib/$(@F)/ -mindepth 1 -type f -name "*.so" -execdir mv '{}' $(CURDIR)/_build/bindist/lib/targets/$(@F)/lib/$(@F)/'{}' \; ; fi $(call copycrosslib,$(@F)) + # Add basename symlinks for nested shared libs (.dylib, .so) in lib/$(@F) + @if [ -d $(CURDIR)/_build/bindist/lib/targets/$(@F)/lib/$(@F) ] ; then \ + cd $(CURDIR)/_build/bindist/lib/targets/$(@F)/lib/$(@F) ; \ + for lib in $$(find . -mindepth 2 \( -name "*.dylib" -o -name "*.so" \) -type f) ; do \ + ln -sf "$$lib" "$$(basename "$$lib")" ; \ + done ; \ + fi # --help @cp -rfp driver/ghc-usage.txt _build/bindist/lib/targets/$(@F)/lib/ @cp -rfp driver/ghci-usage.txt _build/bindist/lib/targets/$(@F)/lib/ @@ -1033,13 +1050,11 @@ CANONICAL_TEST_HC_OPTS = \ -Werror=compat -dno-debug-output # Build timeout utility (needed for some tests) if not already built. -.PHONY: testsuite-timeout -testsuite-timeout: +testsuite/timeout/install-inplace/bin/timeout: $(MAKE) -C testsuite/timeout - # --- Test Target --- -test: _build/bindist testsuite-timeout +test: $(TEST_GHC) $(TEST_GHC_PKG) $(TEST_HP2PS) $(TEST_HPC) $(TEST_RUN_GHC) testsuite/timeout/install-inplace/bin/timeout @echo "::group::Running tests with THREADS=$(THREADS)" >&2 # If any required tool is missing, testsuite logic will skip related tests. TEST_HC='$(TEST_GHC)' \ diff --git a/compiler/GHC/Driver/DynFlags.hs b/compiler/GHC/Driver/DynFlags.hs index 4377094a98cc..9a3fa58603c2 100644 --- a/compiler/GHC/Driver/DynFlags.hs +++ b/compiler/GHC/Driver/DynFlags.hs @@ -878,7 +878,8 @@ packageFlagsChanged idflags1 idflags0 = [ Opt_HideAllPackages , Opt_HideAllPluginPackages , Opt_AutoLinkPackages - , Opt_NoRts ] + , Opt_NoRts + , Opt_NoGhcInternal ] instance Outputable PackageFlag where ppr (ExposePackage n arg rn) = text n <> braces (ppr arg <+> ppr rn) diff --git a/compiler/GHC/Driver/Flags.hs b/compiler/GHC/Driver/Flags.hs index 58e80e41b400..a10670b9eff1 100644 --- a/compiler/GHC/Driver/Flags.hs +++ b/compiler/GHC/Driver/Flags.hs @@ -863,6 +863,7 @@ data GeneralFlag -- temporary flags | Opt_AutoLinkPackages | Opt_NoRts + | Opt_NoGhcInternal | Opt_ImplicitImportQualified -- keeping stuff diff --git a/compiler/GHC/Driver/Session.hs b/compiler/GHC/Driver/Session.hs index 0ca58c338663..5f791ecc219d 100644 --- a/compiler/GHC/Driver/Session.hs +++ b/compiler/GHC/Driver/Session.hs @@ -1314,6 +1314,8 @@ dynamic_flags_deps = [ (NoArg (setGeneralFlag Opt_NoHsMain)) , make_ord_flag defGhcFlag "no-rts" (NoArg (setGeneralFlag Opt_NoRts)) + , make_ord_flag defGhcFlag "no-ghc-internal" + (NoArg (setGeneralFlag Opt_NoGhcInternal)) , make_ord_flag defGhcFlag "fno-state-hack" (NoArg (setGeneralFlag Opt_G_NoStateHack)) , make_ord_flag defGhcFlag "fno-opt-coercion" diff --git a/compiler/GHC/Linker/Static.hs b/compiler/GHC/Linker/Static.hs index 8a634258e7fb..c60e4cc594ca 100644 --- a/compiler/GHC/Linker/Static.hs +++ b/compiler/GHC/Linker/Static.hs @@ -100,11 +100,22 @@ linkBinary' staticLink logger tmpfs dflags unit_env o_files dep_units = do -- explicit packages with the auto packages and all of their -- dependencies, and eliminating duplicates. pkgs <- mayThrowUnitErr (preloadUnitsInfo' unit_env dep_units) + + -- Collect per-package library dirs (deduplicated, non-empty) let pkg_lib_paths = collectLibraryDirs ways_ pkgs - let pkg_lib_path_opts = concatMap get_pkg_lib_path_opts pkg_lib_paths - get_pkg_lib_path_opts l + -- Until: https://github.com/haskell/cabal/issues/11221 is in cabal, + -- we have to deal with cabal passing -dyload deploy, and manually + -- inject rpaths for the rts. + -- Build linker options per (pkg, libdir) + let pkg_lib_path_opts = + concat + [ get_pkg_lib_path_opts pkg l + | pkg <- pkgs + , l <- collectLibraryDirs ways_ [pkg] + ] + get_pkg_lib_path_opts pkg l | osElfTarget (platformOS platform) && - dynLibLoader dflags == SystemDependent && + (dynLibLoader dflags == SystemDependent || unitPackageNameString pkg == "rts") && ways_ `hasWay` WayDyn = let libpath = if gopt Opt_RelativeDynlibPaths dflags then "$ORIGIN" @@ -125,7 +136,7 @@ linkBinary' staticLink logger tmpfs dflags unit_env o_files dep_units = do else ["-Xlinker", "-rpath-link", "-Xlinker", l] in ["-L" ++ l] ++ rpathlink ++ rpath | osMachOTarget (platformOS platform) && - dynLibLoader dflags == SystemDependent && + (dynLibLoader dflags == SystemDependent || unitPackageNameString pkg == "rts") && ways_ `hasWay` WayDyn && useXLinkerRPath dflags (platformOS platform) = let libpath = if gopt Opt_RelativeDynlibPaths dflags diff --git a/compiler/GHC/Unit/State.hs b/compiler/GHC/Unit/State.hs index ed8ea36db6d4..431075870736 100644 --- a/compiler/GHC/Unit/State.hs +++ b/compiler/GHC/Unit/State.hs @@ -1636,7 +1636,11 @@ mkUnitState logger dflags cfg = do -- it modifies the unit ids of wired in packages, but when we process -- package arguments we need to key against the old versions. -- - (pkgs2, wired_map) <- findWiredInUnits logger (rtsWayUnitId dflags:wiredInUnitIds) prec_map pkgs1 vis_map2 + let wired_ids_all = rtsWayUnitId dflags : wiredInUnitIds + wired_ids + | gopt Opt_NoGhcInternal dflags = filter (/= ghcInternalUnitId) wired_ids_all + | otherwise = wired_ids_all + (pkgs2, wired_map) <- findWiredInUnits logger wired_ids prec_map pkgs1 vis_map2 -- -- Sanity check. If the rtsWayUnitId is not in the database, then we have a @@ -1648,6 +1652,7 @@ mkUnitState logger dflags cfg = do , nest 2 $ vcat [ text "pkgs1_count =" <+> ppr (length pkgs1) , text "Opt_NoRts =" <+> ppr (gopt Opt_NoRts dflags) + , text "Opt_NoGhcInternal =" <+> ppr (gopt Opt_NoGhcInternal dflags) , text "ghcLink =" <+> text (show (ghcLink dflags)) , text "platform =" <+> text (show (targetPlatform dflags)) , text "rtsWayUnitId=" <+> ppr (rtsWayUnitId dflags) @@ -1664,7 +1669,9 @@ mkUnitState logger dflags cfg = do <> text " Please check your installation." <> text " If this target doesn't need the RTS (e.g. building a shared library), you can add -no-rts to the relevant package's ghc-options in cabal.project to bypass this check." - let pkgs3 = if gopt Opt_NoRts dflags && not (anyUniqMap (== ghcInternalUnitId) wired_map) + let pkgs3 = if gopt Opt_NoGhcInternal dflags + then pkgs2 + else if gopt Opt_NoRts dflags && not (anyUniqMap (== ghcInternalUnitId) wired_map) then pkgs2 else -- At this point we should have `ghcInternalUnitId`, and the `rtsWiredUnitId dflags`. diff --git a/rts/AutoApply.cmm b/rts/AutoApply.cmm new file mode 100644 index 000000000000..22ed09ee02cd --- /dev/null +++ b/rts/AutoApply.cmm @@ -0,0 +1 @@ +#include diff --git a/rts/AutoApply_V16.cmm b/rts/AutoApply_V16.cmm new file mode 100644 index 000000000000..5cc5142317b6 --- /dev/null +++ b/rts/AutoApply_V16.cmm @@ -0,0 +1 @@ +#include diff --git a/rts/AutoApply_V32.cmm b/rts/AutoApply_V32.cmm new file mode 100644 index 000000000000..9a4427459b5b --- /dev/null +++ b/rts/AutoApply_V32.cmm @@ -0,0 +1 @@ +#include diff --git a/rts/AutoApply_V64.cmm b/rts/AutoApply_V64.cmm new file mode 100644 index 000000000000..343853d6e16a --- /dev/null +++ b/rts/AutoApply_V64.cmm @@ -0,0 +1 @@ +#include diff --git a/rts/configure.ac b/rts/configure.ac index ae110d76dce7..7ee47bd4941b 100644 --- a/rts/configure.ac +++ b/rts/configure.ac @@ -583,36 +583,36 @@ else AC_MSG_ERROR([Failed to run $DERIVE_CONSTANTS --gen-header ...]) fi -AC_MSG_CHECKING([for AutoApply.cmm]) -if $GENAPPLY include/DerivedConstants.h > AutoApply.cmm; then +AC_MSG_CHECKING([for include/rts/AutoApply.cmm.h]) +if mkdir -p include/rts && $GENAPPLY include/DerivedConstants.h > include/rts/AutoApply.cmm.h; then AC_MSG_RESULT([created]) else AC_MSG_RESULT([failed to create]) - AC_MSG_ERROR([Failed to run $GENAPPLY include/DerivedConstants.h > AutoApply.cmm]) + AC_MSG_ERROR([Failed to run $GENAPPLY include/DerivedConstants.h > include/rts/AutoApply.cmm.h]) fi -AC_MSG_CHECKING([for AutoApply_V16.cmm]) -if $GENAPPLY include/DerivedConstants.h -V16 > AutoApply_V16.cmm; then +AC_MSG_CHECKING([for include/rts/AutoApply_V16.cmm.h]) +if mkdir -p include/rts && $GENAPPLY include/DerivedConstants.h -V16 > include/rts/AutoApply_V16.cmm.h; then AC_MSG_RESULT([created]) else AC_MSG_RESULT([failed to create]) - AC_MSG_ERROR([Failed to run $GENAPPLY include/DerivedConstants.h -V16 > AutoApply_V16.cmm]) + AC_MSG_ERROR([Failed to run $GENAPPLY include/DerivedConstants.h -V16 > include/rts/AutoApply_V16.cmm.h]) fi -AC_MSG_CHECKING([for AutoApply_V32.cmm]) -if $GENAPPLY include/DerivedConstants.h -V32 > AutoApply_V32.cmm; then +AC_MSG_CHECKING([for include/rts/AutoApply_V32.cmm.h]) +if mkdir -p include/rts && $GENAPPLY include/DerivedConstants.h -V32 > include/rts/AutoApply_V32.cmm.h; then AC_MSG_RESULT([created]) else AC_MSG_RESULT([failed to create]) - AC_MSG_ERROR([Failed to run $GENAPPLY include/DerivedConstants.h -V32 > AutoApply_V32.cmm]) + AC_MSG_ERROR([Failed to run $GENAPPLY include/DerivedConstants.h -V32 > include/rts/AutoApply_V32.cmm.h]) fi -AC_MSG_CHECKING([for AutoApply_V64.cmm]) -if $GENAPPLY include/DerivedConstants.h -V64 > AutoApply_V64.cmm; then +AC_MSG_CHECKING([for include/rts/AutoApply_V64.cmm.h]) +if mkdir -p include/rts && $GENAPPLY include/DerivedConstants.h -V64 > include/rts/AutoApply_V64.cmm.h; then AC_MSG_RESULT([created]) else AC_MSG_RESULT([failed to create]) - AC_MSG_ERROR([Failed to run $GENAPPLY include/DerivedConstants.h -V64 > AutoApply_V64.cmm]) + AC_MSG_ERROR([Failed to run $GENAPPLY include/DerivedConstants.h -V64 > include/rts/AutoApply_V64.cmm.h]) fi AC_MSG_CHECKING([for include/rts/EventLogConstants.h]) diff --git a/rts/rts.cabal b/rts/rts.cabal index ad0674d5f10a..bb58a1614e5c 100644 --- a/rts/rts.cabal +++ b/rts/rts.cabal @@ -331,6 +331,37 @@ common rts-base-config rts-fs, rts +common rts-cmm-sources-base + if !arch(javascript) + -- FIXME: by virtue of being part of the rts main library, these do not get + -- the flags (debug, threaded, ...) as the sub libraries. Thus we are + -- likely missing -DDEBUG, -DTHREADED_RTS, etc. + -- One solution to this would be to turn all of these into `.h` files, and + -- then have the `AutoApply.cmm` in `rts-c-sources-base` include them. This + -- would mean they are included in the sublibraries which will in turn apply + -- the sublibrary specific (c)flags. + cmm-sources: + AutoApply.cmm + AutoApply_V16.cmm + + if arch(x86_64) + cmm-sources: + Jumps_V32.cmm (-mavx2) + Jumps_V64.cmm (-mavx512f) + AutoApply_V32.cmm (-mavx2) + AutoApply_V64.cmm (-mavx512f) + else + cmm-sources: + Jumps_V32.cmm + Jumps_V64.cmm + AutoApply_V32.cmm + AutoApply_V64.cmm + + -- this is required so we don't have ghc inject ghc-internal (which depends on the rts) + -- during the build phase of this library. + ghc-options: -no-ghc-internal + + common rts-c-sources-base if !arch(javascript) cmm-sources: @@ -584,37 +615,66 @@ common rts-link-options ld-options: -read_only_relocs warning common rts-global-build-flags - ghc-options: -DCOMPILING_RTS + ghc-options: -DCOMPILING_RTS -optc-DCOMPILING_RTS cpp-options: -DCOMPILING_RTS + cmm-options: -DCOMPILING_RTS + cc-options: -DCOMPILING_RTS if !flag(smp) - ghc-options: -DNOSMP + ghc-options: -DNOSMP -optc-DNOSMP cpp-options: -DNOSMP + cmm-options: -DNOSMP + cc-options: -DNOSMP if flag(dynamic) - ghc-options: -DDYNAMIC + ghc-options: -DDYNAMIC -optc-DDYNAMIC cpp-options: -DDYNAMIC + cmm-options: -DDYNAMIC + cc-options: -DDYNAMIC if flag(thread-sanitizer) cc-options: -fsanitize=thread ld-options: -fsanitize=thread common rts-debug-flags - ghc-options: -optc-DDEBUG + ghc-options: -DDEBUG -optc-DDEBUG cpp-options: -DDEBUG -fno-omit-frame-pointer -g3 -O0 + cmm-options: -DDEBUG + cc-options: -DDEBUG -fno-omit-frame-pointer -g3 -O0 common rts-threaded-flags - ghc-options: -DTHREADED_RTS + ghc-options: -DTHREADED_RTS -optc-DTHREADED_RTS cpp-options: -DTHREADED_RTS + cmm-options: -DTHREADED_RTS + cc-options: -DTHREADED_RTS -- the _main_ library needs to deal with all the _configure_ time stuff. library ghc-options: -this-unit-id rts -ghcversion-file=include/ghcversion.h -optc-DFS_NAMESPACE=rts cmm-options: -this-unit-id rts + -- [The AutoApply story] + -- + -- We use GenApply to generate the AutoApply[_V{16,32,64}].cmm files. + -- However cabal will run the ./configure script only for the main library. + -- To work around this shortcoming, we'll generate .cmm.h files (same + -- content as .cmm), and create AutoApply*.cmm files that just + -- + -- #include + -- + -- This way each sublib has it's own properly parameterized .cmm file, while + -- we only generate them once and stick them into the rts library. + -- + -- This is a hack, and it would be great if sublibs had access to their + -- parent libraries auto-gen folders, however as sublibs are supposed to be + -- separate components, this is a non-trivial (impossible?) task to resolve. autogen-includes: ghcautoconf.h ghcplatform.h DerivedConstants.h rts/EventLogConstants.h rts/EventTypes.h + AutoApply.cmm.h + AutoApply_V16.cmm.h + AutoApply_V32.cmm.h + AutoApply_V64.cmm.h install-includes: ghcautoconf.h @@ -622,6 +682,10 @@ library DerivedConstants.h rts/EventLogConstants.h rts/EventTypes.h + AutoApply.cmm.h + AutoApply_V16.cmm.h + AutoApply_V32.cmm.h + AutoApply_V64.cmm.h install-includes: -- Common headers for non-JS builds @@ -694,33 +758,6 @@ library rts-headers, rts-fs - if !arch(javascript) - -- FIXME: by virtue of being part of the rts main library, these do not get - -- the flags (debug, threaded, ...) as the sub libraries. Thus we are - -- likely missing -DDEBUG, -DTHREADED_RTS, etc. - -- One solution to this would be to turn all of these into `.h` files, and - -- then have the `AutoApply.cmm` in `rts-c-sources-base` include them. This - -- would mean they are included in the sublibraries which will in turn apply - -- the sublibrary specific (c)flags. - autogen-cmm-sources: - AutoApply.cmm - AutoApply_V16.cmm - - if arch(x86_64) - cmm-sources: - Jumps_V32.cmm (-mavx2) - Jumps_V64.cmm (-mavx512f) - autogen-cmm-sources: - AutoApply_V32.cmm (-mavx2) - AutoApply_V64.cmm (-mavx512f) - else - cmm-sources: - Jumps_V32.cmm - Jumps_V64.cmm - autogen-cmm-sources: - AutoApply_V32.cmm - AutoApply_V64.cmm - common ghcjs import: rts-base-config @@ -767,29 +804,27 @@ library nonthreaded-nodebug if arch(javascript) import: ghcjs else - import: rts-base-config, rts-c-sources-base, rts-link-options, rts-global-build-flags + import: rts-base-config, rts-cmm-sources-base, rts-c-sources-base, rts-link-options, rts-global-build-flags visibility: public - ghc-options: -optc-DRtsWay="v" - library threaded-nodebug - import: rts-base-config, rts-c-sources-base, rts-link-options, rts-global-build-flags, rts-threaded-flags + import: rts-base-config, rts-cmm-sources-base, rts-c-sources-base, rts-link-options, rts-global-build-flags, rts-threaded-flags visibility: public build-depends: rts if arch(javascript) buildable: False library nonthreaded-debug - import: rts-base-config, rts-c-sources-base, rts-link-options, rts-global-build-flags, rts-debug-flags + import: rts-base-config, rts-cmm-sources-base, rts-c-sources-base, rts-link-options, rts-global-build-flags, rts-debug-flags visibility: public build-depends: rts if arch(javascript) buildable: False library threaded-debug - import: rts-base-config, rts-c-sources-base, rts-link-options, rts-global-build-flags, rts-threaded-flags, rts-debug-flags + import: rts-base-config, rts-cmm-sources-base, rts-c-sources-base, rts-link-options, rts-global-build-flags, rts-threaded-flags, rts-debug-flags visibility: public build-depends: rts if arch(javascript) diff --git a/testsuite/.gitignore b/testsuite/.gitignore index 2c699cf04625..65095f055660 100644 --- a/testsuite/.gitignore +++ b/testsuite/.gitignore @@ -60,6 +60,10 @@ tmp.d *.so *bindisttest_install___dir_bin_ghc.mk *bindisttest_install___dir_bin_ghc.exe.mk +mk/*_ghcconfig*_bin_ghc*.mk +mk/*_ghcconfig*_bin_ghc*.exe.mk +mk/*_ghcconfig*_test___spaces_ghc*.mk +mk/*_ghcconfig*_test___spaces_ghc*.exe.mk mk/ghcconfig*_bin_ghc*.mk mk/ghcconfig*_bin_ghc*.exe.mk mk/ghcconfig*_test___spaces_ghc*.mk diff --git a/testsuite/driver/testlib.py b/testsuite/driver/testlib.py index 609561ceac62..3356d4d2f85e 100644 --- a/testsuite/driver/testlib.py +++ b/testsuite/driver/testlib.py @@ -661,7 +661,19 @@ def collect_size ( deviation, path ): return collect_size_func(deviation, lambda: path) def collect_size_func ( deviation, path_func ): - return collect_generic_stat ( 'size', deviation, lambda way: os.path.getsize(in_testdir(path_func())) ) + # Wrap path resolution to avoid passing None/invalid paths to Path APIs. + def current(_way): + p = path_func() + if p is None: + raise StatsException("No path returned for size collection") + # If p looks absolute, use it directly; else resolve relative to testdir + pth = Path(p) + if not pth.is_absolute(): + pth = in_testdir(p) + if not pth.exists(): + raise StatsException(f"Path not found for size collection: {pth}") + return os.path.getsize(pth) + return collect_generic_stat ( 'size', deviation, current ) def get_dir_size(path): total = 0 @@ -674,7 +686,7 @@ def get_dir_size(path): total += get_dir_size(entry.path) return total except FileNotFoundError: - print("Exception: Could not find: " + path) + raise StatsException(f"Directory not found for size collection: {path}") def collect_size_dir ( deviation, path ): return collect_size_dir_func ( deviation, lambda: path ) @@ -706,7 +718,12 @@ def collect_size_ghc_pkg (deviation, library): # same for collect_size and find_so def collect_object_size (deviation, library, use_non_inplace=False): if use_non_inplace: - return collect_size_func(deviation, lambda: find_non_inplace_so(library)) + try: + return collect_size_func(deviation, lambda: find_non_inplace_so(library)) + except Exception as _: + # should we fail to find inplace, let's try to find non-inplace. + # FIXME: remove the whole inplace nonsense outright. + return collect_size_func(deviation, lambda: find_so(library)) else: return collect_size_func(deviation, lambda: find_so(library)) @@ -723,21 +740,20 @@ def path_from_ghcPkg (library, field): try: result = subprocess.run(ghcPkgCmd, capture_output=True, shell=True) - # check_returncode throws an exception if the return code is not 0. result.check_returncode() - - # if we get here then the call worked and we have the path we split by - # whitespace and then return the path which becomes the second element - # in the array - return re.split(r'\s+', result.stdout.decode("utf-8"))[1] + out = result.stdout.decode("utf-8").strip() + # Expected format: ": " possibly spanning lines; grab text after first colon. + m = re.split(r"^\s*[^:]+:\s*", out, maxsplit=1, flags=re.MULTILINE) + if len(m) == 2: + val = m[1].strip().splitlines()[0].strip() + if val: + return val + raise StatsException(f"ghc-pkg returned no {field} for {library}. Output: {out}") + except subprocess.CalledProcessError as e: + raise StatsException(f"ghc-pkg failed for {library} {field}: {e}") except Exception as e: - message = f""" - Attempt to find {field} of {library} using ghc-pkg failed. - ghc-pkg path: {config.ghc_pkg} - error" {e} - """ - print(message) + raise StatsException(f"Error parsing ghc-pkg output for {library} {field}: {e}") def _find_so(lib, directory, in_place): @@ -772,8 +788,9 @@ def _find_so(lib, directory, in_place): to_match = r'libHS{}-\d+(\.\d+)+-ghc\S+\.' + suffix matches = [] - # wrap this in some exception handling, hadrian test will error out because - # these files don't exist yet, so we pass when this occurs + # Robust error handling: raise a stats exception for missing directory or no match + if directory is None: + raise StatsException(f"No directory provided to find shared object for {lib}") try: for f in os.listdir(directory): if f.endswith(suffix): @@ -781,12 +798,22 @@ def _find_so(lib, directory, in_place): match = re.match(pattern, f) if match: matches.append(match.group()) + if not matches: + raise StatsException(f"Could not find shared object file for {lib} in {directory}") return os.path.join(directory, matches[0]) - except: - failBecause('Could not find shared object file: ' + lib) + except FileNotFoundError: + raise StatsException(f"Directory not found while searching shared object for {lib}: {directory}") + except Exception as e: + raise StatsException(f"Error while searching shared object for {lib} in {directory}: {e}") def find_so(lib): - return _find_so(lib,path_from_ghcPkg(lib, "dynamic-library-dirs"),True) + try: + return _find_so(lib,path_from_ghcPkg(lib, "dynamic-library-dirs"),True) + except Exception as _: + # if we fail to find the inplace so, fallback to trying to find the + # non-inplace so indead; + # FIXME: This whole inplace logic needs to be ripped out! + return _find_so(lib,path_from_ghcPkg(lib, "dynamic-library-dirs"),False) def find_non_inplace_so(lib): return _find_so(lib,path_from_ghcPkg(lib, "dynamic-library-dirs"),False) diff --git a/testsuite/mk/boilerplate.mk b/testsuite/mk/boilerplate.mk index 9ad8b3308e31..333285d2bc3b 100644 --- a/testsuite/mk/boilerplate.mk +++ b/testsuite/mk/boilerplate.mk @@ -260,7 +260,18 @@ $(TOP)/ghc-config/ghc-config : $(TOP)/ghc-config/ghc-config.hs empty= space=$(empty) $(empty) ifeq "$(ghc_config_mk)" "" -ghc_config_mk = $(TOP)/mk/ghcconfig$(subst $(space),_,$(subst :,_,$(subst /,_,$(subst \,_,$(TEST_HC))))).mk +sanitized_hc := $(subst $(space),_,$(subst :,_,$(subst /,_,$(subst \,_,$(TEST_HC))))) +test_hc_hash := $(shell \ + if command -v openssl >/dev/null 2>&1; then \ + openssl dgst -sha256 $(TEST_HC) | awk '{print substr($$2, 1, 8)}'; \ + elif command -v sha256sum >/dev/null 2>&1; then \ + sha256sum $(TEST_HC) | awk '{print substr($$1, 1, 8)}'; \ + elif command -v shasum >/dev/null 2>&1; then \ + shasum -a 256 $(TEST_HC) | awk '{print substr($$1, 1, 8)}'; \ + else \ + echo "no_hash"; \ + fi) +ghc_config_mk = $(TOP)/mk/$(test_hc_hash)_ghcconfig$(sanitized_hc).mk $(ghc_config_mk) : $(TOP)/ghc-config/ghc-config $(TOP)/ghc-config/ghc-config "$(TEST_HC)" >"$@"; if [ "$$?" != "0" ]; then $(RM) "$@"; exit 1; fi diff --git a/testsuite/tests/annotations/should_compile/th/annth.hs b/testsuite/tests/annotations/should_compile/th/annth.hs index 8cc3a242ff92..87768e1a4bac 100644 --- a/testsuite/tests/annotations/should_compile/th/annth.hs +++ b/testsuite/tests/annotations/should_compile/th/annth.hs @@ -24,5 +24,6 @@ main = do runIO $ print (anns :: [String]) anns <- reifyAnnotations (AnnLookupName 'TestTypeTH) runIO $ print (anns :: [String]) + runIO $ hFlush stdout [| return () |] ) hFlush stdout diff --git a/testsuite/tests/ghc-e/should_run/all.T b/testsuite/tests/ghc-e/should_run/all.T index 03ee37cb9ff2..7362b1907419 100644 --- a/testsuite/tests/ghc-e/should_run/all.T +++ b/testsuite/tests/ghc-e/should_run/all.T @@ -6,9 +6,7 @@ test('ghc-e004', req_interp, makefile_test, ['ghc-e004']) test('ghc-e005', req_interp, makefile_test, ['ghc-e005']) test('ghc-e006', req_interp, makefile_test, ['ghc-e006']) -test('T2228', - [req_interp, when(ghc_dynamic(), expect_broken(7298))], - makefile_test, ['T2228']) +test('T2228', req_interp, makefile_test, ['T2228']) test('T2636', req_interp, makefile_test, ['T2636']) test('T3890', req_interp, makefile_test, ['T3890']) test('T7299', req_interp, makefile_test, ['T7299']) diff --git a/testsuite/tests/perf/size/all.T b/testsuite/tests/perf/size/all.T index 4c45cb4d11ff..e5fd683fce7b 100644 --- a/testsuite/tests/perf/size/all.T +++ b/testsuite/tests/perf/size/all.T @@ -84,7 +84,9 @@ test('mtl_so' ,[req_dynamic_ghc, js_skip, windows_skip, collect_obje test('os_string_so' ,[req_dynamic_ghc, js_skip, windows_skip, collect_object_size(size_acceptance_threshold, "os-string")] , static_stats, [] ) test('parsec_so' ,[req_dynamic_ghc, js_skip, windows_skip, collect_object_size(size_acceptance_threshold, "parsec")] , static_stats, [] ) test('process_so' ,[req_dynamic_ghc, js_skip, windows_skip, collect_object_size(size_acceptance_threshold, "process")] , static_stats, [] ) -test('rts_so' ,[req_dynamic_ghc, js_skip, windows_skip, collect_object_size(size_acceptance_threshold, "rts", True)] , static_stats, [] ) +# after the rts-split, there is not signle rts anymore. The single rts package is just headers, and thus empty. We now have one rts per threaded/debug combination. +# they are also sublibs, which means the regex in the test-driver doesn't work for this. Thus for now we disable this test. +# test('rts_so' ,[req_dynamic_ghc, js_skip, windows_skip, collect_object_size(size_acceptance_threshold, "rts", True)] , static_stats, [] ) test('template_haskell_so',[req_dynamic_ghc, js_skip, windows_skip, collect_object_size(size_acceptance_threshold, "template-haskell")] , static_stats, [] ) # terminfo is not built in cross ghc so skip it test('terminfo_so' ,[req_dynamic_ghc, when(config.cross, skip), windows_skip, collect_object_size(size_acceptance_threshold, "terminfo")], static_stats, [] ) diff --git a/testsuite/tests/simplStg/should_compile/T22840.hs b/testsuite/tests/simplStg/should_compile/T22840.hs index f7e4e59bc07f..86ffbf9c3104 100644 --- a/testsuite/tests/simplStg/should_compile/T22840.hs +++ b/testsuite/tests/simplStg/should_compile/T22840.hs @@ -6,9 +6,11 @@ module C where import T22840A import T22840B import Control.Monad.IO.Class +import System.IO (hFlush, stdout) $(liftIO $ do putStrLn "start" putStrLn (disp theT) putStrLn "end" + hFlush stdout return []) diff --git a/utils/hp2ps/hp2ps.cabal b/utils/hp2ps/hp2ps.cabal index 482ea772b934..ea071266a64a 100644 --- a/utils/hp2ps/hp2ps.cabal +++ b/utils/hp2ps/hp2ps.cabal @@ -23,3 +23,10 @@ Executable hp2ps HpFile.c Marks.c Scale.c TraceElement.c Axes.c Dimensions.c Key.c PsFile.c Shade.c Utilities.c + ghc-options: + -- We do _not_ want to auto-link this against rts, base, ... + -- otherwise we end up with broken dependencies. E.g. unlit + -- depending on libHSrts, which then depends on the libHSrts + -- implementation sublib, due to the -u,... flags from the + -- rts. + -no-auto-link-packages \ No newline at end of file diff --git a/utils/unlit/unlit.cabal b/utils/unlit/unlit.cabal index 770567be3a8f..696516dd8f5f 100644 --- a/utils/unlit/unlit.cabal +++ b/utils/unlit/unlit.cabal @@ -10,5 +10,12 @@ Executable unlit cc-options: -DFS_NAMESPACE=rts Default-Language: Haskell2010 Main-Is: unlit.c + ghc-options: + -- We do _not_ want to auto-link this against rts, base, ... + -- otherwise we end up with broken dependencies. E.g. unlit + -- depending on libHSrts, which then depends on the libHSrts + -- implementation sublib, due to the -u,... flags from the + -- rts. + -no-auto-link-packages build-depends: rts-fs