286

If I include <stdlib.h> or <stdio.h> in a C program I don't have to link these when compiling but I do have to link to <math.h>, using -lm with gcc, for example:

gcc test.c -o test -lm

What is the reason for this? Why do I have to explicitly link the math library but not the other libraries?

Chris
  • 39,262
  • 15
  • 126
  • 145
Nope
  • 29,782
  • 41
  • 91
  • 115

13 Answers13

277

The functions in stdlib.h and stdio.h have implementations in libc.so (or libc.a for static linking), which is linked into your executable by default (as if -lc were specified). GCC can be instructed to avoid this automatic link with the -nostdlib or -nodefaultlibs options.

The math functions in math.h have implementations in libm.so (or libm.a for static linking), and libm is not linked in by default. There are historical reasons for this libm/libc split, none of them very convincing.

Interestingly, the C++ runtime libstdc++ requires libm, so if you compile a C++ program with GCC (g++), you will automatically get libm linked in.

crisron
  • 333
  • 1
  • 5
  • 18
ephemient
  • 180,829
  • 34
  • 259
  • 378
  • OK, so this becomes a library design question - why are the libraries partitioned in this way? –  Jun 23 '09 at 17:24
  • 1
    I bet to optimize the build time of UNIX itself (and the toolset that went along with it). At the time, it was probably the most complex thing that was being built in C. – Lou Franco Jun 23 '09 at 17:26
  • anything to do with fpu emulation? but for linux the eventual emulation is in kernel and not the libm.. right? – Joakim Elofsson Jun 23 '09 at 17:27
  • I've read that it's because it was common for Unix hackers to write their own math functions. – Bastien Léonard Jun 23 '09 at 17:31
  • 10
    This has nothing to do with Linux, since it was common long before Linux. I suspect it has something to do with trying to minimize executable size, since there's a lot of programs that don't need math functions. – David Thornley Jun 23 '09 at 17:35
  • 42
    On ancient systems, if math functions were contained in libc, then compiling all programs would be slower, the output executables would be larger, and runtime would require more memory, with no benefit to *most* programs which do not use these math functions at all. These days we have good support for shared libraries, and even when statically linking, the standard libraries are set up so that unused code can be discarded, so none of these are good reasons anymore. – ephemient Jun 23 '09 at 17:38
  • @ephemient: Do you have a link to get relevant information about this? – Eliseo Ocampos Jun 23 '09 at 17:39
  • @ephemient: that last comment is a good reason and likely to be true :-P. Edit that into your post and you've got my +1. – Evan Teran Jun 23 '09 at 17:40
  • 42
    @ephemient Even in the old days, linking to a library did not pull in all the contents of the library to the executable. Linkers, although an often ignored technology, have historically been quite efficent. –  Jun 23 '09 at 17:43
  • 9
    @ephemient Also, shared libraries have been around for longer than you might think. They were invented in the 1950s, not the 1980s. –  Jun 23 '09 at 17:46
  • 1
    It depends on how the objects in the library archive are set up, and since many of those systems predate **me**, I can't accurately make claims about them. It does make sense that the system's creators would do extra work up-front to split the library objects to enable this, though. – ephemient Jun 23 '09 at 17:47
  • 1
    Shared libraries have been around for forever, but as far as I know, many systems still used statically linked libraries even for libc. Stratus VOS, for example, is still deployed and maintained, and most deployments have no shared libraries at all... – ephemient Jun 23 '09 at 17:49
  • 7
    I suppose at the end of the day what we are looking at is nothing more than GCC conservatism: "it's always worked like that". I only wish they applied the same reasoning to their compiler extensions. –  Jun 23 '09 at 17:59
  • 1
    I can't realistically imagine that anything would break if libm were merged into libc (and libm turned into an empty stub, so `-lm` doesn't fail). Oh well. – ephemient Jun 23 '09 at 18:27
  • 1
    @Niel Use -std=c99 or whatever. – Jed Nov 07 '09 at 22:00
  • Why is it that on llvm gcc I can omit -lm? – bot47 Dec 14 '11 at 13:31
  • 1
    Hi, I'm curious why gcc -std=c89 needs -lm flag, clang -std=c89, c99, c11 also need this flag, but gcc -std=c99, c11 do not. GCC 4.8.1, clang 3.5 svn trunk. – sasha.sochka Jan 14 '14 at 16:11
  • Why do you say reasons are not convincing. It makes perfect sense to split math functions from standard library. – doc Dec 09 '19 at 16:03
