CS360 Lab #3 -- Fakemake

  • Jian Huang
  • CS360

  • Now we get to a more fun assignment. The goal is to write a restricted and pared-down version of make(1). This will give you some practice using stat(2v) and system(3).

    Description of fakemake

    Your job is to write the program fakemake. Like make, fakemake's job is to help you automate compiling. Unlike make, fakemake limits itself to making one executable, and assumes that you are using gcc to do your compilation.

    The syntax of fakemake is as follows:

    fakemake [ description-file ]
    
    If no description-file is specified, then it assumes that the description file is the file fmakefile. Obviously, if the description file doesn't exist, then the program should exit with an error.

    Each line of the description file may be one of six things:

    What fakemake does is compile all the .c files into .o files (using gcc -c), and then compile all the .o files into the final executable. Like make, it doesn't recompile files if it is not necessary. It uses the following algorithm to decide whether or not to compile the .c files:

    If the executable file exists, and is more recent than the .o files, and no .c file has been recompiled, then fakemake does not remake the executable. Otherwise, it does remake the executable (using gcc -o).

    Obviously, if a .c or .h file is specified, and it does not exist, fakemake should exit with an error. If there are any compilation errors mid-stream, fakemake should exit immediately.


    Example

    For example, get into a clean directory and then type
    UNIX> cp ~cosc360/lab3/* .
    UNIX> ls
    f.c             f.h             f2.c            makefile        mysort.fm
    f.fm            f1.c            lab.html        mysort.c
    UNIX> make
    gcc -c -g f.c
    gcc -c -g f1.c
    gcc -c -g f2.c
    gcc -g -o f f.o f1.o f2.o
    gcc -c -g -I/home/cosc360/include mysort.c
    gcc -g -o mysort mysort.o /home/cosc360/objs/libfdr.a 
    UNIX> f
    This is the procedure F1 -- in f1.c
    This is the procedure F2 -- in f2.c
    UNIX> mysort < f.c
      f1();
      f2();
    main()
    {
    }
    UNIX> make clean
    rm -f core *.o f mysort
    UNIX> ls
    f.c             f.h             f2.c            makefile        mysort.fm
    f.fm            f1.c            lab.html        mysort.c
    UNIX>
    
    So, this directory contains source code for two programs. The first, f, is made up of three C files: f.c, f1.c and f2.c, and one header file: f.h. The second is mysort.c from the Rbtree-1 lecture. The makefile contains a specification of how to make these programs using make. The file f.fm is the fakemake file for making f, and mysort.fm is the fakemake file for making mysort. Try it out, using the fakemake executable in ~cosc360/lab3/fakemake:
    UNIX> ~cosc360/lab3/fakemake
    fakemake: fmakefile No such file or directory
    UNIX> ~cosc360/lab3/fakemake f.fm
    gcc -c -g f.c
    gcc -c -g f1.c
    gcc -c -g f2.c
    gcc -o f -g f.o f1.o f2.o
    UNIX> touch f.c         
    UNIX> ~cosc360/lab3/fakemake f.fm
    gcc -c -g f.c
    gcc -o f -g f.o f1.o f2.o
    UNIX> rm f
    UNIX> ~cosc360/lab3/fakemake f.fm
    gcc -o f -g f.o f1.o f2.o
    UNIX> touch f.h
    UNIX> ~cosc360/lab3/fakemake f.fm
    gcc -c -g f.c
    gcc -c -g f1.c
    gcc -c -g f2.c
    gcc -o f -g f.o f1.o f2.o
    UNIX> touch f.h
    UNIX> touch f.o f1.o
    UNIX> ~cosc360/lab3/fakemake f.fm
    gcc -c -g f2.c
    gcc -o f -g f.o f1.o f2.o
    UNIX> ~cosc360/lab3/fakemake f.fm
    f up to date
    UNIX> f
    This is the procedure F1 -- in f1.c
    This is the procedure F2 -- in f2.c
    UNIX> ~cosc360/lab3/fakemake mysort.fm
    gcc -c -g -I/home/cosc360/include mysort.c
    gcc -o mysort -g -I/home/cosc360/include mysort.o /home/cosc360/objs/libfdr.a
    UNIX> mysort < f.c
      f1();
      f2();
    main()
    {
    }
    UNIX> rm f.h
    UNIX> ~cosc360/lab3/fakemake f.fm
    fmakefile: f.h: No such file or directory
    UNIX> 
    
    As you can see, fm works according to the above specification. It only recompiles modules when it needs to. When you're in doubt about what your fakemake should do, see what ~cosc360/lab3/fakemake does and emulate its behavior.

    Details

    Obviously, you'll have to use stat() to test the ages of programs. The st_mtime field of the struct stat should be used as the age of the program.

    To execute a string, you use the system() procedure. It executes the given string as if that string is a shell command (sh, not csh, although it shouldn't matter). If it returns zero, the command succeeded. If it returns anything else, the command failed.


    Strategy

    It's my hope that you don't need these sections on strategy too much, but to help you out, here's how I wrote this program.