MagicMakefileV5 Tutorial #1

Create a Simple hello world Project with MagicMakefileV5

We will create a project where there is a hello() function in a library which prints "hello world" to a iostream. In addition there will be an executable program tool which uses the library.

Create Directory Structure

First, create a dir for your project and grab the magicmakefile files:

mkdir hello
cd hello
svn export http://opensource.jdkoftinoff.com/jdks/svn/trunk/magicmakefile/branches/v5/autobuild
./autobuild/make_initial_dirs.sh hello

You will now have the following directory structure:

$ ls -al
total 40
drwxr-xr-x  10 jeffk  staff   578 23 Dec 15:46 .
drwxr-xr-x   3 jeffk  staff   102 23 Dec 15:46 ..
lrwxr-xr-x   1 jeffk  staff    21 23 Dec 15:46 GNUmakefile -> autobuild/GNUmakefile
-rw-r--r--   1 jeffk  staff     0 23 Dec 15:46 LICENSE.txt
-rw-r--r--   1 jeffk  staff     0 23 Dec 15:46 README.txt
drwxr-xr-x   9 jeffk  staff  1326 23 Dec 15:46 autobuild
lrwxr-xr-x   1 jeffk  staff    19 23 Dec 15:46 configure -> autobuild/configure
drwxr-xr-x   3 jeffk  staff   136 23 Dec 15:46 docs
drwxr-xr-x   2 jeffk  staff    68 23 Dec 15:46 examples
drwxr-xr-x   2 jeffk  staff    68 23 Dec 15:46 gui
drwxr-xr-x   2 jeffk  staff    68 23 Dec 15:46 include
lrwxr-xr-x   1 jeffk  staff    17 23 Dec 15:46 package -> autobuild/package
-rw-r--r--   1 jeffk  staff   508 23 Dec 15:46 project.mak
-rw-r--r--   1 jeffk  staff    57 23 Dec 15:46 project.sh
drwxr-xr-x   2 jeffk  staff    68 23 Dec 15:46 src
drwxr-xr-x   2 jeffk  staff    68 23 Dec 15:46 tests
drwxr-xr-x   2 jeffk  staff    68 23 Dec 15:46 tools

Add Project Info

Edit your project information in the project.mak and project.sh files.

The project.mak file should be edited to look like this:

PROJECT=hello
PROJECT_NAME=hello
PROJECT_MAINTAINER=Jeff Koftinoff
PROJECT_COPYRIGHT=Copyright 2007
PROJECT_EMAIL=jeffk@jdkoftinoff.com
PROJECT_LICENSE=GPL
PROJECT_LICENSE_FILE=$(PROJECT_TOP_DIR)/LICENSE.txt
PROJECT_README_FILE=$(PROJECT_TOP_DIR)/README.txt
PROJECT_COMPANY=J.D. Koftinoff Software, Ltd.
PROJECT_WEBSITE=http://www.jdkoftinoff.com/
PROJECT_DESCRIPTION=A simple hello world project to show how to use the MagicMakefile
PROJECT_VERSION=1.0
TOP_LIB_DIRS+=.
SUBLIBS=
INCLUDES+=
DEFINES+=
COMPILE_FLAGS+=-Wall
LINK_FLAGS+=
PKGCONFIG_PACKAGES+=
CONFIG_TOOLS+=

And the project.sh file should be modified to be:

PROJECT="hello"
PROJECT_NAME="hello"
PROJECT_VERSION="1.0"

Fill in LICENSE.txt and README.txt

Since this project is GPLv2, put a copy of the GPLv2 license into the LICENSE.txt file.

Add some info the the README.txt file such as:

This is an example program using the MagicMakefileV5

Add Source Files for the Library

Next, create your header files and source files.

I personally like to make sure that each source file name is unique, even if they are in different subdirs. I also like to prefix header files with the library name. So, the include file will be named hello_hello.h

