简体   繁体   中英

Combining C files with gcc through cmd

i'm trying to figure out how to make an exe with more than 1 c files..

let's say i have 2 c files, first is called main.c and second hello.c.

main.c file is like this...

#include <stdio.h>
#include <stdlib.h>

int main(void)
{

  hello();
  return 0;

}

and hello.c is like this...

#include <stdio.h>
#include <stdlib.h>

void hello(void)
{
  printf("Hello...");
}

how will my main.c file read hello() function from the other file, and how can i compile this files and make an executable with gcc..

The steps i know until now is that(with 1 c file), i open cmd.. go into my project's folder.. path %PATH% with my editor's bin folder and then gcc main.c and -o programsname and i get my exe..

So how can i combine 2 c files like above and make an exe

As far as how to do it, @Barmar has already answered correctly,

gcc -o programname main.c hello.c

will compile bothe the files and link them together.

But I think you are more interested in how it works.

Checkout the following two questions How does the compilation/linking process work? How does C++ linking work in practice?

I'll try to briefly explain here also...

Essentially the command gcc is a not just a compiler, it is what they call a driver. It will take the files main.c and hello.c through many stages of processing and help make an executable out of all that source code.

Based on the fact that gcc got two .c files as argument, it will infer that you want to use the code in both main.c and hello.c to make your executable program.

It will first take both those files individually through preprocessing, compiling and assembling phase. Then it will run the linker and input both files to it.

Preprocessing just expands macros like #include and #define .

Compiling is where the meat of the operations happen, gcc reads the c file and makes a syntax tree out of it, it might try to optimize it depending on the other optimization parameters that you passed, and then it writes a text file for each of the c files. These text files are assembly language representation of the functions written in c.

Compiling is also where gcc's compiler cc1 will encounter the line of code in main.c where you are calling hello(); and wonder what is hello and where is it. The way you can tell the compiler that hello is a function that's going to be defined elsewhere is called forward declaration. This is how it works

void hello(void);

int main(void){
  hello();
  ...

Now when cc1 encounters the call to hello() it understands to be patient and just mark this as a reference to symbol hello that it will eventually have to find.

The best practice for forward declarations is to put them in a header file, usually with the same name as the c file where the code is.

So you'd make a hello.h (like @Barmar already said) and it will read

void hello(void);

and then in the main.c you'd have a #include directive as follows...

#include "hello.h"

int main(void){
  ...

Now the forward declaration in hello.h will be copied into the c code at the time of pre-processing.

In the assembler phase gcc invokes the as assembler utility which is actually not part of the gcc package, but part of binutils package. This is the utility that will take the assembly language text and make binary object files with .o extensions ( hello.o and main.o ). These file contain machine level instructions pertaining to each of the functions defined in both main.c and hello.c .

Finally the real answer to your question lies in the linker ld . Another utility that's part of the binutils package. The linker will first do the simple task of combining all the code from the different .o files into one file which will eventually become the executable. The linker has the ability to take two or more .o files, examine the machine code and find references to foreign objects.. eg the code in main.o has referenced a function from the hello.o file. In the main.o file this is documented as a reference to a symbol, but now the linked can actually find that symbol, so it will connect that reference with the actual code object. This process is called static linking.

Finally when you run a program, the machine code gets loaded, which is essentially a set of function objects and the references between function objects are hard wired at that time based on at which memory address the functions finally get deployed.

I have probably cut many corners in my explanation, but hopefully you get the gist of it and can move forward in your quest to understand how things work.

HTH

gcc -o programname main.c hello.c

Note that this will report a linker error, because the function hello() is not defined anywhere. Either rename the function print to hello , or call print() from main() .

You should also add a declaration of the function in hello.c to main.c . Either put the declaration into the source file by hand, or create hello.h to contain it and use #include "hello.h" . The header file is generally preferable, so that when you change hello.c you only have to update one place, not all the .c files that use it.

The first way is to change main.c to:

#include <stdio.h>
#include <stdlib.h>

void hello(void); // declare external function

int main(void)
{

  hello();
  return 0;

}

The second way is to create hello.h , which contains:

#ifndef HELLO_H
#define HELLO_H

void hello(void);

#endif

And add:

#include "hello.h"

to main.c after all the other #include lines.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM