CS-220 Fall 2016 Lab 1 Hello World

Introduction to Linux

Linux is a UNIX based operating system, widely used in the industry, and often preferred by professionals to more user oriented operating systems.

Unix supports a complete Graphical User Interface (you are using that now), with all of the tools like those you are used to using in Microsoft Windows or Apple OS X, such as web browsers, text editors, and file/directory browsers. However, the full graphic user interface tools are not as standardized on UNIX as they are in other places, and UNIX started out as a command line user interface. Therefore, it is worthwhile to get a basic understanding of the UNIX command line interface. To start this process, open a terminal window to enable command line processing.

Open a Terminal Window

In the upper left corner of the Graphical User Interface (GUI), there is a menu. Choose Activities. This will add sub-menu to your display that has two buttons, Windows and Applications, where "Windows" is currently selected, which shows the list of windows currently open on your desktop. Choose Applications to list all the programs installed on this computer. On the right hand side of this display is a list of categories. From the category list, click on Accessories and click on the icon labeled Terminal. When you click on the terminal icon, a terminal window will open up on your desktop.

A terminal window is surrounded by a border. Within the border is a window title. The window title starts off as Terminal. The terminal window has its own menu line, with labels like File Edit View Search Terminal Help. Feel free to play around with the menu items a little. For instance, can you change the window title to Hello World?

The main body of the terminal window is a scrollable window that runs a UNIX command line. The command line in the UNIX window consists of things that you type, represented here by this font, and things the computer types back to you, represented here by this font.

Command Line Prompts

The computer has typed a "prompt" string in your terminal window to indicate that it is waiting for you to type something. This prompt string starts with the name of the machine you are running on followed by a colon. All of the machines in the lab are named "q22-xx, where xx is a number. For instance, you may see q22-08:.

The second part of the prompt string is the "current directory". More about directories and the current directory shortly, but for now, your current directory is represented by a single tilde character, "~".

The last part of the prompt is a greater than sign, ">", to indicate that the terminal window is waiting for you to type a UNIX command. When you type a command and hit the enter key, that command is passed to the command interpreter. The command interpreter executes the command and possibly types its results back to the terminal window. When it is done, control returns to the terminal window, which prints a prompt, and then waits for your next command. So the entire prompt string will look something like :

   q22-08:~>

UNIX Files and Directories

Note - all the commands described here (plus a few more) are summarized here.

In UNIX, the file system is organized into files and directories, similar to Mac/OS and Windows. (Actually. Mac/OS and Windows copied the directory concept from UNIX.) Each directory is a container which can contain other directories, called sub-directories, or files. The top level directory is called "/", and forward slashes are used to delineate a directory from a sub-directory. Therefore, directory "/import/linux/home/tbarten1/Lab01" is a directory which is the Lab01 subdirectory of the "/import/linux/home/tbarten1" directory, which in turn is the "tbarten1" sub-directory of the "/import/linux/home" directory; and so on. We also say that a directory with a sub-directory is the "parent" directory of the sub-directory. For instance, "/import/linux/home" is the parent directory of the "/import/linux/home/tbarten1" sub-directory.

There are two special directories that UNIX keeps track of. The first is the "current directory", sometimes also called the "working directory". When you type a command in UNIX that needs to know what directory you are talking about, and you don't specify a directory, the "current directory" is the directory that will be used as a default. The "pwd" command stands for "Print Working Directory". At the command prompt in your terminal window, type pwd to see your current directory.

When commands need a file or a directory name, and you type a file or directory name that does not start with a forward slash (/), then UNIX puts the current directory (followed by a forward slash) in front of whatever you typed. For instance, if your current directory is "/import/linux/home/tbarten1", and you type ls Lab01, then UNIX will perform the "ls" command on the directory "/import/linux/home/tbarten1/Lab01".

