Intro to using GNU/Linux for C++ Programming - Part 1: Installation & Shell Basics

This guide will highlight important points on the way of compiling C++ programs in a GNU/Linux environment from the perspective of a GUI/IDE Windows user coming to a Unix-Like system for the first time.

The Linux distribution used is Linux Mint 12, but after installation most of the following will apply to any distro. It assumes general familiarity with C++.

Installation

First download the appropriate Linux Mint image for your system. This guide will be using the 64-bit CD version.

If you plan to use a USB drive or card reader to install Mint, first get Universal USB Installer. It doesn't need to be installed; to run it just start the executable and point it at the disc image you've downloaded.

On restart, press the key indicated for the boot menu (eg F11) and select your CD/DVD or USB drive where the Linux Mint live image is located. At the prompt select 'Start Linux Mint' and run the 'Install Linux Mint' icon on the desktop.

After selecting your language it's going to remind you that you need enough disk space and an internet connection to complete the installation process.

Next you will be presented with a few options. Unless this is the only OS and you don't have anything else on the drive to worry about, you should set up the install manually with the 'Something else' option which will give you the opportunity to setup your partitions.

Because you are limited to four primary partitions on a disk, if you have other pre-existing partitions (such as Windows) you will need to create new partitions as 'logical' rather than 'primary'. In the Linux file system, devices are kept in the /dev/ directory as file names such as 'sda', 'sdb', etc. (for SATA drives) and 'hda', 'hdb' (for IDE drives). Partition files are named after the hard drive they exist on, with an added partition number eg. sda1, sda2, etc.

The first partition you create should be a Linux swap partition at least as large as your system's total amount of RAM (eg 4GB). This is analagous to the Windows 'page file'.

The next partition you create will be ext4 type with the system / (root) as the mount point. After this you can (optionally) add more ext4 partitions for mount points /home (your files) and /usr (program files). An example would be 15GB for root, and 20GB for /home and 20GB for /usr. With the CD version of the Mint installer, a fresh install is around 3GB total so you can get by with less than this but generally no less than 10GB is recommended (plus swap space).

At the bottom of the window you can specify where the boot loader (GRUB) will be installed. If you want the Windows boot loader to remain default, then choose your root partition (eg /dev/sda6). This will require you to create a Linux Mint entry in the Windows boot loader which can be done with a program like Easy BCD. If you would like the Linux boot loader to become default instead, then install to the MBR for the drive (eg /dev/sda). If a Windows installation is detected it will appear as an entry in GRUB. Before you do anything to the Windows MBR, though, ensure you have a Windows CD or some way to restore the MBR should something go wrong.

Continuing with installation, after providing your location and keyboard setup, you will be asked to create your user information. The first field for 'name' is name displayed on your desktop and login. Your computer name is going to be the name for your host machine and will be shown on the command line, so choose something you don't mind looking at a lot. The username below will also appear on the command line and is the name the Linux system knows you by.

After you finish setting up your user, restarting the computer you can now boot normally into Linux Mint (or back to Windows to edit the boot loader).

A note about NVIDIA drivers:
The open source drivers that come pre-installed with Linux Mint do not have 3d acceleration. You should get a driver notification, or you can search programs for "Additional Drivers" to launch the driver manager. This let's you install NVIDIA drivers, but they will likely be a few months old. For the brave, follow this guide as a way to install the latest drivers. Also, you may want to wait installing NVIDIA drivers until after the initial upgrade of your system software (next section).

To launch graphical applications, press the windows key and start typing the application name and hit 'enter' when selected. The up and down arrow keys will allow you to switch between other possible matches.

The Command Line & Package Installation

This guide will show you how to do everything from the command line, so launch the terminal with the key combination CTRL-ALT-T. This is a command line interface (CLI) like the 'CMD prompt' you may have used in Windows, only more powerful. The default (graphical) terminal in Linux Mint 12 is GNOME Terminal.

You can clear the terminal with CTRL-L. Clear the current command with CTRL-U. Copying and pasting is by SHIFT-CTRL-C and SHIFT-CTRL-V.

