Thread: confusion on structuring a project with test files

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #5
    Registered User
    Join Date
    Apr 2021
    Posts
    143
    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:

    1. Compile a C source "translation unit" into an intermediate "object" file.
    2. [optional] Gather multiple object files into a library (static or dynamic).
    3. 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.
    Last edited by aghast; 03-04-2024 at 10:45 AM. Reason: Code block not closed

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 26
    Last Post: 06-12-2013, 05:43 PM
  2. Confusion on header and source files
    By dnguyen1022 in forum C++ Programming
    Replies: 4
    Last Post: 01-17-2009, 03:42 AM
  3. Files declaration confusion
    By guillermoh in forum C Programming
    Replies: 1
    Last Post: 02-04-2008, 10:26 AM
  4. Structuring .cpp's and .h's
    By Sentral in forum Game Programming
    Replies: 20
    Last Post: 06-05-2006, 10:10 AM
  5. Threads, Files and a Test
    By nvoigt in forum Windows Programming
    Replies: 2
    Last Post: 11-14-2005, 09:27 AM

Tags for this Thread