85

Remember that C is an old language and that FPUs are a relatively recent phenomenon. I first saw C on 8-bit processors where it was a lot of work to do even 32-bit integer arithmetic. Many of these implementations didn't even have a floating point math library available!

Even on the first 68000 machines (Mac, Atari ST, Amiga), floating point coprocessors were often expensive add-ons.

To do all that floating point math, you needed a pretty sizable library. And the math was going to be slow. So you rarely used floats. You tried to do everything with integers or scaled integers. When you had to include math.h, you gritted your teeth. Often, you'd write your own approximations and lookup tables to avoid it.

Trade-offs existed for a long time. Sometimes there were competing math packages called "fastmath" or such. What's the best solution for math? Really accurate but slow stuff? Inaccurate but fast? Big tables for trig functions? It wasn't until coprocessors were guaranteed to be in the computer that most implementations became obvious. I imagine that there's some programmer out there somewhere right now, working on an embedded chip, trying to decide whether to bring in the math library to handle some math problem.

That's why math wasn't standard. Many or maybe most programs didn't use a single float. If FPUs had always been around and floats and doubles were always cheap to operate on, no doubt there would have been a "stdmath".

Nosredna
  • 74,873
  • 15
  • 91
  • 122
  • Heh, I am using Pade approximants for (1+x)^y in Java, in a desktop PC. Log, exp and pow are still slow. – quant_dev Jun 24 '09 at 06:23
  • Good point. And I've seen approximations for sin() in audio plugins. – Nosredna Jun 24 '09 at 16:03
  • 12
    This explains why `libm` isn't linked in by default, but math was *standard* from C89 and before that, K&R had *de facto* standardized it, so your "stdmath" remark doesn't make sense. – Fred Foo Nov 14 '11 at 09:36
  • 1
    @FredFoo The types and interfaces were standardized, but not the implementations. I think Nosredna is referring to a standard math library. – Tim Bird Jan 22 '20 at 18:57
78

Because of ridiculous historical practice that nobody is willing to fix. Consolidating all of the functions required by C and POSIX into a single library file would not only avoid this question getting asked over and over, but would also save a significant amount of time and memory when dynamic linking, since each .so file linked requires the filesystem operations to locate and find it, and a few pages for its static variables, relocations, etc.

An implementation where all functions are in one library and the -lm, -lpthread, -lrt, etc. options are all no-ops (or link to empty .a files) is perfectly POSIX conformant and certainly preferable.

Note: I'm talking about POSIX because C itself does not specify anything about how the compiler is invoked. Thus you can just treat gcc -std=c99 -lm as the implementation-specific way the compiler must be invoked for conformant behavior.

Aaron Hall
  • 291,450
  • 75
  • 369
  • 312
