Rust not compiling to executable in Linux - linux

Compiling rust on Linux with rustc or cargo build produces a shared library instead of an executable file.
My file manager (thunar) and file command show that file type as shared library.
And the compiled binary can only be executed via terminal by $ /path/to/file or $ cargo run.
That file cannot be executed just by double clicking as other executables can be.
Output from file command:
$ file rust_bin
rust_bin: ELF 64-bit LSB shared object, x86_64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=cb8cd... , with debug_info, not stripped`

Your compiler produces an executable file. There is no big difference between a shared library and a dynamically linked executable file. They follow the same basic format. The string interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0 indicates that this is an executable and not a library. Libraries don't normally have an interpreter set. Try running file on some files you know are executables, and some other files you know are libraries, and see for yourself. An interpreter is usually a small system program that loads and executes a shared object. A file can actually serve as both a library and an executable at the same time (the most common example is your libc.so.6 or whatever it is called on your system; try running it).
If you can run this executable from your shell but not from your file manager, the problem is with the file manager, not with the executable. You may have to specifically instruct the file manager that your program should run in a terminal. This usually can be done by creating a .desktop file that describes your program. In addition, desktop tools may mis-recognise modern executables as shared libraries. This is a common problem. It too can be remedied by creating a .desktop file for your executable. It is not specific to rust in any way.
Bottom line, there's nothing wrong with rustc or cargo or the way you are running them.

When you create your project initially you can simply use cargo new (or init) to get the right type
cargo new my_project_name
# OR create a lib project
cargo new --lib my_library_name
when you use rustc you can use a command-line option
rustc lib.rs
# lib.rs has to contain a main function
# OR to build a lib
rustc --crate-type=lib lib.rs
Your finding about shared object is misleading your error hunt: https://askubuntu.com/questions/690631/executables-vs-shared-objects - it's not a problem, an executable can be a shared object.
I think in your case the problem is another. What does you binary do? Does basically just print something via stdout and that's it? Maybe this is the reason why double clicking in the gui file browser does not show you anything, it runs a millisecond and is over before you know it.
Have you tried waiting for input at the end of the main function? Just so that the user can read the output and hit Return key.
use std::io;
fn main() {
// do and print stuff
// Wait for return key
let mut input = String::new();
match io::stdin().read_line(&mut input);
}
Not sure how thunar will deal with it but eventually he will open a terminal and show the result and close the terminal when enter is pressed.

cargo build
creates an executable file in target/debug/rust_bin
Then just
./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows
to execute, or just
cargo run
PS: you need to create a Cargo.toml file with the appropriate data inside.

Related

Define location of libgcc_s.so.1

First of all I am in a Debian VPS without SUDO permissions, without possibility of installing anything.
I want to run a program:
./program
And it informs me that it needs libgcc_s.so.1:
ERROR: ld.so: object '/lib/snoopy.so' from /etc/ld.so.preload cannot be preloaded (wrong ELF class: ELFCLASS64): ignored.
./program: error while loading shared libraries: libgcc_s.so.1: cannot open shared object file: No such file or directory
My question is, is there a way to run the program without having to install gcc-multilib (without sudo)?
I thought that maybe I could download gcc-multilib locally and specify the path in execution, but I don't know how.
Depending on how you compiled your program and on the system you are running it on, you should be a able to tell the system to load/find additional libraries in a specific directory using LD_LIBRARY_PATH.
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/your/custom/path/
From the manpage of ld.so
LD_LIBRARY_PATH
A list of directories in which to search for ELF libraries at
execution time. The items in the list are separated by either
colons or semicolons, and there is no support for escaping
either separator.
This variable is ignored in secure-execution mode.
Within the pathnames specified in LD_LIBRARY_PATH, the dynamic
linker expands the tokens $ORIGIN, $LIB, and $PLATFORM (or the
versions using curly braces around the names) as described
above in Rpath token expansion. Thus, for example, the fol‐
lowing would cause a library to be searched for in either the
lib or lib64 subdirectory below the directory containing the
program to be executed:
$ LD_LIBRARY_PATH='$ORIGIN/$LIB' prog
(Note the use of single quotes, which prevent expansion of
$ORIGIN and $LIB as shell variables!)
Here from the error message it seems you are trying to run a 32bit binary on a 64bit system. Adding the correct 32bit libraries should allow you to run your program.
Another option would be to "simply" compile your binary for a 64bit system. But that might be problematic if you not on a native 64bit system and would probably force you to cross compile.

Where are the shared and static libraries of the Rust standard library?

I am trying to compile my Rust project with dynamic linking to reduce the size and provide .so (or .dll on Windows) files with the application just like Qt does for Android. I read Why are Rust executables so huge? and compiled with
cargo rustc -- -C prefer-dynamic
When I run my program, I get this error:
% target/debug/t_pro
target/debug/t_pro: error while loading shared libraries: libstd-a021829e87e39dcf.so: cannot open shared object file: No such file or directory
I got an answer on Reddit.
rustc --print=sysroot
In my case, the .so files are in /home/username/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib and .rlib are in /home/username/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib.
The libraries are installed wherever you chose to install Rust. I use rustup on macOS, so they are installed in ~/.rustup/toolchains/*whatever*/lib/ for me.
Use your operating system's tools to search for files of a specific name.
See also:
How to set the environmental variable LD_LIBRARY_PATH in linux

How to produce executable with rustc?

If I compile this simple program fn main() { println!("Hello"); } with rustc test.rs -o test then I can run it with ./test, but double clicking it in the file manager gives this error: Could not display "test". There is no application installed for "shared library" file. Running file test seems to agree: test: ELF 64-bit LSB shared object....
How can I get rustc, and also tools that use it such as cargo, to produce executables rather than shared objects?
I am using 64-bit Linux (Ubuntu 14.10).
EDIT: I have posted on the Rust forum about this.
EDIT#: So it turns out this is an issue with the file executable.
I don't have the rust compiler and can't find its docs on the internet, but I know how to do shared obkect vs executable in C, so maybe this info will help you out in solving it.
The difference is the -pie option to the linker. With a hello world C program:
$ gcc test.c -ohello -fPIC -pie
$ file hello
hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
If we remove the position-independent flags, we get an executable:
$ gcc test.c -ohello
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
Both generated files work the same way from the command line, but I suspect the difference file sees is changing what your GUI does. (Again, I'm not on Ubuntu... I use Slackware without a gui file manager, so I can't confirm myself, but I hope my guesses will help you finish solving the problem yourself.)
So, what I'd try next if I was on your computer would be to check the rustc man page or rustc --help and see if there's an option to turn off that -pie option to the linker. It stands for "position independent executable", so look for those words in the help file too.
If it isn't mentioned, try rustc -v test.rs -o test - or whatever the verbose flag is in the help file. That should print out the command it uses to link at the end. It'll probably be a call to gcc or ld. You can use that to link it yourself (there's probably a flag -c or something that you can pass to rustc to tell it to compile only, do not link, which will leave just the .o file it generates).
Once you have that, just copy/paste the final link command rustc called and remove the -pie option yourself.... if it is there... and see what happens.
Manually copy/pasting isn't fun to do and won't work with tools, but if you can get it to work at least once, you can confirm my hunch and maybe ask a differently worded question to get more rust users' attention.
You might also be able to tell the file manager how to open the shared object files and just use them. If the manager treated them the same as programs file identifies as executables, as the command line does, everything should work without changing the build process. I don't know how to do that though, but maybe asking on the ubuntu stack exchange will find someone who does.
What you have described is not entirely consistent with what I observe:
$ rustc - -o test <<< 'fn main() { println!("Hello"); }'
$ ./test
Hello
$ file test
test: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=99e97fcdc41eb2d36c950b8b6794816b05cf854c, not stripped
Unless you tell rustc to produce a library with e.g. #![crate_type = "lib"] or --crate-type lib, it will produce an executable.
It sounds like your file manager may be being too smart for its own good. It should just be trusting the executable bit and executing it.

My library does not load on other systems but works fine on the system it was compiled on

My project includes a library and example projects for how to use it. I place the library in the "bin" folder along with all executable examples. I can run the example projects on the machine where they were compiled but when I try to run them on another machine I get:
./example: error while loading shared libraries: libMyLib.so: cannot
open shared object file: No such file or directory
This makes no sense since the library is in the same folder. What is causes it to ignore the library on other machines?
Just because the library is in the same directory as the executable doesn't mean it will look there for it. By default on linux, executables will only look in a limited set of directories, set by ldconfig and the LD_LIBRARY_PATH environment variable.
One trick that is very useful is to link your program with the extra linker option
-Wl,-rpath,'$ORIGIN'
which will cause the executable to also look in the directory the executable is in for shared objects.
You can usually set this by adding to your Makefile:
LDFLAGS := -Wl,-rpath,'$$ORIGIN'
Note the double-$ here -- make will interpret this as a make variable which expands to just $
The current directory is not necessarily a place where the dynamic linker will look for dynamic libraries. The directory where the executable is much less.
You might want to check ldconfig to see where it looks for them.

Compiling library in linux when in another folder

I'm new in Linux. I have a library in a folder next to my C program source but I don't know how to compile it. I've compiled everything when my library was in the same folder as program code file. However, I do not understand how to use the library from another location?
Use gcc's -L option to specify where your library located, and -l option to specify what your library is.
If you're using 'make' to build your program, just open the Makefile and find out where -L option has used.
For example,
gcc -L ./my_program/my_library -lmylib -o my_executable ./my_program/src/my_program.c
Also, you can use LD_LIBRARY_PATH environment variable to specify your library path to your program.
Say that you have ready to run your excutable, but the library is not in any standard library path (such as /usr/lib),
then you can run your program by following command.
$ LD_LIBRARY_PATH=/home/my_name/my_program/my_library my_executable

Resources