Exercise Hello-World

Objective

Learn how to work with makefiles and make utility by making a "Hello, world" program.

Check that your filesharing system works.

Introduction
Directory for the exercise

Make the directory for the hello-excercise with the command (on Lifa)

mkdir --parents ~/public_html/numeric/hello
and do the exercise in that directory.

Tabulator-sign in makefiles in nano-editor

The commands in the makefile must be prefixed with the tabulator-sign (by default) which might not be visible in the nano editor. To make them visible, create a ~/.nanorc file with the content

syntax "makefile" "[Mm]akefile"
color white,magenta " "
(or whatever colors you prefer) where there is the tabulator sign (obtained by pressing the tabulator-key on the keyboard) between the quotes in the second line.

Another solution is to use GNU Make version 3.82+ (which is installed on molveno as /usr/local/bin/make and on lifa as /usr/user/fedorov/bin/make) where the recipe prefix is controlled by the variable .RECIPEPREFIX. You can then set it to any character, for example ";" with the command

.RECIPEPREFIX := ;

Colors in terminal

It seems that on lifa the default value of the TERM environment variable (which specifies the type of the terminal you are using) is vt100, which is colorless. In order to have colors you have to change the value of this variable to xterm. You have to find out in which file this "vt100" is hiding with the command

grep vt100 .*
and then go to that file and change "vt100" to "xterm". Most probably you will have to do the following:

  • On lifa place the following line in your ~/.cshrc file (where ~/ is the alias for your home directory)

    setenv TERM xterm

  • On molveno it should be automatic but if it is not, place the following line in your ~/.profile file

    export TERM=xterm

Syntax highlighting in nano-editor

If syntax highlighting does not work for you on lifa, you can include (one of) the following lines in your ~/.nanorc file:

include /usr/share/nano/c.nanorc # c-syntax highlighting
include /usr/share/nano/java.nanorc # java-syntax highlighting
include /usr/share/nano/python.nanorc # python-syntax highlighting
include /usr/share/nano/tex.nanorc # tex-syntax highlighting
include /usr/users/fedorov/share/nano/fortran.nanorc # fortran-syntax highlighting
Tasks
  1. (6 points) Hello, world

    Create a project with the corresponding makefile with the following targets:

    1. The (default) target "A" the prerequisite of which is a text file, say, out.A.txt (eventually with the text "hello, your_name"):

      A : out.A.txt

      The file out.A.txt should be built by redirecting the output from a program—say mainA—which prints "hello, your_name" on the standard output:

      out.A.txt : mainA
      	./mainA > out.A.txt
      The mainA program should be built from a mainA.c using the recipe

      mainA : mainA.c

      The matinA.c file should look like this,

      #include<stdio.h>
      int main(){
      	printf("hello, user\n");
      	return 0;
      } 

      The interpreted languages, like python, would rather run the program via the interpreter,

      out.A.txt : mainA.py
      	python mainA.py > out.A.txt

      where the mainA.py file should look like this,

      print("hello, user")
    2. Target "cleanA" (without prerequisites) that removes all generated files leaving only the essential files:

      cleanA :
      	rm -f mainA out.A.txt

    Make sure commands make A and make cleanA work as intended.

    Comment an arbitrary line in the makefile explaining its purpose.

  2. (3 points) Linking several object-files (using several source-files)

    Here you will learn how to build a program out of several functions---let us say main, hello, and world---which are specified in separate files: main.c, hello.c, and world.c.

    Extend your makefile: now there must be a default target "all" (remember that default target is the first one) which depends on targets "A" and "B",

    all: A B

    The target B should depend on (in other words it should have as a prerequisite) another file, say out.B.txt (eventually with the same string "hello, user" in it):

    B : out.B.txt

    The file out.B.txt should be built by redirecting the output from another program—say, mainB—which also prints "hello, your_name" on the standard output:

    out.B.txt : mainB
    	./mainB > out.B.txt
    The program mainB must be linked (using make's built-in recipe) from three separate object-code files,
    mainB : mainB.o hello.o user.o
    mainB.o : mainB.c
    hello.o : hello.c
    user.o : user.c
    
    where the last three lines can be actually omitted.

    The files should contain the following functions,

    • hello.c should implement a function that prints "hello, " to the stdout:
      #include<stdio.h>
      void hello(){ printf("hello, "); } 
    • user.c should implement a function that prints "username\n" to the stdout:
      #include<stdio.h>
      void user(){ printf("user\n"); } 
    • mainB.c should implement the main function which simply calls the two previous functions,
      void hello(); void user(); int main(){ hello(); user(); return 0; } 

    For python, instead of compiling and linking, the main.py file has to import the corresponding functions from the hello.py and world.py files.

    The cleanB target has to be created similar to cleanA.

    The general clean target should also be created,

    clean: cleanA cleanB

  3. (2 points) Check

    Create a "checkA" and "checkB" targets that check whether the "A" and "B" targets have been built correctly. For example,

    checkA: out.A.txt
    	@echo "checking target A ..."
    	@printf "hello, fedorov\n" > correct.txt
    	@diff --brief correct.txt out.A.txt
    	@echo "target A seems to be ok ..."
    	@rm -f correct.txt
    
  4. (0 points) Backup (the following instructions are for lifa and molveno only, if you work on your own box ignore this exercise or figure out how to do it on your own box).

    Create a "backup" target that builds an archive of the exercise and backs it up somehow, e.g. by mailing the archive to your NFIT mail account (or any other mail address suitable for backing up):

    backup: hello.tgz
    	ssh $(shell whoami)@lifa.phys.au.dk \
    	'base64 $(shell pwd)/hello.tgz \
    	| mailx -s "hello backup" $(shell whoami)@phys.au.dk'
    hello.tgz: makefile $(shell ls *.c)
    	tar --create --gzip --file=hello.tgz makefile *.c
    	tar --list --file=hello.tgz
    
    You need to run mailx on lifa because all other servers are behind the firewall.

    The utility base64 performs encoding (and decoding) suitable for sending files as emails.

    This code above sends the encoded file directly in the body of the email. If you want to send it as an attachment you have to use the sendmail utility directly:

    email = $(shell whoami)@phys.au.dk
    backup: hello.tgz
    	echo 'From: $(shell whoami)' > tmp
    	echo 'To: $(email)' >> tmp
    	echo 'Subject: hello backup' >> tmp
    	echo 'Mime-Version: 1.0' >> tmp
    	echo 'Content-type: application/x-gzip' >> tmp
    	echo 'Content-Disposition: attachment; filename="$<"' >> tmp
    	echo 'Content-Transfer-Encoding: base64' >> tmp
    	base64 $< >> tmp
    	ssh $(shell whoami)@lifa.phys.au.dk \
    		/usr/lib/sendmail -t -oi < ($shell pwd)/tmp
    	rm -f tmp