R.. GitHub STOP HELPING ICE
  • 195,354
  • 31
  • 331
  • 669
  • 10
    +1 for pointing out that POSIX doesn't require that separated libm, libc and librt libraries exist. As an example, on Mac OS everything is located in a single libSystem (which also includes libdbm, libdl, libgcc_s, libinfo, libm, libpoll, libproc and librpcsvc). – F'x Jan 05 '11 at 20:38
  • 4
    –1 for speculating about library lookup impact on performance without backing it up with a link, or numbers. "Profile. Don't speculate" – F'x Jan 05 '11 at 20:39
  • 14
    This is not speculation. I don't have any published papers, but I've done all the measurements myself and the difference is huge. Just use `strace` with one of the timing options to watch how much startup time is spent on dynamic linking, or compare running `./configure` on a system where all the standard utilities are static-linked versus one where they're dynamic-linked. Even mainstream desktop app developers and systems integrators are aware of the costs of dynamic linking; this is why things like prelink exist. I'm sure you can find benchmarks in some of those papers. – R.. GitHub STOP HELPING ICE Jan 05 '11 at 21:59
  • 1
    Note that POSIX *does* require `-lm` to be accepted and applications which use the math interfaces must use `-lm`, but it can be an internal option handled (or even ignored) by the compiler command, not an actual library file. Or it can just be an empty `.a` file if the interfaces are in the main libc. – R.. GitHub STOP HELPING ICE Jan 05 '11 at 22:15
  • 7
    @FX: Don't know why I forgot to mention this before: `strace -tt` will easily show you the time spent on dynamic linking. It's not pretty. And on Linux, inspecting `/proc/sys/smaps` will show you the memory overhead of additional libraries. – R.. GitHub STOP HELPING ICE Apr 02 '11 at 19:24
  • -1 for "ridiculous historical practice". This is judgmental and IMHO inaccurate. See @Nosredna's answer for why this practice was not at all ridiculous, historically. – Tim Bird Jan 22 '20 at 18:21
  • 3
    @TimBird: Much of that answer seems to be presupposing, incorrectly, that linking a library pulled in everything from it, rather than just the functions (at translation unit granularity, but historically they were properly split into individual functions) that you use. – R.. GitHub STOP HELPING ICE Jan 22 '20 at 22:13
  • @R..GitHubSTOPHELPINGICE: Nope. Most of that answer has to do with speed vs. accuracy, with some mention of space. I did a lot of programming on systems without FPUs back in the day (8086, 286, early 386), and that comment is an accurate description of the tradeoffs for that era (only some of which were about size). – Tim Bird Jan 24 '20 at 20:59
  • 1
    @TimBird: Having the math part of the standard library available by default without writing `-lm` has nothing to do with any of that. It doesn't preclude not using it, or writing your own fast-but-inaccurate version of it. All of those considerations were real but they weren't related to `-lm`. – R.. GitHub STOP HELPING ICE Jan 24 '20 at 21:14
33

Because time() and some other functions are builtin defined in the C library (libc) itself and GCC always links to libc unless you use the -ffreestanding compile option. However math functions live in libm which is not implicitly linked by gcc.

ismail
  • 41,546
  • 8
  • 79
  • 92
28

An explanation is given here:

So if your program is using math functions and including math.h, then you need to explicitly link the math library by passing the -lm flag. The reason for this particular separation is that mathematicians are very picky about the way their math is being computed and they may want to use their own implementation of the math functions instead of the standard implementation. If the math functions were lumped into libc.a it wouldn't be possible to do that.

[Edit]

I'm not sure I agree with this, though. If you have a library which provides, say, sqrt(), and you pass it before the standard library, a Unix linker will take your version, right?

Bastien Léonard
  • 55,374
  • 18
  • 76
  • 92
  • 11
    I don't think there's a guarantee that that'll happen; you might end up with a symbol conflict instead. It would probably depend on the linker and the layout of library. I still find that reason to be weak; if you're making a custom sqrt function, you really shouldn't give it the same name as the standard sqrt function, even if it does the same thing... – ephemient Jun 23 '09 at 20:45
  • 2
    Indeed, making your own function (non-static) named `sqrt` results in a program with undefined behavior. – R.. GitHub STOP HELPING ICE Aug 01 '10 at 20:07
  • @Bastien Good find. And coming to your point, what do you mean by "before the standard library" ? I thought, the standard library is linked in by default and is not required to be linked via command line options. So, the standard library will be the first go-to for the linker and one cannot place their own implementation "before the standard library". – Rocky Inde Mar 05 '15 at 09:17
  • @RockyInde: look at my answer, I think I actually meant “before the standard math library”. But I think there are compiler options to not link the standard C library, which would allow you to pass yours. – Bastien Léonard Mar 05 '15 at 10:51
  • @BastienLéonard I use gcc of version 7.2, which the `-lm` is totally optional. Any ideas – Donghua Liu Jun 22 '18 at 01:30
  • there IS a guarantee that this happens as long as you're not using some underdog distribution from late 2005 – clockw0rk Dec 16 '20 at 11:05
6

There's a thorough discussion of linking to external libraries in An Introduction to GCC - Linking with external libraries. If a library is a member of the standard libraries (like stdio), then you don't need to specify to the compiler (really the linker) to link them.

