1

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
CrazyFrog
  • 323
  • 5
  • 19
  • 1
    `I get error message that certain struct/type are not found when compiling functions.c.` certain means which struct/type , it's from `main.h`? Also you have not included `main.h` in `function.c` file. – Jayesh Bhoi Apr 15 '14 at 06:50
  • Tell us exact errors/problems... Your question is too broad – 0xF1 Apr 15 '14 at 06:50
  • 1
    Why does `main.c` include `build.h` and not include `main.h` or `functions.h`? – Jonathan Leffler Apr 15 '14 at 06:53
  • Hey Jonathan, thanks for pointing it out. That was a modification just for posting here. Original files are build.c/h instead of functions.c/h. I change the name just for generalization. I didn't include function.c/h in main because I got compiler error by doing so, and I think I will just leave it unattached so I don't get confused with the right way for inclusion you guys suggested – CrazyFrog Apr 23 '14 at 18:06
  • Did you get it all sorted out? I didn't get notified about your comment because you didn't prefix my name with @. Two key rules to remember are SPOT (Single Point of Truth) and DRY (Don't Repeat Yourself). Make sure that each type and function has a single place where it is declared (defined for types), and then make sure you use the definitive declaration/definition whenever you need the type or function (or global variable if you actually need to use those). Ultimately, getting this right saves you pain -- lots of it. – Jonathan Leffler Apr 24 '14 at 23:05
  • In the `main` target for your makefile, `gcc -o main.c function1.c function2.c` should obviously be `gcc -o main main.o function1.o function2.o`, or replacing `main` after the `-o` with the desired name of your executable. – Crowman Apr 24 '14 at 23:06
  • 1
    Also, just to be on the safe side, you mention that you've added header guards to each header file, but you do `#define` *different* identifiers in each file, right? In other words, `#ifndef FUNCTION1_H` and `#ifndef FUNCTION2_H`, and not just `#ifndef MY_INCLUDE_GUARD` in each file? If you're still having problems, post the code for `type.h`. – Crowman Apr 24 '14 at 23:11
  • Adding to what @PaulGriffiths says (closely related), you should have `#ifndef TYPE_H_INCLUDED` as the first operational (non-comment, non-blank) line in the `type.h` header (for some distinctive name). The second operational line should be `#define TYPE_H_INCLUDED` where the two names match, and then you need `#endif // TYPE_H_INCLUDED` as the last operational line in the header. You don't state that you do the `#define`; your error message suggests that maybe you don't do the `#define`. – Jonathan Leffler Apr 24 '14 at 23:22
  • @Paul Griffiths Alright guys, thank you so much for your advices! I have corrected my linkage somehow, following these general rules you mentioned. Thought I am still a little confused. I posted my final makefile and my new questions in the post area. Again thank you so much! – CrazyFrog Apr 25 '14 at 07:02

2 Answers2

3

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:

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
2

#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.