Monthly Archives: December 2012

Quick git patch commands

As always, git has many more options…

Creating a git patch is very similar to SVN.

$ git diff [commit-id-before] [commit-id-after] > my.patch
format-patch is a command to create ready-to-send patches. One commit is created in one file. To extract the three topmost commits from the current branch:
$ git format-patch -3
To extract patches from a range of commits:
$ git format-patch commit-id-start..commit-id-end
To extract patches since a commit:
$ git format-patch commit-id
Note: In the latter case, this extracts patches since the commit-id excluded.

Applying a patch

Test the patch:
git apply --check my.patch
Finally, sign it off:
git am --signoff < my.patch

More nice git usage examples can be found in Git memo.

Latitude and Longitude – UTM conversion

Geographic/UTM Coordinate Converter is a great tool for converting from Latitude and Longitude to UTM and vice versa. Some time ago, I had to automate some conversions and I rewrote the javascript code from that website in python.

Sample usage

import latlonutm as ll
[[northing, easting], zone, hemi] = ll.LatLonToUtm(lat, lon)
[lat, lon] = ll.UtmToLatLon(northing, easting, zone, southhemi)

Implementation

'''
This module converts between lat long and UTM coordinates.

Geographic coordinates are entered and displayed in degrees.
Negative numbers indicate West longitudes and South latitudes.
UTM coordinates are entered and displayed in meters.
The ellipsoid model used for computations is WGS84.

Usage:
import latlonutm as ll
[[northing, easting], zone, hemi] = ll.LatLonToUtm(lat, lon)
[lat, lon] = ll.UtmToLatLon(northing, easting, zone, southhemi)

Converted from javascript by Nenad Uzunovic
Original source
http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html
'''

import math

# Ellipsoid model constants (actual values here are for WGS84)
sm_a = 6378137.0;
sm_b = 6356752.314;
sm_EccSquared = 6.69437999013e-03;

UTMScaleFactor = 0.9996;

def DegToFloat(degrees, minutes, seconds):
    '''
    Converts angle in format deg,min,sec to a floating point number
    '''
    if (degrees>=0):
        return (degrees) + (minutes/60.0) + (seconds/3600.0)
    else:
        return (degrees) - (minutes/60.0) - (seconds/3600.0)

def DegToRad(deg):
    '''
    Converts degrees to radians.
    '''
    return (deg / 180.0 * math.pi);

def RadToDeg(rad):
    '''
    Converts radians to degrees.
    '''
    return (rad / math.pi * 180.0);

def ArcLengthOfMeridian(phi):
    '''
    Computes the ellipsoidal distance from the equator to a point at a
    given latitude.

    Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
    GPS: Theory and Practice, 3rd ed.  New York: Springer-Verlag Wien, 1994.

    Inputs:
    phi - Latitude of the point, in radians.

    Globals:
    sm_a - Ellipsoid model major axis.
    sm_b - Ellipsoid model minor axis.

    Outputs:
    The ellipsoidal distance of the point from the equator, in meters.
    '''

    # Precalculate n
    n = (sm_a - sm_b) / (sm_a + sm_b);

    # Precalculate alpha
    alpha = ((sm_a + sm_b) / 2.0) 
        * (1.0 + (math.pow (n, 2.0) / 4.0) + (math.pow (n, 4.0) / 64.0));

    # Precalculate beta
    beta = (-3.0 * n / 2.0) + (9.0 * math.pow (n, 3.0) / 16.0) 
        + (-3.0 * math.pow (n, 5.0) / 32.0);

    # Precalculate gamma
    gamma = (15.0 * math.pow (n, 2.0) / 16.0) 
        + (-15.0 * math.pow (n, 4.0) / 32.0);

    # Precalculate delta
    delta = (-35.0 * math.pow (n, 3.0) / 48.0) 
        + (105.0 * math.pow (n, 5.0) / 256.0);

    # Precalculate epsilon
    epsilon = (315.0 * math.pow (n, 4.0) / 512.0);

    # Now calculate the sum of the series and return
    result = alpha 
        * (phi + (beta * math.sin (2.0 * phi)) 
           + (gamma * math.sin (4.0 * phi)) 
           + (delta * math.sin (6.0 * phi)) 
           + (epsilon * math.sin (8.0 * phi)));

    return result;