You can scroll with SHIFT-page up/down and zoom level can be changed with CTRL-+ and CTRL--. (Note CTRL-+ requires you to hold SHIFT; you can change this to the more natural CTRL-= in Edit>Keyboard Shortcuts).

Pressing 'TAB' while typing a filename will attempt to auto-complete if a matching filename is found. And command history can be scrolled with the up/down arrows. Multiple commands may be entered in the same line by using the ; (semicolon) separator. They will be executed in left to right order.

Before we start looking at various utilities you should know about 'man [command]'. Here you substitute [command] for any of the various commands we will be using. To try it out, have a look at the man pages for the man command itself:
$ man man
To navigate, use the arrow keys or page up/down, and 'q' when finished to return to the command line. Another way to view this information is with the 'info' command. It uses the same sort of syntax (ie: info [command]), but presents the data with a different interface.

The first thing to do with a fresh installation is to upgrade everything to the latest version (you may see a shield icon at the top of the screen trying to get your attention). To achieve the update we are going to use a utility called aptitude. Linux Mint is a Debian based Linux distribution, and software installation/dependency resolution is handled by the Debian package system. Aptitude is going to provide a front-end to apt (Advanced Packaging Tool), a set of utilities for managing Debian packages and repositories. Ultimately, apt utilities are invoking dpkg which works directly with .deb package files.

Aptitude is newer than apt, and many tutorials on the internet will use apt versions of the aptitude commands used here (eg update, install). It is recommended to use aptitude instead when an equivalent command can be found.

Before upgrading anything, we need to refresh the list of packages. The repositories to index are listed in the file /etc/apt/sources.list, and in additional .list files in the directory /etc/apt/sources.list.d/:
$ sudo aptitude update
If you noticed your username in the prompt, that is because you are logged in as the user you created during installation. To use aptitude from the command line requires to be 'root' (similar to being 'administrator' in windows), so we temporarily elevate our permission for this one command with 'sudo' (Super-User Do). This will probably require you to provide your password the first time. Here 'aptitude' is the utility, and 'update' is an option that tells aptitude what we want it to do. Aptitude also has a curses GUI which you can access by running the utility 'aptitude' by itself with no options ('q' to quit). Remember you can view the manual pages for aptitude with 'man aptitude'.

Once the update is complete we upgrade:
$ sudo aptitude upgrade
This may take up to a half hour or more for the first time (less than 10 minutes for the 64-bit CD version with broadband).

When installing new software, remember to 'update' prior to doing so. For example you can install a useful GUI application called Graphical Disk Map with the command:
$ sudo aptitude install gdmap
If there are no extra dependencies to be installed, the installation should go through without prompting to continue. If you install something in this way by mistake, you can easily remove it and its configuration files with:
$ sudo aptitude purge gdmap
The command to search for packages is:
$ aptitude search [packagename]
Try using this command to search for the package 'build-essential'
$ aptitude search build-essential
p   build-essential                                               - Informational list of build-essential packages
The first field 'p' indicates the status of the package: in this case it means the package is not installed and no configuration files remain on the system. Another common state you will see is 'i' indicating the package is currently installed.

If build-essential is not currently installed, install it now. It will add the necessary libraries and compilers to work with C++ code.

Sometime you may need to add a repository in order to install software. As an example, the light-weight audio player DeaDBeeF is available in a 'ppa' repository (Personal Package Archive). To add the ppa, use the command:
$ sudo add-apt-repository ppa:starws-box/deadbeef-player
Here we are using a utility from the apt collection: add-apt-repository. This will create the file /etc/apt/sources.list.d/starws-box-deadbeef-player-raring.list which will be looked at by update:
$ sudo aptitude update
$ sudo aptitude install deadbeef
Now you can enjoy listener supported, freeform, WFMU (by adding the mp3 stream in DeaDBeeF) while you continue to learn about your new open-source OS.

The Shell Environment

