how does gcc -c option work? - c

#include"header.h"
int main(){
function();
return 0;
}
above is simplified form of my code. I implemented function() in header.h file, and put it in the same directory with this code.c file.
I heard that "gcc -c code.c" is "compile but no linking" option, but this code need linking with header.h file. So I guess -c option will flag an error, while it didn't. Though, without -c option it flags an error. Can anyone explain how this -c options works?

Header files have nothing to do with linking. Linking is combining multiple object files and libraries into an executable.
Header files are processed by the compiler, as part of generating an object file. Therefore, gcc -c will process header files.

gcc -c compiles source files without linking.
header files have nothing to do with linking process, they are only used in compilation process to tell compiler the various declaration and function prototypes.
However it is bad practice to implement function in header file, both compilation strategy should work in this case. i.e. gcc with and without c flag

Related

How do I use an external library with gcc?

I am attempting to compile this code:
#include <GLFW/glfw3.h>
int main() {
glfwInit();
glfwTerminate();
return 0;
}
Using this command in MSYS2 on Windows 10:
gcc -Wall runVulkan.c -o runVulkan
as well as this:
gcc -Wall -Llibs/glfw runVulkan.c -o runVulkan
libs/glfw is where I downloaded the library to.
For some reason I keep getting this:
runVulkan.c:1:10: fatal error: GLFW/glfw3.h: No such file or directory
1 | #include <GLFW/glfw3.h>
| ^~~~~~~~~~~~~~
compilation terminated.
It seems like I'm getting something very basic wrong.
I'm just getting started with C, I'm trying to import Vulkan libraries.
Run pacman -S mingw-w64-x86_64-glfw to install GLFW.
Then build using gcc -Wall runVulkan.c -o runVulkan runVulkan.c `pkg-config --cflags --libs glfw3`.
The pkg-config command prints the flags necessary to use GLFW, and the ` backticks pass its output to GCC as flags. You can run it separately and manually pass any printed flags to GCC.
Note that any -l... flags (those are included in pkg-config output) must be specified after .c or .o files, otherwise they'll have no effect.
For me pkg-config prints -I/mingw64/include -L/mingw64/lib -lglfw3.
-I fixes No such file or directory. It specifies a directory where the compiler will look for #included headers. Though it's unnecessrary when installing GLFW via pacman, since /mingw64/include is always searched by default.
-l fixes undefined reference errors, which you'd get after fixing the previous error. -lglfw3 needs a file called libglfw3.a or libglfw3.dll.a (or some other variants).
-L specifies a directory where -l should search for the .a files, though it's unnecessrary when installing GLFW via pacman, since /mingw64/lib is always searched by default.
#include are just headers, for declarations. gcc, as any compilers, needs to know where those .h should be searched.
You can specify that with -I option (or C_INCLUDE_PATH environment variable).
You'll also need -L option, this times to provide the library itself (.h does not contain the library. Just declarations that the compiler needs to know how to compile codes that use the library function's and types).
-L option tells the compiler where to search for libraries.
But here, you haven't specify any libraries (just headers. And I know that it seems logical that they go together. But strictly speaking, there is no way to guess from #include <GLFW/glfw3.h> which library that file contain headers for (that is not just theory. In practice, for example, the well known libc declarations are in many different headers)
So, you will also have to specify a -l option. In your case -lglfw.
This seems over complicated, because in your case you compile and like in a single command (goes from .c to executable directly). But that are two different operations done in one command.
Creation of an executable from .c code source is done in two stage.
Compilation itself. Creating .o from .c (many .c for big codes), so many compilation commands. Using command such as
gcc -I /path/where/to/find/headers -c mycode.c -o mycode.o
Those are not related to the library. So no -l (and therefore no -L) for that. What is compiled is your code, so just your code is needed at this stage. Plus the header files, because your code refers to unknown function and types, and the compiler needs to know, not their code, but at least declarations that they really exist, and what are the types expected and returned by the functions is the headers files.
Then, once all the .o are compiled, you need to put together all compiled code, yours (the .o) and the libraries (which are somehow a sort of .zip of .o) to create an executable. That is called linking. And is done with commands like
gcc -o myexec mycode1.o mycode2.o -L /path/where/to/search/for/libraries -lrary
(-lbla is a compact way to include /path/where/to/search/for/libraries/libbla.so or /path/where/to/search/for/libraries/libbla.a)
At this stage, you no longer need -I or anything related to headers. The code is already compiled, headers has no role left. But you need everything needed to find the compile code of the libraries.
So, tl;dr
At compilation stage (the stage that raises the error you have for now), you need -I option so that the compiler knows where to find GLFW/glfw3.h
But that alone wont avoid you the next error that will occur at linking stage. At this stage, you need -lglfw to specify that you want to use that library, and a -L option so that the compiler knows where to find a libglfw.so

In C how do I compile and then create an executable file with a header and two c files?

I have three C files in total. One is a header [.h] file, two are source [.c] files.
The .h file is called encryption.h and the corresponding source file is encryption.c. The encryption.c has logic, but no main() function. My second c file is called main.c. There I have the main() function that calls methods from encryption.c.
I am compiling these files within terminal on Mac OSx. I am confused on how to compile this, I have tried the following:
gcc -c main.c
gcc -c encryption.c
gcc -c encryption.h
gcc main.o encryption.o encryption.g.gch -o encrypt
This doesn't seem to work though, it says I have a precompiled-header already. I tried finding the answer online, I know it has to be simple, but I haven't had much luck. What is the issue here?
Don't compile the header file. Header files are meant to be included to the source files (using #include directive, in c). Just compile the source files and link them together. Something like
gcc -c main.c
gcc -c encryption.c
gcc main.o encryption.o -o encrypt
or, for shorthand,
gcc main.c encryption.c -o encrypt
Note: If you're bothered about the presence (or absence) of header files while compilation, check the pre-processed output of each source files using gcc -E option.

gcc exit with undefined reference to function in header file

I want to compile a small program which has a pretty straight forward makefile, but I seem unable to get it working. Maybe you can help me. The makefile has the following targets:
visca-cli: visca-cli.c libvisca_hl.o
gcc -Wall -o visca-cli visca-cli.c /usr/local/lib/libvisca.so libvisca_hl.o
libvisca_hl.o: libvisca_hl.c
gcc -Wall -c libvisca_hl.c
I can 'make libvisca_hl.o' successfully and create the .o file. But 'make visca-cli' fails with error messages like
libvisca_hl.c:(.text+0x468a): undefined reference to
`VISCA_get_md_disptime'
for every single function defined in libvisca.h (here it's VISCA_get_md_disptime)
Here are the include sections from the various files (ommitting standard libraries):
In visca-cli.c:
#include "libvisca.h"
#include "libvisca_hl.h"
In libvisca_hl.c:
#include "libvisca_hl.h"
In libvisca_hl.h:
#include "libvisca.h"
All includes quoted with "" are present in the local directory where I run make and where all the sourcefiles are. There are no subfolders. So I guess the problem lies with the makefile? Any help appreciated!
The order of libraries and objects on your compilation/link command line matters. In your case, you just need to put the shared object at the end:
gcc -Wall -o visca-cli visca-cli.c libvisca_hl.o /usr/local/lib/libvisca.so
On most systems /usr/local/lib is already part of the standard library search path, so you could simplify further:
gcc -Wall -o visca-cli visca-cli.c libvisca_hl.o -lvisca

using a function in different .c files (c programming 101)

/me/home/file1.c containes function definition:
int mine(int i)
{
/* some stupidity by me */
}
I've declared this function in
/me/home/file1.h
int mine(int);
if I want to use this function mine() in /me/home/at/file2.c
To do so, all I need to do is:
file2.c
#include "../file1.h"
Is that enough? Probably not.
After doing this much, when I compile file2.c, I get undefined reference to 'mine'
You will also need to link the object file from file1. Example:
gcc -c file2.c
gcc -c ../file1.c
gcc -o program file2.o file1.o
Or you can also feed all files simultaneously and let GCC do the work (not suggested beyond a handful of files);
gcc -o program file1.c file2.c
Don't use ../ in a header. Instead, instruct gcc to use the parent directory as include path:
(in the at directory):
gcc -I../ -c file2.c
After doing this much, when I compile file2.c, I get undefined reference to 'mine'
No, you don't. It's not compiling that causes those errors. It's this other thing, called "linking".
The compiler compiles one "translation unit" - the result of running the preprocessor on one source file, possibly pulling in more stuff via #include - at a time, and then the linker sticks these together to make an executable. Typically the same program serves as both the compiler and linker, with different flags, and typically you can tell it to do everything at once (and not save any temporary files for the compiled translation units). But you do need to tell it what to link, and you do need to compile everything that will be linked.

Including source files in C

So I get the point of headers vs source files. What I don't get is how the compiler knows to compile all the source files. Example:
example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
int example(int argument); // prototype
#endif
example.c
#include "example.h"
int example(int argument)
{
return argument + 1; // implementation
}
main.c
#include "example.h"
main()
{
int whatever;
whatever = example(whatever); // usage in program
}
How does the compiler, compiling main.c, know the implementation of example() when nothing includes example.c?
Is this some kind of an IDE thing, where you add files to projects and stuff? Is there any way to do it "manually" as I prefer a plain text editor to quirky IDEs?
Compiling in C or C++ is actually split up into 2 separate phases.
compiling
linking
The compiler doesn't know about the implementation of example(). It just knows that there's something called example() that will be defined at some point. So it just generated code with placeholders for example()
The linker then comes along and resolves these placeholders.
To compile your code using gcc you'd do the following
gcc -c example.c -o example.o
gcc -c main.c -o main.o
gcc example.o main.o -o myProgram
The first 2 invocations of gcc are the compilation steps. The third invocation is the linker step.
Yes, you have to tell the compiler (usually through a makefile if you're not using an IDE) which source files to compile into object files, and the compiler compiles each one individually. Then you give the linker the list of object files to combine into the executable. If the linker is looking for a function or class definition and can't find it, you'll get a link error.
It doesn't ... you have to tell it to.
For example, whe using gcc, first you would compile the files:
gcc file1.c -c -ofile1.o
gcc file2.c -c -ofile2.o
Then the compiler compiles those files, assuming that symbols that you've defined (like your example function) exist somewhere and will be linked in later.
Then you link the object files together:
gcc file1.o file2.o -oexecutable
At this point of time, the linker looks at those assumtions and "clarifies" them ie. checks whether they're present. This is how it basically works...
As for your IDE question, Google "makefiles"
The compiler does not know the implementation of example() when compiling main.c - the compiler only knows the signature (how to call it) which was included from the header file. The compiler produces .o object files which are later linked by a linker to create the executable binary. The build process can be controlled by an IDE, or if you prefer a Makefile. Makefiles have a unique syntax which takes a bit of learning to understand but will make the build process much clearer. There are lots of good references on the web if you search for Makefile.
The compiler doesn't. But your build tool does. IDE or make tool. The manual way is hand-crafted Makefiles.

Resources