I am learning C with the GCC compiler and Geany (Arch Linux, if it makes a difference). However, I am seeing the words compile and build used interchangeably, both in Geany and on the internet. I am asking for clarification that the way I understand the compiling process is correct, because Googling it is just making me more confused.
Say I write a simple helloworld.c file:
#include <stdio.h>
int main(void)
{
printf("Hello world!");
return 0;
}
If I run gcc -c helloworld.c, the compiler produces a helloworld.o object file. Geany calls this process compilation and the compiler says Compilation finished successfully.
Now, if I run gcc -o helloworld helloworld.c, the compiler produces an executable file called helloworld and Geany calls it building. However, the compiler again says Compilation finished successfully.
I understand that the -c option produces an object file, and that multiple of these can be linked together with libraries to produce an executable file, but I am confused about which scenario is compilation and which is building.
Furthermore, if I had just one source file in the project, such as a single helloworld.c file, is gcc -o helloworld helloworld.c enough to turn the source code into an executable?
Thanks
To answer your 2nd question: yes, gcc -o myprog myprog.c is just fine. So is gcc -o myprog *.c or gcc -o myprog foo.c bar.c baz.c.
To answer your first question: technically speaking, there's no word as 'building' :) However, the word 'building' and 'compiling' can be used interchangeably to describe the whole process of producing a final executable from source code.
In a more precise context you would say there is:
preprocessing, when the preprocessor includes header files, expands macros, etc.
parsing, where the parser tokenizes the source text and produces a structured data model (a so-called Abstract Syntax Tree) of the program flow.
compiling or compilation, when a code generator traverses the AST and generates assembly code from it
assembling, when the compiler driver invokes an assembler program which turns the assembly text into binary object code and finally
linking or linkage, when the compiler driver invokes a linker to look up symbols in libraries, fill in missing addresses, etc.
So, strictly speaking, only the 3rd small step is the compilation; furthermore, using the GNU toolchain and make, people tend to call the first four steps (producing an object file from a .c source file) compilation as one.
More on all this here...
Compiling is generally thought of as turning source code into machine code, but not necessarily also linking the machine code to create a final executable. Building is a more general term to describe the whole process of creating the final executable. Building will involve both compiling and linking. If you aren't using the -c option, then the linking is done automatically, so this would be considered building, but compiling was also part of that process.
You may find the terms being used a bit loosely though.
When you compile a program, the compiler just checks if the file has any compile-time errors (such as syntax and semantic errors) in it. When you "build" the program, the compiler first checks for any errors in it, and then converts the source code into machine code (actual compilation) and creates an executable file in the process.
For your second question, yes gcc -o helloworld helloworld.c alone would be enough to "turn the source code into an executable".
Related
I want to be able to pass arguments to GCC from my C source code, something like this...
// pass the "-ggdb" argument to GCC (I know this won't work!)
#define GCC_DEBUG_ARG -ggdb
int main(void) {
return 0;
}
With this code I'd like to simply run gcc myfile.c which would really run gcc myfile.c -ggdb (as the "-ggdb" argument has been picked up from the C source code).
I'm not interested in using make with the CFLAGS environment variable, I just want to know if its possible to embed GCC options within C source code
What you want to do is not possible in general.
However, recent GCC (e.g. GCC 8 in end of 2018) accepts many options and some of them could be passed by function attributes or by function specific pragmas (However, they don't accept -g but do accept -O2).
Also, you can use -g in every compilation (with GCC, it is mixable with optimization flags such as -O2; so runtime performance won't suffer. Of course the -g will increase compile time and size of produced object file). Notice that (on Linux) the DWARF debug information is visible in the generated assembler file (e.g. try to compile your foo.c with gcc -Wall -g -O -S -fverbose-asm foo.c, look into the generated foo.s, and repeat by removing the -g)
I'd like to simply run gcc myfile.c
That is a very bad habit. You should run gcc -Wall -Wextra -g myfile.c -o myprog to get all warnings (you really want them) and debug info in your executable myprog. Read How to debug small programs before continuing coding your program.
I'm not interested in using make with the CFLAGS environment variable
But you really should. Using make or some other build automation tool (e.g. ninja, omake, rake, etc, etc....) is, in practice, the conventional and usual way of using GCC.
Alternatively, on Linux, write a tiny shell script doing the compilation (this is particularly worthwhile if your program is a single source file; for anything bigger, you really should use some build automation tool). At last, if you use emacs as your source code editor, you could add a few lines of comments (like at end of my manydl.c example) specifying Emacs file variables to tune the compilation (done from emacs)
If these conventions surprise you, read about the Unix philosophy then study -for inspiration- the source code of some existing free software (e.g. on github, gitlab, or in your favorite Linux distribution).
At last, GCC itself is a free software project (but a huge one of more than five millions lines of mostly C++ source code). So you can improve it the way you desire (if you follow its GPLv3+ license), after having studying somehow its source code. That would take you several months (or years) of work (because GCC is very complex to understand).
See also this answer to a related question.
You might also (but I recommend not to, because it is very confusing) play tricks with your PATH variable and have some directory there -e.g. $HOME/bin/, ahead of /usr/bin/ which contains /usr/bin/gcc, with your shell script named gcc; but don't do that, you'll be confused. Instead write some "generic" mygcc shell script which would run /usr/bin/gcc and add appropriate flags to it (I believe it is not worth the effort).
I am currently at the beginning stage of learning how to program in C, and I came across some questions regrading header files. For example
I have a header file named header.h,
which has int comp (int, int) declared in header.h and
defined in header.c
In such case, If i were to compile a test.c using the comp function, I would have to go like
gcc test.c header.c
First question: having to add header.c everytime I gcc seems too inconvenient and redundant. Is it a necessity? If not, is there a way I can get around it? If so, why? Or is it, in fact, not redundant compared to its usage, and am I just complaining?
Second question: if I were to use multiple .c files with functions declared in header.h my gcc would have to go
gcc test.c header.c header2.c header3.c .....
and that again seems too redundant. (and from hereon, same questions as First question..)
Thanks in advance. First time asking questions in SO. Please tell me if there is anyway I can improve the clarity of the question.
I think you are looking for the make, that automates the execution of the files you are compiling.
With the use of make, you don't need to write every time the commands like 'gcc test.c header1.c header2.c ...' in the terminal (if you type the commands directly to the terminal, yes, you will need to do this all the time, which is very redundant and costs lots of time). Using make, you only do this one time, and then all you have to do is run the make command.
You can see more about makefile at https://en.wikibooks.org/wiki/Make.
I hope it can help you.
You could make a shell macro or script to execute the command, if it is too much effort to use shell history feature to re-execute the command.
When your project starts to get complicated it's normal to use a build system in which you configure the build commands in the build system, and then you invoke the build system when you want to build. For example, write a Makefile that lists all the .c files using the right syntax for makefiles, and then type make each time you want to build.
You could consider using an Integrated Development Environment which is a (usually) GUI that includes a build system and other useful features, in which case you just need to hit a key to build and run.
It is often desirable to spread out your code across multiple files; this helps to ease code management. Header files provide a unified way to expose functions defined in libraries or source code files to other source code files without including the actual code for those functions. This way, the same header file can be included in multiple source code files without compiling the same code for each of those files. However, this means that the source code for functions in the header file must be given to the compiler also. As such, you have to give your header.c to the compiler each time you compile.
This does mean that you will compile header.c each time you build your project, which is a bit redundant. One way around this is to compile the header.c into an object file, and then give that the compiler when you build:
gcc -c header.c -o header.o
gcc header.o test.c
Furthermore, software developers often like to distribute their program functions to other developer but without providing the actaul code. To do this, they often use software libraries, which contain the compiled source code, along with header files to access this code. This is probably a little more than what your looking for, so I'll leave you read up on it.
All this is used not to reduce redundancy in your compiler commands, but in your compiled programs. To make programmers' lives easier building their programs, makefiles and IDEs are often used. These may be things you might have to read up on, but the other answers posted here should provide a good starting point.
Writing a simple Makefile is very useful for compiling C programs. Here's an example
CC = gcc
CFLAGS = -g -Wall
OBJECTS = main.o cfile1.o cfile2.o cfile3.o
run: $(OBJECTS)
$(CC) $(CFLAGS) -o run $(OBJECTS)
Don't worry about header files when writing a Makefile; only worry about your ".c" files. This example Makefile assumes that you want to compile main.c, cfile1.c, cfile2.c, and cfile3.c. When adding the C files to your Makefile, make sure to use ".o" instead of ".c".
The Makefile should be in the same directory as your C files and must be named "Makefile" with a capital M. Simply type "make" to compile. Then run the program with "./run".
I am learning C and I just read the term multiple compilation.Till now I had a single file.c and I used the command gcc file.c to compile it and then ./a.out to execute it. But I got confused a little bit. When should I use the multiple compilation instead of the single and which would be the possible reasons that they will lead me to prefer a multiple compilation instead of the single? I searched it and I found some articles but they didn't cover fully my questions. 1 (this is for c++) , 2If i undestood well if I have some files.c in my project eg file1.c, file2.c and then i want to link them, i execute
gcc file1.c
gcc file.c
gcc file1.o file2.o //somehow i have to create the .o files..
Thank you..
Compilation takes time. There's no point in re-compiling C code that hasn't changed. So, for large projects, it makes sense to split the code into multiple files (typically not randomly of course, but into modules of different functionality) and compile them only when needed.
Linking is the process of taking a bunch of object code (what the .o files are called) and turning them into a single program.
There are many steps to compiling.
When you invoke gcc it will create by default an executable file i.e. all steps in one go:
.c -> .i preprocessor
.i -> .s compiler
.s -> .o assembler
*.o -> a.out linker
Generally the first two take up the most time. If you have a large project then recompiling the entire project may take a lot of time when you are developing. So the compiler allows you to stop at a certain point and reuse previous results of files that have not changed:
gcc -E for preprocess only (rarely used)
gcc -S compile, but don't assemble. Useful for debugging or optimising assembly
gcc -c compile, assemble, but don't link. This is the most commonly used one and produces object files. Those contain your assembled functions (object code), but it's not capable of running because not all functions may be present yet, library functions are missing and the executable header has not been linked in.
The final step gcc -o executable *.o will then take all those and link them together to create an executable. Optionally linking libraries into it.
Generally having all functions in one source file will allow the compiler to do the more optimisations (i.e. inlining), but at the cost of compile time.
Have a look at https://cs.senecac.on.ca/~btp200/pages/images/compile_link.png
I have a simple, representative C program, stored in a file called hello.c:
#include <stdio.h>
int main(void)
{
printf('Hello, world\n');
return 0;
}
On my Linux machine, I attempted to compile the program with gcc:
gcc hello.c
which returns an error:
undefined reference to "___gxx_personality_v0" ... etc
As has been discussed before in the context of C++, this problem arises in the linking stage, when gcc attempts to link C libraries to a C++ program, thus giving the error. In one of the answers, someone mentioned that the extension does matter, and that gcc requires the .c extension when compiling C files, and some other extension (e.g. .cpp) when compiling C++ files.
Question: How do I set gcc to use the file extension to determine which compiler to use, since gcc seems to be defaulting to C++ on my system? Specifying the language through the file extension alone doesn't seem to be enough. If I specify the language using the -x flag, gcc functions as expected.
gcc -x c hello.c
Typically, you let make decide this.
GNU Make has built in implicit rules, which automatically pick the right compiler.
Try a Makefile with these contents:
all: some_file.o some_other_file.o
And then place a some_file.cpp and some_other_file.c in the same directory, and gnu make will automatically pick the correct compiler. The linker, you may still have to provide yourself. When mixing C and C++, it's usually easiest to link with g++, like so:
program.exe: some_file.o some_other_file.o
g++ -o $# #^
This is the same as:
program.exe: some_file.o some_other_file.o
g++ -o program.exe some_file.o some_other_file.o
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.