1

I have a strange problem when I try to compile the below minimal example. The first call to sqrt poses no problem, but the second one raises a linker error which I don't understand because I do specify the math library when calling gcc. When I comment the second line, it compiles/links correctly.

Here is the code:

// File wtf_sqrt.c
#include <math.h>

int main (int argc, char *argv[]) {
  int x = 3;  // Just an int...
  
  sqrt(3);  // This line works fine
  sqrt(x);  // But this one seems to give the linker trouble. Why?
  
  return 0;
}

Here is my compilation command:

gcc -lm -o wtf_sqrt wtf_sqrt.c

And here is the error returned:

/tmp/ccgQN7y7.o: In function `main':
wtf_sqrt.c:(.text+0x1c): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status

I use gcc version 7.5.0 on an Ubuntu 18.04 LTS. libc6-dev is installed (proof is, sqrt works when I use it as in the first line of main). The code was written in gedit, so it should not be a problem with a blank character. Not sure what other info I can give you…

At this point, I really suspect this is a problem with my config/distribution, but I wanted some external advice.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • runs fine for me on cent os 7, may be the os you are using does not have it installed – csavvy Nov 12 '20 at 10:55
  • 4
    Order of arguments _might_ matter. Try moving `-lm` to after all of your source/object files. – aragaer Nov 12 '20 at 10:56
  • 3
    `sqrt(3);` can be replaced by the compiler with the square root of 3. Or optimized out, since it is not doing anything. – Weather Vane Nov 12 '20 at 10:58
  • 1
    Please see [Link order of libraries](https://www.linuxtopia.org/online_books/an_introduction_to_gcc/gccintro_18.html) – Weather Vane Nov 12 '20 at 11:02
  • 1
    Libraries are searched where they appear on the command line, so if `sqrt` is not referenced by the files that precede it, it may not be included. Move the `-lm` option to the end and it should work. – Tom Karzes Nov 12 '20 at 11:03
  • I think this is it, thank you so much! – MFolschette Nov 12 '20 at 13:01
  • [-lm doesnt work unless it's at the end of the command](https://stackoverflow.com/q/46722261/995714), [Why does the order of '-l' option in gcc matter?](https://stackoverflow.com/q/11893996/995714) – phuclv Nov 12 '20 at 13:24

3 Answers3

1

As suggested in comments by users aragaer, Weather Vane and Tom Karzes, the problem was the position of -lm in the compilation command. I falsely supposed that providing it first would be the correct way since then the linker might know where to find the function, but instead I should have provided it last so that the linker would already know that I need sqrt from my program. In fact, it is not only the order of -l options that matter, but also the order of files (to be) compiled. So the correct command is:

gcc -o wtf_sqrt wtf_sqrt.c -lm

As explained by user Weather Vane, the first call to sqrt is probably replaced or removed due to an optimization, thus producing no error.

1

This question actually has two parts, each of which is a duplicate of prior questions.

The fact that sqrt does not cause a link error when called with a constant argument is that the compiler evaluates it during compilation, as answered here, here, and here.

The fact that a link error is obtained even when -lm is included in the link is that -lm must be listed after modules that use the math library, as answered here, here, here, and here.

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

The problem might be in the argument that sqrt() takes. This is the function in math.h header:

_Check_return_ _CRT_JIT_INTRINSIC double __cdecl sqrt(_In_ double _X);

As you can see, the parameter type the function takes is a double. In your first sqrt() call, you pass the value of 3 by just typing it inside the parenthesis - the compiler probably treats this 3 as a double and compiles successfully. But in the second call, you pas as an argument x, which is an int (and you don't convert it into double). As C doesn't support function overloading, the compiler can't find the sqrt function which takes an int parameter and it pops up an error. Casting x into double should fix the problem:

sqrt((double)x);
pazdinh0_
  • 1
  • 1
  • The function which I pasted in here is from windows header, and you're using Ubuntu. But even in Linux "math.h" header shows that "sqrt" takes a double as a parameter – pazdinh0_ Nov 12 '20 at 12:04
  • Thank you for this suggestion. However, I forgot to mention that I already tried to cast `x` to `double` or even change the type of the variable, but it changes nothing. Plus, I found many examples on the web using `sqrt` on an `int` so I suppose it is not a problem. – MFolschette Nov 12 '20 at 13:00
  • 1
    `As C doesn't support function overloading, the compiler can't find the sqrt` makes no sense - C has implicit conversion, which occurs when calling a function. – KamilCuk Nov 12 '20 at 13:15