Search code examples
clinkerextern

C: compiling and linking component programs separately using 'ld'?


I am trying to understand extern and linking. As a simple demonstration I have written two C files: a main file which uses a function and another file that defines the function:

/* main.c */
#include <stdio.h>
extern void print_nos(int, int);
int main(void) {
    print_nos(10, 20);
    return 0;
}
/* print_nos.c */
#include <stdio.h>
void print_nos(int lower, int higher) {
    int i;
    for (i = lower; i <= higher; i++)
        printf("%d ", i);
    printf("\n");
}

I have two questions pertaining to this:

1)

I know that I can simply pass both files as arguments to gcc at once:

gcc -o main main.c print_nos.c

And this works fine, but I wanted to do the linking explicitly using ld, so I did:

$ gcc -c main.c        # produces main.o
$ gcc -c print_nos.c   # produces print_nos.o
$ ld -o main main.o print_nos.o -lc
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401050

As you can see, I get the above warning and when I try to run the output file :

$ ./main
-bash: ./main: No such file or directory

I do not have much experience in assembly so I do not where to begin troubleshooting this - any help is appreciated.

2)

Secondly, when I remove the extern specifier, and try running gcc -o main.c print_nos.c the program compiles just fine. Does a function need to be declared extern at all? When I peeked into all the standard include files like stdlib, stdio, etc I saw that all the functions have an extern declaration. Should I therefore use extern in my case (in actual code resembling the one above)?


Solution

  • I wouldn't recommend using ld directly unless you know what you're doing and have a good reason. If you want to compile modules separately (which is a good idea, so you can recompile only the ones whose source files have changed) you can use gcc to do both the compiling and linking, like this:

    gcc -c main.c        # produces main.o
    gcc -c print_nos.c   # produces print_nos.o
    gcc -o main main.o print_nos.o
    

    As for the extern specifier, you don't need it for functions. Function declarations are implicitly extern by default.