Commit 5f6a8204 authored by Tamar Christina's avatar Tamar Christina

Add gen-dll as replacement for dll-split

Summary:
This tool can be used to generate dll's for any list of object files
given to it. It will then repartition them automatically to fit within
a dll and generates as many dll's as needed to do this. Cyclic dependencies
between these generated dlls are handle automatically so there is no need
to tell it how to partition.

It is also a lot more general than `dll-split` as it is able to split any
package not just `libGHC`. It also uses a trick using GNU style import libraries
to hide the splitting from the rest of the pipeline. Which means come linking time
you don't need to know which dll contains what symbol or how many split dlls were
created.

The import libraries are by default created with libtool. However since libtool is BFD
based it is very slow. So if present and detected by configure the `genlib` tool
from the msys2 project is used. This makes a difference of about ~45 minutes when compiling.

To install `genlib` run `pacman -Sy mingw-w64-$(uname -m)-tools-git`.

More detailed explaination of the process can be found here
https://ghc.haskell.org/trac/ghc/wiki/WindowsDynamicLinking

Test Plan: ./validate

Reviewers: austin, hvr, bgamari, erikd, simonmar

Reviewed By: bgamari

Subscribers: snowleopard, rwbarton, thomie, erikd, #ghc_windows_task_force

GHC Trac Issues: #5987