def UTMCentralMeridian(zone):
    '''
    Determines the central meridian for the given UTM zone.

    Inputs:
    zone - An integer value designating the UTM zone, range [1,60].

    Outputs:
    The central meridian for the given UTM zone, in radians, or zero
    if the UTM zone parameter is outside the range [1,60].
    Range of the central meridian is the radian equivalent of [-177,+177].
    '''
    return DegToRad(-183.0 + (zone * 6.0));

def FootpointLatitude(y):
    '''
    Computes the footpoint latitude for use in converting transverse
    Mercator coordinates to ellipsoidal coordinates.

    Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
    GPS: Theory and Practice, 3rd ed.  New York: Springer-Verlag Wien, 1994.

    Inputs:
    y - The UTM northing coordinate, in meters.

    Outputs:
    The footpoint latitude, in radians.
    '''

    # Precalculate n (Eq. 10.18)
    n = (sm_a - sm_b) / (sm_a + sm_b);

    # Precalculate alpha_ (Eq. 10.22)
    # (Same as alpha in Eq. 10.17)
    alpha_ = ((sm_a + sm_b) / 2.0) 
        * (1 + (math.pow (n, 2.0) / 4) + (math.pow (n, 4.0) / 64));

    # Precalculate y_ (Eq. 10.23)
    y_ = y / alpha_;

    # Precalculate beta_ (Eq. 10.22)
    beta_ = (3.0 * n / 2.0) + (-27.0 * math.pow (n, 3.0) / 32.0) 
        + (269.0 * math.pow (n, 5.0) / 512.0);

    # Precalculate gamma_ (Eq. 10.22)
    gamma_ = (21.0 * math.pow (n, 2.0) / 16.0) 
        + (-55.0 * math.pow (n, 4.0) / 32.0);

    # Precalculate delta_ (Eq. 10.22)
    delta_ = (151.0 * math.pow (n, 3.0) / 96.0) 
        + (-417.0 * math.pow (n, 5.0) / 128.0);

    # Precalculate epsilon_ (Eq. 10.22)
    epsilon_ = (1097.0 * math.pow (n, 4.0) / 512.0);

    # Now calculate the sum of the series (Eq. 10.21)
    result = y_ + (beta_ * math.sin (2.0 * y_)) 
        + (gamma_ * math.sin (4.0 * y_)) 
        + (delta_ * math.sin (6.0 * y_)) 
        + (epsilon_ * math.sin (8.0 * y_));

    return result;

