What default libraries are taken while compiling C project with GCC - c

I have simple application:
#include <stdio.h>
int main( int argc, char ** argv )
{
printf( "hello");
exit( 0 );
}
When I compile it with command
gcc -c count_words.c
I have warning:
warning: incompatible implicit declaration of built-in function ‘exit’ [enabled by default]
exit( 0 );
I was trying to find where exit() function is defined. And found that it is defined in stdlib.h. But it is not included in my project and no additional libs defined in compile command.
Correct me if I'm wrong, but looks like gcc takes some libs as default. What are these libs and is it possible to tell gcc not include them?
Why compiler is not happy regarding exit(0) assuming that it somehow includes stdlib.h as default?

Let's take your example:
#include <stdio.h>
int main( int argc, char ** argv )
{
printf("hello\n");
exit(56);
}
Although we get a warning on compilation:
~$ gcc test.c -o test
test.c: In function ‘main’:
test.c:6:5: warning: implicit declaration of function ‘exit’ [-Wimplicit-function-declaration]
exit(56);
^
test.c:6:5: warning: incompatible implicit declaration of built-in function ‘exit’
test.c:6:5: note: include ‘<stdlib.h>’ or provide a declaration of ‘exit’
Anyway, I think you have tried to run it and make sure it works:
~$ ./test
hello
~$ echo $?
56
#Mat was right when he said that:
You're mixing up including headers and linking to libraries. Those are
two completely different things
The C compiler and linker are totally separate tools. Let's look on this. Actually, this program depends on the standard C library (as all programs if you didn't pass -nostdlib to compiler) and a couple of system libraries (like loader and vdso). You may see it with:
~$ ldd test
linux-vdso.so.1 (0x00007fff1b128000)
libc.so.6 => /lib64/libc.so.6 (0x00007f804389f000)
/lib64/ld-linux-x86-64.so.2 (0x0000557744537000)
These three library is a minimal set for any program. The exit function is defined in the standard library or libc.so.6 in our case. Now let's look on the compilation process in verbose mode. You can achieve this by the passing -v or --verbose option to compiler:
gcc test.c -o test --verbose
If you will execute this, you will find lines like these:
#include <...> search starts here:
/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include
/usr/local/include
/usr/include
So, compile knows where to search header files for stdlib and it starts to search it to find declaration for non-local functions. Note that it searches only in header files which are included in your source code file. It can find printf declaration in thestdio.h, but can't locate declaration of the exit.
After this step, the compile starts to link your program with libraries:
/usr/libexec/gcc/x86_64-redhat-linux/5.3.1/collect2 ... -lc ...
Where collect2 is gcc util which tries to link your program with lc which is standard C library. Note that the process consists from two steps: compilation and linking. That's why your program works.
Additionally, gcc supports -M option which will tell you about dependencies of the main file. So, if you will execute it, you will see the set of header files including stdio.h, but not stdlib.h:
$ gcc -M test.c
test.o: test.c /usr/include/stdc-predef.h /usr/include/stdio.h \
/usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
Or even better, try to pass -E option to gcc:
$ gcc -E test.c
and you will see result right after the first stage - preprocessing stage. I think it is the easiest way to understand why you are getting this warning.

assuming that it somehow includes stdlib.h as default?
It simply doesn't. That wouldn't be standards-compliant.
So, when you use exit, it has never been declared, so there's you implicit declaration upon usage. However, the fact to you implement exit nowhere else will only become a problem at the final linkage.
Now, GCC knows damn well that you are about to get into trouble, so it warns you.
Simply actually include stdlib.h and you should be fine.

The "library" in question is gcc/builtins.def from the gcc source tree.
That's not just a header file though, and it does not provide declarations for you to use. But it has proper prototypes to check yours against.
Calling undeclared exit() results in implicit declaration like this:
int exit(int);
Search "c implicit declarations" for the gory details. In this case however GCC has its own prototype for exit() from builtins.def:
void exit(int) __attribute__((nothrow,noreturn));
These declarations do not match, and that's what you are being warned about.

Your code works with warning not with error. If you add
#include <stdlib.h>
then no warning anymore ;)

Related

