Haskell standalone executable without using 'stack exec' - haskell

How would one go about creating an executable from a stack generated framework (stack new myprog simple)?
myprog.cabal shows myprog as executable that can be executed using stack exec myprog.
However: using ./myprog will not work. Not unless I call ghc --make src/Main.hs. This works obviously and nicely embeds the modules, but now the executable is called Main.
Is there a way to have stack compile myprog as a complete executable that can be called from anywhere assuming the environmental path is set?

As you may already be aware, stack build builds the executable, but then places it in a stack-specific path which can most easily be accessed using stack exec. However, there is another command: stack install, which then copies the executable to a convenient location. Normally the default location is in ~/.local/bin (I think), but you can use stack install --local-bin-path <PATH> to copy the executable to <PATH>. For instance, use stack install --local-bin-path . to place the executable in your current working directory, or use stack install --local-bin-path bin to place it in your ./bin/ directory. You can then run the executable using <PATH>/my-exe.

Related

Does an executable need so file even after it is linked during the creation?

I have started looking into the concepts of linking libraries with exes and working in Linux machine. I'm struggling to understand the concept of linking so files with executables.
app:$(CC) $(CFLAGS) $(LDFLAGS) app.o app_dep.o -L . -ldynamic -Wl,-rpath . \
-o app
I'm trying to create an executable app with the above lines in makefile. I have to link it with a libdynamic.so file which exists in the working directory. So i used -L flag and -rpath to point to the directory and name of the so file. It worked and executable is created.
But when i tried to run the executable, it again complains that libdynamic.so: cannot open shared object file: No such file or directory.
Why do i need it since i linked the sharedlibrary during the creation of executable itself?
If the answer to the question is "Yes, it is required to point to the lib even it is linked". How could i point to the folder where it presents during the execution of binary?
One way i found is using LD_LIBRARY_PATH environment variable. Is there any other way to do without environment variable?
Thanks
Why do i need it since i linked the sharedlibrary during the creation of executable itself?
Because linking against a shared library does not embed that shared library into the executable. That is the main difference between linking with a shared versus archive library.
How could i point to the folder where it presents during the execution of binary?
There are no "folders" in UNIX. They are directories.
The correct link command to make an executable look in current directory is:
gcc -o app app.o ... -L. -ldynamic -Wl,-rpath=.
Note that in general it's a really bad idea to do so: your executable will or will not run depending on your current directory (or it may use different versions of libdynamic.so depending on which directory you are in).
Your link command should have worked if you invoked app in the directory with libdynamic.so present (i.e. if you invoked it like ./app), but not if you used /path/to/app (and were not in the same directory).
A significantly better approach is to do this:
gcc -o app app.o ... -L. -ldynamic -Wl,-rpath='$ORIGIN'
That tells the app binary to look for libdynamic.so in the same directory in which app is located, regardless of your current directory.

Compile stack script instead of running it

