How to link a simple program in Windows with Mingw GCC - c

I have a simple "Hello World!" c program, named hello.c on my desktop:
#include <stdio.h>
int main() {
printf("Hello world!\n");
return 0;
}
I run the following commands.
I pre-process it with : cpp hello.c > hello.i
I compile it with : gcc -S hello.i
I assemble it with : as -o hello.o hello.s
All good so far. But, i'm unable to link it. I've tried, among other commands, these:
ld -o hello.exe hello.o
ld -o hello.exe hello.o -lgcc
ld -o hello.exe hello.o -nostdlib -lgcc
Nothing works. The link errors i get in every single case are :
hello.o:hello.c:(.text+0x9): undefined reference to `__main'
hello.o:hello.c:(.text+0x15): undefined reference to `puts'
How can i link this assembled program hello.o in order to finally produce the executable program hello.exe? What am i missing? [Using Windows 8.1, Mingw version 0.6.2.] Thanks in advance.

Even if your answers to clarification questions are not particularly useful:
Try something like
ld hello.o -lmsvcrt -entry=_main -subsystem=console -o hello.exe
If you want to see the linker command line the standard gcc uses, invoke gcc like so:
gcc test.c -o test -Wl,-v
The last lines output is what you should be using...

If you want to compile something rather than experimenting with tools, don't link it using the linker directly. Use gcc, which will call the linker for you with the right options:
Compile step:
gcc -c hello.c
Link step:
gcc -o hello.exe hello.o
Or all in one:
gcc -o hello.exe hello.c
You can also use a simple Makefile, then run make:
all: hello.exe

Related

Cannot find -lCommunication collect2: error: ld returned 1 exit status

I do not know gcc and c well. In my /home/pi/Desktop/intern/adis16227_generic directory I have following 5 files.
ADIS16227.c
ADIS16227.h
Communication.c
Communication.h
main.c
main.c
#include<stdio.h>
#include "Communication.h" // Communication definitions.
int main() {
printf("hello!!\n");
unsigned char status = 0;
status = SPI_Init(0, 1000000, 1, 1);
printf("%u", status);
return 0;
}
Run command:
$ sudo gcc -L /home/pi/Desktop/intern/adis16227_generic main.c -lCommunication
Error:
/usr/bin/ld: cannot find -lCommunication
collect2: error: ld returned 1 exit status
Question:
What I am missing here?
What do I need to run the code?
-l is for libraries, and you never built a library from your Communication.c. The simplest solution is just add Communication.c to your compiler command line.
For larger projects, compile each translation unit separately with the -c switch like this:
gcc -c -Wall -Wextra -pedantic -omain.o main.c
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
and so on ... (as a suggestion, I added some common warning options here, they help you spot errors)
The resulting .o files are object code. That's already compiled machine code, but with meta-information needed for a linker to link it with other object code into a complete executable.
Then link them all with one command:
gcc -oprogram main.o Communication.o
If you actually want a library from -- say -- Communication.c and ADIS16227.c, you could compile both to object code:
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
gcc -c -Wall -Wextra -pedantic --oADIS16227.o ADIS16227.c
and then use ar to create a static library from them:
ar rcs libCommunication.a Communication.o ADIS16227.o
Then your initial compiler command would work (with the -lCommunication switch).
Final piece of advice: Never compile as root. This is completely unnecessary. So remove your sudo here.
those options:
-L /home/pi/Desktop/intern/adis16227_generic -lCommunication
suggest that the linker should find libCommunication.a (or .so) in the /home/pi/Desktop/intern/adis16227_generic directory.
But there are only sources in this directory. The linker won't build the sources of your "Communication" library for you.
So you could build the library and link with it:
gcc -c ADIS16227.c Communication.c
ar r libCommunication.a ADIS16227.o Communication.o
but maybe the fastest & quickest way to achieve a successful build would be:
sudo gcc -o main *.c
so it compiles all the files of the directory into the executable called main
Of course, it makes compilation times longer, but maybe it's not noticeable.
First move into the /home/pi/Desktop/intern/adis16227_generic directory:
cd /home/pi/Desktop/intern/adis16227_generic
Then, compile the source:
gcc ADIS16227.c Communication.c main.c -I .
You can now run your compiled program (called by default a.out):
./a.out
You have to compile separatedly files and then compile main with related obj file.
gcc -c Communication.c Communication.h
gcc main.c Communication.o -o main

Am I writing this makefile correctly?

