Autoconf - Automake

http://sources.redhat.com/automake/automake.html

Cross Compile for AVR

emerge crossdev
crossdev -t avr
ln -s /usr/i686-pc-linux-gnu/avr/lib/ldscripts /usr/libexec/gcc/avr/ldscripts

Cross Compile for PPC

First install eldk described here .

Automake and Autoconf

We use automake and autoconf, because cmake cannot cross compile yet. At first we need some files for automake:

touch NEWS
touch README
touch AUTHORS
touch ChangeLog

Create a autogen.sh:

#!/bin/sh
rm -f config.cache
rm -f acconfig.h

autoreconf --force --install -I config -I m4
#autoconf
#autoheader
#automake --add-missing

./configure "$@"

echo
echo "Now type 'make' to compile."

We have the following directory structure:

/
 -> i2c

Now create a file called configure.ac:

AC_INIT(icecube, 0.1)
AC_PREREQ(2.5)
AC_CONFIG_SRCDIR([i2c/readMax6633.c])
AC_CONFIG_AUX_DIR(config)

AM_INIT_AUTOMAKE(1.8)

AC_PROG_CC

dnl Checks for header files.
AC_CONFIG_HEADER(config.h)
AC_HEADER_STDC
AC_CONFIG_FILES([Makefile i2c/Makefile])
AC_OUTPUT

And a file Makefile.am:

EXTRA_DIST = autogen.sh configure
SUBDIRS = i2c

In the directory i2c create a file Makefile.am:

INCLUDES = -I/usr/local/eldk/ppc_6xx/usr/include

bin_PROGRAMS = readMax6633
readMax6633_SOURCES = readMax6633.c

Now execute the script autogen.sh with:

./autogen.sh --host=ppc-6xx --prefix=/usr/local/eldk/ppc_6xx/usr/local

To cross-compile now do the following:

export CROSS_COMPILE=ppc_6xx-
make

cmake

Create a file CMakeLists.txt:

project (ICECUBE)

SET(CMAKE_C_FLAGS "-O")
add_subdirectory(i2c)

And a file i2c/CMakeLists.txt:

add_executable (readMax6633 readMax6633.c)

Now execute:

CC=ppc_6xx-gcc cmake .

Kernel Module for 2.6

With Normal Makefile

The hello world program. With normal Makefile, the Makefile:

ARCH		:= i386
CROSS_COMPILE	:= 
#CROSS_COMPILE	:= ppc_6xxx-
INSTALL		:= install -c

INSTALL_DATA	:= $(INSTALL) -m 644
KERNELVERSION	:= $(shell uname -r)
# KERNELVERSION	:= 2.6.16-mpc52xx-gc92bc8e3
EXTRA_CFLAGS 	:= -g -I/usr/realtime/include -I/usr/include/ -ffast-math -mhard-float

KDIR		:= /lib/modules/$(KERNELVERSION)/build
PWD		:= $(shell pwd)

obj-m		:= hello_world.o

all:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
#	gcc -o scope scope.c
clean:
	rm -f *.o *.ko *.mod.o *.mod.c .*.{cmd,flags} Modules.symvers
	rm -rf config.status config.log autom4te*.cache .tmp_versions

The hello_world.c:

#include <linux/module.h>
#include <asm/io.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_fifos.h>

MODULE_LICENSE("GPL");


int init_module(void)
{
   printk("in init_module\n");
   return 0;
}

void cleanup_module(void)
{
   printk("in cleanup_module\n");
   return;
}

With Automake and Autoconf

create the directory structure:

mkdir test
cd test
mkdir src
mkdir m4
touch NEWS
touch README
touch AUTHORS
touch ChangeLog

Now we create the Makefile.am:

ACLOCAL_AMFLAGS = -I m4

SUBDIRS = src
EXTRA_DIST = autogen.sh

Now we create a m4 script to get the kernel-source named m4/acinclude.m4:

dnl check for kernel source