Differential Revision: https://phabricator.haskell.org/D3883
parent 3c6b2fc3
......@@ -176,6 +176,7 @@ _darcs/
/testlog*
/utils/mkUserGuidePart/mkUserGuidePart.cabal
/utils/runghc/runghc.cabal
/utils/gen-dll/gen-dll.cabal
/extra-gcc-opts
/sdistprep
......
......@@ -1145,6 +1145,9 @@ else
fi
fi])
fp_prog_ar_args=$fp_cv_prog_ar_args
if test "$HostOS" != "mingw32"; then
ArCmd = "$(cygpath -m $ArCmd)"
fi
AC_SUBST([ArCmd], ["$fp_prog_ar"])
AC_SUBST([ArArgs], ["$fp_prog_ar_args"])
......
......@@ -391,6 +391,8 @@ then
OBJDUMP="${mingwbin}objdump.exe"
fp_prog_ar="${mingwbin}ar.exe"
AC_PATH_PROG([Genlib],[genlib])
# NB. Download the perl binaries if required
if ! test -d inplace/perl ||
test inplace/perl -ot ghc-tarballs/perl/ghc-perl*.tar.gz
......@@ -420,13 +422,25 @@ then
AC_PATH_PROG([OBJDUMP],[objdump])
AC_PATH_PROG([DllWrap],[dllwrap])
AC_PATH_PROG([Windres],[windres])
AC_PATH_PROG([Genlib],[genlib])
fi
DllWrapCmd="$DllWrap"
WindresCmd="$Windres"
HAVE_GENLIB=False
if test "$HostOS" = "mingw32"
then
if test "$Genlib" != ""; then
GenlibCmd="$(cygpath -m $Genlib)"
HAVE_GENLIB=True
fi
fi
AC_SUBST([DllWrapCmd])
AC_SUBST([WindresCmd])
AC_SUBST([GenlibCmd])
AC_SUBST([HAVE_GENLIB])
FP_ICONV
FP_GMP
......@@ -587,18 +601,6 @@ esac
ObjdumpCmd="$OBJDUMP"
AC_SUBST([ObjdumpCmd])
dnl ** Which ar to use?
dnl --------------------------------------------------------------
if test "$HostOS" != "mingw32"; then
AC_CHECK_TARGET_TOOL([AR], [ar])
if test "$AR" = ":"; then
AC_MSG_ERROR([cannot find ar in your PATH])
fi
fi
ArCmd="$AR"
fp_prog_ar="$AR"
AC_SUBST([ArCmd])
dnl ** Which ranlib to use?
dnl --------------------------------------------------------------
AC_PROG_RANLIB
......@@ -610,9 +612,21 @@ RANLIB="$RanlibCmd"
dnl ** which libtool to use?
dnl --------------------------------------------------------------
AC_CHECK_TARGET_TOOL([LIBTOOL], [libtool])
LibtoolCmd="$LIBTOOL"
LIBTOOL="$LibtoolCmd"
# The host normalization on Windows breaks autoconf, it no longer
# thinks that target == host so it never checks the unqualified
# tools for Windows. I don't know why we do this whole normalization thing
# as it just breaks everything.. but for now, just check the unqualified one
# if on Windows.
if test "$HostOS" = "mingw32"
then
AC_PATH_PROG([LIBTOOL],[libtool])
LibtoolCmd="$(cygpath -m $LIBTOOL)"
else
AC_CHECK_TARGET_TOOL([LIBTOOL], [libtool])
LibtoolCmd="$LIBTOOL"
LIBTOOL="$LibtoolCmd"
fi
AC_SUBST([LibtoolCmd])
# Here is where we re-target which specific version of the LLVM
# tools we are looking for. In the past, GHC supported a number of
......@@ -1249,7 +1263,7 @@ checkMake380() {
checkMake380 make
checkMake380 gmake
AC_CONFIG_FILES([mk/config.mk mk/install.mk mk/project.mk compiler/ghc.cabal ghc/ghc-bin.cabal utils/runghc/runghc.cabal libraries/ghc-boot/ghc-boot.cabal libraries/ghc-boot-th/ghc-boot-th.cabal libraries/ghci/ghci.cabal settings docs/users_guide/ghc_config.py docs/index.html libraries/prologue.txt distrib/configure.ac])
AC_CONFIG_FILES([mk/config.mk mk/install.mk mk/project.mk compiler/ghc.cabal ghc/ghc-bin.cabal utils/runghc/runghc.cabal utils/gen-dll/gen-dll.cabal libraries/ghc-boot/ghc-boot.cabal libraries/ghc-boot-th/ghc-boot-th.cabal libraries/ghci/ghci.cabal settings docs/users_guide/ghc_config.py docs/index.html libraries/prologue.txt distrib/configure.ac])
AC_OUTPUT
[
if test "$print_make_warning" = "true"; then
......@@ -1302,6 +1316,7 @@ echo "\
ranlib : $RanlibCmd
windres : $WindresCmd
dllwrap : $DllWrapCmd
genlib : $GenlibCmd
Happy : $HappyCmd ($HappyVersion)
Alex : $AlexCmd ($AlexVersion)
Perl : $PerlCmd
......
......@@ -152,3 +152,13 @@ Template Haskell
- Blank strings can now be used as values for environment variables using the
System.Environment.Blank module. See :ghc-ticket:`12494`
Build system
~~~~~~~~~~~~
- ``dll-split`` has been removed and replaced with an automatic partitioning utility ``gen-dll``.
This utility can transparently split and compile any DLLs that require this. Note that the ``rts`` and
``base`` can not be split at this point because of the mutual recursion between ``base`` and ``rts``.
There is currently no explicit dependency between the two in the build system and such there is no way
to notify ``base`` that the ``rts`` has been split, or vice versa.
(see :ghc-ticket:`5987`).
......@@ -539,6 +539,9 @@ utils/runghc/dist-install/package-data.mk: $(fixed_pkg_prev)
iserv/stage2/package-data.mk: $(fixed_pkg_prev)
iserv/stage2_p/package-data.mk: $(fixed_pkg_prev)
iserv/stage2_dyn/package-data.mk: $(fixed_pkg_prev)
ifeq "$(Windows_Host)" "YES"
utils/gen-dll/dist-install/package-data.mk: $(fixed_pkg_prev)
endif
# the GHC package doesn't live in libraries/, so we add its dependency manually:
compiler/stage2/package-data.mk: $(fixed_pkg_prev)
......@@ -646,6 +649,9 @@ BUILD_DIRS += includes
BUILD_DIRS += rts
BUILD_DIRS += bindisttest
BUILD_DIRS += utils/genapply
ifeq "$(Windows_Host)" "YES"
BUILD_DIRS += utils/gen-dll
endif
# When cleaning, don't add any library packages to BUILD_DIRS. We include
# ghc.mk files for all BUILD_DIRS, but they don't exist until after running
......@@ -1393,6 +1399,7 @@ distclean : clean
$(call removeFiles,ghc/ghc-bin.cabal)
$(call removeFiles,libraries/ghci/ghci.cabal)
$(call removeFiles,utils/runghc/runghc.cabal)
$(call removeFiles,utils/gen-dll/gen-dll.cabal)
$(call removeFiles,settings)
$(call removeFiles,docs/users_guide/ug-book.xml)
$(call removeFiles,docs/users_guide/ug-ent.xml)
......
......@@ -207,11 +207,25 @@ ifneq "$$(findstring dyn, $1)" ""
ifeq "$$(TargetOS_CPP)" "mingw32"
$$(rts_$1_LIB) : $$(rts_$1_OBJS) $$(ALL_RTS_DEF_LIBS) rts/dist/libs.depend rts/dist/build/$$(LIBFFI_DLL)
"$$(RM)" $$(RM_OPTS) $$@
"$$(rts_dist_HC)" -this-unit-id rts -shared -dynamic -dynload deploy \
-no-auto-link-packages -Lrts/dist/build -l$$(LIBFFI_NAME) \
`cat rts/dist/libs.depend` $$(rts_$1_OBJS) $$(ALL_RTS_DEF_LIBS) \
$$(rts_dist_$1_GHC_LD_OPTS) \
-o $$@
# Call out to the shell script to decide how to build the dll.
# Making a shared library for the RTS.
# $$1 = dir
# $$2 = distdir
# $$3 = way
# $$4 = extra flags
# $$5 = extra libraries to link
# $$6 = object files to link
# $$7 = output filename
# $$8 = link command
# $$9 = create delay load import lib
# $$10 = SxS Name
# $$11 = SxS Version
$$(gen-dll_INPLACE) link "rts/dist/build" "rts/dist/build" "" "" "$$(ALL_RTS_DEF_LIBS)" "$$(rts_$1_OBJS)" "$$@" "$$(rts_dist_HC) -this-unit-id rts -no-hs-main -shared -dynamic -dynload deploy \
-no-auto-link-packages -Lrts/dist/build -l$$(LIBFFI_NAME) \
`cat rts/dist/libs.depend | tr '\n' ' '` \
$$(rts_dist_$1_GHC_LD_OPTS)" "NO" \
"$(rts_INSTALL_INFO)-$(subst dyn,,$(subst _dyn,,$(subst v,,$1)))" "$(ProjectVersion)"
else
ifneq "$$(UseSystemLibFFI)" "YES"
LIBFFI_LIBS = -Lrts/dist/build -l$$(LIBFFI_NAME)
......
......@@ -134,20 +134,23 @@ endif # "$3" "v"
$(call profEnd, build-package-way($1,$2,$3))
endef # build-package-way
# $1 = dir
# $2 = distdir
# $3 = way
# $4 = extra flags
# $5 = object files to link
# $6 = output filename
define build-dll
$(call cmd,$1_$2_HC) $($1_$2_$3_ALL_HC_OPTS) $($1_$2_$3_GHC_LD_OPTS) $4 $5 \
-shared -dynamic -dynload deploy \
$(addprefix -l,$($1_$2_EXTRA_LIBRARIES)) \
-no-auto-link-packages \
-o $6
# Now check that the DLL doesn't have too many symbols. See trac #5987.
SYMBOLS=`$(OBJDUMP) -p $6 | sed -n "1,/^.Ordinal\/Name Pointer/ D; p; /^$$/ q" | tail -n +2 | wc -l`; echo "Number of symbols in $6: $$SYMBOLS"
case `$(OBJDUMP) -p $6 | sed -n "1,/^.Ordinal\/Name Pointer/ D; p; /^$$/ q" | grep "\[ *0\]" | wc -l` in 1) echo DLL $6 OK;; 0) echo No symbols in DLL $6; exit 1;; [0-9]*) echo Too many symbols in DLL $6; $(OBJDUMP) -p $6 | sed -n "1,/^.Ordinal\/Name Pointer/ D; p; /^$$/ q" | tail; exit 1;; *) echo bad DLL $6; exit 1;; esac
# Call out to the shell script to decide how to build the util dll.
# 1 = dir
# 2 = distdir
# 3 = way
# 4 = extra flags
# 5 = extra libraries to link
# 6 = object files to link
# 7 = output filename
# 8 = link command
# 9 = create delay load import lib
# 10 = SxS Name
# 11 = SxS Version
$(gen-dll_INPLACE) link "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$(call cmd,$1_$2_HC) $(subst -no-hs-main,,$($1_$2_$3_ALL_HC_OPTS) $($1_$2_$3_GHC_LD_OPTS)) \
-shared -dynamic -dynload deploy \
$(addprefix -l,$($1_$2_EXTRA_LIBRARIES)) \
-no-auto-link-packages" "$8" \
"$9" "${10}"
endef
This diff is collapsed.
# -----------------------------------------------------------------------------
#
# (c) 2009 The University of Glasgow
#
# This file is part of the GHC build system.
#
# To understand how the build system works and how to modify it, see
# http://ghc.haskell.org/trac/ghc/wiki/Building/Architecture
# http://ghc.haskell.org/trac/ghc/wiki/Building/Modifying
#
# -----------------------------------------------------------------------------
dir = utils/gen-dll
TOP = ../..
include $(TOP)/mk/sub-makefile.mk
-- WARNING: gen-dll.cabal is automatically generated from gen-dll.cabal.in by
-- ./configure. Make sure you are editing gen-dll.cabal.in, not gen-dll.cabal.
Name: gen-dll
Version: 0.1
Copyright: XXX
License: BSD3
-- XXX License-File: LICENSE
Maintainer: ghc-devs@haskell.org
author: Tamar Christina
Synopsis: Generate GHC core boot library dlls
Description:
This package is responsible for building DLLs that are delay loaded and
create optimized import libraries that can be used to delay load DLLs.
Particularly the RTS. This allows us to delay the loading of the DLL while
still having const data imports work. It also allows us to work around
certain dlltool limitations and the very slow BFD import lib implementation.
build-type: Simple
cabal-version: >=1.10
Executable gen-dll
Default-Language: Haskell2010
Main-Is: Main.hs
Build-Depends: base >= 3 && < 5 ,
pretty >= 1.1 && < 1.2,
process >= 1.2 && < 1.9,
filepath >= 1.3 && < 1.5,
directory >= 1.1 && < 1.4,
containers >= 0.5 && < 0.6
Extra-Libraries: Shell32
ghc-options: -UGEN_SXS
-DHAS_GENLIB=@HAVE_GENLIB@
-DNM_TOOL_BIN="\"@NmCmd@\""
-DLIB_TOOL_BIN="\"@LibtoolCmd@\""
-DGENLIB_TOOL_BIN="\"@GenlibCmd@\""
-DAR_TOOL_BIN="\"@ArCmd@\""
# -----------------------------------------------------------------------------
#
# (c) 2009 The University of Glasgow
#
# This file is part of the GHC build system.
#
# To understand how the build system works and how to modify it, see
# http://ghc.haskell.org/trac/ghc/wiki/Building/Architecture
# http://ghc.haskell.org/trac/ghc/wiki/Building/Modifying
#
# -----------------------------------------------------------------------------
utils/gen-dll_USES_CABAL = YES
utils/gen-dll_PACKAGE = gen-dll
utils/gen-dll_dist_PROGNAME = gen-dll
utils/gen-dll_dist_INSTALL = NO
utils/gen-dll_dist_INSTALL_INPLACE = YES
$(eval $(call build-prog,utils/gen-dll,dist,0))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment