One issue with running binaries on the Guix System is that they are not aware of the actual location of libraries. They want to use globally-installed libraries, but guix has them installed only in the store. There are two solutions: create an environment where the binary can find the libraries, or patch the binary to find the libraries.
For both solutions, you need to know which libraries you will need. Try this (ldd comes from the glibc package):
$ ldd my-binary
linux-vdso.so.1 (0x00007ffe80da9000)
libdl.so.2 => not found
libc.so.6 => /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/libc.so.6 (0x00007f7651b77000)
/gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/ld-linux-x86-64.so.2 (0x00007f7651d3b000)
Now, you know which library files are required. Note them and find the packages that are needed, in addition to glibc, to run the package.
with a container
The first solution requires you to create a container, where you expose the libraries and binaries in a global location. Note how we use -s i686-linux to build an environment for that architecture, instead of the default one.
PROFILE=$(guix environment -C -N --ad-hoc glibc ... -s i686-linux -- bash -c 'echo $GUIX_ENVIRONMENT')
guix environment -C -N --ad-hoc glibc ... -s i686-linux --expose=$PROFILE/lib=/lib --expose=$PROFILE/lib=/lib64
The first line creates the PROFILE variable that contains the path to the profile we create for the environment. It runs the echo command and exists immediately. Using single quotes is essential, as don't want bash from outside the environment to expand the variable. The second command actually lets you enter the environment. If the program needs a graphical display, you'll need to share/expose more things.
with patchelf
The second solution is to patch the binary, which lets you run it in your normal environment, which means for instance less troubles for accessing the graphical interface, audio or other hardware. This uses patchelf, and there are two ways of doing it: the manual way (quick and dirty) or the packaging way.
quick and dirty
The quick and dirty way is to build each dependency you noted before like so (for glibc):
$ guix build glibc -s i686-linux
/gnu/store/9728x9zhj8d3zlyzsjpz342jpccrgkgd-glibc-2.31
this gives you a store path, and ensures the library is present in your store.
Now, with patchelf (from the patchelf package):
patchelf --set-interpreter /gnu/store/...-glibc-.../lib/ld-linux.so.2
patchelf --set-rpath /gnu/store/...-glibc-.../lib:/gnu/store/.../lib:/gnu/store/.../lib:...
this sets the interpreter to ld-linux.so.2 (for 32 bits), and the rpath, which is the search path for dynamic libraries. It should be a colon-separated list of directories where the required libraries are located.
This method is relatively quick, but dirty, as it doesn't register any gc root, and you'll need to redo it again every time you update guix or run the garbage collector.
using a package
The last possibility is to create a package definition for your binary, that will register dependency information, and you can also use this method to install the binary in your profile. You could use the binary-build-system in nonguix: https://gitlab.com/nonguix/nonguix
a drawback of this method is that it copies the binary to the store, and the binary could be large. But using a package definition is more future-proof, as you can always build it again and update the package. The binary build system essentially does the patchelf commands above for you, in a more declarative way. You could define a package in that way:
(package
(name "my-binary")
(version "version")
(source (local-file "/home/..."))
(build-system binary-build-system)
(arguments
`(#:patchelf-plan
`(("my-binary" ("libc" "gcc:lib" ...)))
#:install-plan
`(("my-binary" "bin/"))))
(inputs
`(("gcc:lib" ,gcc "lib")))); note how the first string must match the one in
; patchelf-plan. libc is already implicitely defined
Then, you can build this package with something like:
guix build -s i686-linux -f my-package.scm