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?