The GNOME Terminal (Xterm-based) is known as a 'pseudo-terminal' because it is not a direct connection to the computer. Type the command 'ps' (Process Status):
$ ps
PID TTY          TIME CMD
1902 pts/0    00:00:00 bash
3462 pts/0    00:00:00 ps
This default ps command shows only the processes that belong to your user ID, and are running in the current terminal. The terminal for each process is identified under the 'TTY' field (TTY, common to Unix-like operating systems, is an abbreviation for 'teletype': essentially an historic term from the days of electro-mechanical video terminals. For more information, see Text-Terminal-HOWTO and The TTY demystified).

In this case the terminal is pts/0 (Psuedo-Terminal Slave). This can also be seen with the command:
$ tty
/dev/pts/0
This returns the terminal currently connected to the standard input and reveals that the tty file /pts/0 actually lives in the device directory.

Processes don't always have to be associated with a terminal. If you try process status with the option 'everything':
$ ps -e
You will see many processes have a question mark in the TTY field because they do not belong to any terminal. Some processes, however belong to terminals tty0 through tty7. Note your desktop windows server, Xorg, belongs to tty7. You can access any of the seven 'virtual terminals' with the key combination CTRL-ALT-F# where '#' is a terminal number from 1-7. This is useful if you need to perform some task that requires you to shut down Xorg. If the desktop is still running, you can get back to it with CTRL-ALT-F7.