Can GCC warn about undefined functions in libraries?

Consider the following test project:
test.h:
#ifndef TEST_H
#define TEST_H
void test1(int);
void test2(int);
#endif /* TEST_H */
text.c:
#include "test.h"
void test1(int x) { (void) x; }
Oops, I forgot to define test2()! I would like some kind of feedback when I do this, preferably refusal to compile although a warning at least would be nice. However GCC 10.2 (on Ubuntu 20.10) compiles it fine with no warnings:
gcc -Wall -Wextra -Wpedantic -std=c11 -o libtest.o -c test.c
I think I understand why: what if test2() is actually meant to come from another library, maybe a system library? Make it the problem of whichever program ends up linking everything into an executable! But I want to know about it before then. In this case, it's not declared in any included header file. It's not called anywhere. Can that be detected?
I've tried:
--no-undefined which resulted in gcc: error: unrecognized command-line option ‘--no-undefined’; did you mean ‘-Wno-undef’?
-Wno-undef - accepted but no warning
-z,defs - accepted but no warning
-Wimplicit-function-declaration - accepted but no warning
-Werror=missing-declarations - I know this is for the opposite situation but I was getting desperate.
This isn't possible, as no linking is performed at the stage of assembling a static library.
I'd suggest having a "test container" for your library. Set up your build system to build the test executable any time you are building the library. It could even just be a single .c file in the same directory as the library sources, but obviously not in the list of objects that are part of the library.
The test executable calls all of the functions that you wish to be entry points for the library.
Probably that is something you should be doing anyway in order to test the library's functionality before doing a release.

How a standard library differ from user defined header file (.h) and its implementation file (.c) in C?

