Search code examples
gccmakefilecompilationg++object-files

Can you create independent layers of abstraction when linking object files with GCC?


I have some files like:

a.c a.h
b.c b.h
c.c c.h
d.c d.h

where a uses b, b uses c, c uses d.

When compiling, is there a way that I can only link a directly to b instead of including all of them in my compile statement?

somehow use:

gcc a.o b.o

instead of:

gcc a.o b.o c.o d.o

I want to do this so that a doesn't have to worry about if b or c or d is implemented using any other files, and instead can just point itself directly to b.o

Side Question, is there a way to also do a wild card object command like that also goes into file recursively:

gcc *.o

I'm curious and just in case the best case scenario above isn't possible


Solution

  • You seem to have a slight misconception of how compiling and linking work.

    Suppose the files look like this:

    //a.h
    // nothing in particular
    
    //a.c
    #include "b.h"
    int main()
    {
      bravo();
      return 0;
    }
    
    //b.h
    void bravo();
    
    //b.c
    #include "c.h"
    void bravo()
    {
      charlie();
    }
    
    //c.h
    void charlie();
    
    //c.c
    #include "d.h"
    void charlie()
    {
      delta();
    }
    

    and so on.

    As you can see, the code in a.c refers to code declared in b.h and defined in b.c. It does not refer to anything in c or d.

    You can build a.o by compiling [1]:

    gcc -c a.c    
    

    The "-c" means "build the binary object file and stop, don't try to build an executable". The compiler notices the line

    #include "b.h"
    

    and pulls "b.h" into the code. It does not look at b.c, because no one has told it to. It sees that this code uses bravo(), which has not been defined, and it trusts that someone will provide this function when the time comes to build an executable. The compiler neither knows nor cares about b.c, charlie(), delta() nor any of the c or d files.

    When it comes time to build an executable, the linker comes into play [2]:

    gcc a.o b.o c.o d.o
    

    The linker can build an executable out of these files because all of the functions that are called, are defined, so it can tie up all of the loose ends. This:

    gcc a.o b.o
    

    will not work. The linker says "hold on, I can't build a complete program out of this, you call charlie(), but I see no definition of charlie()!"

    [1] There is some disagreement about whether this should be called "compiling a.c" or "compiling a.o", but that is not important here.

    [2] Notice that gcc contains both a compiler and a linker, as well as other things. It's like a Swiss Army knife.