If you take a look in the pts directory:
$ ls /dev/pts
0  ptmx
You can see the pseudo-terminal 'master' file ptmx. Even though there is no physical device connection in a pseudo-terminal, your terminal slave can communicate with ptmx as if it was a serial device port. The ls command introduced here shows you the contents of your current directory if used without argument (like 'dir' in DOS/Windows):
$ ls
Desktop  Documents  Downloads  Music  Pictures  Public  Templates  Videos
This is the content of your home directory. A shorthand way of writing your home directory is with ~ (tilde) and (if you haven't changed directories) you should see that the command prompt displays your current directory as '~', preceding the '$' symbol. If you're not sure what directory your home is, use pwd (Print Working Directory):
yourname@your-computer ~ $ pwd
/home/yourname
This particular prompt (yourname@your-computer /directory $) is characteristic of the bash shell.
yourname@your-computer ~ $ sh
$ ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  1734  1728  0  80   0 -  7297 wait   pts/0    00:00:00 bash
0 S  1000  3052  1734  0  80   0 -  1066 wait   pts/0    00:00:00 sh
0 R  1000  3053  3052  0  80   0 -  3450 -      pts/0    00:00:00 ps
$ exit
yourname@your-computer ~ $
Here we have started a different shell, sh (Bourne Shell, the ancestor of bash), and the prompt changes. Looking at the long (-l) output of ps allows us to see the PPID field (Parent-Process ID). This is telling us that ps is the child process of sh, and sh is the child process of bash. When ps is done, it automatically exits and returns us to the sh prompt. Exiting from sh returns control to bash and we're back where we started.

Change directories 'cd' with no argument will return you to your home directory. Otherwise, specify a directory to change there:
$ cd /usr/bin
$ cd ~/Documents
$ cd
$ pwd
/home/yourname
When you look at the contents of a directory with ls, by default you are not shown hidden files or directories which are hidden by fact of their having a '.' at the beginning of their filename. To see them, use the 'all' option -a:
$ ls -a
.              .cache   Documents    .gegl-0.0        .gstreamer-0.10  .local               .profile                   Templates
..             .config  Downloads    .gimp-2.6        .gtk-bookmarks   .mozilla             Public                     .thumbnails
.aptitude      .dbus    .esd_auth    .gksu.lock       .gvfs            Music                .pulse                     Videos
.bash_history  Desktop  .fontconfig  .gnome2          .ICEauthority    .nvidia-settings-rc  .pulse-cookie              .Xauthority
.bash_logout   .dmrc    .gconf       .gnome2_private  .linuxmint       Pictures             .sudo_as_admin_successful  .xsession-errors
Every directory has two 'special' hidden directories: . (current directory) and .. (parent directory).
$ ls ../../media
0123-4567  floppy  floppy0  PENDRIVE  RAID1
$ ls /media
0123-4567  floppy  floppy0  PENDRIVE  RAID1
Issued from your home directory, the two commands above give the contents of the same directory: /media.

Normally when referring to files or directories in your present working directory, the current directory is assumed and may be omitted:
$ cd .config
$ cat user-dirs.locale 
en_US
$ pwd
/home/yourname/.config
(The command 'cat' is used to print the contents of a file directly do the console. Other commands to view file contents are 'head' and 'less'; see manual pages for more information)

This is by way of saying that when you try to run an executable file, you have to explicitly include the current directory in the path. This is because executables that you run without providing the current directory in the path are only those that are in various 'bin' directories on your system (eg. /bin, /sbin, /usr/bin). This is how you are able to call utilities like 'ls' from anywhere on the system: the bin folders are searched for the appropriate executable. To see which bin folder a particular executable is located:
$ which ls
/bin/ls
$ which which
/usr/bin/which
Now to handle executables not existing in any 'bin' directory:
$ cd ~/Documents
$ touch hello.sh
$ vi hello.sh
$ cat hello.sh
#!/bin/bash
echo Hello World
$ ls -la
total 12
drwxrwxr-x 2 yourname yourname 4096 2011-12-27 12:42 .
drwxr-xr-x 6 yourname yourname 4096 2011-12-27 12:41 ..
-rw-rw-r-- 1 yourname yourname   30 2011-12-27 12:42 hello.sh
$ ./hello.sh
bash: ./hello.sh: Permission denied
$ chmod +x hello.sh
$ ls -l
total 4
-rwxrwxr-x 1 yourname yourname 30 2011-12-27 12:42 hello.sh
$ ./hello.sh
Hello World
There are a few things introduced here, but broadly in outline we created an executable file (a bash script) and ran it. The script specifies in the first line (beginning with the 'hashbang': #!) that the proper shell to use is /bin/bash, and the second line is the command we want to be run by bash. For an introduction to scripting in bash, see BASH Programming Introduction HOWTO and for advanced topics, see Advanced Bash-Scripting Guide.

After navigating to the proper folder, we first create an empty file with 'touch'. If the file was already existing, touch would update the file's time-stamp. This step is optional, because in the next command when we use the text editor 'vi', the file would be created when we write it to disk.

Vi works differently than most modern text editors. There are two modes of operation: command mode and insert mode. And it starts in command mode. To begin typing, switch to insert mode with the 'i' key. To return to command mode press 'ESC'. There are many commands which are explained here. The two you might need to finish editing the file is 'x' to delete the character under the cursor, and 'dd' to delete the current line, and 'O' to insert a blank line above the cursor (these are all issued while in command mode). When you're done editing, 'ZZ' in command mode will save the file and quit vi.

An alternative to vi that comes installed on Linux Mint 12 is nano. The reason why you were shown how to use vi is because nano isn't standard on all Linux distros, but you are pretty much guaranteed to be able to use vi on most 'hardcore' Unix-like implementations. A more powerful vi-like editor, Vim, is available to install using aptitude.

After we finish editing, 'cat' prints the content of the file to the console, letting you see its contents. The command 'echo' which the script is instructed to run will simply print the supplied text (Hello World) to the console.

Next we use 'ls -la': list all (-a) the files in the directory in the 'long' (-l) format. This allows us to see information on file permissions, sizes, and timestamps.

The first field is where we see file permissions. The first character is the filetype, eg. '-' for a regular file and 'd' for a directory. Next we have three groups of three permission types: r (read), w (write), and x (execute). Always in that order. If, in place of a letter, you see a dash (-), this means that particular permission is disallowed for that user. The first three permissions are for the file owner (user), the second three are for the file group, and the last three are for others not specified by owner or group. The owner and group here are both 'yourname' which you can see in the third and fourth fields.

Both hidden directories (. and ..) have execute permission for all users. This is normal and directories are required to have execute permission in order to function properly. However, our 'executable' shell script does not have executable permission just yet. To add this permission we use the command 'chmod'. The first argument, +x, indicates we are adding execute permissions, and the second argument is the filename. (+x adds the permission for all users; if we wanted to only change for just the owner (user), group, or others, we could use u+x, g+x, or o+x).

Now the script can be executed and note that you are required to specify where hello.sh is located with ./ (current directory).

More File Manipulation

Here is how you would create a new directory and move hello.sh into it:
$ mkdir mydir
$ mv hello.sh mydir
To create the directory the command is 'mkdir' which creates the directory with appropriate permissions of the name we provided: mydir. Moving the file with mv we provided the filename, hello.sh, and the destination directory, mydir. We can also use the mv command to rename files or directories:
$ mv mydir mysh
$ cd mysh
$ mv hello.sh hola.sh
$ cd ..
$ ls mysh
hola.sh
To copy (cp) and remove (rm) files
$ cd mysh
$ cp hola.sh hello.sh
$ rm hola.sh
$ ls
hello.sh
Directories will be excluded from the cp or rm command unless the -r (recursive) option is used.
$ cp . ~/Public
cp: omitting directory `.'
$ cp -r . ~/Public
$ ls ~/Public
hello.sh
$ rm ~/Public/hello.sh
$ cp -r . ~/Public/mydir
$ ls ~/Public
mydir
$ ls ~/Public/mydir
hello.sh
$ rm ~/Public/mydir
rm: cannot remove `/home/yourname/Public/mydir': Is a directory
$ rm -r ~/Public/mydir
$ cd ..
$ cp -r mysh ~/Public
$ ls ~/Public
mysh
$ rm -r ~/Public/mydir
Notice how copying the current directory (.) works a little bit different than other directories. With the command 'cp -r . ~/Public' only the contents of the current directory are copied into ~/Public. Only when we provide a directory name do we get a new directory created in ~/Public. However at the end of the example, when we copy the directory mysh explicitly, a new directory is created: ~/Public/mysh.

Mounting drives from the command line

The utility fdisk will provide you with a way of managing your hard drive space. To list the various storage devices on your system:

$ sudo fdisk -lu

Disk /dev/sda: 250.1 GB, 250059350016 bytes

    ...
Immediately following 'Disk' is the name of the drive (eg /dev/sda). This is the name you will use to mount a drive (if it is not already mounted):
$ sudo mount /dev/sdc mymount
$ sudo umount mymount
In this example I mount a drive at '/dev/sdc' in local directory 'mymount'. Drives are un-mounted with the 'umount [mount-point]' command.

To automatically mount a drive at startup, edit the file /etc/fstab as root and add a line of the form:
/dev/partition /directory type defaults 0 0
Here you would substitute the appropriate partition you found with fdisk, at an existing directory of your choosing, with an appropriate file system type (eg ext3, ext4, ntfs-3g). Optionally you can have the drive mount as read-only by changing the string 'defaults' to 'ro,defaults'.

Once this line is saved in the /etc/fstab file, you can apply the change by using the mount command option '-a':
$ sudo mount -a
If you have saved the line correctly you should see the disk is now mounted as a result.

Pipelines

From the command line you are able to redirect the standard output of a process to the standard input of another process (a feature of Unix-like systems).

An example would be to send the output of the command ps -e to the input of the utility grep (may be interpreted as standing for 'global regular expression printer') in order to find a specific process in the list. We use the symbol | (pike) to specify the standard output of the left hand side is piped to the standard input of the right hand side.
$ ps -e | grep Xorg
 1115 tty7     00:00:40 Xorg
Grep only shows lines that matched the string we provided: 'Xorg'. This line is somewhat less useful without the column labels. We can use regular expression to match a number of terms:
$ ps -el > myfile
$ grep "TTY\|Xorg" myfile
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S     0  1140  1115  5  80   0 - 37438 poll_s tty7     00:00:57 Xorg
With a regular expression of this sort, the quote marks are required. The seperator \| is essentially a logical 'or': we are returned lines matching any one of the terms. We also introduced another form of output redirection with the > (greater than) symbol: the output of the left-hand side is written to the filename on the right-hand side.

This is a common example and in fact there exists a specialized utility for this purpose:
$ pgrep -l Xorg
1140 Xorg
As you can see 'pgrep' will find the processes matching the query provided (the -l option includes the process name in the output).

Part 2: GCC & Python

No comments:

Post a Comment