def MapLatLonToXY(phi, lambda_pt, lambda_ctr):
    '''
    Converts a latitude/longitude pair to x and y coordinates in the
    Transverse Mercator projection.  Note that Transverse Mercator is not
    the same as UTM; a scale factor is required to convert between them.

    Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
    GPS: Theory and Practice, 3rd ed.  New York: Springer-Verlag Wien, 1994.

    Inputs:
    phi - Latitude of the point, in radians.
    lambda_pt - Longitude of the point, in radians.
    lambda_ctr - Longitude of the central meridian to be used, in radians.

    Outputs:
    xy - A 2-element array containing the x and y coordinates
    of the computed point.
    '''

    # Precalculate ep2
    ep2 = (math.pow (sm_a, 2.0) - math.pow (sm_b, 2.0)) / math.pow (sm_b, 2.0);

    # Precalculate nu2
    nu2 = ep2 * math.pow (math.cos (phi), 2.0);

    # Precalculate N
    N = math.pow (sm_a, 2.0) / (sm_b * math.sqrt (1 + nu2));

    # Precalculate t
    t = math.tan (phi);
    t2 = t * t;
    # tmp = (t2 * t2 * t2) - math.pow (t, 6.0);

    # Precalculate l
    l = lambda_pt - lambda_ctr;

    # Precalculate coefficients for l**n in the equations below
    #   so a normal human being can read the expressions for easting
    #   and northing
    #   -- l**1 and l**2 have coefficients of 1.0
    l3coef = 1.0 - t2 + nu2;

    l4coef = 5.0 - t2 + 9 * nu2 + 4.0 * (nu2 * nu2);

    l5coef = 5.0 - 18.0 * t2 + (t2 * t2) + 14.0 * nu2 
        - 58.0 * t2 * nu2;

    l6coef = 61.0 - 58.0 * t2 + (t2 * t2) + 270.0 * nu2 
        - 330.0 * t2 * nu2;

    l7coef = 61.0 - 479.0 * t2 + 179.0 * (t2 * t2) - (t2 * t2 * t2);

    l8coef = 1385.0 - 3111.0 * t2 + 543.0 * (t2 * t2) - (t2 * t2 * t2);

    # Calculate easting (x)
    xy = [0.0, 0.0]
    xy[0] = N * math.cos (phi) * l 
        + (N / 6.0 * math.pow (math.cos (phi), 3.0) * l3coef * math.pow (l, 3.0)) 
        + (N / 120.0 * math.pow (math.cos (phi), 5.0) * l5coef * math.pow (l, 5.0)) 
        + (N / 5040.0 * math.pow (math.cos (phi), 7.0) * l7coef * math.pow (l, 7.0));

    # Calculate northing (y)
    xy[1] = ArcLengthOfMeridian (phi) 
        + (t / 2.0 * N * math.pow (math.cos (phi), 2.0) * math.pow (l, 2.0)) 
        + (t / 24.0 * N * math.pow (math.cos (phi), 4.0) * l4coef * math.pow (l, 4.0)) 
        + (t / 720.0 * N * math.pow (math.cos (phi), 6.0) * l6coef * math.pow (l, 6.0)) 
        + (t / 40320.0 * N * math.pow (math.cos (phi), 8.0) * l8coef * math.pow (l, 8.0));

    return xy;

