How to produce executable with rustc? - rust

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.

Related

Rust not compiling to executable in 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.

what does "-sh: executable_path:not found" mean

i am trying to run an executable in linux shell ( OpenELEC on raspberry pi )
OpenELEC:~ # /storage/fingi/usr/lib/autossh/autossh
-sh: /storage/fingi/usr/lib/autossh/autossh: not found
What does the "not found" in this case mean ?
If i try to do ldd:
OpenELEC:~ # ldd /storage/fingi/usr/lib/autossh/autossh
/usr/bin/ldd: eval: line 1: /storage/fingi/usr/lib/autossh/autossh: not found
And if i do file:
OpenELEC:~ # file /storage/fingi/usr/lib/autossh/autossh
/storage/fingi/usr/lib/autossh/autossh: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=599207c47d75b62ede5f214f9322ae2a18643eb7, stripped
The file type is in correct format . But it wont work adn wont give more descriptive error msg either.
Since openELEC is very restrictive, i had copied the autossh executable from a raspbmc installation . I have done it for several other executables as well ( screen , boost libraries etc ) and they work fine .
Can anyone suggest what might be the issue?
Edit 1:
as was suggested, this is the output of file command on an executable ( also copied from raspbmc ) that is working:
OpenELEC:~ # file /storage/fingi/usr/bin/screen
/storage/fingi/usr/bin/screen: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=5c58f047a25caa2c51a81d8285b4f314abc690e7, stripped
What does the "not found" in this case mean ?
This usually means that the executable cannot find one or more (shared) libraries to satisfy its external symbols.
This usually happens when no libraries are stored in the initramfs, or there is a shared library missing that the executable needs.
This can also happen if the executable is built with a C library that is incompatible with the runtime library, e.g. uClibc versus glibc/eglibc.
strings executable | less is the quickest way to see the required libraries and external symbols that the executable requires.
Or
Recompile your program and use static linking by specifying the -static option.
Check that the file has been set to executable permissions with ls -l if it hasn't change with chmod +x /storage/fingi/usr/lib/autossh/autossh

How to see which static libraries were used for gcc/g++ compilation from the generated binary?

Context: I'm using a linux toolchain (includes g++, other build tools, libs, headers, etc) to build my code with statically linked libraries. I want to ensure that I'm using ONLY libraries/headers from my toolchain, not the default ones on the build machine. I can use strace to see what g++ is doing (which libraries it is using) while it is compiling which would be helpful in a normal scenario - but my build system has many wrappers around g++ that hide all of the output.
Question: is there a way to obtain from a statically-linked binary any useful information regarding the library and header files which were used to create the binary? I've taken a look at the objdump tool but I'm not sure if it will help much.
Just pass -v to g++ or gcc at link time. It will show all the linked libraries. Perhaps try make CC='gcc -v' CXX='g++ -v'
More generally, -v passed g++ or gcc shows you the underlying command with its arguments because gcc or g++ is just a driver program (starting cc1, ld or collect2, as, ...)
By passing the -H flag to GCC (i.e. g++ or gcc) you can see every included header. So you can check that only the heanders you expect are included.
You cannot see what static library has been linked, because linking a static library just means linking the relevant object file members in it, so a static library can (and usually is) linked in only partly.
You could use the nm command to find names from such libraries.
If you can simply recompile, then there are ways (using some of the techniques that Basile explained) to get the headers and libraries (static or dynamic) but, unfortunately, there is no way to know which libraries were used after the compilation is complete.

Does linker include libc.so.6 in statically linked file?

When I link executable elf file dynamically it needs libc.so.6 shared library.
When I link executable elf file statically it doesn't need libc.so.6 shared library (it's not surprise).
Does it mean, that to assemble executable file with --static, linker includes libc.so.6 in it?
If not - what file does linker include? where can I search it?
As far as I know, linker includes static libraries in statically assembled file.
If you link as static, the linker will link all the needed object (.o) files from the static libraries (.a). For example, the following command lists the object files which are included in the libc6 library:
ar t /usr/lib/libc.a
(the exact path to libc.a of course differs from system to system)
So answer to your question is no, it will not link the whole libc6 library, but only the needed object files. And also, it doesn't do anything with libc.so.6, since this is only for dynamic linking. It works with the libc.a - static version of the library.
According to #janneb comment, the smallest unit to be linked is "section", so it might not even need to link the whole object files.
The linker is the ld command. If you use that command, it does what you ask. Notice that GNU ld can accept scripts
However, most people are using the gcc command. This is a compiler from the Gnu Compiler Collection suite. Actually, the gcc command is just a driver program, which will run cc1 (the proper C compiler), as, ld and collect2 (which deals with initializations, etc. then invoke the linker).
To understand what exact command[s] gcc is running, pass it the -v program flag.
When you pass -static to gcc it will probably link with e.g. /usr/lib/x86_64-linux-gnu/libc.a or some other static form of the GNU Libc library.

how to make sure a program or shared library is compiled with -g, in linux

I want to make sure my execute program is debug-able, what command can get the infomation.
I am a fan of using file to get information on executables and shared libraries.
The one key you are looking for is stripped in the description. If it is stripped it definitely does not have your debug symbols. Sadly, I am thinking a binary can still have no debug info but not be stripped.
$ file /usr/bin/file
/usr/bin/file: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped
You can use objdump with the --debugging and --debugging-tags options

Resources