Create the file include/hello_hello.h which contains the prototype for our hello() function:


#ifndef  HELLO_HELLO_H
#define  HELLO_HELLO_H

#include <iostream>

namespace HelloProject
{
  void hello( std::ostream &s );
}

#endif

And create the body of the function in the file src/hello.cpp


#include "hello_hello.h"

namespace HelloProject
{
  void hello( std::ostream &s )
  {
    s << "Hello, World" << std::endl;
  }
}

Add Source File for the Tools

Create a file tools/hello1.cpp:

#include "hello_hello.h"

int main( int argc, char **argv )
{
  HelloProject::hello( std::cout );
  return 0;
}

Configure and Build it

We need to make a temporary subdir to build the project in. The configure stage creates a GNUmakefile and sets up the paths to install to.

mkdir build
cd build
../configure --target-platform-posix=1 --prefix=$HOME/examples --debug=1

Now, we can build it:

make

and get the results

CXX    : hello_hello.cpp
AR     : libhello.a(hello_hello.o)
ar: creating archive .../build/lib/libhello.a
CXX    : hello1.cpp
LINKING tool: hello1.o

The raw build results are in the build subdir:

$ ls -l build/
total 0
drwxr-xr-x  3 jeffk  staff  102 23 Dec 16:59 docs
drwxr-xr-x  2 jeffk  staff   68 23 Dec 16:59 examples
drwxr-xr-x  2 jeffk  staff   68 23 Dec 16:59 gui
drwxr-xr-x  2 jeffk  staff  102 23 Dec 16:59 lib
drwxr-xr-x  2 jeffk  staff  204 23 Dec 16:59 obj
drwxr-xr-x  2 jeffk  staff   68 23 Dec 16:59 tests
drwxr-xr-x  2 jeffk  staff  136 23 Dec 16:59 tools

The hello1 executable is built in build/tools

$ ls -l build/tools/
total 32
-rwxr-xr-x  1 jeffk  staff   1208 23 Dec 16:59 hello-config
-rwxr-xr-x  1 jeffk  staff  10080 23 Dec 16:59 hello1

We can run the hello1 program right away:

$ ./build/tools/hello1 
Hello, World

Installing the package

make install

and now the program is installed into $HOME/examples/bin :

$ ls -lR /Users/jeffk/examples
total 0
drwxr-xr-x  2 jeffk  staff  102 23 Dec 17:36 bin

/Users/jeffk/examples/bin:
total 24
-rwxr-xr-x  1 jeffk  staff  10080 23 Dec 16:59 hello1

Installing the development package

make install-dev

and now the program, include files, library, and config tool is installed into $HOME/examples :

$ ls -lR /Users/jeffk/examples
total 0
drwxr-xr-x  2 jeffk  staff  136 23 Dec 17:40 bin
drwxr-xr-x  3 jeffk  staff  102 23 Dec 17:40 include
drwxr-xr-x  2 jeffk  staff  102 23 Dec 17:40 lib

/Users/jeffk/examples/bin:
total 32
-rwxr-xr-x  1 jeffk  staff   1208 23 Dec 16:59 hello-config
-rwxr-xr-x  1 jeffk  staff  10080 23 Dec 16:59 hello1

/Users/jeffk/examples/include:
total 0
drwxr-xr-x  2 jeffk  staff  102 23 Dec 17:40 hello-1.0

/Users/jeffk/examples/include/hello-1.0:
total 8
-rw-r--r--  1 jeffk  staff  122 23 Dec 16:54 hello_hello.h

/Users/jeffk/examples/lib:
total 40
-rw-r--r--  1 jeffk  staff  17944 23 Dec 16:59 libhello.a

Notice the hello-config script. It is automatically generated and functions like the gnu pkg-config system. If you want to write another program that uses this library, you run the hello-config to obtain the appropriate compiler options to use the library for compiling and linking.

The options available for hello-config are:

