D.Program depends on D.Simple.Utils

Hi, I was about to extend Dist.Simple.Utils with a method called mkSharedLibName, which depends on Compiler information, hence Dist.Simple.Utils was about to import Dist.Compiler. I ran into this dependency loop: Module imports form a cycle for modules: Cabal-1.1.7:Distribution.Compiler imports: <..> Distribution.Program <...> Cabal-1.1.7:Distribution.Program imports: <..> Distribution.Simple.Utils <..> Cabal-1.1.7:Distribution.Simple.Utils imports: <..> Distribution.Compiler <..> make: *** [.depend] Error 1 After a short discussion on #ghc, Esa Ilari Vuokko explained that Dist.* is not supposed to depend on Dist.Simple.*, so it seems reasonable to break the dependency cycle at "Program -> Simple.Utils". Program imports 'die' and two program execution helpers 'rawSystemExit' and 'rawSystemStdout' from Simple.Utils. Two dependencies on 'die' could be removed easily, hunk ./Distribution/Program.hs 192 - Nothing -> die ("Cannot find " ++ prog ++ " on the path") $ + Nothing -> return EmptyLocation hunk ./Distribution/Program.hs 213 - _ -> die ("cannot determine version of " ++ name ++ " :\n" ++ show str) + _ -> return prog { programVersion = Nothing } but the other two uses seems rather ok to me (is it ok to _|_ when an API is used in an illegal way?), namely: rawSystemProgram _ prog@(Program { programLocation = EmptyLocation }) _ = die ("Error: Could not find location for program: " ++ programName prog) Esa suggested a wider refactoring, namely to remove rawSystemExit and rawSystemStdout from Program.hs. Esa, you could explain the details? Would it be ok to move 'die' and the rawSystem helpers into the Dist.* hierarchy if this takes longer to resolve? -- Fruhwirth Clemens - http://clemens.endorphin.org

On Thu, 2007-08-23 at 11:57 +0200, Clemens Fruhwirth wrote:
Hi,
I was about to extend Dist.Simple.Utils with a method called mkSharedLibName, which depends on Compiler information, hence Dist.Simple.Utils was about to import Dist.Compiler. I ran into this dependency loop:
Module imports form a cycle for modules: Cabal-1.1.7:Distribution.Compiler imports: <..> Distribution.Program <...> Cabal-1.1.7:Distribution.Program imports: <..> Distribution.Simple.Utils <..> Cabal-1.1.7:Distribution.Simple.Utils imports: <..> Distribution.Compiler <..> make: *** [.depend] Error 1
After a short discussion on #ghc, Esa Ilari Vuokko explained that Dist.* is not supposed to depend on Dist.Simple.*, so it seems reasonable to break the dependency cycle at "Program -> Simple.Utils".
Actually, I think Program and Compiler (though perhaps not CompilerFlavour) should move under Simple. These two modules are intimately connected with the simple build system, they're not just declarative information like the rest of Distribution.* So then it'd be ok for them to use Utils. If mkSharedLibName needs Program then I don't think should go in Utils. Why does it need Program? Perhaps those functions for constructing file names should go in the InstallDirs module. Duncan

At Thu, 23 Aug 2007 13:32:02 +0100,
Duncan Coutts
On Thu, 2007-08-23 at 11:57 +0200, Clemens Fruhwirth wrote:
Hi,
I was about to extend Dist.Simple.Utils with a method called mkSharedLibName, which depends on Compiler information, hence Dist.Simple.Utils was about to import Dist.Compiler. I ran into this dependency loop:
Module imports form a cycle for modules: Cabal-1.1.7:Distribution.Compiler imports: <..> Distribution.Program <...> Cabal-1.1.7:Distribution.Program imports: <..> Distribution.Simple.Utils <..> Cabal-1.1.7:Distribution.Simple.Utils imports: <..> Distribution.Compiler <..> make: *** [.depend] Error 1
After a short discussion on #ghc, Esa Ilari Vuokko explained that Dist.* is not supposed to depend on Dist.Simple.*, so it seems reasonable to break the dependency cycle at "Program -> Simple.Utils".
Actually, I think Program and Compiler (though perhaps not CompilerFlavour) should move under Simple. These two modules are intimately connected with the simple build system, they're not just declarative information like the rest of Distribution.*
Ok, fine.
So then it'd be ok for them to use Utils. If mkSharedLibName needs Program then I don't think should go in Utils. Why does it need Program?
This is the 'offending' patch http://hpaste.org/2384. Sniplet: -- Implement proper name mangling for dynamical shared objects -- libHS<packagename>-<compilerFlavour><compilerVersion> -- e.g. libHSbase-2.1-ghc6.6.1.so mkSharedLibName :: FilePath -- ^file Prefix -> String -- ^library name. -> Compiler -- get the compiler version -> String mkSharedLibName pref lib comp = pref > ("libHS" ++ lib ++ "-" ++ (compilerDSOTag comp) ++ (showVersion (compilerVersion comp)) ++ ".so") It makes use of compiler information, because we decided to mangle the compiler name and compiler version into the library name. The compiler name is obtained by compilerDSOTag (dynamic shared object tag) and the name is simply the printed representation of the compiler version. (I still need to add a proper parametrization for the extension; .dll/.dylib/.so). But the suggested move from Compiler to Simple.Compiler does not break the cycle, as Simple.Compiler depends on Program, which depends on Simple.Utils which because of my change depends on Simple.Compiler. We could move the filename generating functions to a different module (InstallDir) and evade the problem, but I guess that's not what we want to do. (but it's fine with me, as I can proceed with my agenda of dynamic library support in cabal) -- Fruhwirth Clemens - http://clemens.endorphin.org

On Thu, 2007-08-23 at 15:10 +0200, Clemens Fruhwirth wrote:
Actually, I think Program and Compiler (though perhaps not CompilerFlavour) should move under Simple. These two modules are intimately connected with the simple build system, they're not just declarative information like the rest of Distribution.*
Ok, fine.
So then it'd be ok for them to use Utils. If mkSharedLibName needs Program then I don't think should go in Utils. Why does it need Program?
This is the 'offending' patch http://hpaste.org/2384.
Sniplet: -- Implement proper name mangling for dynamical shared objects -- libHS<packagename>-<compilerFlavour><compilerVersion> -- e.g. libHSbase-2.1-ghc6.6.1.so mkSharedLibName :: FilePath -- ^file Prefix -> String -- ^library name. -> Compiler -- get the compiler version -> String mkSharedLibName pref lib comp = pref > ("libHS" ++ lib ++ "-" ++ (compilerDSOTag comp) ++ (showVersion (compilerVersion comp)) ++ ".so")
It makes use of compiler information, because we decided to mangle the compiler name and compiler version into the library name. The compiler name is obtained by compilerDSOTag (dynamic shared object tag) and the name is simply the printed representation of the compiler version. (I still need to add a proper parametrization for the extension; .dll/.dylib/.so).
What we do in the InstallDirs module is just to pass the PackageIdentifier of the compiler rather than passing the Compiler itself. Then you don't need to import Compiler and there's no cycle :-) it means callers have to do: mkSharedLibName blah blah (compilerId (compiler lbi)) ranther than mkSharedLibName blah blah (compiler lbi) but that's pretty trivial. Duncan
participants (2)
-
Clemens Fruhwirth
-
Duncan Coutts