Distributing a program with support files

Hi, I'm wanting to release a Haskell program, but am confused how I should distribute the associated files it needs. On Windows I would use the functions to find the path of the executable, and find the support files relative to that - in Haskell (because of Linux) that isn't the case. The basic setup I have is: foo.exe - main binary library.hs - required by the binary examples\*.hs - a massive tree of examples, which can be used by the binary foo.exe also needs to create temporary files relative to library.hs and the examples. Thanks Neil

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Neil Mitchell wrote:
Hi,
I'm wanting to release a Haskell program, but am confused how I should distribute the associated files it needs. On Windows I would use the functions to find the path of the executable, and find the support files relative to that - in Haskell (because of Linux) that isn't the case.
The basic setup I have is:
foo.exe - main binary library.hs - required by the binary examples\*.hs - a massive tree of examples, which can be used by the binary
foo.exe also needs to create temporary files relative to library.hs and the examples.
I think the standard Unix technique (not that I like it) is: Find out at compile time (e.g. ./configure or later): -where to put the executable (e.g. /usr/local/bin/NAME or /usr/bin/NAME -where to put the library files (e.g. in /usr/local/share/NAME/ or /usr/share/NAME/) and embed this knowledge in the executable Find out at run time: where to put temporary files: environment-variable TMPDIR if it exists, otherwise /tmp . GHC/libraries might have utility functions for some of those, such as finding the temp-dir... or maybe Cabal for the build-time things... (If you can do without creating temporary files, that's usually a better approach for that :) Isaac -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGWY4THgcxvIWYTTURAqNiAJ9HuwsYkYgFMv2iFt8Q+Cge6cQfVgCeKmRY ATVnn14r9e3iicdIyCXWS1A= =yQs7 -----END PGP SIGNATURE-----

Yes, GHC itself has exactly this problem. We use one method for Windows (the one you describe) and a different one entirely for Unix. This isn't a problem with Haskell; it's just that different OSs have different conventions. Perhaps Cabal (or some library) could make it easy for us all to avoid re-inventing this wheel? Simon | -----Original Message----- | From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Neil | Mitchell | Sent: 27 May 2007 14:36 | To: Haskell Café | Subject: [Haskell-cafe] Distributing a program with support files | | Hi, | | I'm wanting to release a Haskell program, but am confused how I should | distribute the associated files it needs. On Windows I would use the | functions to find the path of the executable, and find the support | files relative to that - in Haskell (because of Linux) that isn't the | case. | | The basic setup I have is: | | foo.exe - main binary | library.hs - required by the binary | examples\*.hs - a massive tree of examples, which can be used by the binary | | foo.exe also needs to create temporary files relative to library.hs | and the examples. | | Thanks | | Neil | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe

On Sun, 2007-05-27 at 14:36 +0100, Neil Mitchell wrote:
Hi,
I'm wanting to release a Haskell program, but am confused how I should distribute the associated files it needs. On Windows I would use the functions to find the path of the executable, and find the support files relative to that - in Haskell (because of Linux) that isn't the case.
The basic setup I have is:
foo.exe - main binary library.hs - required by the binary examples\*.hs - a massive tree of examples, which can be used by the binary
foo.exe also needs to create temporary files relative to library.hs and the examples.
list the support files in the "data-files:" stanza in the .cabal file. Then import the Paths_<pkg> module that Cabal generates for you. It exports a few functions including: getDataDir :: IO FilePath So if you listed: data-files: library.hs, examples\foo.hs, ... then you'd say dataDir <- getDataDir doSomething (dataDir > "library" <.> "hs" ) doSomething (dataDir > "examples" > "foo" <.> "hs" ) This should be portable between linux and windows (and everything else for that matter). Duncan

Hi Duncan,
list the support files in the "data-files:" stanza in the .cabal file. Then import the Paths_<pkg> module that Cabal generates for you. It exports a few functions including:
getDataDir :: IO FilePath
A few questions: 1) How do I test this? I'll need to develop in Hugs and GHC without going through Cabal building. Should I fake up a Paths_<pkg> module? 2) Is there any reasonable limit on the number of data files? Is 1000 too many? 3) Can I create files in this DataDir directory? It does seem that creating a new Paths_<pkg> module and include it is not very pleasant. It requires everyone to compile from source to get the paths working, which doesn't make much sense. Thanks Neil

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Neil Mitchell wrote:
It does seem that creating a new Paths_<pkg> module and include it is not very pleasant. It requires everyone to compile from source to get the paths working, which doesn't make much sense.
Why? If it's a binary package, the IO will return the compiled-in path, which on the same distribution/whatever, should be the correct path. In particular, on Windows, I assume that the IO returns something that is in fact relative to the current position of the executable at the time of its running (am I wrong?) Isaac -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGXAKuHgcxvIWYTTURAnjmAJ9XWxwgt8ci6bHKaGu37qM0RhsbDwCePx5B gvnLrktVxhjW9x36YN8VOrI= =hVKj -----END PGP SIGNATURE-----

Hi Isaac
Why? If it's a binary package, the IO will return the compiled-in path, which on the same distribution/whatever, should be the correct path. In particular, on Windows, I assume that the IO returns something that is in fact relative to the current position of the executable at the time of its running (am I wrong?)
Yhc has cross-platform bytecode. Thats pretty useless if people are going to have to recompile anyway... On Windows the path is relative to the current binary, but not relative in a good way - in practice if you haven't installed it in "C:\Program Files" a precompiled binary isn't going to work. Thanks Neil

On Mon, 2007-05-28 at 20:35 +0100, Neil Mitchell wrote:
Hi Duncan,
list the support files in the "data-files:" stanza in the .cabal file. Then import the Paths_<pkg> module that Cabal generates for you. It exports a few functions including:
getDataDir :: IO FilePath
A few questions:
1) How do I test this? I'll need to develop in Hugs and GHC without going through Cabal building. Should I fake up a Paths_<pkg> module?
Or just use cabal and copy the .hs module it generates.
2) Is there any reasonable limit on the number of data files? Is 1000 too many?
They have to be listed in the .cabal file, so you might get bored adding them all and decide to send in a patch to support glob/wildcards :-)
3) Can I create files in this DataDir directory?
Probably not necessarily. For example if under unix you install the package globally then the data dir will probably be in some read-only directory under /usr/share. If it's a per-user install it might be writable. For per-user writable stuff you probably want getAppUserDataDirectory from System.Directory.
It does seem that creating a new Paths_<pkg> module and include it is not very pleasant. It requires everyone to compile from source to get the paths working, which doesn't make much sense.
As Isaac mentioned, on windows it is relocatable I think. You can see the code than Cabal generates. If you want patches so it'll work with yhc without using #ifdefs and using dynamic tests instead then I'm happy to look at patches that do that. This isn't set in stone and if you have better general workable solutions then do suggest them. Duncan

Neil Mitchell wrote:
Hi Duncan,
list the support files in the "data-files:" stanza in the .cabal file. Then import the Paths_<pkg> module that Cabal generates for you. It exports a few functions including:
getDataDir :: IO FilePath
A few questions:
1) How do I test this? I'll need to develop in Hugs and GHC without going through Cabal building. Should I fake up a Paths_<pkg> module?
2) Is there any reasonable limit on the number of data files? Is 1000 too many?
3) Can I create files in this DataDir directory?
It does seem that creating a new Paths_<pkg> module and include it is not very pleasant. It requires everyone to compile from source to get the paths working, which doesn't make much sense.
The idea is that you get to refer to your data files without any explicit paths, Cabal chooses where to install them, and it works on any OS. Furthermore, on Windows you can generate a relocatable binary distribution, because Windows lets you put the files in a path relative to the binary. The Cabal docs describe how to do it. Also check out Happy, Alex and Haddock - they all have data files that come with the package. Personally, I think it works nicely! Cheers, Simon
participants (5)
-
Duncan Coutts
-
Isaac Dupree
-
Neil Mitchell
-
Simon Marlow
-
Simon Peyton-Jones