$ /Users/jeffk/examples/bin/hello-config --help
Usage: --help --version --prefix --compiler-prefix --includes --defines --libs --cflags --cxxflags --cppflags --mflags --mmflags --cc --cxx --ldflags

And in this case, we can get the appropriate compiler flag by doing:

$ /Users/jeffk/examples/bin/hello-config --cflags
 -DDEBUG=1 -DTARGET_PLATFORM_POSIX=1 -I/Users/jeffk/examples/include/hello-1.0 -Wall -g 

and the linker flags with:

$ /Users/jeffk/examples/bin/hello-config --libs
-L/Users/jeffk/examples/lib -lhello 

The appropriate way to use the hello-config script is in your makefiles or build systems for other programs that use this library. For instance:

gcc $(/Users/jeffk/examples/bin/hello-config --cflags) -c somefile.cpp -o somefile.o
gcc $(/Users/jeffk/examples/bin/hello-config --libs) somefile.o -o somefile

You may want to try the following for more information:

make help
make compile_info

Cross Compiling for WIN32

To show a glimpse of the MagicMakefile's power, imagine you want to now build a win32 version of your hello package. First, you must have either i386-mingw32-g++ or i586-mingw32msvc-g++installed on your computer. On mac os x, you can use http://www.macports.org/ or http://fink.sourceforge.net/ - and on linux distributions like debian or ubuntu you can use the debian package manager programs to find and install mingw32 cross compilers.

Make a new subdir for building in the project dir and run a single command line:

$ mkdir buildw
$ cd buildw

run the autobuild.sh script to do the configuration and building and packaging in one step. Here we run it to build both release package (the hello1.exe), development package (the include and library files) using the i386-mingw32-g++ cross compiler. The packages will be stored in a zip file:

$ ../autobuild/autobuild.sh package-dev cross-mingw32-i386 release zip 

This gives us the build log:

CXX    : hello_hello.cpp
AR     : libhello.a(hello_hello.o)
i386-mingw32-ar: creating /Users/jeffk/src/tmp/hello/hello/buildw/build/lib/libhello.a
CXX    : hello1.cpp
LINKING tool: hello1.o
DOCS : in /Users/jeffk/src/tmp/hello/hello/docs/html
PACKAGE-ZIP
  adding: hello-1.0/ (stored 0%)
  adding: hello-1.0/programs/ (stored 0%)
  adding: hello-1.0/programs/hello1.exe (deflated 63%)
hello-config
PACKAGE-DEV-ZIP
  adding: hello-1.0/ (stored 0%)
  adding: hello-1.0/include/ (stored 0%)
  adding: hello-1.0/include/hello-1.0/ (stored 0%)
  adding: hello-1.0/include/hello-1.0/hello_hello.h (deflated 13%)
  adding: hello-1.0/lib/ (stored 0%)
  adding: hello-1.0/lib/libhello.a (deflated 54%)
  adding: hello-1.0/programs/ (stored 0%)
  adding: hello-1.0/programs/hello-config (deflated 73%)

Now, we can see in the buildw/packages directory, the zip files that are built:

$ ls -l packages/
total 176
-rw-r--r--  1 jeffk  staff  85270 23 Dec 21:52 hello-1.0-win32-i386.zip
-rw-r--r--  1 jeffk  staff   2535 23 Dec 21:52 hello-dev-1.0-win32-i386.zip

And the contents of the main package file:

$ unzip -l packages/hello-1.0-win32-i386.zip 
Archive:  packages/hello-1.0-win32-i386.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  12-23-07 21:51   hello-1.0/
        0  12-23-07 21:52   hello-1.0/programs/
   228352  12-23-07 21:52   hello-1.0/programs/hello1.exe
 --------                   -------
   228352                   3 files

And the contents of the development package:

$ unzip -l packages/hello-dev-1.0-win32-i386.zip 
Archive:  packages/hello-dev-1.0-win32-i386.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  12-23-07 21:51   hello-1.0/
        0  12-23-07 21:51   hello-1.0/include/
        0  12-23-07 21:51   hello-1.0/include/hello-1.0/
      122  12-23-07 16:54   hello-1.0/include/hello-1.0/hello_hello.h
        0  12-23-07 21:52   hello-1.0/lib/
     1762  12-23-07 21:52   hello-1.0/lib/libhello.a
        0  12-23-07 21:52   hello-1.0/programs/
     1265  12-23-07 21:52   hello-1.0/programs/hello-config
 --------                   -------
     3149                   8 files

There are other package types besides zip files. Depending on what other tools you have installed you can build:

  • tgz files with the 'tgz' packager
  • win32 setup programs with the 'nsis' packager, via the nullsoft installer at http://nsis.sourceforge.net/
  • debian .deb packages with the 'dpkg' packager
  • macosx .pkg packages with the 'macosx' packager (currently not functional)
  • redhat style .rpm packages with 'rpmbuild' (currently not functional)
  • epm native packages with the 'epm' packager, available from http://www.easysw.com/epm/

Creating WIN32 Setup.exe Programs

Once you have makensis installed on your linux or mac, you can use call autobuild.sh with nsis package type. For instance, on ubuntu:

$ ../autobuild/autobuild.sh package cross-mingw32msvc-i586 release nsis --prefix=hello

It generates the following output:

make[1]: Entering directory `/mnt/hdb1/jeffk/src/tmp/hello/buildw'
CXX    : hello_hello.cpp
AR     : libhello.a(hello_hello.o)
i586-mingw32msvc-ar: creating /home/jeffk/src/tmp/hello/buildw/build/lib/libhello.a
CXX    : hello1.cpp
LINKING tool: hello1.o
make[1]: Leaving directory `/mnt/hdb1/jeffk/src/tmp/hello/buildw'
DOCS : in /home/jeffk/src/tmp/hello/docs/html
PACKAGE-NSIS
makensis hello-1.0-win32-i386.nsi
MakeNSIS v2.28-1 - Copyright 1995-2007 Contributors
See the file COPYING for license details.
Credits can be found in the Users Manual.

Processing config: 
.....
......
Output: "setup-hello-1.0.exe"
Install: 2 pages (128 bytes), 3 sections (2 required) (3144 bytes), 221 instructions (6188 bytes), 134 strings (2264 bytes), 1 language table (234 bytes).
Uninstall: 2 pages (128 bytes), 
1 section (1048 bytes), 50 instructions (1400 bytes), 72 strings (1235 bytes), 1 language table (226 bytes).
Datablock optimizer saved 8374 bytes (~4.8%).

Using zlib compression.

EXE header size:               57344 / 45568 bytes
Install code:                   2493 / 12334 bytes
Install data:                  95093 / 303213 bytes
Uninstall code+data:           10761 / 15055 bytes
CRC (0xB105E946):                  4 / 4 bytes

Total size:                   165695 / 376174 bytes (44.0%)

