125

I have the following code (stripped down to the bare basics for this question):

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

double f1(double x)
{
    double res = sin(x);
    return 0;
}

/* The main function */
int main(void)
{
    return 0;
}

When compiling it with gcc test.c I get the following error, and I can't work out why:

/tmp/ccOF5bis.o: In function `f1':
test2.c:(.text+0x13): undefined reference to `sin'
collect2: ld returned 1 exit status

However, I've written various test programs that call sin from within the main function, and those work perfectly. I must be doing something obviously wrong here - but what is it?

alk
  • 69,737
  • 10
  • 105
  • 255
robintw
  • 27,571
  • 51
  • 138
  • 205

4 Answers4

148

You have compiled your code with references to the correct math.h header file, but when you attempted to link it, you forgot the option to include the math library. As a result, you can compile your .o object files, but not build your executable.

As Paul has already mentioned add "-lm" to link with the math library in the step where you are attempting to generate your executable.

In the comment, linuxD asks:

Why for sin() in <math.h>, do we need -lm option explicitly; but, not for printf() in <stdio.h>?

Because both these functions are implemented as part of the "Single UNIX Specification". This history of this standard is interesting, and is known by many names (IEEE Std 1003.1, X/Open Portability Guide, POSIX, Spec 1170).

This standard, specifically separates out the "Standard C library" routines from the "Standard C Mathematical Library" routines (page 277). The pertinent passage is copied below:

Standard C Library

The Standard C library is automatically searched by cc to resolve external references. This library supports all of the interfaces of the Base System, as defined in Volume 1, except for the Math Routines.

Standard C Mathematical Library

This library supports the Base System math routines, as defined in Volume 1. The cc option -lm is used to search this library.

The reasoning behind this separation was influenced by a number of factors:

  1. The UNIX wars led to increasing divergence from the original AT&T UNIX offering.
  2. The number of UNIX platforms added difficulty in developing software for the operating system.
  3. An attempt to define the lowest common denominator for software developers was launched, called 1988 POSIX.
  4. Software developers programmed against the POSIX standard to provide their software on "POSIX compliant systems" in order to reach more platforms.
  5. UNIX customers demanded "POSIX compliant" UNIX systems to run the software.

The pressures that fed into the decision to put -lm in a different library probably included, but are not limited to:

  1. It seems like a good way to keep the size of libc down, as many applications don't use functions embedded in the math library.
  2. It provides flexibility in math library implementation, where some math libraries rely on larger embedded lookup tables while others may rely on smaller lookup tables (computing solutions).
  3. For truly size constrained applications, it permits reimplementations of the math library in a non-standard way (like pulling out just sin() and putting it in a custom built library.

In any case, it is now part of the standard to not be automatically included as part of the C language, and that's why you must add -lm.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • 4
    why for sin (math.h), we need -lm option explicitly but not for printf() fn defined in stdio.h, I doubt on GNU's linker capabilities. As in VCC it works and on mac too as flarn2006 mentioned. – linuxD Mar 21 '13 at 05:55
  • 2
    @KeithThompson Added a lot to the answer to kill the comment. Enjoy. – Edwin Buck Jul 12 '17 at 15:11
  • Note that the system library on a Mac (running Mac OS X or macOS) includes the mathematical functions. There is a library to satisfy references to `-lm` in builds, but you don't need to use `-lm` to get the mathematical functions linked. The major issue leading to the separation of the maths library from the rest was that CPUs did not always have floating-point built-in; there were floating-point co-processors (80387, etc) and so on, so there were lots of ways to provide the functionality (using software floating point libraries, or using hardware, with different amounts of support). – Jonathan Leffler Aug 26 '17 at 19:52
  • Also note that the modern POSIX specification for [`c99`](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html) 'extended desciption — standard libraries' specifies the libraries somewhat differently — noting that the content of `-lm` (as one amongst a number of others) may be linked without necessarily needing an explicit mention on the linking command line. The quote in the answer is from SVID 4th Edition (dated July 1995). It is historically relevant, but no longer determinative. – Jonathan Leffler Aug 26 '17 at 20:12
85

I still have the problem with -lm added:

gcc -Wall -lm mtest.c -o mtest.o
mtest.c: In function 'f1':
mtest.c:6:12: warning: unused variable 'res' [-Wunused-variable]
/tmp/cc925Nmf.o: In function `f1':
mtest.c:(.text+0x19): undefined reference to `sin'
collect2: ld returned 1 exit status

I discovered recently that it does not work if you specify -lm first. The order matters. You must specify -lm last, like this:

gcc mtest.c -o mtest.o -lm

That links without problems.

So, you must specify the libraries at the end.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
Anyeos
  • 851
  • 6
  • 2
  • 1
    It is a problem that has been bugging gcc since forever :) I though that five years and 2 major releases would have cured it, instead it is still there! Amusing :) – Lorenzo Dematté Nov 14 '13 at 08:47
  • I also had the same problem suing the latest gcc 4.9 – Santiago Sep 12 '15 at 13:04
  • Happy to report that this does not happen with gcc 5.4 or gcc 6.2.1. – Pockets Jan 12 '17 at 18:43
  • 1
    Always link libraries after object files. That always works. Linking libraries before object files sometimes works and sometimes doesn't. (There are occasional exceptions — but they are very seldom encountered and you'll know when it's relevant and what to do, because the manuals for the library you're using will tell you, or because you wrote the manual.) – Jonathan Leffler Aug 26 '17 at 20:02
  • Thanks for this answer! This order problem still exists with `gcc --version` of `gcc (Ubuntu 8.4.0-1ubuntu1~18.04) 8.4.0`. This fails: `gcc -lm -Wall -Wextra -Werror -O3 -std=c17 math_sin_is_undefined.c -o bin/a`, but this passes: `gcc -Wall -Wextra -Werror -O3 -std=c17 math_sin_is_undefined.c -o bin/a -lm`. This also passes: `gcc -Wall -Wextra -Werror -O3 -std=c17 math_sin_is_undefined.c -lm -o bin/a`. – Gabriel Staples Mar 14 '22 at 03:45
  • See also [this comment by @paxdiablo](https://stackoverflow.com/questions/5248919/undefined-reference-to-sqrt-or-other-mathematical-functions#comment126310454_5248951) which adds additional clarification on what position `-lm` must take. – Gabriel Staples Mar 14 '22 at 04:24
42

You need to link with the math library, libm:

$ gcc -Wall foo.c -o foo -lm 
nos
  • 223,662
  • 58
  • 417
  • 506
Paul R
  • 208,748
  • 37
  • 389
  • 560
13

I had the same problem, which went away after I listed my library last: gcc prog.c -lm

blackappy
  • 625
  • 7
  • 11