Using --make with -odir and hierarchical modules

The GHC manual needs to specify what happens when you use -odir and hierarchical modules with --make. I posted to the list about this before but it was not resolved: http://www.haskell.org/pipermail/glasgow-haskell-users/2002-October/004178.h... Here is an example: . |-- Library | |-- Bar | | `-- Module.hs | `-- Foo | `-- Module.hs `-- Program |-- Program.hs `-- output Program.hs uses Bar.Module and Foo.Module. Then, doing cd to Program # ghc -i../Library --make Program ghc-5.04.2: chasing modules from: Program Compiling Bar.Module ( ../Library/Bar/Module.hs, ../Library/Bar/Module.o ) Compiling Foo.Module ( ../Library/Foo/Module.hs, ../Library/Foo/Module.o ) Compiling Main ( Program.hs, ./Program.o ) ghc: linking ... everything works fine. Using -odir: # ghc -i../Library -odir output --make Program ghc-5.04.2: chasing modules from: Program Compiling Bar.Module ( ../Library/Bar/Module.hs, output/Module.o ) Compiling Foo.Module ( ../Library/Foo/Module.hs, output/Module.o ) Compiling Main ( Program.hs, output/Program.o ) ghc: linking ... <LONG LINKER ERROR> Error, since both modules are compiled to the same file. This should not happen. What should be done about it? Solution 1: -odir is relative to the source directory (files will end up in Library/Bar/output/Module.o and Library/Foo/output/Module.o). This is a change of semantics from the earlier behaviour of -odir (files are put in another place). On the other hand, it may be more natural to put files relative to their source, like --make without -odir does. The question remains what to do if -odir is an absolute path. Solution 2: files put in -odir are put in directories (files will end up in Program/output/Bar/Module.o and Program/output/Foo/Module.o) This is also a slight change in semantics, since files are put in directories. May affect Makefiles that does "ar output/*.o" or similar. Solution 3: files put in -odir will have their full module name (files will end up in Program/Output/Bar.Module.o and Program/Output/Foo.Module.o) This is an ever lesser change in semantics, and is better than solution 2 in my opinion. I would recommend using solution 1 if the path name is relative and solution 3 if it's absolute. Regards, Martin -- Martin Norbäck d95mback@dtek.chalmers.se Kapplandsgatan 40 +46 (0)708 26 33 60 S-414 78 GÖTEBORG http://www.dtek.chalmers.se/~d95mback/ SWEDEN OpenPGP ID: 3FA8580B

Martin Norbäck
The GHC manual needs to specify what happens when you use -odir and hierarchical modules with --make.
It may be of interest to note that hmake currently uses solution 2 below.
Solution 2: files put in -odir are put in directories (files will end up in Program/output/Bar/Module.o and Program/output/Foo/Module.o) This is also a slight change in semantics, since files are put in directories. May affect Makefiles that does "ar output/*.o" or similar.
Regards, Malcolm

Martin Norbäck wrote:
What should be done about it?
Solution 1: -odir is relative to the source directory (files will end up in Library/Bar/output/Module.o and Library/Foo/output/Module.o). This is a change of semantics from the earlier behaviour of -odir (files are put in another place). On the other hand, it may be more natural to put files relative to their source, like --make without -odir does. The question remains what to do if -odir is an absolute path.
Perhaps a more fundamental question than what is "natural" is what the intended use of "-odir" is and what is most useful in that context. One might also want "-odir" and "-hidir" to behave similarly, even though the role or .hi files and .o files are rather different.
Solution 2: files put in -odir are put in directories (files will end up in Program/output/Bar/Module.o and Program/output/Foo/Module.o) This is also a slight change in semantics, since files are put in directories. May affect Makefiles that does "ar output/*.o" or similar.
Well, ar does not support directories anyway, so if the objective here is to build a link library, the leaf names had better be distinct. (At least GNU make does seem to allow putting two object files with the same name into a link library if done as a single operation, but my guess is that doing so is asking for trouble.)
Solution 3: files put in -odir will have their full module name (files will end up in Program/Output/Bar.Module.o and Program/Output/Foo.Module.o) This is an ever lesser change in semantics, and is better than solution 2 in my opinion.
At least that would ensure unique names in archives. On the other hand, "-odir" should preferably work the same way regardless of whether "--make" is used or not. And if "--make" is not used, a tool like "Make" is probably used instead. And in that case, it is often usefull to be able to derive the output file name from the input file name, which would seem hard with solution 3. But then again, if "Make" is used, it might not be necessary to use "-odir" in the first place. Since compilation is taking place file by file, "-o" should be enough to put files wherever they need to go.
I would recommend using solution 1 if the path name is relative and solution 3 if it's absolute.
This seems both a bit complicated and error prone and to me. Moreover, there are all sorts of reasons for why one in some cases might want to use a relative path name and in other cases a relative one, and I would be surprised if these reasons coinside with a desire to use solution 1 whenever the path is relative and solution 3 otherwise. So whatever the best solution is, don't make it depend on the form of the path. All the best, /Henrik -- Henrik Nilsson Yale University Department of Computer Science nilsson@cs.yale.edu