EDIT: After reading some of the other answers and comments, I think the libc.a reference and the libm reference that it links to both have a lot to say about why the two are separate.

Note that many of the functions in 'libm.a' (the math library) are defined in 'math.h' but are not present in libc.a. Some are, which may get confusing, but the rule of thumb is this--the C library contains those functions that ANSI dictates must exist, so that you don't need the -lm if you only use ANSI functions. In contrast, `libm.a' contains more functions and supports additional functionality such as the matherr call-back and compliance to several alternative standards of behavior in case of FP errors. See section libm, for more details.

Bill the Lizard
  • 369,957
  • 201
  • 546
  • 842
  • 1
    Which doesn't answer the question of why you have to link in the match libraries separately. Obviously you want to have to link OpenGL libraries separately, but arguably the math libraries are generally useful. – David Thornley Jun 23 '09 at 17:33
  • @David: Right you are. It wasn't clear to me from the question that this was the bit that the OP was asking about. I was editing my answer as you commented. – Bill the Lizard Jun 23 '09 at 17:45
  • I know the reason I compiled a program that uses the `sqrt` function and it works without including the library via `-lm`. Thanks! – L_K Jun 01 '17 at 03:04
5

As ephemient said, the C library libc is linked by default and this library contains the implementations of stdlib.h, stdio.h and several other standard header files. Just to add to it, according to "An Introduction to GCC" the linker command for a basic "Hello World" program in C is as below:

ld -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o 
/usr/lib/crti.o /usr/libgcc-lib /i686/3.3.1/crtbegin.o
-L/usr/lib/gcc-lib/i686/3.3.1 hello.o -lgcc -lgcc_eh -lc 
-lgcc -lgcc_eh /usr/lib/gcc-lib/i686/3.3.1/crtend.o /usr/lib/crtn.o

Notice the option -lc in the third line that links the C library.

ardsrk
  • 2,357
  • 2
  • 19
  • 33
3

I think it's kind of arbitrary. You have to draw a line somewhere (which libraries are default and which need to be specified).

It gives you the opportunity to replace it with a different one that has the same functions, but I don't think it's very common to do so.

EDIT: (from my own comments): I think gcc does this to maintain backwards compatibility with the original cc. My guess for why cc does this is because of build time -- cc was written for machines with far less power than we have now. A lot of programs have no floating-point math and they probably took every library that wasn't commonly used out of the default. I'm guessing that the build time of the UNIX OS and the tools that go along with it were the driving force.

Lou Franco
  • 83,503
  • 14
  • 127
  • 183
  • i think the mentality behind the question is that the contents of libm are largely part of the standard C library, why aren't they in libc? – Evan Teran Jun 23 '09 at 17:15
  • 1
    The why for gcc is to maintain compatibility with the original cc in AT&T Unix. I used 3B2s in 1988 and you had to -lm to get math. It seemed completely arbitrary to me at the time. In Visual Studio, I don't remember ever having to add math, but you have to add other seemingly c-runtime libraries sometimes. I assume that the compiler vendors have a reason (build time?), but right now, I bet gcc is just trying to be backwards compatible. – Lou Franco Jun 23 '09 at 17:20
3

If I put stdlib.h or stdio.h, I don't have to link those but I have to link when I compile:

stdlib.h, stdio.h are the header files. You include them for your convenience. They only forecast what symbols will become available if you link in the proper library. The implementations are in the library files, that's where the functions really live.

Including math.h is only the first step to gaining access to all the math functions.

Also, you don't have to link against libm if you don't use it's functions, even if you do a #include <math.h> which is only an informational step for you, for the compiler about the symbols.

stdlib.h, stdio.h refer to functions available in libc, which happens to be always linked in so that the user doesn't have to do it himself.

Adrian Panasiuk
  • 6,875
  • 5
  • 30
  • 53
2

stdio is part of the standard C library which, by default, gcc will link against.