AC_DEFUN([AC_PATH_KERNEL_SOURCE_SEARCH],
[
  kerneldir=missing
  kernelext=ko
  no_kernel=yes

  if test `uname` != "Linux"; then
    kerneldir="not running Linux"
  else
    for dir in /usr/src/kernel-source-`uname -r` /usr/src/linux-`uname -r` /usr/src/linux /lib/modules/`uname -r`/build ${ac_kerneldir}; do
      if test -d $dir; then
        kerneldir=`dirname $dir/Makefile`/
        no_kernel=no
      fi;
    done
  fi

  if test x${no_kernel} != xyes; then
    if test -f ${kerneldir}/Makefile; then
      if test "${ac_pkss_mktemp}" = "yes"; then
        ac_pkss_makefile=`mktemp /tmp/LIRCMF.XXXXXX`
      else
        ac_pkss_makefile=/tmp/LIRCMF.XXXXXX
      fi
      cat ${kerneldir}/Makefile >${ac_pkss_makefile}
      echo "lirc_tell_me_what_cc_is:" >>${ac_pkss_makefile}
      echo "	echo \$(CC)" >>${ac_pkss_makefile}

      kernelcc=`make -s -C ${kerneldir} -f ${ac_pkss_makefile} lirc_tell_me_what_cc_is`

      echo "lirc_tell_me_what_version_is:" >>${ac_pkss_makefile}
      echo "	echo \$(VERSION)" >>${ac_pkss_makefile}
      echo "lirc_tell_me_what_patchlevel_is:" >>${ac_pkss_makefile}
      echo "	echo \$(PATCHLEVEL)" >>${ac_pkss_makefile}
      version=`make -s -C ${kerneldir} -f ${ac_pkss_makefile} lirc_tell_me_what_version_is`
      patchlevel=`make -s -C ${kerneldir} -f ${ac_pkss_makefile} lirc_tell_me_what_patchlevel_is`
      if test ${version} -eq 2; then
        if test ${patchlevel} -lt 5; then
          kernelext=o
        fi
      fi
      rm -f ${ac_pkss_makefile}
    else
      kerneldir="no Makefile found"
      no_kernel=yes
    fi
  fi
  ac_cv_have_kernel="no_kernel=${no_kernel} \
		kerneldir=\"${kerneldir}\" \
		kernelext=\"${kernelext}\" \
		kernelcc=\"${kernelcc}\""
]
)

AC_DEFUN([AC_PATH_KERNEL_SOURCE],
[
  AC_CHECK_PROG(ac_pkss_mktemp,mktemp,yes,no)
  AC_PROVIDE([AC_PATH_KERNEL_SOURCE])
  AC_MSG_CHECKING(for Linux kernel sources)

  AC_ARG_WITH(kerneldir,
    [  --with-kerneldir=DIR    kernel sources in DIR], 

    ac_kerneldir=${withval}
    AC_PATH_KERNEL_SOURCE_SEARCH,

    ac_kerneldir=""
    AC_CACHE_VAL(ac_cv_have_kernel,AC_PATH_KERNEL_SOURCE_SEARCH)
  )
  
  eval "$ac_cv_have_kernel"

  AC_SUBST(kerneldir)
  AC_SUBST(kernelcc)
  AC_SUBST(kernelext)
  AC_MSG_RESULT(${kerneldir})
]
)

Create now the file configure.ac:

dnl Proccess this file with autoconf to produce a configure script.
AC_INIT(hello_world, 0.1)
AC_PREREQ(2.5)
AC_CONFIG_SRCDIR(src/hello_world.c)
AC_CONFIG_AUX_DIR(config)

AM_INIT_AUTOMAKE(1.8)

dnl Checks for programms
AC_PROG_CC

AC_PATH_KERNEL_SOURCE

default_moduledir=/lib/modules/`uname -r`/misc
AC_ARG_WITH(moduledir,
[  --with-moduledir=DIR    kernel modules in DIR (/lib/modules/`uname -r`/misc)],
moduledir=${withval},
moduledir=${default_moduledir})

AC_SUBST(moduledir)

AC_OUTPUT(Makefile src/Makefile)