I am learning how to write C code in Linux and I am learning makefiles at a very beginner level.
I am having problems when making shared libraries.
The exercise is to make a simple function calculator C program with files:
main.c
add.c
subt.c
mult.c
div.c
The names of the files define the function they do.
The function in the file subt.c is in the static library:
libsubstatic.a
The function in the file mult.c is in the shared library:
libmultshared.so
For this program, I write the following makefile:
calc.exe: main.o add.o div.o libsubstatic.a libmultshared.so
gcc -o calc.exe main.o add.o div.o libsubstatic.a -Wl,-rpath,/home/ahmed/Desktop/labTask3 -lmultshared.so
main.o: main.c header.h
gcc -c main.c
add.o: add.c header.h
gcc -c add.c
libsubstatic.a: subt.o
ar cr libsubstatic.a subt.o
subt.o: subt.c header.h
gcc -c subt.c
libmultshared.so: mult.o
gcc -shared -fPIC -o libmultshared.so mult.o
mult.o: mult.c header.h
gcc -c -fPIC mult.c
div.o: div.c header.h
gcc -c div.c
The path where the code and makefile is placed:
/home/ahmed/Desktop/labTask3
I get the following message after I type "make" in the terminal:
gcc -o calc.exe main.o add.o div.o libsubstatic.a -Wl, -rpath, /home/ahmed/Desktop/labTask3 -lmultshared.so
gcc: error: unrecognized command line option ‘-rpath,’
make: *** [calc.exe] Error 1
What am I missing? Did I write this makefile correctly?
Please explain shared libraries, my concept might be faulty.
Please help.
Note that, I'm new to linux and I don't have much experience in makefiles.
EDIT: I removed the spaces as directed in the first answer. Now the terminal says:
gcc -o calc.exe main.o add.o div.o libsubstatic.a -Wl,-rpath,/home/ahmed/Desktop/labTask3 -lmultshared.so
/usr/bin/ld: cannot find -lmultshared.so
collect2: error: ld returned 1 exit status
make: *** [calc.exe] Error 1
Should I do something with the "-lmultshared.so"? What should I do?
-Wl, -rpath, /home/ahmed/Desktop/labTask3
Get rid of the spaces. This should all be one long argument.
-Wl,-rpath,/home/ahmed/Desktop/labTask3
See this excellent answer by #KerrekSB for a detailed explanation about passing arguments to the linker with -Wl.

How to make c program as executable in windows 7

