Run SWI-Prolog binary without swipl installed on the machine - binaryfiles

I want to run swi-prolog program on the machine (actually a server) where there is no prolog installed.
The prolog code swipl_test.pl:
main :- write('Hello, world\n').
On the local machine 4.4.0-64-generic #85~14.04.1-Ubuntu SMP Mon Feb 20 12:10:54 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux making the binary hello with SWI-Prolog version 7.2.3 for amd64:
swipl --goal=main --toplevel=halt --stand_alone=true --foreign=save -o hello1 -c swipl_test.pl
Moving hello on the remote machine 2.6.32-5-amd64 #1 SMP Wed Jun 17 16:09:06 UTC 2015 x86_64 GNU/Linux gives the following error:
error while loading shared libraries: libswipl.so.7.2: cannot open shared object file: No such file or directory
How I can prepare a self-contained binary from a prolog code?
I do not have sudo rights on the remote machine.

I had the same problem and i could solve it looking for the shared libraries necessary for the execution of my program. You can find these libraries by executing the ldd command. Once you have them, you can distribute them in the same directory as your executable and set the LD_LIBRARY_PATH variable so that the executable can find them.
This happens because, as clarified in the documentation, when using the option --stand_alone = true the executable becomes a copy of swipl with the saved state and, if SWI-Prolog is statically linked (by default in Linux/386) and the state does not use external packages, there will be no problems to run the program on another machine. Otherwise (our case) the shared objects must be made available so that the executable can find them. In Linux, these shared objects are found using ldd (in your case, the library libswipl.so.7.2). Therefore, you should look for this library (by default in /usr/lib) and copy it to the directory of your executable to distribute it with it. Then, in the machine where you are going to run the program, you must set the LD_LIBRARY_PATH variable so that the executable knows where to find those libraries that it needs to run, that is, the same directory where it is, or use chrpath(1) to change the address where the executable will search.

It is became available and possible to install swi prolog as:
pkg install swi-prolog
This will fix it

Related

