-
Notifications
You must be signed in to change notification settings - Fork 697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Directly call in-library functions to build packages #9871
base: master
Are you sure you want to change the base?
Conversation
I tried compiling this with
but it fails because |
253e4d5
to
d4a6532
Compare
I've updated the PR now, but please note that this PR is still work in progress and there are quite a few issues that I have yet to resolve. I didn't know about |
17278dc
to
c209ca5
Compare
7392807
to
bbc2418
Compare
e34ac10
to
0085999
Compare
2469702
to
c3554cd
Compare
I have successfully built all of the |
ee74d63
to
243f1c8
Compare
ceb9782
to
b24aaba
Compare
configureCompiler | ||
:: Verbosity | ||
-> SetupScriptOptions | ||
-> IO (Compiler, ProgramDb, SetupScriptOptions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In #9735 I was bothered by this threaded mutable state. Removing it boilds down to splitting SetupScriptOptions
in V1/V2 versions. The first has many unknown because it's made with miminal planning but the V2 version has already everything we might want to know.
&& bt == Custom = | ||
return (packageVersion pkg, Nothing, options') | ||
installedCabalVersion verbosity pkg _bt options' compiler progdb = do | ||
index <- maybeGetInstalledPackages verbosity options' compiler progdb |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
installedCabalVersion
is only called once (L949) and right after configureCompiler
which pre-emptively calls maybeGetInstalledPackages
knowing it's going to needed here.
If I got this right, this function signature can be simplified down to
installedCabalVersion
:: Verbosity
-> InstalledPackageIndex
-> VersionRange
-> PackageId
-> BuildType
-> IO (Version, Maybe InstalledPackageId)
which has the advantage of not dealing with SetupScriptOptions
mutation's. See my attempt https://github.com/haskell/cabal/pull/9735/files#diff-6ff0f0024945e11d4f23279d3d025c146ef7b28d15e29fefe73f1dab10a80325R793-R799
This is great, I definitely wanted your feedback about |
b24aaba
to
4528849
Compare
= do | ||
abiOK <- | ||
if buildType' == Hooks | ||
then do | ||
-- NB: compileExternalSetupMethod compiles the hooks executable. | ||
_ <- compileExternalSetupMethod verbosity options pkg Hooks | ||
externalHooksABI <- externalSetupHooksABI $ hooksProgFilePath (useWorkingDir options) (useDistPref options) | ||
let internalHooksABI = hooksVersion | ||
return $ externalHooksABI == internalHooksABI | ||
else return True | ||
if abiOK | ||
then do | ||
debug verbosity $ "Using in-library setup method with build-type " ++ show buildType' | ||
return $ with (cabalVersion, LibraryMethod, options) | ||
else do | ||
debug verbosity $ "Hooks ABI mismatch; falling back to external setup method." | ||
withExternalSetupMethod |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand correctly, in case of the Hooks build-type, this boils down to:
_ <- compileExternalSetupMethod verbosity options pkg Hooks
externalHooksABI <- externalSetupHooksABI $ hooksProgFilePath (useWorkingDir options) (useDistPref options)
let internalHooksABI = hooksVersion
let abiOk = externalHooksABI == internalHooksABI
if abiOk
return $ with (cabalVersion, LibraryMethod, options)
else do
withExternalSetupMethod
Is there an advantage of using the LibraryMethod
given we had to compile an external setup anyway just to check the ABI?
Now I am wondering, is this always the case? That is, is there a case where we are sure we can use the library method without compiling the script first?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right that currently we compile both the external hooks executable and the setup executable here, even though we only need to compile the hooks executable in this code path (falling back to the setup executable when there is an ABI mismatch). I can refactor the code to avoid the compilation of the external setup executable (it makes sense to do so).
I think the existing "cabal version" logic (what's at the top of withSetupMethod
) effectively guarantees that we will have matching Cabal ABI, but given that we need to compile the external hooks executable anyway it makes sense to do an additional version check as belt-and-braces (mismatched Binary instance errors can be a real nightmare to debug). I don't think there's any other work that we can avoid doing, other than not compiling the Setup executable if we don't need it; we need to compile the hooks executable when using build-type: Hooks.
BTW, there are other benefits to going through the in-library method even if we pessimistically compile the setup executable, for instance we skip re-configuring things that cabal-install
has already configured.
This commit makes it so that cabal-install emits PackageDescription parser warnings at normal verbosity or above. Previously, we used to emit warnings at verbosity >= verbose, but now that we are going through in-library methods this meant we could skip ever emitting some warnings, which is not desirable.
4705b31
to
d41884b
Compare
This commit modifies the SetupWrapper mechanism, adding a new way of building a package: directly calling Cabal library functions (e.g. 'build', 'configure' etc). This currently requires a bit of GADT trickery to accomodate the fact that configure returns a LocalBuildInfo which must then be passed to subsequent phases, while with the old Setup interface everything returns IO () and communication is done through the filesystem (the local build info file). To handle 'build-type: Hooks', this commit introduces the hooks-exe package, which contains: - the hooks-exe library, used to compile a set of SetupHooks into an external executable, - the hooks-cli library, which is used by cabal-install to communicate with an external hooks executable. This package depends on the new `CommunicationHandle` functionality from haskell/process#308.
The `hooks-exe` package enables `SetupHooks` values to be converted into a `Setup.hs` executable which can be executed independently of Cabal. The `Setup.hs` executable wrapping `SetupHooks` is quite important to preserve the interface used by other tools when packages migrate to `Hooks` from `Custom`. Even though `hooks-exe` is an internal dependency required by the `Setup.hs` wrapper around `SetupHooks`, it is a dependency nonetheless. Given the internal nature of `hooks-exe`, we don't want to impose on our users the obligation to add a dependency on `hooks-exe` in their setup-depends field. Instead, we want `hooks-exe` to be implicitly added to the setup dependencies. This commit does that exactly.
This commit updates the bootstrap plans to account for the new local hooks-exe package, which cabal-install depends on.
This commit contains testsuite changes to account for the change in how cabal-install calls Cabal. The most common change is that we emit warnings at a slightly different point during compilation.
This SetupMethod is no longer used; it is replaced by the InLibrary SetupMethod which directly calls Cabal library functions instead of going through defaultMain.
This moves some functions to the top-level and threads through the required arguments. This helps to separate concerns a bit more, as opposed to having all functions defined in one big blob.
157cbb5
to
24de4e0
Compare
`reusingGHCCompilationArtifacts` assumed the existence of a build folder where objects were written (even if empty), but with InLibrary calls this is no longer necessarily true. Previously, the build folder ended up always existing because the call of `configure` through `Setup` created the folder. However, now that we may call Cabal the library directly, the existence of this directory is no longer guaranteed. Easy fix: don't try to copy the build folder if it doesn't exist yet.
24de4e0
to
8a51434
Compare
Template Β: This PR does not modify
cabal
behaviour (documentation, tests, refactoring, etc.)This PR modifies
cabal-install
to directly go through theCabal
library when building packages, instead of theSetup
interface (except of course forbuild-type: Custom
packages).Overview of changes:
LibraryMethod
toSetupMethod
(*), in which we directly invoke theCabal
configure
,build
, ... functions.configure
returns aLocalBuildInfo
which must then be passed to subsequent phases, while with the oldSetup
interface everything returnsIO ()
and communication is done through the filesystem (e.g. the local build info file).hooks-exe
, provisioning:CallHooksExe
: the API for communicating with an external hooks executable (cabal-install
depends on this)HooksExe
: the necessary functions for creating a hooks executable (cabal-install
adds a dependency on this when compiling a package withbuild-type: Hooks
).CommunicationHandle
functionality fromprocess
PR #308.(*) NB:
SetupMethod
/SetupWrapper
is now a bit of a misnomer, because the whole aim of this PR is to no longer go through theSetup
interface (and its oldUserHooks
incarnations such asdefaultMainWithHooks
). New naming conventions welcome!The main change is in
Distribution.Client.SetupWrapper
: we add a newSetupMethod
(probably a misnomer at this point because we no longer go throughSetup
; new names for this datatype are welcome) in which we directly invoke theCabal
configure
,build
etc functions rather than going throughSetup
(or the equivalentdefaultMainWithUserHooks
interface).TODO:
process
PR #308.hooks-exe
library when compiling the hooks executable for a package withbuild-type: Hooks
.SetupHooks.hs
.LocalBuildInfo
obtained at the end of configuring, between using the in-library method and going throughSetup
, and make them as consistent as it makes sense to make them.build-tool-depends: blah
in whichblah
needs to access its data directories. This is important, as data directories are another part of process-global state (like the working directory) that is set upon invoking an externalSetup
executable (seeDistribution.Client.SetupWrapper.internalSetupMethod
).BuildToolPaths
test which currently occasionally triggersopenBinaryFile: invalid argument (Bad file descriptor)
hsc2hs
.