def MapXYToLatLon(x, y, lambda_ctr):
    '''
    Converts x and y coordinates in the Transverse Mercator projection to
    a latitude/longitude pair.  Note that Transverse Mercator is not
    the same as UTM; a scale factor is required to convert between them.

    Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J.,
    GPS: Theory and Practice, 3rd ed.  New York: Springer-Verlag Wien, 1994.

    Inputs:
    x - The easting of the point, in meters.
    y - The northing of the point, in meters.
    lambda_ctr - Longitude of the central meridian to be used, in radians.

    Outputs:
    philambda - A 2-element containing the latitude and longitude
    in radians.

    Remarks:
    The local variables Nf, nuf2, tf, and tf2 serve the same purpose as
    N, nu2, t, and t2 in MapLatLonToXY, but they are computed with respect
    to the footpoint latitude phif.

    x1frac, x2frac, x2poly, x3poly, etc. are to enhance readability and
    to optimize computations.
    '''

    # Get the value of phif, the footpoint latitude.
    phif = FootpointLatitude (y);

    # Precalculate ep2
    ep2 = (math.pow (sm_a, 2.0) - math.pow (sm_b, 2.0)) 
        / math.pow (sm_b, 2.0);

    # Precalculate cos (phif)
    cf = math.cos (phif);

    # Precalculate nuf2
    nuf2 = ep2 * math.pow (cf, 2.0);

    # Precalculate Nf and initialize Nfpow
    Nf = math.pow (sm_a, 2.0) / (sm_b * math.sqrt (1 + nuf2));
    Nfpow = Nf;

    # Precalculate tf
    tf = math.tan (phif);
    tf2 = tf * tf;
    tf4 = tf2 * tf2;

    # Precalculate fractional coefficients for x**n in the equations
    #   below to simplify the expressions for latitude and longitude.
    x1frac = 1.0 / (Nfpow * cf);

    Nfpow *= Nf;   # now equals Nf**2)
    x2frac = tf / (2.0 * Nfpow);

    Nfpow *= Nf;   # now equals Nf**3)
    x3frac = 1.0 / (6.0 * Nfpow * cf);

    Nfpow *= Nf;   # now equals Nf**4)
    x4frac = tf / (24.0 * Nfpow);

    Nfpow *= Nf;   # now equals Nf**5)
    x5frac = 1.0 / (120.0 * Nfpow * cf);

    Nfpow *= Nf;   # now equals Nf**6)
    x6frac = tf / (720.0 * Nfpow);

    Nfpow *= Nf;   # now equals Nf**7)
    x7frac = 1.0 / (5040.0 * Nfpow * cf);

    Nfpow *= Nf;   # now equals Nf**8)
    x8frac = tf / (40320.0 * Nfpow);

    # Precalculate polynomial coefficients for x**n.
    #   -- x**1 does not have a polynomial coefficient.
    x2poly = -1.0 - nuf2;

    x3poly = -1.0 - 2 * tf2 - nuf2;

    x4poly = 5.0 + 3.0 * tf2 + 6.0 * nuf2 - 6.0 * tf2 * nuf2 
        - 3.0 * (nuf2 *nuf2) - 9.0 * tf2 * (nuf2 * nuf2);

    x5poly = 5.0 + 28.0 * tf2 + 24.0 * tf4 + 6.0 * nuf2 + 8.0 * tf2 * nuf2;

    x6poly = -61.0 - 90.0 * tf2 - 45.0 * tf4 - 107.0 * nuf2 
        + 162.0 * tf2 * nuf2;

    x7poly = -61.0 - 662.0 * tf2 - 1320.0 * tf4 - 720.0 * (tf4 * tf2);

    x8poly = 1385.0 + 3633.0 * tf2 + 4095.0 * tf4 + 1575 * (tf4 * tf2);

    # Calculate latitude
    philambda = [0.0, 0.0]
    philambda[0] = phif + x2frac * x2poly * (x * x) 
        + x4frac * x4poly * math.pow (x, 4.0) 
        + x6frac * x6poly * math.pow (x, 6.0) 
        + x8frac * x8poly * math.pow (x, 8.0);

    # Calculate longitude
    philambda[1] = lambda_ctr + x1frac * x 
        + x3frac * x3poly * math.pow (x, 3.0) 
        + x5frac * x5poly * math.pow (x, 5.0) 
        + x7frac * x7poly * math.pow (x, 7.0);

    return philambda

def LatLonToUTMXY(lat, lon, zone):
    '''
    Converts a latitude/longitude pair to x and y coordinates in the
    Universal Transverse Mercator projection.

    Inputs:
    lat - Latitude of the point, in radians.
    lon - Longitude of the point, in radians.
    zone - UTM zone to be used for calculating values for x and y.
    If zone is less than 1 or greater than 60, the routine
    will determine the appropriate zone from the value of lon.

    Outputs:
    xy - A 2-element array where the UTM x and y values will be stored.
    '''

    xy = MapLatLonToXY(lat, lon, UTMCentralMeridian(zone));

    # Adjust easting and northing for UTM system.
    xy[0] = xy[0] * UTMScaleFactor + 500000.0;
    xy[1] = xy[1] * UTMScaleFactor;
    if (xy[1] < 0.0):
        xy[1] = xy[1] + 10000000.0;

    return xy;

