- Using the Zoo
- Using Unix
- Editing C programs
- Compiling programs
- Version control
- Submitting assignments
1. Using the Zoo
1.1. Getting an account
To get an account in the Zoo, follow the instructions at http://zoo.cs.yale.edu/cgi-bin/accounts.pl. You will need your NetID and password to sign up for an account.
Even if you already have an account, you still need to use this form to register as a CS 223 student, or you will not be able to submit assignments.
1.2. Getting into the room
The Zoo is located on the third floor of Arthur K Watson Hall, toward the front of the building. If you are a Yale student, your ID should get you into the building and the room. If you are not a student, you will need to get your ID validated in AKW 008a to get in after hours.
1.3. Remote use
2. Using Unix
The Zoo runs a Unix-like operating system called Linux. Most people run Unix with a command-line interface provided by a shell. Each line typed to the shell tells it what program to run (the first word in the line) and what arguments to give it (remaining words). The interpretation of the arguments is up to the program.
2.1. Getting a shell prompt in the Zoo
When you log in to a Zoo node directly, you may not automatically get a shell window. If you use the default login environment (which puts you into the KDE window manager), you need to click on the picture of the display with a shell in from of it in the toolbar at the bottom of the screen. If you run Gnome instead (you can change your startup environment using the popup menu in the login box), you can click on the foot in the middle of the toolbar. Either approach will pop up a terminal emulator from which you can run emacs, gcc, and so forth.
The default login shell in the Zoo is bash, and all examples of shell command lines given in these notes will assume bash. You can choose a different login shell on the account sign-up page if you want to, but you are probably best off just learning to like bash.
2.2. The Unix filesystem
Most of what one does with Unix programs is manipulate the filesystem. Unix files are unstructured blobs of data whose names are given by paths consisting of a sequence of directory names separated by slashes: for example /home/accts/some-user/cs223/hw1.c. At any time you are in a current working directory (type pwd to find out what it is and cd new-directory to change it). You can specify a file below the current working directory by giving just the last part of the pathname. The special directory names . and .. can also be used to refer to the current directory and its parent. So /home/accts/some-user/cs223/hw1.c is just hw1.c or ./hw1.c if your current working directory is /home/accts/some-user/cs223, cs223/hw1.c if your current working directory is /home/accts/some-user, and ../cs223/hw1.c if your current working directory is /home/accts/some-user/illegal-downloads.
All Zoo machines share a common filesystem, so any files you create or change on one Zoo machine will show up in the same place on all the others.
2.3. Unix command-line programs
Here are some handy Unix commands:
man program will show you the on-line documentation for a program (e.g., try man man or man ls). Handy if you want to know what a program does. On Linux machines like the ones in the Zoo you can also get information using info program, which has an Emacs-like interface.
ls lists all the files in the current directory. Some useful variants:
ls /some/other/dir; list files in that directory instead.
ls -l; long output format showing modification dates and owners.
mkdir dir will create a new directory in the current directory named dir.
rmdir dir deletes a directory. It only works on directories that contain no files.
cd dir changes the current working directory. With no arguments, cd changes back to your home directory.
pwd ("print working directory") shows what your current directory is.
mv old-name new-name changes the name of a file. You can also use this to move files between directories.
cp old-name new-name makes a copy of a file.
rm file deletes a file. Deleted files cannot be recovered. Use this command carefully.
chmod changes the permissions on a file or directory. See the man page for the full details of how this works. Here are some common chmod's:
chmod 644 file; owner can read or write the file, others can only read it.
chmod 600 file; owner can read or write the file, others can't do anything with it.
chmod 755 file; owner can read, write, or execute the file, others can read or execute it. This is typically used for programs or for directories (where the execute bit has the special meaning of letting somebody find files in the directory).
chmod 700 file; owner can read, write, or execute the file, others can't do anything with it.
- emacs, gcc, make, gdb, git
- See corresponding sections.
2.4. Stopping and interrupting programs
Sometimes you may have a running program that won't die. Aside from costing you the use of your terminal window, this may be annoying to other Zoo users, especially if the process won't die even if you close the terminal window or log out.
There are various control-key combinations you can type at a terminal window to interrupt or stop a running program.
Interrupt the process. Many processes (including any program you write unless you trap SIGINT using the sigaction system call) will die instantly when you do this. Some won't.
Suspend the process. This will leave a stopped process lying around. Type jobs to list all your stopped processes, fg to restart the last process (or fg %1 to start process %1 etc.), bg to keep running the stopped process in the background, kill %1 to kill process %1 politely, kill -KILL %1 to kill process %1 whether it wants to die or not.
Send end-of-file to the process. Useful if you are typing test input to a process that expects to get EOF eventually or writing programs using cat > program.c (not really recommmended). For test input, you are often better putting it into a file and using input redirection (./program < test-input-file); this way you can redo the test after you fix the bugs it reveals.
- Quit the process. Sends a SIGQUIT, which asks a process to quit and dump core. Mostly useful if ctrl-C and ctrl-Z don't work.
If you have a runaway process that you can't get rid of otherwise, you can use ps g to get a list of all your processes and their process ids. The kill command can then be used on the offending process, e.g. kill -KILL 6666 if your evil process has process id 6666. Sometimes the killall command can simplify this procedure, e.g. killall -KILL evil kills all process with command name evil.
2.5. Running your own programs
If you compile your own program, you will need to prefix it with ./ on the command line to tell the shell that you want to run a program in the current directory (called '.') instead of one of the standard system directories. So for example, if I've just built a program called count, I can run it by typing
Here the "$ " is standing in for whatever your prompt looks like; you should not type it.
Any words after the program name (separated by whitespace---spaces and/or tabs) are passed in as arguments to the program. Sometimes you may wish to pass more than one word as a single argument. You can do so by wrapping the argument in single quotes, as in
$ ./count 'this is the first argument' 'this is the second argument'
2.6. Input and output
Some programs take input from standard input (typically the terminal). If you are doing a lot of testing, you will quickly become tired of typing test input at your program. You can tell the shell to redirect standard input from a file by putting the file name after a < symbol, like this:
$ ./count < huge-input-file
A '>' symbol is used to redirect standard output, in case you don't want to read it as it flies by on your screen:
$ ./count < huge-input-file > huger-output-file
A useful file for both input and output is the special file /dev/null. As input, it looks like an empty file. As output, it eats any characters sent to it:
$ ./sensory-deprivation-experiment < /dev/null > /dev/null
You can also pipe programs together, connecting the output of one to the input of the next. Good programs to put at the end of a pipe are head (eats all but the first ten lines), tail (eats all but the last ten lines), more (lets you page through the output by hitting the space bar, and tee (shows you the output but also saves a copy to a file). A typical command might be something like ./spew | more or ./slow-but-boring | tee boring-output. Pipes can consist of a long train of programs, each of which processes the output of the previous one and supplies the input to the next. A typical case might be:
$ ./do-many-experiments | sort | uniq -c | sort -nr
which, if ./do-many-experiments gives the output of one experiment on each line, produces a list of distinct experimental outputs sorted by decreasing frequency. Pipes like this can often substitute for hours of real programming.
3. Editing C programs
To write your programs, you will need to use a text editor, preferably one that knows enough about C to provide tools like automatic indentation and syntax highlighting. There are three reasonable choices for this in the Zoo: kate, emacs, and vim (which can also be run as vi). Kate is a GUI-style editor that comes with the KDE window system; it plays nicely with the mouse, but Kate skills will not translate well into other environements. Emacs and Vi have been the two contenders for the One True Editor since the 1970s—if you learn one (or both) you will be able to use the resulting skills everywhere. My personal preference is to use Vi, but Emacs has the advantage of using the same editing commands as the shell and gdb command-line interfaces.
3.1. Writing C programs with Emacs
To start Emacs, type emacs at the command line. If you are actually sitting at a Zoo node it should put up a new window. If not, Emacs will take over the current window. If you have never used Emacs before, you should immediately type C-h t (this means hold down the Control key, type h, then type t without holding down the Control key). This will pop you into the Emacs built-in tutorial.
3.1.1. My favorite Emacs commands
General note: C-x means hold down Control and press x; M-x means hold down Alt (Emacs calls it "Meta") and press x. For M-x you can also hit Esc and then x.
Get help. Everything you could possibly want to know about Emacs is available through this command. Some common versions: C-h t puts up the tutorial, C-h b lists every command available in the current mode, C-h k tells you what a particular sequence of keystrokes does, and C-h l tells you what the last 50 or so characters you typed were (handy if Emacs just garbled your file and you want to know what command to avoid in the future).
- C-x u
Undo. Undoes the last change you made to the current buffer. Type it again to undo more things. A lifesaver. Note that it can only undo back to the time you first loaded the file into Emacs--- if you want to be able to back out of bigger changes, use git (described below).
- C-x C-s
- Save. Saves changes to the current buffer out to its file on disk.
- C-x C-f
- Edit a different file.
- C-x C-c
Quit out of Emacs. This will ask you if you want to save any buffers that have been modified. You probably want to answer yes (y) for each one, but you can answer no (n) if you changed some file inside Emacs but want to throw the changes away.
- Go forward one character.
- Go back one character.
- Go to the next line.
- Go to the previous line.
- Go to the beginning of the line.
Kill the rest of the line starting with the current position. Useful Emacs idiom: C-a C-k.
- "Yank." Get back what you just killed.
- Re-indent the current line. In C mode this will indent the line according to Emacs's notion of how C should be indented.
- M-x compile
Compile a program. This will ask you if you want to save out any unsaved buffers and then run a compile command of your choice (see the section on compiling programs below). The exciting thing about M-x compile is that if your program has errors in it, you can type C-x ` to jump to the next error, or at least where gcc thinks the next error is.
3.2. Using Vi instead of Emacs
If you don't find yourself liking Emacs very much, you might want to try Vim instead. Vim is a vastly enhanced reimplementation of the classic vi editor, which I personally find easier to use than Emacs. Type vimtutor to run the tutorial. You can always get out by hitting the Escape key a few times and then typing :qa! .
For more details, see UsingVim.
4. Compiling programs
4.1. Using gcc
A C program will typically consist of one or more files whose names end with .c. To compile foo.c, you can type gcc foo.c. Assuming foo.c contains no errors egregious enough to be detected by the extremely forgiving C compiler, this will produce a file named a.out that you can then execute by typing ./a.out.
If you want to debug your program using gdb or give it a different name, you will need to use a longer command line. Here's one that compiles foo.c to foo (run it using ./foo) and includes the information that gdb needs: gcc -g3 -o foo foo.c
By default, gcc doesn't check everything that might be wrong with your program. But if you give it a few extra arguments, it will warn you about many (but not all) potential problems: gcc -g3 -Wall -std=c99 -pedantic -o foo foo.c
4.2. Using make
For complicated programs involving multiple source files, you are probably better off using make than calling gcc directly. Make is a "rule-based expert system" that figures out how to compile programs given a little bit of information about their components.
For example, if you have a file called foo.c, try typing make foo and see what happens.
In general you will probably want to write a Makefile, which is named Makefile or makefile and tells make how to compile programs in the same directory. Here's a typical Makefile:
# Any line that starts with a sharp is a comment and is ignored # by Make. # These lines set variables that control make's default rules. # We STRONGLY recommend putting "-Wall -std=c99 -pedantic" in your CFLAGS. CC=gcc CFLAGS=-g3 -Wall -std=c99 -pedantic # The next line is a dependency line. # It says that if somebody types "make all" # make must first make "hello-world". # By default the left-hand-side of the first dependency is what you # get if you just type "make" with no arguments. all: hello-world # How do we make hello-world? # The dependency line says you need to first make hello-world.o # and hello-library.o hello-world: hello-world.o hello-library.o # Subsequent lines starting with a TAB character give # commands to execute. Note the use of the CC and CFLAGS # variables. $(CC) $(CFLAGS) -o hello-world hello-world.o hello-library.o echo "I just built hello-world! Hooray!" # We can also declare that several things depend on one thing. # Here we are saying that hello-world.o and hello-library.o # should be rebuilt whenever hello-library.h changes. # There are no commands attached to this dependency line, so # make will have to figure out how to do that somewhere else # (probably from the builtin .c -> .o rule). hello-world.o hello-library.o: hello-library.h # Command lines can do more than just build things. For example, # "make test" will rebuild hello-world (if necessary) and then run it. test: hello-world ./hello-world # This lets you type "make clean" and get rid of anything you can # rebuild. The -f tells rm not to complain about files that aren't # there. clean: rm -f hello-world *.o
Given a Makefile, make looks at each dependency line and asks: (a) does the target on the left hand side exist, and (b) is it older than the files it depends on. If so, it looks for a set of commands for rebuilding the target, after first rebuilding any of the files it depends on; the commands it runs will be underneath some dependency line where the target appears on the left-hand side. It has built-in rules for doing common tasks like building .o files (which contain machine code) from .c files (which contain C source code). If you have a fake target like all above, it will try to rebuild everything all depends on because there is no file named all (one hopes).
4.2.1. Make gotchas
Make really really cares that the command lines start with a TAB character. TAB looks like eight spaces in Emacs and other editors, but it isn't the same thing. If you put eight spaces in (or a space and a TAB), Make will get horribly confused and give you an incomprehensible error message about a "missing separator". This misfeature is so scary that I avoided using make for years because I didn't understand what was going on. Don't fall into that trap--- make really is good for you, especially if you ever need to recompile a huge program when only a few source files have changed.
If you use GNU Make (on a zoo node), note that beginning with version 3.78, GNU Make prints a message that hints at a possible SPACEs-vs-TAB problem, like this:
$ make Makefile:23:*** missing separator (did you mean TAB instead of 8 spaces?). Stop.
If you need to repair a Makefile that uses spaces, one way of converting leading spaces into TABs is to use the unexpand program:
$ mv Makefile Makefile.old $ unexpand Makefile.old > Makefile
The standard debugger on the Zoo is gdb. See C/Debugging.
6. Version control
When you are programming, you will make mistakes. If you program long enough, these will eventually include true acts of boneheadedness like accidentally deleting all of your source files. You are also likely to spend some of your time trying out things that don't work, at the end of which you'd like to go back to the last version of your program that did work. All these problems can be solved by using a version control system.
There are six respectable version control systems installed on the Zoo: rcs, cvs, svn, bzr, hg, and git. If you are familiar with any of them, you should use that. If you have to pick one from scratch, I recommend using git. For details, see UsingGit, or look at the tutorials available at http://git-scm.org.
7. Submitting assignments
The submit command is is found in /c/cs223/bin on the Zoo. Here is the documentation (adapted from comments in the script):
submit assignment-number file(s) unsubmit assignment-number file(s) check assignment-number makeit assignment-number [file] protect assignment-number file(s) unprotect assignment-number file(s) retrieve assignment-number file[s] testit assignment-number test The submit program can be invoked in eight different ways: /c/cs223/bin/submit 1 Makefile tokenize.c unique.c time.log submits the named source files as your solution to Homework #1; /c/cs223/bin/check 2 lists the files that you have submitted for Homework #2; /c/cs223/bin/unsubmit 3 error.submit bogus.solution deletes the named files that you had submitted previously for Homework #3 (i.e., withdraws them from submission, which is useful if you accidentally submit the wrong file); /c/cs223/bin/makeit 4 tokenize unique runs "make" on the files that you submitted previously for Homework #4; /c/cs223/bin/protect 5 tokenize.c time.log protects the named files that you submitted previously for Homework #5 (so they cannot be deleted accidentally); and /c/cs223/bin/unprotect 6 unique.c time.log unprotects the named files that you submitted previously for Homework #6 (so they can be deleted); and /c/cs223/bin/retrieve 7 Csquash.c retrieves copies of the named files that you submitted previously for Homework #7 /c/cs223/bin/testit 8 BigTest runs the test script /c/cs223/Hwk8/test.BigTest.
The submit program will only work if there is a directory with your name and login on it under /c/cs223/class. If there is no such directory, you need to make sure that you have correctly signed up for CS223 using the web form. Note that it may take up to an hour for this directory to appear after you sign up.