gcc linking with static libraries - c

I am reading a book titled "An Introduction to GCC" and would like some clarification. The book indicates that the code below will cause an error but when I compile, it builds and runs perfectly:
#include <math.h>
#include <stdio.h>
int main (void) {
double x = sqrt (2.0);
printf ("The square root of 2.0 is %f\n", x);
return 0;
}
I quote from the book "Trying to create an executable from this source file alone causes the compiler to give an error at the link stage:"
$ gcc -Wall calc.c -o calc
/tmp/ccbR6Ojm.o: In function `main':
/tmp/ccbR6Ojm.o(.text+0x19): undefined reference
to `sqrt'
The solution that the book gives is that you are supposed to include the path to the math library ‘libm.a’ as follows:
$ gcc -Wall calc.c /usr/lib/libm.a -o calc
It would be very inconvenient to have to specify the paths to built in libraries that we use in our programs. I can understand the reason for adding the path to my own custom libraries, but libm.a is built into gcc. And although the book is quite old (published in 2004), what has changed with more modern versions of gcc, so that we do not need to include the path to libm.a?
* UPDATE *
I noticed that the answer given by taskinoor demonstrates updated code that requires that I use the -lm flag if the value passed to sqrt() is not known at compile time.
I learned C/C++ using VS but my goal now is to learn and use gcc. I have Visual Studio 2013 and the VS compiler/linker does not seem so picky. For example, I am able to compile just about any simple program without having to specify mysterious compiler flags.
I am learning on gcc version 5.4 that comes with KUBUNTU 16.04.1

sqrt (2.0);
Modern GCC is well capable to determine that you are trying to find square root of a constant and thus it is able to calculate that in compile time. Your object code does not contain an actual call to sqrt.
If you use a variable which is input via scanf at run then it won't link without libm.
int main() {
double x;
scanf("%lf", &x);
printf("%lf\n", sqrt(x));
return 0;
}
Without libm gcc 4.8.4 on Ubuntu 14.04 this results:
/tmp/ccVO2fRY.o: In function `main':
sqrt.c:(.text+0x2c): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
But if I put a constant instead of x like your example then it links fine without libm.
P.S: I don't know the exact version since when GCC is able to do this. Hopefully someone else can point to that.

I've noticed that on some operating systems, common libraries are available without explicit linking. In particular, I've often taken a working C project originally developed on my Mac, and the project would not compile on Linux until I explicitly linked against the libraries I used (like libm).
Of course, this is typically for dynamic rather than static linking...

Related

I have not included the <unistd.h> header file, why can I still invoke the getpid() function successfully?

Code as below:
int main (int argc, char *argv[]) {
long pid = (long)getpid();
long test = pid + 1;
}
Have not included any head files, still can compile code successfully and still can run program successfully.
Why?
Environment info: Ubuntu 18.04.2 LTS, gcc (Ubuntu 4.8.5-4ubuntu8) 4.8.5
Have not included any head files,still can compile code successfully.
still can run program successfuly.Why?
Why not?
All question of whether the particular code presented conforms to the language standard notwithstanding, language non-conformance does not imply that compilation or execution must fail. Instead, you get undefined behavior, which can manifest in any manner within the power of the machine to produce, including compiling successfully and running as intended.
In your particular case, however, you are using GCC 4.8.5. The GCC 4.8 series defaults to compiling for the C90 standard, with GNU extensions. C90 allows calls to functions with no in-scope declaration, for compatibility with earlier, pre-standardization practice. That is no longer allowed in C99 or later, but many implementations nevertheless continue to accept it as an extension.
It should be understood, however, that C interprets some argument lists differently when the called function has an in-scope prototype than when it doesn't (which may be the case even for functions that are declared, because not all declarations provide prototypes). You may be able to get away with calling undeclared functions under some circumstances, but it is poor style, and if you do it enough then it will bite you at some point.
Note also that GCC 4 definitely has the ability to emit warnings about usage such as yours, even when compiling in C90 or GNU90 mode. You would be well served to turn on the -Wall option when you compile, and maybe additional warning options as well.
Normally, to use a dynamic library function you would have to link against the specified library at compile time through the -l switch, like for example gcc -lm prog.c when using the mathematic functions (from libm).
However, since it's so common, GCC always links the standard C library by default, meaning that doing gcc prog.c is actually the same as doing gcc -lc prog.c. This is always done whether you include any header or not.
The second thing that makes this work, is that GCC assumes any function that has not been declared at compile time to have the signature int func(void). In this case, the signature is quite similar to the one of the real getpid() function.
If you take a look at your compiled program with the ldd tool to show which dynamic libraries are required, you'll see that the program is linked against libc:
$ ldd prog
linux-vdso.so.1 (0x00007ffede7d0000)
==> libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0f47018000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0f475b9000)
When your program runs, it asks the dynamic loader where (at which address) to find the getpid function before calling it the first time. The dynamic loaders checks the loaded libraries, and finds a function with that name in libc, so everything seems to work without a problem.
You can tell GCC to not link against the standard library by default using the -nostdlib compiler switch, but this is not that useful in your case. The real solution is to always treat warnings about implicit function declarations as errors (-Werror=implicit-function-declaration).
If your compiler doesn't give this warning by default, I would suggest you to upgrade it to a newer version. GCC 4 is definitely not the latest version available for Ubuntu 18.
$ sudo apt update
$ sudo apt upgrade

CMPLX Yields Undefined Symbol with GCC

I'm trying to hunt down a problem using complex literals when compiling with GCC. Consider the following
#include <stdio.h>
#include <complex.h>
int main(void)
{
double complex z = CMPLX(0.0, -1.0);
printf("z = %.1f%+.1fi\n", creal(z), cimag(z));
return 0;
}
(slightly modified from the reference page). If I compile with Clang, it works as expected. However, if I use GCC I get an undefined reference error
gcc -std=c11 mwe.c
mwe.c: 6:24 warning: implicit declaration of function 'CMPLX' ...
mwe.c:(...) undefined reference to `CMPLX'
I have tried this with GCC 4.7 and 7.2 on Linux and GCC 9 on MacOS. The error messages change, but the net result remains the same. Reviewing the reference for CMPLX, this should be valid C11. Based on this answer and this post, it appears like GCC accepted this construct before.
My bottom line question is: Why can't I use CMPLX with GCC?
It appears like this is caused by a header/library disconnect on the systems I have. Compiling with the -save-temps flag, it appears GCC uses the system header for complex.h. This means the selected Xcode SDK's usr/include/complex.h on MacOS and /usr/include/complex.h on Linux. On MacOS, the CMPLX macro is only defined when using Clang. The Linux I have is RHEL 6 meaning the header is aimed at GCC 3 which did not have CMPLX. Based on the discussion on this bug report, it looks like making sure the macro is defined is not up to GCC.
The short answer is: The compiler/platform combination doesn't support it. Use the native compiler or update the system.