def UTMXYToLatLon(x, y, zone, southhemi):
    '''
    Converts x and y coordinates in the Universal Transverse Mercator
    projection to a latitude/longitude pair.

    Inputs:
    x - The easting of the point, in meters.
    y - The northing of the point, in meters.
    zone - The UTM zone in which the point lies.
    southhemi - True if the point is in the southern hemisphere;
    false otherwise.

    Outputs:
    latlon - A 2-element array containing the latitude and
    longitude of the point, in radians.
    '''
    x -= 500000.0;
    x /= UTMScaleFactor;

    # If in southern hemisphere, adjust y accordingly.
    if (southhemi):
        y -= 10000000.0;

    y /= UTMScaleFactor;

    cmeridian = UTMCentralMeridian(zone);
    latlon = MapXYToLatLon(x, y, cmeridian);

    return latlon

def LatLonToUtm(lat, lon):
    '''
    Converts lat lon to utm

    Inputs:
    lat - lattitude in degrees
    lon - longitude in degrees

    Outputs:
    xy - utm x(easting), y(northing)
    zone - utm zone
    hemi - 'N' or 'S'
    '''

    if ((lon < -180.0) or (180.0 <= lon)):
        print 'The longitude you entered is out of range -', lon
        print 'Please enter a number in the range [-180, 180).'
        return 0

    if ((lat < -90.0) or (90.0 < lat)):
        print 'The latitude you entered is out of range -', lat
        print 'Please enter a number in the range [-90, 90].'

    # Compute the UTM zone.
    zone = math.floor ((lon + 180.0) / 6) + 1;

    # Convert
    xy = LatLonToUTMXY (DegToRad(lat), DegToRad(lon), zone);

    # Determine hemisphere
    hemi = 'N'
    if (lat < 0):
        hemi = 'S'

    return [xy, zone, hemi]

def UtmToLatLon(x, y, zone, hemi):
    '''
    Converts UTM coordinates to lat long

    Inputs:
    x - easting (in meters)
    y - northing (in meters)
    zone - UTM zone
    hemi - 'N' or 'S'

    Outputs:
    latlong - [lattitude, longitude] (in degrees)
    '''
    if ((zone < 1) or (60 < zone)):
        print 'The UTM zone you entered is out of range -', zone
        print 'Please enter a number in the range [1, 60].'
        return 0

    if ((hemi != 'N') and (hemi != 'S')):
        print 'The hemisphere you entered is wrong -', hemi
        print 'Please enter N or S'

    southhemi = False
    if (hemi == 'S'):
        southhemi = True

    # Convert
    latlon = UTMXYToLatLon(x, y, zone, southhemi)

    # Convert to degrees
    latlon[0] = RadToDeg(latlon[0])
    latlon[1] = RadToDeg(latlon[1])

    return latlon

Hopefully somebody finds it useful.

Linux Scheduler

Mainline linux kernel distribution received a number of real-time additions over that last few years. More details on OASDL site. Here is my small experiment with a program that changes it’s own scheduling policy and example on how to see traced kernel events using ftrace.

Example below shows how to change scheduling policy from within the program itself. Note, if the scheduling policy does not change at runtime a perhaps cleaner and easier solution is provided via schedtool (command line tool).

#include <sched.h>
#include <stdio.h>
#include <unistd.h>

const char * ParsePolicy(int policy)
{
  switch (policy){
  case SCHED_FIFO  : return "SCHED_FIFO";
  case SCHED_RR    : return "SCHED_RR";
  case SCHED_OTHER : return "SCHED_OTHER";
  case SCHED_BATCH : return "SCHED_BATCH";
  default : return "Did not recognize policy";
  }
}

int GetPolicy()
{
  int policy = sched_getscheduler(0);
  if (policy == -1){
    perror(__FUNCTION__);
    return -1;
  }

  fprintf(stdout, "%s - %sn", __FUNCTION__, ParsePolicy(policy));

  return policy;
}

