10

I want to compile a Haskell program on one Linux box, and then run it on another Linux box. However, this doesn't seem to work at all. I get errors about missing libraries.

Presumably when I install GHC, the package manager also installs all the libraries and stuff that it needs. [I note with some irritation that at least one packaging system fails to install GCC, which GHC apparently can't function without...] But of course, the target system does not have these dependencies installed. So if I copy the compiled binary to the target system, it just fails to run.

Is there some way around this problem? I'm used to working with Windows, where if you compile something, it just works on all Windows systems. (At least, it does until you actually try to use non-standard facilities like database access or something...) I compiled Hello World in Haskell, copied it to another Linux box, and it complained about libgmp.so.10 missing or some cryptic mumbo-jumbo like that.

Just to make things interesting: I only have FTP access to the target machine, not shell access. I'm not even completely sure what OS it's running. So I can change my build machine any way I want, but I can't do anything to the target machine other than copy files to it.

MathematicalOrchid
  • 61,854
  • 19
  • 123
  • 220
  • i would start but looking up that error on google along with the name of the linux distribution at hand , chances are its an error other people are getting with the repository packages – pyCthon Jul 19 '12 at 18:56
  • 1
    see also http://stackoverflow.com/questions/10539857/statically-link-gmp-to-an-haskell-application-using-ghc-llvm – sdcvvc Jul 19 '12 at 19:14
  • @sdcvvc Your link takes me to several very relevant-looking discussions. – MathematicalOrchid Jul 19 '12 at 19:19
  • 9
    I have to laugh at "if you compile something, it just works on all Windows systems.". Have you heard of the term "DLL Hell"? That term didn't come from Linux. ;-) – Daniel Wagner Jul 19 '12 at 21:32
  • Wait, how are you running this program on the target machine with only FTP access and no SSH access? – alternative Jul 20 '12 at 01:12
  • 1
    @DanielWagner You realise that "DLL hell" stopped being an issue about 10 years ago, right? – MathematicalOrchid Jul 20 '12 at 08:17
  • @alternative It's called CGI. – MathematicalOrchid Jul 20 '12 at 08:17
  • 2
    @MathematicalOrchid, DLL hell still exists. If program A needs "mylib.dll v3.0" and then program B requires "mylib.dll v4.0", program A stops working because it doesn't support the new overwritten DLL. Windows has two solutions to the problem: creating multiple copies of libraries with slightly different names and making executables link to specific versions (thus creating "d3dx9_1.dll" through "d3dx9_43.dll" on my computer), or creating a system of "virtual overlays" over system32 so that a program gets the DLL it itself installed. Both solutions lead to huge memory waste and disk overhead. – dflemstr Jul 20 '12 at 14:37
  • @MathematicalOrchid any reason why you can't use static linking? Since you might not control the target system of use, static linking, however much it isn't a great idea, might work in this case. Or if you can package your binary in a standard format (like a .deb or so), then you can ask the target 'customer' to do an apt-get or such and the required dependencies will get downloaded. – Gangadhar Jul 22 '12 at 06:08

2 Answers2

10

Linux behaves just like Windows in this regard. If you compile a Haskell executable on Linux, it will run on any Linux distribution with the right libraries. The problem is that in Windows, the Haskell executables aren't compiled with a dynamic version of libgmp; they are compiled with a static version (so that the library is compiled into the executable) exactly because it can be so difficult to handle dlls on Windows when distributing executables. It is comparably easy to handle the installation of new libraries on Linux.

What you can do is to copy the libgmp.so.10 (which might be a symbolic link to a different file) out of /usr/lib into the same directory as your executable. You can then set the LD_LIBRARY_PATH environment variable to ".", meaning the current directory, before launching your executable. This will make Linux look for libraries in the same directory as executables that it launches, making it find the library. This can be done with a launcher script:

#!/bin/sh
export LD_LIBRARY_PATH=.
`dirname "$0"`/myexecutable "$@"

Saving this script and marking it as executable with chmod +x myscript will make your executable work.

You can use the ldd command to check what other libraries your executable might need and that aren't on the target system.

dflemstr
  • 25,947
  • 5
  • 70
  • 105
  • So does that mean that GMP is the _only_ library that's causing a problem? I thought the trouble was that Linux generally doesn't support moving arbitrary binary files around without extensive support from a complex package manager... – MathematicalOrchid Jul 19 '12 at 19:19
  • 2
    A package manager just manages packages. Files are copied. There is no magic involved. – dflemstr Jul 19 '12 at 19:21
  • Sure. Several hundred _million_ files. In exactly the correct combination. There is no magic involved - just a hell of a lot of hard work. ;-) – MathematicalOrchid Jul 19 '12 at 19:28
  • 2
    You see, both ELF (used in linux) and PE (used in windows) executable file formats support static and dynamic linking. In all major linux distributions most of installed binaries are dynamically linked by distro maintainers against shared libraries which this distro also provides. So moving, say, `/usr/bin/gnome-panel` to another linux system may be difficult, since shared libraries names are compiled into the binary and it may not be possible to resolve them in foreign distro. On the other hand, nothing prevents you from compiling your binary and *statically* link it... – Vladimir Matveev Jul 19 '12 at 20:08
  • 3
    ..against all its dependencies. You will get large binary file with all the code it needs to run. You can supply `-static` option to GHC and it should compile your binary with all libraries included into it. – Vladimir Matveev Jul 19 '12 at 20:11
  • The libraries which GHC link with the simplest possible program on my system are the following: `linux-vdso.so.1, libgmp.so.10, libm.so.6, librt.so.1, libdl.so.2, libgcc_s.so.1, libc.so.6, libpthread.so.0, /lib/ld-linux-x86-64.so.2`. Of all these only non-system library is `libgmp.so.10`, all others are deeply system libs, so it is highly possible that they will have the same names on other linux distro. – Vladimir Matveev Jul 19 '12 at 20:18
0

If you wish to move executable between machines, you have to link in statically, making single executable without external library dependencies. How to do it depends on compiler, and ghc has -static flag, that 'links static version of haskell libraries'.

btw, check, that you do not try to run 64-bit executable on 32 bit machine. 32-bit executable on 64 bit machine should work in most cases, but... well, it depends on configuration of target box, so check that this is not the case as well.

permeakra
  • 612
  • 6
  • 12