Compiling issue: undefined reference to pthread_cleanup_push_defer_np() and pthread_cleanup_pop_restore_np()

I am currently writing a C program with threads and I make use of pthread_cleanup_push_defer_np() and pthread_cleanup_pop_restore_np(). Provided that:
I have included pthread.h;
I am compiling with -pthread option;
I am on Ubuntu 14.04 and using gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1);
when compiling I get back a nasty undefined reference error to the above mentioned functions and I can't figure out why. I have tried to take a look into pthread.h and it seems those two functions are commented out, so I am wondering whether I need to enable them in some way or use some other kind of options. I've read the manual pages and google it up but I can't find a solution, so I would appreciate a little help. Here it is a snippet:
void *start_up(void *arg)
{
char *timestamp;
// ... code ...
timestamp = get_current_timestamp("humread");
pthread_cleanup_push_defer_np(free, timestamp);
// ... some other code
pthread_cleanup_pop_restore_np(1);
// ... more code ...
}
I compile with
gcc -pthread -o server *.c
The manual of pthread_cleanup_push_defer_np and pthread_cleanup_pop_restore_np say these two (non portable) functions are GNU extensions and are enabled
by defining _GNU_SOURCE:
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
pthread_cleanup_push_defer_np(), pthread_cleanup_pop_defer_np():
_GNU_SOURCE
This results in linker error (as opposed to compile time error) because your compiler is pre-C99 (or you are compiling in pre-C99 mode) and assumes these functions return int by default.
The rule functions-return-int if no prototype is present has been removed since C99. Enabling more compiler switches can help you with better diagnostics.

Given .dll, .lib, and .h, and would like to write a C program using a function in the DLL

So, I have TVZLib.h, TVZlib.dll, and TVZlib.lib, and I am using gcc to compile the following program (it's a simple test case). The complier gives me the error:
"undefined reference to '_imp__TVZGetNavigationMatrix'"
Yet. when I comple the program with a different type of parameter for the function's call, it complains that it's not the correct parameter (requires *float). To me, that means that it at least has found the function, as it knows what it wants.
From my research, I can tell that people think it's to do with the linking of the library, or the order in which I link, but I've tried all of the gcc commands in all combinations, and all give me the same error, so I'm desperate for some help.
#include <stdlib.h>
#include <stdio.h>
#include "TVZLib.h"
int main() {
float floatie = 2;
float *ptr = &floatie;
TVZGetNavigationMatrix(ptr);
getchar();
return 0;
}
Thanks a lot in advance!
My compiler command:
gcc dlltest.c -L. TVZLib.lib
The header file (TVZLib.h).
And the direct output:
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccuDpoiE.o:dlltest.c:(.text+0x2c): undefined reference to `_imp__TVZGetNavigationMatrix'
collect2: ld returned 1 exit status
It's been a while since I've been compiling natively on Windows...
Did you intend to link statically against TVZlib.lib? That's not happening.
By default, gcc will pick the dynamic version of a library if it finds both a static and a dynamic lib. If you want to force gcc to link statically, you can use the -static option.
If memory serves me right the _imp__ prefix is a sign that a DLL was loaded (_imp__ symbol prefix is used for the trampoline function that calls into the DLL).

Undefined reference to `sin` [duplicate]

This question already has answers here:
Undefined reference to sqrt (or other mathematical functions)
(5 answers)
Closed 4 years ago.
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?
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:
The UNIX wars led to increasing divergence from the original AT&T UNIX offering.
The number of UNIX platforms added difficulty in developing software for the operating system.
An attempt to define the lowest common denominator for software developers was launched, called 1988 POSIX.
Software developers programmed against the POSIX standard to provide their software on "POSIX compliant systems" in order to reach more platforms.
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:
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.
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).
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.
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.
You need to link with the math library, libm:
$ gcc -Wall foo.c -o foo -lm
I had the same problem, which went away after I listed my library last: gcc prog.c -lm

Resources