You're having the same problem, only backwards.
The C compiler can traditionally do a lot of things, and that is causing your confusion. Specifically, the compiler can also invoke the linker, ld, automatically to merge object files and libraries into executables.
Here are the steps that need to happen:
- Compile a C source "translation unit" into an intermediate "object" file.
- [optional] Gather multiple object files into a library (static or dynamic).
- Link one or more object files, along with zero or more libraries, into an executable file.
Your problem is occurring in step 3. Many times, you are reaching step 3 without meaning to do so.
First, the -c option to the C compiler tells it to "compile only." Meaning it should stop after step 1. You want to use this a lot!
Next, when you have multiple object files, it doesn't matter where they are. It only matters if you have all of them, and if you invoke the compiler or linker on them correctly.
The compiler is smart enough to act in lieu of the linker. So I'm never going to have you run the linker directly. Just invoke the compiler and let it figure out what needs doing, and do it.
You have two potential executable programs you can produce here. There is main.c which I really hope contains a main, and there is also test_segment.c which you have shown us contains a main().
So you need to (1) add makefile targets for your executables; and (2) make sure you pass all the required files to the compiler.
Your makefile, according to your last post, contains these lines:
Code:
test_segment: test_segment.c segment
gcc -Wall -o test_segment
main : main.c
gcc -Wall -o main main.c
segment : segment.c
gcc -Wall -o segment segment.c
The problem here is that you are invoking gcc to compile executables, but
not passing the right parameters to compile executables.
The segment target should not exist, IIUC. segment is not a program,
with a main(), it is just a bunch of functions that relate to "code segment"
objects. So the only rule you need for compiling segment.c is to produce
an object file (or maybe a library, when you have more of these files, but
that's later).
Let's rewrite that to stop after compiling, and produce an object file:
Code:
segment.o : segment.c
gcc -Wall -c segment.c -o segment.o
Next, there is test_segment.c, which you specify a dependency on segment-the-program,
but which really depends on segment.o. Sadly, you didn't give segment.o to gcc in your
make recipe. Let's fix that:
Code:
test_segment: test_segment.c segment.o
gcc -Wall test_segment.c segment.o -o test_segment
We can be a bit more clear, though, by separating the compile-the-c part
from the link-the-objects part:
Code:
test_segment: test_segment.c segment.o
gcc -Wall -c test_segment.c -o test_segment.o
gcc -Wall test_segment.o segment.o -o test_segment
Finally, we can separate the two steps so that make has a chance to only
execute the parts that really need to be done:
Code:
test_segment: test_segment.o segment.o
gcc -Wall test_segment.o segment.o -o test_segment
test_segment.o : test_segment.c
gcc -Wall -c test_segment.c -o test_segment.o
The same is true for main.c and the main executable:
Code:
main: main.o segment.o
gcc -Wall main.o segment.o -o main
main.o : main.c
gcc -Wall -c main.c -o main.o
Please note that had you left the test/ subdirectory in place, this would all
still be needed. The only difference would be the presence of a / in the
names of some of the targets.
Also, note: when you are creating tests for a subsystem, one common
case is to create "unit tests." With unit tests, you test very detailed parts
of the interface and implementation code -- whatever you think might be
broken. One result of that, for C (and C++) programs, is that you may
want to be able to call static functions, and/or access static variables.
As you may know, file-scope objects marked static are not visible to code
in other translation units (that is, "other C source files").
The standard way to get around this, for unit tests only, is to #include the
file to be tested inside the unit test code. That has the follow-on effect of
changing the structure of the Makefile, since you no longer need to have
the separate object file.