The build tool stack has the feature to treat a usually compiled haskell source file as a script. (https://docs.haskellstack.org/en/stable/GUIDE/#script-interpreter)
Is it also possible to create a compiled executable the same way?
I searched the help section of stack and stack script, but could not find an options that make this possible.
script.hs:
#!/usr/bin/env stack
{-
stack script
--resolver lts-13.14
--package turtle
-}
main = print "hello"
So if given it the right permissions, this file can be executed. I guess behind the scenes stack compiles the file and then just runs it. And I'd like to just get the compiled intermediate binary.
No, it's not compiled. It's run through runhaskell which is a Haskell interpreter. If you want to compile it... do that. Instead of running the script,
take the --resolver and --package options from the script comment and pass them like this
stack ghc --resolver lts-13.14 --package turtle test.hs
The script command takes both --compile and --optimize as flags, which will instruct Stack to first compile to an executable (optionally with -O2 optimization level) before running.

How to completely bootstrap GHC & cabal from source

I would like to install pandoc, but I have some restrictions due to the Corporate IT policies:
I cannot download any binaries.
Every executable has to be build from sources
Only Google Chrome have an access to internet (proxy restrictions)
So I downloaded Pandoc sources but it depends on haskell. Thus I downloaded ghc-7.8.4-src.tar.bz2
Unfortunately I discovered that I need GHC to build GHC. I downloaded ghc-7.4.1-i386-unknown-linux.tar.bz2 and I got this error:
$ ./configure
checking for path to top of build tree... ./configure: line 2113: utils/ghc-pwd/dist-install/build/tmp/ghc-pwd: cannot execute binary file: Exec format error
configure: error: cannot determine current directory
In "/usr/src/ghc-7.4.1/utils/ghc-pwd/dist-install/build/tmp/usr/src/ghc-7.4.1/utils/ghc-pwd/dist-install/build/tmp" I found a binary that should not be here. I cannot execute binaries.
I also discovered that I need cabal for which I need to install Haskell first.
It seems It's the snake that bites its own tail...
Is there a method that I can use to build Pandod, Haskell, Cabal and all the other dependencies?
Usually if I need a program, I just download the sources, execute ./configure, solve the dependencies issues and eventually run make install. In this case it seems I need my whole lifetime just to understand what I need to build Pandoc...
I would try using the newly (beta-)released stack tool [1]
Recipe to download GHC and build pandoc:
Obtain the stack executable [2]
Run:
$ stack setup
Add the recommended directory to your PATH (will be something like $HOME/.stack/progams/...arch.../ghc-7.8.4/bin)
Run:
$ stack install pandoc
Look for the pandoc executable in $HOME/.local/bin.
Links:
[1]: https://www.fpcomplete.com/blog/2015/06/announcing-first-public-beta-stack
[2]: https://github.com/commercialhaskell/stack/wiki/Downloads

Where do I find (and run) an executable compiled with a cabal sandbox?

I'm compiling my myProgram.lhs with the use of a cabal sandbox (set up with cabal sandbox init). I'm using a simplest approach I've come up with:
cabal exec -- ghc myProgram
or (having a rule in Makefile)
cabal exec -- make myProgram
After that, in my source directory, appears myProgram.o, but not the executable myProgram.
How do I run the resulting program?
cabal exec -- ./myProgram
doesn't work.
Now, I've come up with a simplest approach to test it:
cabal exec -- runghc myProgram.lhs
but I don't like this.
Do you know where the resulting executable is?
(I haven't created any cabal file for my project yet. I simply used to compile the program with bare ghc and test it, then--when I needed custom dependencies--I set up the cabal sanbox and installed the dependencies manually there.)
This didn't actually look like a problem of cabal exec, and it wasn't!
My history
Simultaneously with starting to use the cabal sandbox, I explicitly gave a custom name to my module in the source file (myProgram.lhs). And in such case just a bare ghc (without cabal exec) wouldn't generate the executable, too, as answered in Cabal output is redirected but not generated. (I simply couldn't test the bare ghc command, because I had the dependencies in the sandbox, so my module wouldn't compile.)
Explanation
Explanation quoted from that Q&A:
I get the warning
output was redirected with -o, but no output will be generated because there is no main module.
A quote from The Haskell 98 Report:
A Haskell program is a collection of modules, one of which, by convention, must be called Main and must export the value main.
The solution
A solution is to add -main-is MyProgram.main to ghc opts. Then it generates the executable.
./myProgram simply appears in my source directory now, no matter whether I call
ghc -main-is MyProgram.main myProgram
or
cabal exec -- ghc -main-is MyProgram.main myProgram

Problems using a shared library

I am following the explanation in this page and this page trying to build and use shared libraries on Ubuntu Linux.
I am building the libraries and application using a cross-compiler on my PC, than copying the files to the target system and running there.
Finally, I am at the stage where all symlinks are defined correctly and the I am able to run the application - but not in the required form.
Let's say that I have a shared library libtest.so.1.0 in a directory /home/ysap/libs. I then created the symlinks libtest.so.1 and libtest.so in the same directory, both pointing to the library file.
In the directory /home/ysap/apps I have an application program app.e that uses the test library.
Now, to run the application, I can type:
> LD_LIBRARY_PATH=/home/ysap/libs ./app.e
and the application runs nicely. However, I'd like to eliminate the assignment, so I tried typing:
> export LD_LIBRARY_PATH=/home/ysap/libs
> ./app.e
but unfortunately I get an error message, saying:
./app.e: error while loading shared libraries: libtest.so.1: cannot open shared object file: No such file or directory
I also tried typing:
> ldconfig -n /home/ysap/libs
and
> sudo ldconfig -n /home/ysap/libs
but it does not help.
What am I doing wrong? How can I make app.e run w/o the variable assignment?
Update 1:
The application uses the mmap() call, so it has to be run with sudo priviledge. The actual invocation line is:
> sudo LD_LIBRARY_PATH=/home/ysap/libs ./app.e
Is it possible that the export-ed variable is not updated in the sudo environment?
Update 2:
Output of ldd ./app.e:
libtest.so.1 => /home/ysap/libs/libtest.so.1 (0xb6faa000)
libgcc_s.so.1 => /lib/arm-linux-gnueabi/libgcc_s.so.1 (0xb6f85000)
libc.so.6 => /lib/arm-linux-gnueabi/libc.so.6 (0xb6ea4000)
/lib/ld-linux.so.3 (0xb6fb7000)
The sudo problem is as #duskwuff states, but if you want to compile an application, and not need to modify the LD_LIBRARY_PATH variable, when linking the application you can use the $ORIGIN variable, which is recognized by most recent versions of linux.
If all the libraries are in the current directory, then when you link the application, you use the extra option:
-Wl,-R'$ORIGIN'
You need to quote the option to prevent it being expanded by the shell when compiling.
If you're putting it into a Makefile then you use:
-Wl,-R\$$ORIGIN
the $$ is for make to use a $, the \ is to prevent the shell that is invoked from the command line expanding the variable before passing it into the command.
You can use any symbolic path reference, so if you had a structure where binaries were in bin/ and libraries were in lib/, you can use $ORIGIN/../lib.
This works for dlopen as well, so it will find libraries when they are being dynamically loaded at run-time
Loading libraries from a user-specified path is a security risk, so sudo always strips out all LD_ environment variables, including LD_LIBRARY_PATH.

Resources