int SetPolicy(int policy)
{
  pid_t pid = getpid();
  fprintf(stdout, "pid = %dn", (int)pid);

  fprintf(stdout, "%s - %sn", __FUNCTION__, ParsePolicy(policy));

  struct sched_param param;
  param.sched_priority = sched_get_priority_max(policy);

  fprintf(stdout, "max priority = %dn", param.sched_priority);

  int setsch = sched_setscheduler(pid, policy, &amp;param);
  if (setsch == -1)
    perror(__FUNCTION__);

  return setsch; // 0 - OK, -1 - fail
}

long long BusyWait(long long cycles)
{
  while(cycles)
    cycles--;
  return cycles;
}

int main()
{
  GetPolicy();

  long long wait = 200000000;

  SetPolicy(SCHED_FIFO);
  GetPolicy();
  BusyWait(wait);

  SetPolicy(SCHED_RR);
  GetPolicy();
  BusyWait(wait);

  SetPolicy(SCHED_OTHER);
  GetPolicy();
  BusyWait(wait);

  SetPolicy(SCHED_BATCH);
  GetPolicy();
  BusyWait(wait);

  return 0;
}

Since the program uses a simple while counter as a busy wait, you need to compile it without optimization flags.

  gcc -Wall -O0 test_schedule.c -o test_schedule

Now, in order to actually see what is happenning under the hood, we use ftrace (tracing functionality built-in in most newer kernels), trace-cmd, and kernelshark. These packages are in default Ubuntu repositories and can be installed with "sudo apt-get install trace-cmd kernelshark".

trace-cmd has many useful options. I suggest reading the man page. In this case, I will show a simple use case for the example above. We will run trace command that will execute the scheduler test from above and store scheduling info.

sudo trace-cmd record -e sched ./test_schedule

This command saves trace.dat, and shows output that looks like this:

$ sudo trace-cmd record -e sched ./test_schedule
disable all
enable sched
path = /sys/kernel/debug/tracing/events/sched/enable
path = /sys/kernel/debug/tracing/events/*/sched/enable
GetPolicy - SCHED_OTHER
pid = 10628
SetPolicy - SCHED_FIFO
max priority = 99
GetPolicy - SCHED_FIFO
pid = 10628
SetPolicy - SCHED_RR
max priority = 99
GetPolicy - SCHED_RR
pid = 10628
SetPolicy - SCHED_OTHER
max priority = 0
GetPolicy - SCHED_OTHER
pid = 10628
SetPolicy - SCHED_BATCH
max priority = 0
GetPolicy - SCHED_BATCH
offset=535000
offset=575000
offset=700000
offset=886000
offset=9ea000
offset=9f9000
offset=b57000
offset=cbc000
Kernel buffer statistics:
  Note: "entries" are the entries left in the kernel ring buffer and are not
        recorded in the trace data. They should all be zero.

CPU: 0
entries: 0
overrun: 0
commit overrun: 0
bytes: 2708
oldest event ts: 274629.435366
now ts: 274630.751883

CPU: 1
entries: 0
overrun: 0
commit overrun: 0
bytes: 2620
oldest event ts: 274630.577012
now ts: 274630.752018

CPU: 2
entries: 0
overrun: 0
commit overrun: 0
bytes: 1056
oldest event ts: 274630.581643
now ts: 274630.752128

CPU: 3
entries: 0
overrun: 0
commit overrun: 0
bytes: 3020
oldest event ts: 274630.578163
now ts: 274630.752241

CPU: 4
entries: 0
overrun: 0
commit overrun: 0
bytes: 3872
oldest event ts: 274630.514477
now ts: 274630.752359

CPU: 5
entries: 0
overrun: 0
commit overrun: 0
bytes: 1728
oldest event ts: 274630.579316
now ts: 274630.752472

CPU: 6
entries: 0
overrun: 0
commit overrun: 0
bytes: 852
oldest event ts: 274630.581604
now ts: 274630.752558

CPU: 7
entries: 0
overrun: 0
commit overrun: 0
bytes: 2300
oldest event ts: 274630.574664
now ts: 274630.752643

trace.dat is a file readable by kernelshark

If we start kernelshark in the same directory, it will automatically open trace.dat and we can closely analyze events that happened during this run.

Useful links:

Long lines in emacs

“Modes such as AutoFillMode insert a line ending after the last word that occurs before the value of option 'fill-column' (a column number).”

“Besides relying on this fill-as-you-type behavior, you can manually fill an existing paragraph with command 'fill-paragraph' ('M-q'). Instead of wrapping a single line around to the next window line, the line is divided into two separate lines, separated by a line ending.”

Source: EmacsWiki: Line Wrap

CMake Experiences

Content is stored in CMakeLists.txt

Need to specify minimum version:

cmake_minimum_required(VERSION 2.6)

Specify project name:

project(Tutorial)

Find libraries using pkg-config. First argument becomes variable prefix, last argument is the actual library name.

find_package(PkgConfig)
pkg_check_modules(BULLET REQUIRED bullet)

Set CFLAGS:

add_definitions(-g -Wall)
# Set include dirs
include_directories(
  ${BULLET_INCLUDE_DIRS}
)

Add a program and link flags:

add_executable(TutorialApplication TutorialApplication.cc)
target_link_libraries(TutorialApplication
  ${BULLET_LIBRARIES}
  )

Make uninstall can be implemented by following directions on CMake FAQ. Simple solution is to just remove files listed in install_manifest.txt like this:

xargs rm < install_manifest.txt

BASH_SOURCE

BASH_SOURCE variable is a LIFO stack of scripts that are currently being called.
From official documentation:

BASH_SOURCE
An array variable whose members are the source filenames where the corresponding shell function names in the FUNCNAME array variable are defined. The shell function ${FUNCNAME[$i]} is defined in the file${BASH_SOURCE[$i]} and called from ${BASH_SOURCE[$i+1]}

This functionality combined with readlink -f creates useful combination that can make writing scripts less prone to relative path errors.

Example:

Script aaa.sh

#!/bin/bash
echo "from ${BASH_SOURCE[0]} : BASH_SOURCE = ${BASH_SOURCE[*]}"
source bbb.sh

Script bbb.sh

#!/bin/bash
echo "from ${BASH_SOURCE[0]} : BASH_SOURCE = ${BASH_SOURCE[*]}"
source ccc.sh

Script ccc.sh

#!/bin/bash
echo "from ${BASH_SOURCE[0]} : BASH_SOURCE = ${BASH_SOURCE[*]}"
for i in ${BASH_SOURCE[@]}; do
    readlink -f $i
done

Running script aaa.sh provides ouput that looks like this:

from aaa.sh : BASH_SOURCE = aaa.sh
from bbb.sh : BASH_SOURCE = bbb.sh aaa.sh
from ccc.sh : BASH_SOURCE = ccc.sh bbb.sh aaa.sh
/tmp/ccc.sh
/tmp/bbb.sh
/tmp/aaa.sh

Simple Makefile

Sometimes when I am building simple examples and/or learning new pieces of software I find it useful to have a quick and dirty Makefile handy. Here is my example:

CXXFLAGS = -g -Wall
LDFLAGS = -pthread

.phony : default clean all
default : all

clean :
rm -vf *.o $(PROGRAMS)

define ADD_PROGRAM # template
PROGRAMS += $(1)
all  : $(1)
$(1) : $(2)
g++ -o $$@ $$^ $(LDFLAGS)
endef # end ADD_PROGRAM

$(eval $(call ADD_PROGRAM,example,example.o))

The reason I like this Makefile is because template implementation makes it cleaner to add more programs to the mix. Also, it keeps track of all the programs that are built and cleans them up properly. Basically, it saves me a few copy and pastes…