Sunday, October 7, 2007

Setting Environment Variables From Make Targets

In my current project I needed to pass some pass information to some of my automated unit test programs. I needed the path that the program is being executed from to be able to read test data. As I am using a unit test framework I didn't have access to the command line variables and didn't want to take the time to change the framework to support this. So I decided to define an environment variable with the path information for the program. The unit tests can be run in two different ways, which needed different mechanisms to define the environment variable. The makefiles are setup with rules to run a single set of tests (e.g. make check_config), or running all unit tests (e.g. make check).

To support running a single set of unit tests the make file defines two targets. One that exports the environment variable and one that executes the test. For example:

TST_CONFIG_MODULE := $(d)/test_config
...
check_config : export TST_DIR:= \
$(dir $(TST_CONFIG_MODULE) )
check_config : $(TST_CONFIG_MODULE)
$(TST_CONFIG_MODULE)

Where the TST_CONFIG_MODULE defines the test program. The first check_config target exports an environment variable TST_DIR that is the directory component of, $(d), of TST_CONFIG_MODULE. The make file has to be structured this way as $(d) will not be valid by the time the target is evaluated.

For the second case the makefiles add test modules to the macro CHECK_MODULES and the check target just executes each element of this macro. As this is executed in a shell the target becomes:


check : $(CHECK_MODULES)
@for m in $(CHECK_MODULES) ; do \
export TST_DIR=`dirname $$m`; \
$$m;
done


It is a bit of a kludge to use the dirname executable to get the directory path from the test program name. Doing this assumes that we have dirname installed and that it is on the path. Bash has a built in to do this, ${dirname file}, but there does not seem to be such a builtin in sh.

Setting a Macro to Wildcarded Files

I found a mistake in one of my macro definitions. The macro was to hold all of the public header files and was defined as:

HEADERS := $(d)/*.h

This only set HEADERS to src/include/*.h instead of setting it to the files. To get they desired result the macro was changed to:

HEADERS := $(wildcard $(d)/*.h)

Saturday, August 4, 2007

Fortune Cookie Says

Hard words break no bones, fine words butter no parsnips.

Friday, July 6, 2007

Fortune Cookie Says

You will have a bright future.

Friday, June 8, 2007

Allowing Local Overrides in Make

I've been setting up a new project at work. I wanted to set up the makefile to allow a programmer to override settings without making changes to the makefiles. Make, unfortunately, does not provide a direct way to do this. I added a shell command to test for the existence of local file, and if found to return it. Make then tests the local file macro and includes the local rules file if defined. Adding the local rules file to svn ignore help to prevent any accidental changes to the makefiles. To illustrate here is the makefile.

## our directories
##
BASE_DIR := $(PWD)
RULES_DIR := rules
DOC_DIR := doc
SRC_DIR := src

## misc definitions
##
KERNEL := $(shell uname -s)
MACHINE := $(shell uname -m)
RULES_FILE := $(KERNEL)_$(MACHINE).mk
LOCAL_RULES := $(shell if [[ -e rules.local ]]; then echo rules.local; fi )

## load rules
##
dir := $(RULES_DIR)
include $(dir)/$(RULES_FILE)

# local overrides
ifdef LOCAL_RULES
include $(LOCAL_RULES)
endif

dir := $(DOC_DIR)
include $(dir)/Rules.mk

dir := $(SRC_DIR)
include $(dir)/Rules.mk

Friday, May 18, 2007

Fortune Cookie Says

A surprise treat awaits you.


Simplicity and clarity should be your theme in dress.

Sunday, April 22, 2007

Calendar Dimension

While working on a data mart and reporting system for a project I needed a way of pulling data for specific time periods for reports. This was done by using a calendar dimension, which is a table that specifies time frames primarily for reporting purposes. The dimension can be setup for any level of granularity that one needs. Since my smallest reporting period was a single month I setup a table like:
CREATE TABLE calendar_dim(
calendar_id NUMBER,
year NUMBER,
quarter NUMBER,
month_number NUMBER,
month_name VARCHAR2,
month_abbr VARCHAR2 )

The calendar_dim table is then populated with the calendar data that you need like:
1, 2006, 1, 1, 'January', 'JAN'
2, 2006, 1, 2, 'February', 'FEB'

Each table that contains dated information has a calendar_id column like:

CREATE TABLE foo_bar(
calendar_id NUMBER NOT NULL,
foo VARCHAR,
bar NUMBER )

The calendar dimension can then be used to control the time frame that queries are run for. As an example the following query sums the value bar over the first quarter of the year 2006.
SELECT fb.foo, SUM(fb.bar)
FROM foo_bar fb, calendar_dim c
WHERE
fb.calendar_id = c.calendar_id AND
c.year = 2006 AND
c.quarter = 1
GROUP BY
fb.foo;