Reputation: 609
In folder test
, I create hello.h
,hello.c
,main.c
.
My goal is to create a static lib from hello.h
, hello.c
and an executable file from the library and main.c
.
The following is what I have done.
hello.h:
#ifndef HELLO_H
#define HELLO_H
void hello(const char* name);
#endif
hello.c:
#include <stdio.h>
void hello(const char* name){
printf("hello %s! \n",name);
}
main.c:
#include "hello.h"
int main(){
hello("everyone");
return 0;
}
In the terminal (in the test
folder): I run
gcc -c hello.c
ar crv libmyhello.a hello.o // to create a staticlib
gcc -c main.c
ld -o Cuteee hello.o -lmyhello
>>> ld: cannot find -lmyhello
I wonder if anything is wrong?
Upvotes: 1
Views: 2267
Reputation: 61137
This takes account of your comments:
Then I tried ld -o Cuteee main.o -L. -lmyhello but still fails with ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0 ./libmyhello.a(hello.o): In function 'hello': hello.c:(.text+0x1e): undefined reference to 'printf' I am puzzled again.
gcc
is the GCC tooldriver for compiling and linking C programs.
When you invoke it with options and inputs that signify you want to a compile a C
source file, say hello.c
, it first invokes the GNU C compiler, cc1
, to compile hello.c
file to a temporary assembly file, say /tmp/cc8bfSqS.s
. It quietly adds to the compiler commandline
various boilerplate options that are invariant for compiling C
on your system, to spare you the trouble.
Then it invokes the GNU assembler, as
, to assemble /tmp/cc8bfSqS.s
to the object file
hello.o
.
You can pick out all of this from the compilation output if you ask gcc
to be verbose,
e.g.
gcc -v -c hello.c
When you invoke gcc
with options and inputs that signify you want to link
object files and possibly libraries into a program or shared library,
it invokes the GCC internal tool collect2
to do it - which
in turn invokes the system linker ld
- and gcc
quietly adds to the commandline
many boilerplate options, libraries and object files that are always
required for linking a C language program or shared library, once again to
spare you trouble.
You have used gcc
to compile hello.c
and main.c
and allowed it to Do The Right
Thing behind the scenes. You haven't attempted to invoke cc1
and as
yourself.
But in contrast, when you come to link your program, you haven't used gcc
; you've
invoked ld
yourself, without any of the boilerplate additions to the
the commandline that gcc
would make. That's why the linkage fails.
If you link your program with gcc
in verbose mode:
gcc -v -o Cuteee main.o -L. -lhello
you can pick the collect2
commandline out of the output, something like:
/usr/lib/gcc/x86_64-linux-gnu/7/collect2 \
-plugin /usr/lib/gcc/x86_64-linux-gnu/7/liblto_plugin.so \
-plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper \
-plugin-opt=-fresolution=/tmp/ccgWPdno.res \
-plugin-opt=-pass-through=-lgcc \
-plugin-opt=-pass-through=-lgcc_s \
-plugin-opt=-pass-through=-lc \
-plugin-opt=-pass-through=-lgcc \
-plugin-opt=-pass-through=-lgcc_s \
--sysroot=/ --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu \
--as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
-pie -z now -z relro -o Cuteee \
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o \
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o \
/usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o -L. \
-L/usr/lib/gcc/x86_64-linux-gnu/7 \
-L/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu \
-L/usr/lib/gcc/x86_64-linux-gnu/7/../../../../lib \
-L/lib/x86_64-linux-gnu -L/lib/../lib \
-L/usr/lib/x86_64-linux-gnu \
-L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/7/../../.. \
main.o -lhello -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc \
--as-needed -lgcc_s --no-as-needed \
/usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o \
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
All of those options that are passed to collect2
are passed through to
ld
. So if you replace /usr/lib/gcc/x86_64-linux-gnu/7/collect2
with
ld
in that monster commandline (or rather the commandline you get on
your own system), you will find that it links your program ./Cuteee
.
That is what linking the program with gcc
does, over an above:
ld -o Cuteee hello.o -lmyhello
One of the errors that your linkage attempt fails on:
cannot find entry symbol _start
is due to the fact that you haven't linked Scrt1.o
(/usr/lib/x86_64-linux-gnu/Scrt1.o
,
in the commandline above) which contains the C runtime initialization code for
a dynamically linked C program: it defines the symbol _start
, whose address is the entry point of the program,
to which the loader passes initial control at runtime, and after program initialization
is complete it calls main
.
The other linkage error:
undefined reference to 'printf
is due to the fact that you haven't linked the standard C library, -lc
(/lib/x86_64-linux-gnu/libc.so.6
).
Programmers don't link with ld
directly if they don't have to - e.g.
unless they're targeting an application to a bare-metal environment, and you
can see why.
Upvotes: 1
Reputation: 16540
the following proposed code:
And now the proposed changes to the posted code and command line statements:
hello.h
#ifndef HELLO_H
#define HELLO_H
void hello( const char* );
#endif
=======================
hello.c:
#include <stdio.h>
#include "hello.h"
void hello(const char* name)
{
printf("hello %s! \n",name);
}
========================
main.c:
#include "hello.h"
int main( void )
{
hello("everyone");
return 0;
}
=========================
In terminal (in test folder):
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c hello.c -o hello.o -I.
ar crv libmyhello.a hello.o
=========================
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c main.c -o main.o -I.
ld -static main.o -o Cuteee -L. -lmyhello
=========================
./Cuteee
=========================
this should eliminate the error message:
>>> ld: cannot find -lmyhello
Upvotes: 1
Reputation: 2616
You need to provide -L
to let gcc know where to look for your -l
libraries:
gcc -c hello.c
ar crv libmyhello.a hello.o
gcc -c main.c
gcc main.o -L. -lmyhello -o Cuteee
To create the final executable it's enough to use gcc, ld is not needed.
See this question in order to understand why you probably don't need to use ld
specifically.
Upvotes: 2