/lib/i386-linux-gnu/libc.so.6: version `GLIBC_2.34' [duplicate]

I'm very new to Yesod and I'm having trouble building Yesod statically
so I can deploy to Heroku.
I have changed the default .cabal file to reflect static compilation
if flag(production)
cpp-options: -DPRODUCTION
ghc-options: -Wall -threaded -O2 -static -optl-static
else
ghc-options: -Wall -threaded -O0
And it no longer builds. I get a whole bunch of warnings and then a
slew of undefined references like this:
Linking dist/build/personal-website/personal-website ...
/usr/lib/ghc-7.0.3/libHSrts_thr.a(Linker.thr_o): In function
`internal_dlopen':
Linker.c:(.text+0x407): warning: Using 'dlopen' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/unix-2.4.2.0/libHSunix-2.4.2.0.a(HsUnix.o): In
function `__hsunix_getpwent':
HsUnix.c:(.text+0xa1): warning: Using 'getpwent' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/unix-2.4.2.0/libHSunix-2.4.2.0.a(HsUnix.o): In
function `__hsunix_getpwnam_r':
HsUnix.c:(.text+0xb1): warning: Using 'getpwnam_r' in statically
linked applications requires at runtime the shared libraries from the
glibc version used for linking
/usr/lib/libpq.a(thread.o): In function `pqGetpwuid':
(.text+0x15): warning: Using 'getpwuid_r' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/libpq.a(ip.o): In function `pg_getaddrinfo_all':
(.text+0x31): warning: Using 'getaddrinfo' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/site-local/network-2.3.0.2/
libHSnetwork-2.3.0.2.a(BSD__63.o): In function `sD3z_info':
(.text+0xe4): warning: Using 'gethostbyname' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/site-local/network-2.3.0.2/
libHSnetwork-2.3.0.2.a(BSD__164.o): In function `sFKc_info':
(.text+0x12d): warning: Using 'getprotobyname' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/ghc-7.0.3/site-local/network-2.3.0.2/
libHSnetwork-2.3.0.2.a(BSD__155.o): In function `sFDs_info':
(.text+0x4c): warning: Using 'getservbyname' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/libpq.a(fe-misc.o): In function `pqSocketCheck':
(.text+0xa2d): undefined reference to `SSL_pending'
/usr/lib/libpq.a(fe-secure.o): In function `SSLerrmessage':
(.text+0x31): undefined reference to `ERR_get_error'
/usr/lib/libpq.a(fe-secure.o): In function `SSLerrmessage':
(.text+0x41): undefined reference to `ERR_reason_error_string'
/usr/lib/libpq.a(fe-secure.o): In function `initialize_SSL':
(.text+0x2f8): undefined reference to `SSL_check_private_key'
/usr/lib/libpq.a(fe-secure.o): In function `initialize_SSL':
(.text+0x3c0): undefined reference to `SSL_CTX_load_verify_locations'
(... snip ...)
If I just compile with just -static and without -optl-static
everything builds fine but the application crashes when it tries to
start on Heroku.
2011-12-28T01:20:51+00:00 heroku[web.1]: Starting process with command
`./dist/build/personal-website/personal-website -p 41083`
2011-12-28T01:20:51+00:00 app[web.1]: ./dist/build/personal-website/
personal-website: error while loading shared libraries: libgmp.so.10:
cannot open shared object file: No such file or directory
2011-12-28T01:20:52+00:00 heroku[web.1]: State changed from starting
to crashed
I tried adding libgmp.so.10 to the LD_LIBRARY_PATH as suggested in here
and then got the following error:
2011-12-28T01:31:23+00:00 app[web.1]: ./dist/build/personal-website/
personal-website: /lib/libc.so.6: version `GLIBC_2.14' not found
(required by ./dist/build/personal-website/personal-website)
2011-12-28T01:31:23+00:00 app[web.1]: ./dist/build/personal-website/
personal-website: /lib/libc.so.6: version `GLIBC_2.14' not found
(required by /app/dist/build/personal-website/libgmp.so.10)
2011-12-28T01:31:25+00:00 heroku[web.1]: State changed from starting
to crashed
2011-12-28T01:31:25+00:00 heroku[web.1]: Process exited
It seems that the version of libc that I'm compiling against is
different. I tried also adding libc to the batch of libraries the
same way I did for libgmp but this results in a segmentation fault
when the application starts on the Heroku side.
Everything works fine on my PC. I'm running 64bit archlinux with ghc
7.0.3. The blog post on the official Yesod blog looked pretty easy
but I'm stumped at this point. Anyone have any ideas? If there's a way to get this thing working without building statically I'm open to that too.
EDIT
Per Employed Russians answer I did the following to fix this.
First created a new directory lib under the project directory and copied the missing shared libraries into it. You can get this information by running ldd path/to/executable and heroku run ldd path/to/executable and comparing the output.
I then did heroku config:add LD_LIBRARY_PATH=./lib so when the application is started the dynamic linker will look for libraries in the new lib directory.
Finally I created an ubuntu 11.10 virtual machine and built and deployed to Heroku from there, this has an old enough glibc that it works on the Heroku host.
Edit:
I've since written a tutorial on the Yesod wiki
I have no idea what Yesod is, but I know exactly what each of your other errors means.
First, you should not try to link statically. The warning you get is exactly right: if you link statically, and use one of the routines for which you are getting the warning, then you must arrange to run on a system with exactly the same version of libc.so.6 as the one you used at build time.
Contrary to popular belief, static linking produces less, not more, portable executables on Linux.
Your other (static) link errors are caused by missing libopenssl.a at link time.
But let's assume that you are going to go the "sane" route, and use dynamic linking.
For dynamic linking, Linux (and most other UNIXes) support backward compatibility: an old binary continues to work on newer systems. But they don't support forward compatibility (a binary built on a newer system will generally not run on an older one).
But that's what you are trying to do: you built on a system with glibc-2.14 (or newer), and you are running on a system with glibc-2.13 (or older).
The other thing you need to know is that glibc is composed of some 200+ binaries that must all match exactly. Two key binaries are /lib/ld-linux.so and /lib/libc.so.6 (but there are many more: libpthread.so.0, libnsl.so.1, etc. etc). If some of these binaries came from different versions of glibc, you usually get a crash. And that is exactly what you got, when you tried to place your glibc-2.14 libc.so.6 on the LD_LIBRARY_PATH -- it no longer matches the system /lib/ld-linux.
So what are the solutions? There are several possibilities (in increasing difficulty):
You could copy ld-2.14.so (the target of /lib/ld-linux symlink) to the target system, and invoke it explicitly:
/path/to/ld-2.14.so --library-path <whatever> /path/to/your/executable
This generally works, but can confuse an application that looks at argv[0], and breaks for applications that re-exec themselves.
You could build on an older system.
You could use appgcc (this option has disappeared, see this for description of what it used to be).
You could set up a chroot environment matching the target system, and build inside that chroot.
You could build yourself a Linux-to-olderLinux crosscompiler
You have several issues.
You should not build production binaries on bleeding edge distributions. The libraries on the production system will not be forward compatible.
You should not link glibc statically - it will always at runtime try to load additional libraries. For example cpu-based assembly. That is what your first warnings are about.
The last linker errors look like they are related to a missing openssl library on the command line.
But all in all - downgrade your distribution.
I had similar problems launching to Heroku (which uses glibc-2.11) where I had an application that required glibc-2.14, but I did not have access to the source and could not re-build it. I tried many things and nothing worked.
My workaround was to launch the service on Amazon Elastic Beanstalk and just provide an API interface.
I found the information provided useful as well, I think the various descriptions miss a critical issue I also ran into while forcing an updated version of Vagrant to start working again.
It's the dependency references internal to something like complicated installs, like Yesod to Heroku. Those interanl refences need to be preserved.
This is the script I wrote to make problems go away (at least, hopefully, for a little while):
#!/bin/bash
cd $HOME/
GLIBC_VERSION="2.17"
GLIBC_PREFIX="/usr/glibc/"
VAGRANT_VERSION="2.2.19"
# Install the basic build system utilities.
yum groupinstall -y "Development tools"
yum install -y curl patchelf
# Grab the tarball with the GNU libc source code.
curl -Lfo glibc-${GLIBC_VERSION}.tar.gz "https://ftp.gnu.org/gnu/glibc/glibc-${GLIBC_VERSION}.tar.gz"
echo "a3b2086d5414e602b4b3d5a8792213feb3be664ffc1efe783a829818d3fca37a glibc-${GLIBC_VERSION}.tar.gz" | sha256sum -c || exit 1
# Extract the secrets and get ready to rumble.
tar xzvf glibc-${GLIBC_VERSION}.tar.gz
# The configure script requrires an independent build directory.
mkdir -p glibc-build && cd glibc-build
# Configure glibc with a GLIBC_PREFIX so it doesn't conflict with distro libc files..
../glibc-${GLIBC_VERSION}/configure --prefix="${GLIBC_PREFIX}" --libdir="${GLIBC_PREFIX}/lib" \
--libexecdir="${GLIBC_PREFIX}/lib" --enable-multi-arch
# Compile and then install GNU libc.
make -j8 && make install
# Download and install Vagrant.
curl -Lfo vagrant_${VAGRANT_VERSION}_x86_64.rpm "https://releases.hashicorp.com/vagrant/${VAGRANT_VERSION}/vagrant_${VAGRANT_VERSION}_x86_64.rpm"
echo "990e8d2159032915f21c0f1ccdcbca1a394f7937e06e43dc1dabe605d208dc20 vagrant_${VAGRANT_VERSION}_x86_64.rpm" | sha256sum -c || exit 1
yum install -y vagrant_${VAGRANT_VERSION}_x86_64.rpm
# Patch the binaries and shared libraries inside the Vagrant directory, so they use the new version of GNU libc.
(find /opt/vagrant/ -type f -exec file {} \; )| grep "dynamically linked" | awk -F':' '{print $1}' | while read FILE ; do
patchelf --set-rpath /opt/vagrant/embedded/lib:/opt/vagrant/embedded/lib64:/usr/glibc/lib:/usr/lib64:/lib64:/lib --set-interpreter /usr/glibc/lib/ld-linux-x86-64.so.2 "${FILE}"
done
The script should be pretty easy to understand, and adapt easily to whatever MacGuffin you want to make work, provied you understand it.
The only tricky part is the rpath you pass to patchelf. Upi need to make sure you preserve the search paths, and precedence your software requires. Or you end up fixing one problem only to create another equally frustrating roadblock.
P.S. Don't forget the update the hashes for any file you down. In particular, you need to compile/install a different version of GNU libc, you will need to update that hash to match the version you want to use.

Cross compiled binary not running on RPI, did I compile it correctly?

I am trying to cross compile a small rust application for the RPI. I am cross compiling because compiling directly on the PI takes way too long and it hits 75C.
I followed various instructions, but what I ended up doing is this:
Install "armv7-unknown-linux-gnueabihf" target with rustup
Download rpi tools from here: https://github.com/raspberrypi/tools
Add the "tools/arm-bcm2708/arm-linux-gnueabihf/bin/" folder to PATH
Add ".cargo/config" file with:
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
run "cargo build --target armv7-unknown-linux-gnueabihf --release"
scp the file to the RPI
chmod +x the_file
do "./the_file"
I get bash: ./the_file: No such file or directory
Yes, I am indeed in the right directory.
So this is the output from "file":
ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically
linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.32,
with debug_info, not stripped
I'm not experienced enough with this sort of stuff to determine if the binary that I produced is suitable to be run on an RPI3 B.
Did I produce the correct "type" of binary?
P.S. I am running DietPi distro on the PI. It is based on debian if that's of any relevance.
So I solved this by cheating. I found https://github.com/rust-embedded/cross which took about 30 seconds to get going and now I can cross compile to pretty much anything. I highly recommend it!
The error message "No such file or directory" is not about the your executable but about the dynamic libraries linked to it which are missing from the target system.
To find out which libraries your executable needs you have to run the following command.
ldd /usr/bin/lsmem
This will output something like this
linux-vdso.so.1 (0x00007fffc87f1000)
libsmartcols.so.1 => /lib/x86_64-linux-gnu/libsmartcols.so.1 (0x00007fe82fe71000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe82fc7f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe82fedd000)
Now you have to check that all this libraries are available on your system. rust-cross probably uses the correct linker for your target so that is probably the reason this works with it. To modify the linker see https://stackoverflow.com/a/57817848/5809980

Compiling tsocks-1.8 in Solaris 10 SPARC

I have a ORACLE/Sun SPARC server with Solaris 10 SPARC OS installed
I am attempting to install tsocks-1.8beta4.tar.gz into Solaris
However in my PuTTY terminal is the following error....
ld: fatal: library -lc not found
This error is being generated by the saveme.c file within the tsocks directory. It contains the following line I believe is causing the fault
unlink("/etc/ld.so.preload")
I dont have the file ld.so.preload inside my Solaris 10 SPARC OS
What shall I do next?
tsocks makes many, many Linux-specific assumptions, such as /etc/ld.so.preload being used, and attempting to statically link portions of the tsocks package.
Solaris 10 does not have a static libc.a. You can not statically link any executable on Solaris 10 and later against system libraries such as libc and libm.
See Static Linking - where did it go?:
With Solaris 10 you can no longer build a static executable. It's not that ld(1) doesn't allow static linking, or using archives, it's just that libc.a, the archive version of libc.so.1, is no longer provided. This library provides the interfaces between user land and the kernel, and without this library it is rather hard to create any form of application.
We've been warning users against static linking for some time now, and linking against libc.a has been especially problematic. Every solaris release, or update (even some patches) has resulted in some application that was built against libc.a, failing. The problem is that libc is supposed to isolate an application from the user/kernel boundary, a boundary which can undergo changes from release to release.
If an application is built against libc.a, then any kernel interface it references is extracted from the archive and becomes a part of the application. Thus, this application can only run on a kernel that is in-sync with the kernel interfaces used. Should these interfaces change, the application is treading on shaky ground.
...

Detecting current gcc installation

In the sake of automatically-detecting native GCC installation from within a program, I would like to get the current path to gcc.exe or its root folder.
But when I type gcc -print-prog-name=gcc it simply prints back gcc which is obviously not what I was expecting.
How do I use gcc or other components supposedly installed on the system alongside gcc to retrieve the path to the gcc installation or executable?
For Linux at least, the "native GCC installation" might reasonably be
interpreted as the GCC installation that is invoked through /usr/bin/gcc.
But on that interpretation, there can be no doubt about its installation
path.
Whenever you invoke gcc, if such a program is found at all, it is
simply the first program called gcc that that is found in one of the
directories listed in the value of environment variable PATH, in the
environment of the invocation. True on Linux and other Unix-like OSes.
True on Windows.
Imagine that gcc had an option --whereami that made it print its installation
path on the standard output. The answer you will get will be the answer
given by the first installation of gcc that is found in the operative PATH at
the time of invocation. There might be any number of GCC installations on
a system each of which will yield a different answer for gcc --whereami whenever
that installation is the first to be discovered in the operative PATH.
Selection of different GCC installations via different PATH settings is
commonplace on Windows, where the notion of "the native installation of GCC"
has no meaning. But it is applicable on Linux too and sometimes used. The point is: no
matter what command you run to find out where gcc is installed, any
answer you get is in principle dependent on the operative PATH -
unless you run the command with an absolute filename:
/usr/bin/gcc --whereami
which of course amounts to deciding the answer before you ask the question.
The only cross-platform method by which you can discover the directory from
which gcc will be run, if at all, by a command gcc ..., is to get the
operative PATH (programmatically, use getenv),
parse out the the directories it contains left to right and for successive
directories query the filesystem for the existence of an executable gcc
within it, stopping when you find one.
And since this can only give an answer for the operative PATH,
and since the value of PATH needs parsed differently on Windows and
Unix-like OSes, you might just as well invoke the OS-specific utility that does the same
thing.
Unix-like:
$ which gcc
/usr/bin/gcc
Windows:
C:\>where gcc
C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev0\mingw64\bin\gcc.exe
And note that in the Windows case, I needed to select my mingw-w64 terminal environment to get an answer.
To execute commands and get their output programmatically, see How can I run an external program from C and parse its output?. On Windows, call _popen
instead of popen.

"unexpected R_X86_64_64 relocation for dynamic symbol" when using Cgo

I am trying to create binding for a C library using Cgo. I have package which uses Cgo to import the library and make some calls to it. It compiles and installs fine. But when trying to use that package from a Go program, I get the the error "unexpected R_X86_64_64 relocation for dynamic symbol" when linking.
Any ideas?
It appears in the assembly generation routines in the 6g compiler:
case 256 + R_X86_64_64:
if(targ->dynimpname != nil && !targ->dynexport)
diag("unexpected R_X86_64_64 relocation for dynamic symbol %s",
targ->name);
r->type = D_ADDR;
return;
The R_X86_64_64 is a type of a symbol in the library. For more information about relocation in the amd64 architecture consult page ~70 here.
Is it possible that you mix 386 compiled library with amd64 code?
The compiler should report the exact symbol which caused the problem. Can you try linking with a minimal library containing other symbols, and try to locate a minimal example where it fails?
Did you manage to use cgo with any library at all?
I agree with Elazar that it seems plausible that mixing of 32-bit and 64-bit code is involved.
Have you tried gccgo?
Works like a charm :
root#Ubuntu-1304-raring-64-minimal:/etc# uname -a
Linux Ubuntu-1304-raring-64-minimal 3.8.13.4 #2 SMP Mon Jul 8 23:59:05 CEST 2013 x86_64 x86_64 x86_64 GNU/Linux
do this sequence :
cd /usr/local
mkdir /var/go
apt-get install mercurial
hg clone https://code.google.com/p/go/
After that create a /etc/profile.d/go.sh with the follewing contents and make it executable:
export GOPATH=/var/go
export GOROOT=/usr/local/go
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOBIN
export GOROOT_FINAL=/var/go
export GOHOSTARCH=amd64
export GOARCH=amd64
export CGO_ENABLED=1
And then restart your shell. NO source xxx will be working properly - be warned! In a new shell do this :
cd /usr/local/go/src
./make.bash
do the thing, and then copy all the things from /usr/local/go to /var/go - or there's a way to merge both directories by symlink, whatever you prefer. After that comment GOROOT_FINAL in go.sh script above AND restart your shell again. And you're ok with latest working Go language!
root#Ubuntu-1304-raring-64-minimal:/usr/work/golang/go/src# go version
go version devel +35d5bae6aac8 Fri Oct 18 10:45:19 2013 +0400 linux/amd64
Note bene : Two shell restarts are required - found it myself in a hard way.

Resources