For a simple "hello world" application, I used the following commands in order to create an .exe file using the GCC Compiler:
cpp hello.c > hello.i
(successful)
gcc -S hello.i
(successful)
as -o hello.o hello.s
(succesful)
When finally linking the files with the following command to obtain an .exe, I get an error:
C:\C_Experiments\test>ld -o test2.exe test2.o
test2.o:test2.c:(.text+ 0 x 9): undefined reference to __main
test2.o:test2.c:(.text+0 x 15): undefined reference to printf
ld: test2.o: bad reloc address 0x0 in section `.pdata'
You need to link with the runtime library which contains the startup function and all other standard functions.
Why not skip the preprocessor and assembler step, and go directly to object file? And also use gcc when linking which will add the needed extra libraries automatically? Or for simple single-source-file programs go directly to executable?
Either
$ gcc hello.c -c -o hello.o
$ gcc hello.o -o hello
Or
$ gcc hello.c -o hello

Error compiling c using gcc on AIX

I'm trying to build a simple c application using gcc on aix
gcc -I. -c hello.c -o hello.o
gcc -o helloWorld hello.o -L helloHelper.so -ldl
I get the following errors
ld 0711-317 ERROR: Undefined symbol: .PrintHello
PrintHello is a method in the library helloHelper.
I can build the application in windows.
The option -L is for indicating directories where to search for libraries. To link a dynamic library directly, just put it in the linker command:
gcc -o helloWorld hello.o helloHelper.so -ldl
Other option would be to use -lhelloHelper but then the library should be called libhelloHelper.so.
Try this:
gcc -o helloworld hello.o -L. -lhelloHelper -ldl

Running gcc's steps manually, compiling, assembling, linking

If you have a simple C program, like
int main(void) {return 0;}
It can be compiled with gcc -o test test.c.
As I understand, gcc performs compiling, assembling then linking. The latter two steps are achieved by it running as and ld.
I can generate the assembly code by using gcc -S test.c.
What would you type into a terminal, to convert the assembly code into an executable?
(the reason for doing so is to learn assembly)
These are the different stages using gcc
gcc -E --> Preprocessor, but don't compile
gcc -S --> Compile but don't assemble
gcc -c --> Preprocess, compile, and assemble, but don't link
gcc with no switch will link your object files and generate the executable
// main.c
#include <stdio.h>
int main(void)
{
printf("Hello World !\n");
return 0;
}
For preprocessing, compiling, assembling and then finally linking the simple aforementioned hello world program, follow the steps below:
Step 1/4) Preprocess main.c to generate main.i:
$: gcc -E main.c -o main.i
NOTE: You could call the C preprocessor directly as well:
$: cpp main.c -o main.i
Step 2/4) Compile main.i to generate main.s:
$: gcc -S main.i -o main.s
Step 3/4) Assemble main.s to generate main.o:
$: as main.s -o main.o
NOTE: You can combine the aforementioned steps 1, 2 and 3 by using the -c (small C) flag of gcc:
$: gcc -c main.s -o main.o // OR $: gcc -c main.c -o main.o
Step 4/4) Link main.o with other necessary object files namely, crti.o & crtn.o (they define function prologs & epilogs, respectively), crt1.o (contains _start symbol for bootstrapping the initial execution of the program), libc.so path or -lc flag for libc and then finally set the name of the dynamic linker, to generate a dynamically linked ELF executable:
On x86_64:
$: ld /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/x86_64-linux-gnu/crtn.o /usr/lib/x86_64-linux-gnu/crt1.o -lc main.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o main_ELF_executable
OR (if you'd like to specify path to libc.so)
$: ld /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/x86_64-linux-gnu/crtn.o /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/libc.so main.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o main_ELF_executable
On 32-bit ARM:
$: ld /usr/lib/arm-linux-gnueabihf/crti.o /usr/lib/arm-linux-gnueabihf/crtn.o /usr/lib/arm-linux-gnueabihf/crt1.o -lc main.o -dynamic-linker /lib/ld-linux.so.3 -o main_ELF_executable
OR (if you'd like to specify path to libc.so)
$: ld /usr/lib/arm-linux-gnueabihf/crti.o /usr/lib/arm-linux-gnueabihf/crtn.o /usr/lib/arm-linux-gnueabihf/crt1.o /usr/lib/arm-linux-gnueabihf/libc.so main.o -dynamic-linker /lib/ld-linux-armhf.so.3 -o main_ELF_executable
You can then run the ELF executable 'main_ELF_executable':
$: ./main_ELF_executable
Hello World !
Sources:
https://linux.die.net/man/1/gcc
https://linux.die.net/man/1/ld
https://dev.gentoo.org/~vapier/crt.txt
gcc test.s -o test will compile the test from test.s for you.
NASM might also be worth your time -- it might be easier / more friendly than gcc for compiling assembly.
After you do gcc -S -o test.s test.c, type gcc -o test test.s.
As you may or may not know, the four stages of compilation are to preprocess (-E), compile to assembly (-S), assemble to object code (-c), and finally link. The hardest for me to figure out was how to use the preprocessor output. Here's how to do it:
gcc -E hello.c | gcc -S -xc -o hello.s -
gcc -c hello.s -o hello.o
gcc hello.o -o hello
You can have gcc start and stop the compilation process wherever you want. gcc test.s -o test will have it compile test.s from assembly into an executable.
what I did was first I run the preprocessor by
clang++ test.cpp -E > test.i
then compiled it with ...
clang++ -S test.i
it should create a assembly file test.s ... then make the machine insturction file by
as test.s -o test.o
now you need to link it which is kinda confusing for dumb peoples like me ...
so we don't know the arguments for our last process which is linking ... to find out ... run
clang++ -v test.s
it should give you some big text of something ... find this line "-dynamic-linker" ... there's definately a -dynamic-linker in your output text ... now copy the text from -dynamic-linker to rest of the output ... just copy everything afterwards including "-dynamic-linker" ... now what i got is ...
-dynamic-linker /system/bin/linker -o a.out /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtbegin_dynamic.o -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0 -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../.. -L/data/data/com.termux/files/usr/lib -L/system/lib /data/data/com.termux/files/usr/tmp/test-169b42.o -lc++_shared -lgcc -ldl -lm -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtend_android.o
in this what you have to change is where your object file is ... in my case it is /data/data/com.termux/files/usr/tmp/test-169b42.o ... i need to change it to where my test.o file is ... /data/data/com.termux/files/home/CPP/Cpp_Log/hello_world/test.o ... this is where my test.o file is ...
so the argument we have to pass is ...
-dynamic-linker /system/bin/linker -o a.out /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtbegin_dynamic.o -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0 -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../.. -L/data/data/com.termux/files/usr/lib -L/system/lib /data/data/com.termux/files/home/CPP/Cpp_Log/hello_world/main.o -lc++_shared -lgcc -ldl -lm -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtend_android.o
now to link ... use the ld ... so the command is ld args -o test or in our case ...
ld -dynamic-linker /system/bin/linker -o a.out /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtbegin_dynamic.o -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0 -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../.. -L/data/data/com.termux/files/usr/lib -L/system/lib /data/data/com.termux/files/home/CPP/Cpp_Log/hello_world/main.o -lc++_shared -lgcc -ldl -lm -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtend_android.o -pie -o test ...
since andriod 5+ can only run pie elf executables ... i also added the "-pie" (position independent executable) before the -o test ...
now it should give you a executable file test ... just run it by ./test
it should work

Resources