How a standard library like libc.a (static library) which is included using #include <stdio.h> in our main.c differ from user defined header file (cube.h) included in main.c with its implementation file (cube.c) in C ?
I mean both are header files but one's implementation is a static library (.a) and others is source file (.c) .
You would have the definition (implementation) in, say, cube.c
#include "cube.h"
int cube( int x ) {
return x * x * x;
}
Then we'll put the function declaration in another file. By convention, this is done in a header file, cube.h in this case.
int cube( int x );
We can now call the function from somewhere else, main.c for instance, by using the #include directive (which is part of the C preprocessor) .
#include "cube.h"
#include <stdio.h>
int main() {
int c = cube( 10 );
printf("%d", c);
...
}
Also if I included include guards in cube.h what would happen when I include cube.h in both main.c and cube.c . Where it will get included?
A programming language is not the same as its implementation.
A programming language is a specification (written on paper; you should read n1570, which practically is the C11 standard), it is not a software. The C standard specifies a C standard library and defines the headers to be #include-d.
(you could run your C program with a bunch of human slaves and without any computers; that would be very unethical; you could also use some interpreter like Ch and avoid any compiler or object or executable files)
How a standard library like libc.a (static library) which is included using #include <stdio.h> ... differs from a user file cube.c
The above sentence is utterly wrong (and makes no sense). libc.a does not #include -or is not included by- the <stdio.h> header (i.e. file /usr/include/stdio.h and other internal headers e.g. /usr/include/bits/stdio2.h). That inclusion happens when you compile your main.c or cube.c.
In principle, <stdio.h> might not be any file on your computer (e.g. #include <stdio.h> could trigger some magic in your compiler). In practice, the compiler is parsing /usr/include/stdio.h (and other included files) when you #include <stdio.h>.
Some standard headers (notably <setjmp.h>, <stdreturn.h>, <stdarg.h>, ....) are specified by the standard but are implemented with the help of special builtins or attributes (that is "magic" things) of the GCC compiler.
The C standard knows about translation units.
Your GCC compiler processes source files (grossly speaking, implementing translation units) and starts with a preprocessing phase (processing #include and other directives and expanding macros). And gcc runs not only the compiler proper (some cc1) but also the assembler as and the linker ld (read Levine's Linkers and Loaders book for more).
For good reasons, your header file cube.h should practically start with include guards. In your simplistic example they are probably useless (but you should get that habit).
You practically should almost always use gcc -Wall -Wextra -g (to get all warnings and debug info). Read the chapter about Invoking GCC.
You may pass also -v to gcc to understand what programs (e.g. cc1, ld, as) are actually run.
You may pass -H to gcc to understand what source files are included during preprocessing phase. You can also get the preprocessed form of cube.c as the cube.i file obtained with gcc -C -E cube.c > cube.i and later look into that cube.i file with some editor or pager.
You -or gcc- would need (in your example) to compile cube.c (the translation unit given by that file and every header files it is #include-ing) into the cube.o object file (assuming a Linux system). You would also compile main.c into main.o. At last gcc would link cube.o, main.o, some startup files (read about crt0) and the libc.so shared library (implementing the POSIX C standard library specification and a bit more) to produce an executable. Relocatable object files, shared libraries (and static libraries, if you use some) and executables use the ELF file format on Linux.
If you code a C program with several source files (and translation units) you practically should use a build automation tool like GNU make.
If I included include guards in cube.h what would happen when I include cube.h in both main.c and cube.c ?
These should be two different translation units. And you would compile them in several steps. First you compile main.c into main.o using
gcc -Wall -Wextra -g -c main.c
and the above command is producing a main.o object file (with the help of cc1 and as)
Then you compile (another translation unit) cube.c using
gcc -Wall -Wextra -g -c cube.c
hence obtaining cube.o
(notice that adding include guards in your cube.h don't change the fact that it would be read twice, once when compiling cube.c and the other time when compiling main.c)
At last you link both object files into yourprog executable using
gcc -Wall -Wextra -g cube.o main.o -o yourprog
(I invite you to try all these commands, and also to try them with gcc -v instead of gcc above).
Notice that gcc -Wall -Wextra -g cube.c main.c -o yourprog is running all the steps above (check with gcc -v). You really should write a Makefile to avoid typing all these commands (and just compile using make, or even better make -j to run compilation in parallel).
Finally you can run your executable using ./yourprog (but read about PATH), but you should learn how to use gdb and try gdb ./yourprog.
Where it cube.h will get included?
It will get included at both translation units; once when running gcc -Wall -Wextra -g -c main.c and another time when running gcc -Wall -Wextra -g -c cube.c. Notice that object files (cube.o and main.o) don't contain included headers. Their debug information (in DWARF format) retains that inclusion (e.g. the included path, not the content of the header file).
BTW, look into existing free software projects (and study some of their source code, at least for inspiration). You might look into GNU glibc or musl-libc to understand what a C standard library really contains on Linux (it is built above system calls, listed in syscalls(2), provided and implemented by the Linux kernel). For example printf would ultimately sometimes use write(2) but it is buffering (see fflush(3)).
PS. Perhaps you dream of programming languages (like Ocaml, Go, ...) knowing about modules. C is not one.
TL;DR: the most crucial difference between the C standard library and your library function is that the compiler might intimately know what the standard library functions do without seeing their definition.
First of all, there are 2 kinds of libraries:
The C standard library (and possibly other libraries that are part of the C implementation, like libgcc)
Any other libraries - which includes all those other libraries in /usr/lib, /lib, etc.., or those in your project.
The most crucial difference between a library in category 1 and a library in category 2 library is that the compiler is allowed to assume that every single identifier that you use from category 1 library behaves as if it is the standard library function and behaves as if in the standard and can use this fact to optimize things as it sees fit - this even without it actually linking against the relevant routine from the standard library, or executing it at the runtime. Look at this example:
% cat foo.c
#include <math.h>
#include <stdio.h>
int main(void) {
printf("%f\n", sqrt(4.0));
}
We compile it, and run:
% gcc foo.c -Wall -Werror
% ./a.out
2.000000
%
and correct result is printed out.
So what happens when we ask the user for the number:
% cat foo.c
#include <math.h>
#include <stdio.h>
int main(void) {
double n;
scanf("%lf\n", &n);
printf("%f\n", sqrt(n));
}
then we compile the program:
% gcc foo.c -Wall -Werror
/tmp/ccTipZ5Q.o: In function `main':
foo.c:(.text+0x3d): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
Surprise, it doesn't link. That is because sqrt is in the math library -lm and you need to link against it to get the definition. But how did it work in the first place? Because the C compiler is free to assume that any function from standard library behaves as if it was as written in the standard, so it can optimize all invocations to it out; this even when we weren't using any -O switches.
Notice that it isn't even necessary to include the header. C11 7.1.4p2 allows this:
Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header.
Therefore in the following program, the compiler can still assume that the sqrt is the one from the standard library, and the behaviour here is still conforming:
% cat foo.c
int printf(const char * restrict format, ...);
double sqrt(double x);
int main(void) {
printf("%f\n", sqrt(4.0));
}
% gcc foo.c -std=c11 -pedantic -Wall -Werror
% ./a.out
2.000000
If you drop the prototype for sqrt, and compile the program,
int printf(const char * restrict format, ...);
int main(void) {
printf("%f\n", sqrt(4));
}
A conforming C99, C11 compiler must diagnose constraint violation for implicit function declaration. The program is now an invalid program, but it still compiles (the C standard allows that too). GCC still calculates sqrt(4) at compilation time. Notice that we use int here instead of double, so it wouldn't even work at runtime without proper declaration for an ordinary function because without prototype the compiler wouldn't know that the argument must be double and not the int that was passed in (without a prototype, the compiler doesn't know that the int must be converted to a double). But it still works.
% gcc foo.c -std=c11 -pedantic
foo.c: In function ‘main’:
foo.c:4:20: warning: implicit declaration of function ‘sqrt’
[-Wimplicit-function-declaration]
printf("%f\n", sqrt(4));
^~~~
foo.c:4:20: warning: incompatible implicit declaration of built-in function ‘sqrt’
foo.c:4:20: note: include ‘<math.h>’ or provide a declaration of ‘sqrt’
% ./a.out
2.000000
This is because an implicit function declaration is one with external linkage, and C standard says this (C11 7.1.3):
[...] All identifiers with external linkage in any of the following subclauses (including the future library directions) and errno are always reserved for use as identifiers with external linkage. [...]
and Appendix J.2. explicitly lists as undefined behaviour:
[...] The program declares or defines a reserved identifier, other than as allowed by 7.1.4 (7.1.3).
I.e. if the program did actually have its own sqrt then the behaviour is simply undefined, because the compiler can assume that the sqrt is the standard-conforming one.

Using a function from another C file placed in another directory?

Say I have a parent directory A with two subdirectories B and C.
Sub-directory C has a helper.c and helper.h as shown:
//helper.c
void print(){
printf("Hello, World!\n");
}
//helper.h
void print();
Now, in sub directory B, I have a main.c which just calls the print function:
//main.c
#include<stdio.h>
#include"../C/helper.h"
void main(){
print();
}
I tried the following commands for compiling main.c:
Command 1: gcc main.c //Gives undefined reference to 'print' error
Command 2: gcc main.c ../C/helper.c //Compiles successfully
Now I removed the #include"../C/helper.h" from main .c and tried the Command 2 again. It still works.
So I have the following questions:
i) What difference does it make whether the helper.h file is included or
helper.c?
ii) Why command 1 fails?
iii) Is there a way to compile my C program without having to specify
helper.c everytime?
What happens when you execute:
Command 1: gcc main.c //Gives undefined reference to 'print' error
When execute gcc main.c
Compiler compiles main.c and creates objective file. This file will contain unresolved link to function print(). Because there is no implementation of function print() in main.c file.
After compilation gcc tries to make full executable file. To do this gcc combines all objective files and tries to resolve all unresolved links. As you remember there is unresolved link for function print(), gcc can't find implementation and raise the error.
When you execute
Command 2: gcc main.c ../C/helper.c //Compiles successfully
gcc compiles both files. Second file ../C/helper.c contains implementation of function print(), so linker can find it and resolve reference to it in function main().
i) What difference does it make whether the helper.h file is included or helper.c?
In your case helper.h contains forward declaration of function print(). This gives information to compiler how to make call of function print().
ii) Why command 1 fails?
See above.
iii) Is there a way to compile my C program without having to specify helper.c everytime?
Use make utility. Compile helper.c in separate objective file helper.o and use it in linkage command.
helper.o: ../C/helper.c ../C/helper.h
gcc -c ../C/helper.c
main.o: main.c main.h
gcc -c main.c
testprog: main.o helper.o
g++ main.o helper.o -o testprog
See make utility manual for details.
Commands should be indented by TAB.
First you need to understand that #include simply adds whatever text is in the #include parameter to the position in the file the statement is in, for example:
//file1.h
void foo();
//main.c
#include "file1.txt"
int main(int argc, char **argv)
{
foo();
return 0;
}
Will cause the pre-compilation to generate this unified file for compilation:
//main.c.tmp
void foo();
int main(int argc, char **argv)
{
foo();
return 0;
}
So to answer your first and second questions:
When you include a header file (or any file) that only contains declarations (i.e function signatures) without definitions (i.e function implementations), as in the example above, the linker will fail in finding the definitions and you will get the 'undefined reference' error.
When you include a c code file (or any file) that contains definitions, these definitions will be merged to your code and the linker will have them, that's why it works.
and as for your third question
It is bad practice to include c files directly in other c files, the common approach is to keep separate c files with headers exposing the functionality they provide, include the header files and link against the compiled c files, for example in your case:
gcc main.c helper.c -o out
Will allow you to include helper.c in main.c and still work because you instructed the compiler to compile both files instead of just main.c so when linking occurs the definitions from the compilation will be found and you will not get the undefined behavior error
This is, in a nutshell. I abstracted a lot of what's going on to pass on the general idea. this is a nice article describing the compilation process in fair detail and this is a nice overview of the entire process.
I'll try to answer:
i) What difference does it make whether the helper.h file is included or helper.c?
When you include a file, you don't want to expose your implementation, hence its better to include h files, that contains only the "signatures" - api of your implementation.
ii) Why command 1 fails?
When you compile you must add all your resources to the executable, otherwise he won't compile.
iii) Is there a way to compile my C program without having to specify
helper.c everytime?
You can use Makefile to compile your program. Maybe this tutorial can help you.
i) What difference does it make whether the helper.h file is included
or helper.c?
Including helper.c means that helper.c gets compiled each time as if it were part of main.c
Including helper.h lets the compiler know what argument types the function print() takes and returns so the compiler can give an error or warning if you call print() incorrectly
ii) Why command 1 fails?
The compiler is not being told where to find the actual code for the print function. As explained, including the .h file only helps the compiler with type checking.
iii) Is there a way to compile my C program without having to specify
helper.c everytime?
You can compile it once into an object file and optionally you can add that obj to a static or dynamically loaded library. You still need to help the compiler find that obj or library. For example,
gcc -c helper.c
gcc main.c helper.o
The correct way to avoid compiling modules that don't need compiling is to use a Makefile. A Makefile compares when a module was last compiled compared to when it was last modified and that way it knows what needs to be compiled and what doesn't.

What libc and can I omit it's includes in my project?

I have simple program without includes that compiles with some warnings:
int main(int argc, char **argv)
{
printf("hello");
exit(0);
}
Compile:
gcc hello.c
Warning:
In function ‘main’:
warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
printf("hello");
^
warning: incompatible implicit declaration of built-in function ‘exit’ [enabled by default]
exit( 0 );
^
compilation command is very simple and not contains information regarding include library files that contains printf and exit. Correct me if I'm wrong, but looks that gcc links my project to these libraries by default. That points me to thinking that include files of libc libraries is not required?
Correct me once again. I got warnings because GCC somehow knows some basic functions of libc and these functions has different params. But since GCC checks all libc it founds correct function anyway.
What is libc at all. Is it some standard set of binary object and header files?
looks that gcc links my project to these libraries by default. That points me to thinking that include files of libc libraries is not required?
Includes and linking are not related that way. The includes contain function prototypes that instruct the compiler about the return value type and parameters of a given function. When a function call happens, and there is no prototype for it yet the compiler assumes it returns int and that may lead to undefined behavior.
The program will be linked to the standard libraries and function definitions will be available, but since the program was compiled with the assumption that these functions all return int there can be runtime errors related to this, which cannot be predicted since the behavior is undefined.
I got warnings because GCC somehow knows some basic functions of libc and these functions has different params. But since GCC checks all libc it founds correct function anyway.
No, it has nothing to do with gcc knowing anything but the opposite, it has to do with gcc not knowing how to call these functions.
What is libc at all. Is it some standard set of binary object and header files?
libc is a binary file libc.so.6 in current glibc and it's the runtime library with all the symbols needed by a standard c program, it does not include math.h funcions for example (that is libm.so.6).
You still need header files in your c programs for the reasons explained above, or at least declarations of the standard functions you use. These declaration are called prototypes and are required by the compiler in order to correctly compile your code.
NOTE: Always compile with at least -Wall -Werror, like this
gcc -Wall -Werror hello.c

Implicit Declaration Of Function

I've just organized my code by using headers, but just as I've done this, I got a warning that turned into an error when linking.
I have a code(use of a function that is inside a header) in test.c that is like this:
#include "test1.h"
/* Some code */
main()
{
Testing();
}
And my test1.h header is like this:
void Testing();
void print(int, int, int, const char*);
And at test1.c
void Testing()
{
print(0xF9, 27, 5, "\xC9\\xBB");
}
void print(int colour, int x, int y, const char *string)
{
volatile char *video=(volatile char*)0xB8000 + y*160 + x*2;
while(*string != 0)
{
*video=*string;
string++;
video++;
*video=colour;
video++;
}
}
When I try to compile the code, I got this:
ubuntu#eeepc:~/Development/Test$ gcc -o test.o -c test.c -Wall -Wextra -nostdlib -nostartfiles -nodefaultlibs
test.c: In function ‘main’:
test.c:11: warning: implicit declaration of function ‘Testing’
ubuntu#eeepc:~/Development/Test$
At the time it's just a simple warning, but when I try to link it...
ubuntu#eeepc:~/Development/Test$ ld -T linker.ld -o kernel.bin loader.o test.o
test.o: In function main':
test.c:(.text+0xfc): undefined reference toTesting'
What I need to do?
Edit: To reflect the OP's question I have struck out some lines of my answer despite being upvoted...
Why is kernel.c flagged up in the compiler, even though you don't have it mentioned here? Am I missing something...
gcc -o test.o -c test.c -Wall -Wextra -nostdlib -nostartfiles -nodefaultlibs
kernel.c: In function ‘main’:
kernel.c:11: warning: implicit declaration of function ‘Testing’
ubuntu#eeepc:~/Development/Test$
maybe you need to do it this way somewhere in your header file as I'm judging you want kernel to access this function:
extern void Testing();
And, take out all your functions and place them in a separate .c file, they should not be in there in the first place... for example:
Testing.c
/* all your functions here */
Testing.h
/* Only global, external variables and function prototypes */
Hope this helps,
Best regards,
Tom.
I can't recreate your problem. This works as expected when I try to compile your code on an Ubuntu machine (Which based on your paste, I assume you're using.)
Are you sure the #include is happening correctly?
Try using -E instead of -c to see what the whole code the compiler is trying to compile looks like.
Somewhat of a shot in the dark here, since my C is a bit rusty, but does C allow you to put function bodies in a header? I don't recall that it does. Try moving the definition of Testing() and print() into a .c file? You could also try compiling as C++ as see if that fixes it, if you don't need/want C.
You included test.h into main.c, while your declarations, according to what your wrote, are in test1.h. Note the 1 in the name.
In addition to that, you are compiling test.c and linking test.o, while in reality the name of your file is test1.c. Again, note the 1 in the name.
Edit: Now you edited the name of the file included into main.c. After the edit it is safe to assert that most of the symptoms you describe are not possble with the current versions of the files. Re-verify what you are doing, post updated disgnostic information and/or post real code.
Still, you compiler and linker lines are referring to old file names.
i donno whats causing this , but i had this problem just now .
try to delete the .h file and put the declarations of the functions on the top of .c file itself .
in this case , delete the test1.h and put the declarations of functions of test1.c in test1.c.
and include test1.c in test.c
you wont get that warning message any more , nor the following linking errors .

Resources