To change your current directory, use the "cd" (Change Directory) command, where the argument to the command is the directory that you want to become the current directory. UNIX uses the short-hand ".." to indicate "parent of the current directory". Type the command cd ... Notice how the prompt changes. Then type pwd to find out the current directory. Then type the command to change your current directory back to the directory you came from.

The second important directory for UNIX is your "home" directory. Your home directory is the directory that is your current directory when you first log in to a UNIX machine. Typically, your home directory is the starting place for your own personal disk space in UNIX. You have the authority to create files and sub-directories from your home directory, but others usually cannot read or write files in your home directory. The "cd" command with no arguments makes your home directory the current directory. In UNIX, there is a shorthand for your home directory - a single tilde. Thus "cd ~" and "cd" do the same thing. Notice that the tilde shorthand notation is used in the command prompt.

To list the contents of a directory, use the "ls" command, specifying the name of the directory as an argument. To list the contents of the current directory (which should now be your home directory", type ls. To list the contents of the top level directory, type ls /.

Commands can have special options to control how they operate. In UNIX, the convention is to indicate parameters which change how a command operates through the use of "flags". A flag starts with a dash, "-", followed usually by a single letter (but sometimes a full word.) For instance, the -l flag to the ls command tells ls to list more information about each file or subdirectory. Try typing ls -l to get a "long" list of what is in your home directory. You will see one line for each entry. The beginning of each line has a bunch of characters... rwxd, etc. If the very first character is a "d", the line refers to a sub-directory. If the first character is a dash, "-", the line refers to a file. Do you have any files in your home directory?

Managing Files and Directories

With your home directory as current directory, type mkdir junk. Then try an ls -l. Notice that your have created a new sub-directory of your home directory called "junk". Now, type ls -l junk. Notice that the "junk" sub-directory is empty. Now type cd junk to make the junk sub-directory your current diretory.

Type gedit test.txt. This opens a "gedit" editor widow on your desktop, and you are currently editing file "test.txt" in directory "~/junk". Look back at your terminal window, and notice that there is no prompt. The "gedit" command has not finished yet, so you are not allowed to type any new commmands on your command window. Exit out of the "gedit" editor window, and notice that the command line prompt appears after the "gedit" window closed. Normally, the UNIX command line processor runs on only one command at a time - but when you have an editor window open, it would be nice to be able to edit and run commmands at the same time. To fix this problem, type gedit test.txt&. In UNIX, an ampersand (&) at the end of a command tells UNIX to start the command in a new process, but as soon as the commmand is started, don't wait for it to stop... keep doing what you were doing. In this case, that means print the command prompt, and wait for the next command. Check your terminal window, and notice that there is a new prompt. In UNIX, when a command ends with an ampersand, we say it is "running in the background".

In the terminal window, do an ls -l. Notice that the directory is still empty, even though the editor is working on "test.txt". In the gedit window, do a Save. Then go back to the terminal window and do another ls -l. Notice that the test.txt file has been created in the junk subdirectory. Close the gedit window, and look at the terminal window again. Notice that when a background command ends, a message appears on the terminal window.

Now, do a cd to get back to your home directory, and type rmdir junk. What happens? Next, type rm junk/test.txt. Then do ls -l junk. Try removing the junk subdirectory again. Did it work this time?

If you would like to learn more about UNIX, there is a good tutorial here

Writing your First C program

From your home directory, make a sub-directory called "Lab_01", and cd to that directory. Then edit file "hello.c", and type the following text into that file...

#include <stdio.h>
int main(int argc,char **argv) {
   printf("Hello World - welcome to C!\n");
   return 0;
}

Notice that as you type, the gedit editor highlights and colors your code, based on the C syntax. Gedit knows to do this because of the .c file type.

Save your file.

In your terminal window, type the command: gcc -g -Wall -o helloWorld hello.c. If you have any compile errors, they will get printed to the screen, and you need to fix them. Compiler warnings will get printed to the screen as well. If there are errors, the output file will not be created, but if there are warnings, the output file is still created. It just might not work as expected. If nothing gets printed to the screen, there were not errors or warnings... you did good!

If you want to learn more about the gcc command, here is a link to the On-line gcc manual.

Once your file compiles cleanly, run the resulting command by typing ./helloWorld. What happened?

Using the "make" command

If you are not still in the Lab01 subdirectory, cd to that directory.

If you still have an edit window open, type gedit Makefile. (If not, use the same command, but put an & on the end to run in the background.) Type the following text into your Makefile in the edit window...

helloWorld : hello.c
  gcc -g -Wall -o helloWorld hello.c
  
test : helloWorld
  ./helloWorld
  
clean:
  -rm helloWorld

These represent three "make" rules, with the real target of "helloWorld", and phony targets of "test" and "clean". Make sure that the second line of each rule starts with a tab... not with spaces. The "helloWorld" target builds the helloWorld executable file, the "test" target runs that executable, and the "clean" target removes the exectuable.

Run the command make clean. What happened? If you get a line that looks like:
Makefile:2: *** missing separator. Stop.
Then you did not start the second line of each rule with a tab. Go back and edit your Makefile and make sure the second line of each rule starts with a tab. Once you have things working, do an ls command to see the list of files in the Lab01 directory.

Now run the command make test. What happened this time?

Run the command make test again. Are your results different?

Running the GDB debugger

Next we are going to start the debugger... gdb. Start the debugger by typing: gdb helloWorld. This will result in several messages from gdb about loading your program and starting the debugging environment, and end with the gdb prompt: (gdb).

Note that if at any point in running gdb, you get into some state that is unexpected and doesn't work, you can always type the gdb command quit at the gdb prompt, and start this section again.

At the GDB prompt, type list to list the source of your program.

At the GDB prompt, type break 3 to set a breakpoint at line 3 of your program.

At the GDB prompt, type run. This will start your program and run it until either your program ends, or it hits a break point. Luckily, we have already set a breakpoint at line 3 of your program, so it should stop there. What shows up on your screen when the program stopped?

At the GDB prompt, type print argc to print the current value of the argc variable. What is the value of argc? By convention, C passes two arguments to the "main" function. The first is an integer. Most often, we call this argument "argc" to represent the count of the number of arguments passed to this function. The second argument is of type "char **", which literally means a pointer to a pointer to a character, but really (and we'll learn more about this later) indicates that the second argument is an array of character strings - where each character string represents an argument to the program.

At the GDB prompt, type print argv[0] to print the current value of the first argument (the argument with index 0). What is it? Again, by convention, C treats the executable file itself as the first argument to your program.

At the GDB prompt, type next to move to the next line of your program. What shows up in the terminal window?

Continue typing next until your program finishes. How do you know your program finished? Note that you may have to type next several times before it becomes obvious that gdb has finished.

Note that even though your program has finished, the gdb prompt is still open. Now we will rerun your program. At the GDB prompt, type run arg1 arg2. What happened?

Again, type print argc. What is the value of argc now?

Print out the value of all of the argument strings. The first time you ran, there was only one argument string in argv[0]. Now, there are more arguments available, so you should be able to print out argv[1], ... Note that if you had not been running under the gdb debugger, then you pass argument strings to the program by typing them on the command line, after the command line name. For instance, outside of gdb, I could run ./helloWorld arg1 arg2 and get the same results as running helloWorld in gdb, and running run arg1 arg2.

What happens when you try to print out past the end of the list of arguments. For instance, what do you get if you run the command print argv[3] to print the "4th" argument? What about the fifth? The sixth?

When you are done, type quit at the gdb prompt to exit out of gdb, and get back to the command line.

For more information about the GDB debugger, see the On-line GDB manual

Lab Report

Download and edit the following file: lab1_report.txt. Then submit your editted file on Blackboard in the Lab 1 submission area.