Henrik Nilsson wrote:
[...] Well, ar does not support directories anyway, so if the objective here is to build a link library, the leaf names had better be distinct. (At least GNU make does seem to allow putting two object files with the same name into a link library if done as a single operation, but my guess is that doing so is asking for trouble.) [...]
Allowing leaf names to be equal is essential for the whole hierarchical module business! Otherwise you would get evil non-local interactions between different modules. And in practice it doesn't seem to be a problem for ar/ld, because the base package and the GLUT package have lots of examples for equal leaf names (see below). I'm not sure how ar/ld handle this exactly, but I guess it works because of an index in the archive. From the Linux ar man page: ... ar creates an index to the symbols defined in relocatable object modules in the archive when you specify the modi fier s. Once created, this index is updated in the archive whenever ar makes a change to its contents (save for the q update operation). An archive with such an index speeds up linking to the library, and allows rou tines in the library to call each other without regard to their placement in the archive. You may use nm -s or nm --print-armap to list this index table. If an archive lacks the table, another form of ar called ranlib can be used to add just the table. ... Newer ar versions to add this index automatically, other need an explicit ranlib. The GHC installation process takes care of that automatically. Cheers, S. --------------------------------------------------------------------------- Leaf name "clashes" in the current GHC version: libHSGLUT.a: Graphics.UI.GLUT.Window Graphics.UI.GLUT.Callbacks.Window libHSbase.a: Data.Array Foreign.Marshal.Array Data.Array.Base GHC.Base Data.Char Text.ParserCombinators.Parsec.Char Control.Monad.Error Foreign.C.Error Foreign.Marshal.Error System.IO.Error Text.ParserCombinators.Parsec.Error Control.Exception GHC.Exception Data.Array.IO GHC.IO System.IO Data.Int GHC.Int Control.Monad.ST.Lazy Data.STRef.Lazy Control.Monad.List Data.List GHC.List GHC.Posix Text.Regex.Posix Foreign.Ptr GHC.Ptr GHC.Read Text.Read Data.STRef GHC.STRef Control.Monad.ST Data.Array.ST GHC.ST GHC.Show Text.Show Data.Array.Storable Foreign.Storable GHC.Storable Control.Monad.ST.Strict Data.STRef.Strict Foreign.C.Types System.Posix.Types Debug.QuickCheck.Utils Foreign.Marshal.Utils GHC.Weak System.Mem.Weak

Sven Panne wrote:
Allowing leaf names to be equal is essential for the whole hierarchical module business!
Obviously, yes.
Otherwise you would get evil non-local interactions between different modules. And in practice it doesn't seem to be a problem for ar/ld, because the base package and the GLUT package have lots of examples for equal leaf names (see below).
Interesting.
I'm not sure how ar/ld handle this exactly, but I guess it works because of an index in the archive. From the Linux ar man page:
Yes, I did notice, as I wrote, that at least GNU ar seemed to cope with putting many files having the same name into an archive if the archive is built in a single operation. Maybe the index is instrumental in that. Maybe not. However, I can't really see how this would work if an archive is updated incrementally, for example as per default Make rules. For example, if an archive "fie.a" contains two "foo.o", and one does ar rv fie.a foo.o then how could ar possibly know which "foo.o" to replace? So I would be a bit nervous about putting files with the same names into an archive. At least one has to be careful when constructing the archive to make it work. And if some libraries really rely on this, it would be nice to know that this is universally supported by all ar programs, linkers, compilers, etc. Alternatively, maybe one should reconsider how object files are named. /Henrik -- Henrik Nilsson Yale University Department of Computer Science nilsson@cs.yale.edu
participants (5)
-
Henrik Nilsson
-
Malcolm Wallace
-
Martin Norbäck
-
nilsson@cs.yale.edu
-
Sven Panne