And we are left with a bare-bones win32 setup-hello-1.0.exe program. To customize the installer, you need to edit package/nsis/*.nsi

Building Linux Debian/Ubuntu Packages

On linux i386, we would use the following autobuild.sh command line:

$ ../autobuild/autobuild.sh packages linux-i386 release dpkg --prefix=/opt/hello
make[1]: Entering directory `/mnt/hdb1/jeffk/src/tmp/hello/build'
CXX    : hello_hello.cpp
AR     : libhello.a(hello_hello.o)
ar: creating /home/jeffk/src/tmp/hello/build/build/lib/libhello.a
CXX    : hello1.cpp
LINKING tool: hello1.o
make[1]: Leaving directory `/mnt/hdb1/jeffk/src/tmp/hello/build'
DOCS : in /home/jeffk/src/tmp/hello/docs/html
PACKAGE-DPKG
dpkg-deb: building package `hello' in `/home/jeffk/src/tmp/hello/build/packages/hello-1.0-linux-i386.deb'.
hello-config
PACKAGE-DEV-DPKG
dpkg-deb: building package `hellodev' in `/home/jeffk/src/tmp/hello/build/packages/hello-dev-1.0-linux-i386.deb'.
DOCS-DEV :
PACKAGE-DOCSDEV-DPKG
dpkg-deb: building package `hellodocsdev' in `/home/jeffk/src/tmp/hello/build/packages/hello-docs-dev-1.0-linux-i386.deb'.

zip error: Nothing to do! (try: zip -r /home/jeffk/src/tmp/hello/build/packages/hello-testresults-1.0-linux-i386.zip . -i .)
make: ["/home/jeffk/src/tmp/hello/build/packages"/hello-testresults-1.0-linux-i386.zip] Error 12 (ignored)

Ignore the last zip error - it is just complaining that there are no test results to zip up.

Now, in the packages directory we have 3 debian .deb files:

  • hello-1.0-linux-i386.deb
  • hello-dev-1.0-linux-i386.deb
  • hello-docs-dev-1.0-linux-i386.deb

To see the information in the deb files, use dpkg --info:

$ dpkg --info ./packages/hello-1.0-linux-i386.deb 
 new debian package, version 2.0.
 size 4308 bytes: control archive= 431 bytes.
     278 bytes,    16 lines      control              
      22 bytes,     4 lines   *  postinst             #!/bin/sh
      22 bytes,     4 lines   *  postrm               #!/bin/sh
      22 bytes,     4 lines   *  preinst              #!/bin/sh
      22 bytes,     4 lines   *  prerm                #!/bin/sh
 Version: 1.0
 Package: hello
 Priority: optional
 Architecture: i386
 Essential: no
 Depends:
 Pre-Depends:
 Recommends:
 Suggests:
 Installed-Size:
 Maintainer: Jeff Koftinoff
 Conflicts:
 Replaces:
 Provides:
 Description: A simple hello world project to show how to use the MagicMakefile

To install the package, use dpkg -i:

$ sudo dpkg -i ./packages/hello-1.0-linux-i386.deb 
Selecting previously deselected package hello.
(Reading database ... 237590 files and directories currently installed.)
Unpacking hello (from .../hello-1.0-linux-i386.deb) ...
Setting up hello (1.0) ...

$ /opt/hello/bin/hello1 
Hello, World

And then uninstall it with dpkg -r:

$ sudo dpkg -r hello
(Reading database ... 237592 files and directories currently installed.)
Removing hello ...
$ /opt/hello/bin/hello1 
-bash: /opt/hello/bin/hello1: No such file or directory

To customize the debian package building, edit the files in the package/dpkg directory.

More Functionality

Doxygen Docs

If you have the excellent Doxygen tool installed from http://www.stack.nl/~dimitri/doxygen/ - then the MagicMakefile can also automatically build the doxygen generated documentation.

Try change the previous autobuild.sh run to:

$ ../autobuild/autobuild.sh package-docs-dev cross-mingw32-i386 release zip --prefix=hello 

And it will build 3 packages : The main package, the development package, and the doxygen docs, all in their own zip file.

Shipping built packages

The autobuild.sh script will also manage shipping your build results to another server. Change the target from package-docs-dev to ship-all, and add the scp destination via the --ship-to= argument like this:

$ ../autobuild/autobuild.sh ship-all cross-mingw32-i386 release zip --prefix=hello --ship-to=jeffk@some_server:some_dir

Re-Running autobuild jobs

When you run the ../autobuild/autobuild.sh script, it creates a script also called autobuild.sh in your build directory. Running it effectively re-runs the autobuild job.

More to Come

The MagicMakefileV5 has many more features, the next tutorial is coming SOON and will be at MagicMakefileV5/Tutorial2?