The math function implementations are in a separate libm file that is not linked to by default so you have to specify it -lm. By the way, there is no relation between those header files and library files.

  • 4
    he knows that..he is asking *why* – Evan Teran Jun 23 '09 at 17:14
  • He says why. Simon explains that some libraries are linked to by default, like stdio whereas the math library is not linked to by default so it has to be specified. – mnuzzo Jun 23 '09 at 17:17
  • 5
    I would say that the nature of the question is asking why libm is not linked by default (or even seperate from libc) since its contents are largely part of the c standard library. – Evan Teran Jun 23 '09 at 17:21
2

I would guess that it is a way to make apps which don't use it at all perform slightly better. Here's my thinking on this.

x86 OSes (and I imagine others) need to store FPU state on context switch. However, most OSes only bother to save/restore this state after the app attempts to use the FPU for the first time.

In addition to this, there is probably some basic code in the math library which will set the FPU to a sane base state when the library is loaded.

So, if you don't link in any math code at all, none of this will happen, therefore the OS doesn't have to save/restore any FPU state at all, making context switches slightly more efficient.

Just a guess though.

EDIT: in response to some of the comments, the same base premise still applies to non-FPU cases (the premise being that it was to make apps which didn't make use libm perform slightly better).

For example, if there is a soft-FPU which was likley in the early days of C. Then having libm separate could prevent a lot of large (and slow if it was used) code from unnecessarily being linked in.

In addition, if there is only static linking available, then a similar argument applies that it would keep executable sizes and compile times down.

Evan Teran
  • 80,654
  • 26
  • 169
  • 231
  • If you don't link with libm but touch the x87 FPU through other means (operations on floats, for example), the x86 kernel does need to save FPU state. I don't think this is a very good guess... – ephemient Jun 23 '09 at 17:20
  • of course if you manually use the FPU the kernel will still need to save/restore its state. I was saying that if you never use it (including not using libm) then it wont have to. – Evan Teran Jun 23 '09 at 17:24
  • Really it can very highly depend on the kernel. The math library the kernel uses could have a save_FPU_on_switch() function that turns it on, while others just detect if the FPU was touched. – Earlz Jun 23 '09 at 17:25
  • 1
    If I recall correctly, the whole issue long predates floating point coprocessors even being on microprocessors. – Nosredna Jun 23 '09 at 17:27
  • @earlz: the approach of having the math library request saving would be a terrible design. What if they use the FPU by some other means? The only sane approach (besides just always saving/restoring) would be to detect usage and then start saving/restoring. – Evan Teran Jun 23 '09 at 18:14
1

Note that -lm may not always need to be specified even if you use some C math functions.

For example, the following simple program:

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

int main() {

    printf("output: %f\n", sqrt(2.0));
    return 0;
}

can be compiled and run successfully with the following command:

gcc test.c -o test

Tested on gcc 7.5.0 (on Ubuntu 16.04) and gcc 4.8.0 (on CentOS 7).

The post here gives some explanations:

The math functions you call are implemented by compiler built-in functions

See also:

jdhao
  • 13,374
  • 7
  • 87
  • 151
0

All libraries like stdio.h and stdlib.h have their implementation in libc.so or libc.a and get linked by the linker by default. The libraries for libc.so are automatically linked while compiling and is included in the executable file.
But math.h has its implementations in libm.so or libm.a which is seperate from libc.so and it does not get linked by default and you have to manually link it while compiling your program in gcc by using -lm flag.

The gnu gcc team designed it to be seperate from the other header files, while the other header files get linked by default but math.h file doesn't.

Here read the item no 14.3, you could read it all if you wish: Reason why math.h is needs to be linked
Look at this article: why we have to link math.h in gcc?
Have a look at the usage: using the library

  • This has been already said here in other answers. And this doesn't even answer the question. The question is why libm is not linked by default. – bolov Nov 26 '20 at 04:51
  • It meant that math.h is libraray file is seperately written in libm.so where as for the other header files it is in libc.so, while other header files are automatically linked but math.h is needed to be linked manually by adding -lm flag – Saptarshi das Nov 26 '20 at 11:02
  • All are part of the standard library. The question is why are not all linked by default. "Because that's how how gcc team designed it" is a poor answer. The question was what is the reason. And there are great answers here that go into detail on the historical reasons. Your edit makes your answer better, but I still fail to see what value it adds over all the other answers here. – bolov Nov 26 '20 at 13:19