2

I'm trying to compile this program in ubuntu 18.04, 64 bits:

#include <math.h>
#include <stdio.h>

int main() {
  double x = 1.9;
  float y = 1.8;

  int x2 = ceil(x);
  int y2 = ceil(y);

  printf("%d, %d\n", x2, y2);
  return 0;
}

The gcc command I'm using is:

gcc -std=c99 -lm main.c -o main

And the error I'm obtaining is:

/tmp/ccWL94J9.o: In function `main':
main.c:(.text+0x30): undefined reference to `ceil'
main.c:(.text+0x41): undefined reference to `ceil'
collect2: error: ld returned 1 exit status

Although, if I replace ceil(x) by ceil(1.2) for example, and something similar for ceil(y), I can build and execute the program.

In addition, I have checked that I do have libm.so installed:

bash> find /usr/lib -name "*libm.so*"
/usr/lib/x86_64-linux-gnu/libm.so

What I'm missing?

Dan
  • 2,452
  • 20
  • 45

2 Answers2

1

With the following line, it compiles:

gcc -std=c99 main.c -o main -lm

(putting -lm after -o main)

See https://stackoverflow.com/a/11894098/4030665

Dan
  • 2,452
  • 20
  • 45
0

With some expressions E, particularly constants, the compiler can evaluate ceil(E) while it is compiling, and it does so if this optimization is not disabled. Then the compiler generates code that uses the result and does not call ceil. When the compiler fails to evaluate ceil(E) during compilation, it generates code that calls ceil.

The switch -lm is an abbreviation for the standard math library. The linker processes input files in the order they appear on the command line. When the linker processes a library, it extracts from the library all object modules that contain a definition for a symbol that is currently needed (referenced but not defined) in the executable file (or other output) it is building.

GCC maintains the order of the various units on its command line. Given -lm main.c, it compiles main.c to product an object module, and then it passes -lm and the object module to the linker in that order. Since the math library is first, when the linker processes it, it has not yet seen any symbols that reference it, and therefore it does not take any modules from the library.

If GCC is instead given main.c -lm, the linker processes the math library after the object module for main. Then, when the linker is processing the math library, it will know that main references ceil, so it will extract from the math library the module that defines ceil.

Thus gcc -std=c99 -lm main.c -o main will work with source code that uses only constants with ceil but will not work with the source code in the example, but gcc -std=c99 main.c -lm -o main will work.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312