Question

I again re-edited my question and this time it is final.

note: the program is working (thanks for all the help). But I still have some confusion about how the dependency/linkage actually works. Specifically I would like to be walked through the process that the makefile compiles and runs. (example, the compiler first looks at main.c, starting from line 1, which is main.h, goes into main.h, starting from line 1, which points to function1.h, and so on.)

My main question here is though: is it true that compiler/makefile operates in a backwards way, that is once the compiler reaches the last stop (no more link), it started to gather the content recursively and put it in the object file. And what happens if we have multiple object file and the connect is cross-linked? Should each object file be independent from each other?

Below is my final result. I know it is a lot of parts, but I have tried my best to put them in a organized way and added description.

FINALE MAKEFILE / DEPENDENCY

File layout

primary module: main.c supplementary modules: builder1.c, builder2.c builder1_function.c builder2_function.c header files: main.h control.h builder1.h builder2.h builder1_function.h builder2_function.h builder1_shared.h builder2_shared.h

1) main.c uses calls one primary function from each of builder1.c and builder2.c

2) builder1_function, builder2_function store child functions used by the primary function in builder1.c and builder2.c

3) builder1 has a set of new structures just used by it, builder2 has another set of new structures just used by it. These structures are declared in builder1_shared.h and builder2_shared.h.

4) function prototypes are declared in builder1.h builder2.h main.h

5) main.c, builder1.c, builder2.c share some constants and all uses standard libraries. These constants are declared in control.h

6) control.h: declare system-wide constants

HEADER DEPENDENCY

main.c: *include* main.h and *define* system-wide constants (declared in control.h)
main.h: *include* all std libs, *include* control.h, *include* builder1.h, *include* builder2.h

builder1.c: *include* builder1.h, uses system-wide constants, child functions of builder1, and new structures of builder1, stdlib
build1.h: *include* builder1_funcion.h *include* builder1_share.h *include* primary function prototype

builder1_function.c: *include* builder1_function.h
builder1_function.h: *include* builder1_shared.h *include* child function prototype

builder_shared.h: *include* main.h, declare new structure for buidler1

builder2.c: *include* builder2.h, uses system-wide constants, child functions of builder2, and new structures of builder2, stdlib
build2.h: *include* builder2_funcion.h *include* builder2_share.h *include* primary function prototype

builder2_function.c: *include* builder2_function.h
builder2_function.h: *include* builder2_shared.h *include* child function prototype

builder_shared.h: *include* main.h, declare new structure for buidler2

MAKEFILE

main: main.o builder1.o builder1_function.o builder2.o builder2_function.o
gcc -o main main.c builder1.c builder1_function.c builder2.c builder2_function.c -g

builder1.o: builder1.c
gcc -c  builder1.c

builder1_function.o: builder1_function.c
gcc -c builder1_function.c

builder2.o: builder2.c
gcc -c builder2.c

builder2_function.o: builder2_function.c
gcc -c builder2_function.c
Was it helpful?

Solution

Headers provide information to multiple source files. If a source file doesn't provide any services to other files, it doesn't need any header. That means main.h might not be needed, but functions.h is needed. A header should contain the minimum necessary code to allow consumers to use the functions (and variables) defined in the source code. Any other headers should be included directly in the source code (so the headers should be small, and self-contained, and idempotent).

Note that the main source file corresponding to a header (main.c for main.h, or functions.h for functions.c) should include the header as the first included file. This ensures that the header is self-contained; it won't compile if it is not. Each consumer of services from another source file should include the corresponding header. Each non-static function (and global variable if you have any) should be declared in precisely one header; that header should be used wherever the function (or global variable) is needed.

Given your problem, it appears that functions.c should include main.h (and main.h is therefore needed).

In your makefile, you should probably use:

OBJECTS = main.o functions.o

all:  main

main: ${OBJECTS}
    ${CC} -o $@ ${OBJECTS} ${CFLAGS} ${LDFLAGS} ${LDLIBS}

main.o:      main.h functions.h
functions.o: functions.h main.h

See also:

OTHER TIPS

#include is a pre-processing command that just does text inclusion - nothing more complex or magic than that.

So:

  • if a .c file has code that uses a structure, then it needs to include the header file that defines that structure.

  • if a .c file implements or calls a function, then it needs to include the header file that decares that function's prototype (this is usually the header file that matches the .c file that implements the function).

  • if a .c file uses certain system calls or types, then it needs to include the relevant system header file

Once you've got used to the concept of #include, you'll be able to work out how to structure your modules and header files efficiently and elegantly, for easy reading and maintenance.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top