Search code examples
clinkergentoogcc4

Linking multiple C source files


I'm on gentoo linux with GCC 4.4.5 installed. I can compile and link such program without any errors using gcc main.c -o main, and the command ./main returns result correctly.

[main.c] 
#include <math.h>
#include <stdio.h>
int main(void)
{
    double c = ceil(2.5);
    printf("The ceil of 2.5 is %f\n", c);
    return 0;
}

But when I put the invokation of ceil into another source file, the problem occurs.

[calc.h]
#ifndef _CALC_H_
#define _CALC_H_
double myceil(double n);
#endif

[calc.c]
#include <math.h>
#include "calc.h"
double myceil(double n)
{
    return ceil(n);
}

[main1.c]
#include <stdio.h>
#include "calc.h"
int main(void)
{
    double c = myceil(2.5);
    printf("The ceil of 2.5 is %f\n", c);
    return 0;
}

Using the command gcc calc.c main1.c -o main1, such error occurs:

/tmp/cc6GhJvZ.o: In function `myceil':
calc.c:(.text+0x19): undefined reference to `ceil'
collect2: ld returned 1 exit status

So why did the annoying error "undefined references" happen in the latter case? And I know the error could be eliminated by adding an library -lm, however, I just want to know why gcc will throw the error in the latter case.


Solution

  • My guess is that GCC optimizes ceil(2.5) to a constant, whereas ceil(n) is not constant because n is not known when compiling calc.c, and it needs to reference the function. You can confirm this by looking at the assembly output (gcc -S).

    Update: Here's what gcc 4.2.1 on x86 gave me for something similar to your first example:

    .LC1:
        .string "%f\n"
        // [snip]
    main:
        // [snip]
        fldl    .LC0
        fstpl   4(%esp)
        movl    $.LC1, (%esp)
        call    printf
        // [snip]
    .LC0:
        .long   0
        .long   1074266112
    

    Here we see printf being called with a double constant.

    Now if I do something similar to your second example:

    myceil:
        // [snip]
        fldl    -8(%ebp)
        fstpl   (%esp)
        call    ceil
        // [snip]
    

    Here we see ceil being referenced.

    So yeah. I'd say your call is being optimized to a constant in the one that works without -lm.