Now generate the src/Makefile.am:

EXTRA_DIST = Makefile.kernel Makefile.common
EXTRA_PROGRAMS = automake_dummy
automake_dummy_SOURCES = hello_world.c

module_DATA = hello_world.o

include ./Makefile.common
      Note: The user can specify the locations of these directories when running the configure script. For more info, run configure --help.

Create the Makefile.common:

KERNEL_LOCATION=@kerneldir@
KBUILD_VERBOSE = 1

ARCH		:= i386
CROSS_COMPILE	:= 
#CROSS_COMPILE	:= ppc_6xxx-

#KERNELVERSION	:= $(shell uname -r)
# KERNELVERSION	:= 2.6.16-mpc52xx-gc92bc8e3
HELLO_WORLD_EXTRA_CFLAGS = -g -I/usr/realtime/include -I/usr/include/ -ffast-math -mhard-float

PWD		:= $(shell pwd)


export HELLO_WORLD_EXTRA_CFLAGS module_DATA

$(module_DATA): $(automake_dummy_SOURCES)
	mv Makefile Makefile.automake
	cp Makefile.kernel Makefile
	$(MAKE) -C $(KERNEL_LOCATION) SUBDIRS=$(PWD) modules \
		KBUILD_VERBOSE=$(KBUILD_VERBOSE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
	mv Makefile.automake Makefile

CLEANFILES = $(module_DATA) .$(module_DATA).{cmd,flags} .$(module_DATA:.o=.@kernelext@).cmd \
	$(module_DATA:.o=.mod.c) .$(module_DATA:.o=.mod.o.cmd) $(module_DATA:.o=.@kernelext@) \
	Modules.symvers *~

clean:
	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
	rm -rf .tmp_versions 

Create Makefile.kernel:

EXTRA_CFLAGS += $(HELLO_WORLD_EXTRA_CFLAGS)

obj-m=$(module_DATA)
MI_OBJS = $(module_DATA)

all clean:
	$(warning **************************************************)
	$(warning *** Makefile trick not undone, trying to recover *)
	$(warning **************************************************)
	mv Makefile.automake Makefile
	$(MAKE) $@

# The following is needed for 2.5 kernels and also let's the makefile work
# when things get screwed.
ifneq (,$(wildcard $(KERNEL_LOCATION)/Rules.make))
include $(KERNEL_LOCATION)/Rules.make
endif

Print Source Code

To have a nice output the following command can be used to generate a nice files.pdf with the complete project print in highlighted colors:

find . -name '*.js' -or -name '*.json' -or -name '*.html'\
|xargs enscript -r -2 --file-align=1 --highlight --color --line-numbers -o - |ps2pdf - files.pdf
-r print landscape
-2 two pages by side
--file-align=1 every file on one page
--highlight and --color highlight the code with color
--line-numbers include line numbers
-o - print the output to stdout

Test-Framework

Installation

To install it type:

emerge sys-devel/automake
emerge sys-devel/autoconf
emerge dev-libs/check

or
apt-get install autoconf automake check

Setting up with autoconf and automake

Create a directory for your project and create a file autogen.sh:

#!/bin/sh
if [ -n "$CHECK_DIR" ]; then
    aclocal -I $CHECK_DIR
else
    aclocal
fi
autoconf
autoheader
automake --add-missing

./configure "$@"

echo
echo "Now type 'make check' to compile."

Create the file Makefile.am:

INCLUDES=@CHECK_CFLAGS@

if HAVE_CHECK
TESTS=check_money
else
TESTS=
endif

noinst_PROGRAMS=$(TESTS)

lib_LIBRARIES= libmoney.a

libmoney_a_SOURCES= \
    money.h\
    money.c

check_money_SOURCES= \
	 money.h\
	 money.c\
	 check_money.c

check_money_LDADD= @CHECK_LIBS@

Now create the file configure.in:

dnl Process this file with autoconf to produce a configure script.
AC_INIT(money.h)
AM_INIT_AUTOMAKE(money,0.2)

dnl Checks for programs.
AC_PROG_AWK
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S

dnl This macro is defined in check.m4 and tests if check.h and libcheck.a
dnl can be found. It sets CHECK_CFLAGS and CHECK_LIBS accordingly.
dnl AM_PATH_CHECK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
AM_PATH_CHECK(,[have_check="yes"],
	AC_MSG_WARN([Check not found; cannot run unit tests!])
	[have_check="no"])
AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes")

dnl Checks for header files.
AM_CONFIG_HEADER(config.h)

dnl Checks for typedefs, structures, and compiler characteristics.

dnl Checks for library functions.

AC_OUTPUT(Makefile)

Create the programm itself

Create the file money.c:

#include <money.h>

Create the file money.h:

#ifndef MONEY_H
#define MONEY_H

#endif

Create the file check_money.c:

#include <check.h>
#include <stdlib.h>
#include "money.h"

START_TEST (test1)
{
}
END_TEST

int main(void)
{
   return 0;
}

Create the testroutines

Edit check_money.c:

#include <check.h>
#include <stdlib.h>
#include "money.h"

Money *five_dollars;
void setup(void)
{
   five_dollars=money_create(5, "USD");
}

void teardown(void)
{
   money_free(five_dollars);
}

START_TEST (test_create)
{
   fail_unless(money_amount(five_dollars)==5, 
          "Amount not set correctly on creation");
   fail_unless(strcmp(money_currency(five_dollars), "USD") == 0, 
          "Currency not set correctly on creation");
}
END_TEST

START_TEST (test_neg_create)
{
   Money *m=money_create(-1, "USD");
   fail_unless(m == NULL,
          "NULL should be returned on attempt to create with a negative amount");
}
END_TEST

START_TEST (test_zero_create)
{
   Money *m=money_create(0,"USD");
   fail_unless(money_amount(m)==0,"Zero is a valid amount of money");
}
END_TEST

Suite *money_suite(void)
{
   Suite *s=suite_create("Money");
   TCase *tc_core=tcase_create("Core");
   TCase *tc_limits=tcase_create("Limits");
   
   
   suite_add_tcase (s, tc_core);
   suite_add_tcase (s, tc_limits);
   

   tcase_add_test(tc_core, test_create);
   tcase_add_checked_fixture(tc_core, setup, teardown);
   
   tcase_add_test(tc_limits, test_neg_create);
   tcase_add_test(tc_limits, test_zero_create);
   
   return s;
}


int main(void)
{
   int nf;
   Suite *s=money_suite();
   SRunner *sr=srunner_create(s);

   srunner_set_log(sr, "test.log");
   
   srunner_run_all(sr, CK_NORMAL);
   nf=srunner_ntests_failed(sr);

   srunner_free(sr);
   return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

Create the functions

Edit money.h:

#ifndef MONEY_H
#define MONEY_H

typedef struct Money Money;

Money *money_create(int amount, char *currency);
int money_amount(Money *m);
char *money_currency(Money *m);
void money_free(Money *m);

#endif

Edit money.c:

#include <stdlib.h>
#include <money.h>

struct Money
{
      int amount;
      char *currency;
};

Money *money_create(int amount, char *currency) 
{ 
   if(amount <0)
      return NULL;
   Money *m = malloc(sizeof(Money));
   if(m == NULL)
      return NULL; 
   m->amount=amount;
   m->currency=currency;
   return m;
}
int money_amount(Money *m) 
{ 
  return m->amount; 
}
char *money_currency(Money *m) 
{ 
  return m->currency; 
}

void money_free(Money *m) 
{ 
   free(m);
}

Performing the checks

To prepare the compilation type:

./autogen.sh
./configure

To check if everything is fine and compile it type:

make check

Using Cmake

We create a simple program from two object files which are link to some external libraries. Create the file CMakeLists.txt:

PROJECT(measure)
ADD_EXECUTABLE(measure video.c Xgraphics.c)

Now we need to create the Makefile with:

cmake .

Now easily compile with:

make

Valgrind

http://www.cprogramming.com/debugging/valgrind.html