pandora-build example – Getting Started with pandora-build

May 13th, 2010

Monty Taylor one of the primary contributors to the drizzle project has done some great work putting together a automake/autoconf framework which has been released as pandora-build The framework came about as a result of trying to maintain and improve the build system for several projects mostly related to drizzle or at least belonging to the drizzle developers. It was a pain to duplicate the work in multiple places and it was obvious the setup would be of great use to other projects and so it was pulled out, cleaned up, and released as a skeletal project. One of the best “features” of the project is that it turns on as much -W* and related flags as possible thus ensuring your code is as clean, portable, and bug-free as the compiler is capable of. It can take some getting used to, but trust me this is a very good thing.

If you go and grab the tarball you’ll have a pretty good start on a build system for you project, but as it stands there’s essentially no documentation on what to do next. Given that I’m intending to write a quick-start guide to getting a project off the ground with pandora-build. This post will also give you a starts on working with dynamically linked libraries and executables that depend on them. We’ll also use build out a basic unit test framework using cppunit.

Before we get started I wanted lament the lack of decent autotools documentation on the internet and to mention a good book/source of information that I grabbed several years ago: GNU Autoconf, Automake, and Libtool. There’s another book on the subject that is not yet available (as of this writing May/2010,) but it looks promising: GNU Autoconf, Automake, and Libtool

Ok, with that taken care of the first you’ll want to do is to make sure you have a few dependencies satisfied, a rough list of which follows:

  • g++/make/etc.
  • automake
  • autoconf
  • autoconf-archive
  • libtool
  • python
  • libcppunit (devel libs)

On ubuntu you can run the following to install them:

  sudo apt-get install build-essential automake autoconf autoconf-archive libtool \
    python libcppunit-dev

To check out the results of this tutorial download pandora-example.tar.gz.

Once those are out of the way we can move on to downloading a release of pandora-build which can be found on the right-hand side of the pandora-build project page. Next we need to extract the files and rename the directory.

    $ tar xvzf pandora-build-*.tar.gz
    $ mv pandora-build-*/ pandora-example/
    $ cd pandora-example

We can now look around at the base files. Most of them we’ll leave as-is, but there’s a few changes we’ll need to make. We’ll first look at configure.ac and modify the header and AC_INIT information to suit our project. After that we’ll add a AM_PATH_CPPUNIT line just before AC_CONFIG_FILES and add our pkg-config file to AC_CONFIG_FILES directive. Finall we’ll add some parameters to PANDORA_CANONICAL_TARGET to indicate that we want warnings, that we require cxx, and that we want to skip the shared library visibility checks and support, which you actually shouldn’t do, but it complicates the example. (see http://gcc.gnu.org/wiki/Visibility for information about visibility and look for a future post on the subject.) Anyway, after making these changes configure.ac should look like the following:

# pandora-example
AC_DEFUN([PANDORA_EXAMPLE_VERSION],[0.01])

AC_INIT([pandora-example],PANDORA_EXAMPLE_VERSION,
        [http://something.pandora-example.com])
AC_CONFIG_SRCDIR([m4/pandora_canonical.m4])
AC_CONFIG_AUX_DIR(config)

PANDORA_CANONICAL_TARGET(warnings-always-on, require-cxx, skip-visibility)

AM_PATH_CPPUNIT(1.9.6)

AC_CONFIG_FILES(Makefile helloworld/helloworld.pc)

AC_OUTPUT

We now need to make a few modifications to Makefile.am, namely removing most of it’s contents leaving only ACLOCAL_AMFLAGS. Following that we’ll place a few variable declarations up top and add a couple include directives. We’ll end up with the following Makefile.am:

# pandora-example

ACLOCAL_AMFLAGS= -I m4

# includes append to these:
SUFFIXES =
TESTS =
check_PROGRAMS =
noinst_HEADERS =
nobase_nodist_include_HEADERS =
nobase_dist_include_HEADERS =
bin_PROGRAMS =
sbin_PROGRAMS =
lib_LTLIBRARIES =
noinst_LTLIBRARIES =
noinst_PROGRAMS =

include helloworld/include.am
include tests/include.am

We won’t be making use of all of those variables now, but it doesn’t hurt anything to have them in there so that if/when they’re necessary we don’t have to go back and add them. If you prefer feel free to remove everything we’re not immediately using.

Ok, that’s it for the editing portion of things, now we’ll need to create some directories and files. We’ll start by building the directory structure:

    $ mkdir -p helloworld/include/helloworld-1.0 tests

And then continue on to create some files in those directories starting with helloworld/include.am:

# vim:ft=automake

# library

INCNAME=helloworld-1.0

lib_LTLIBRARIES+=helloworld/libhelloworld.la

helloworld_libhelloworld_ladir=$(includedir)/$(INCNAME)
helloworld_libhelloworld_la_CPPFLAGS=-I. -I$(srcdir)/helloworld/include
helloworld_libhelloworld_la_LDFLAGS=
helloworld_libhelloworld_la_HEADERS=\
			 helloworld/include/$(INCNAME)/phrase.h
helloworld_libhelloworld_la_SOURCES=\
			 helloworld/phrase.cpp

pkgconfigdir= $(libdir)/pkgconfig
pkgconfig_DATA= helloworld/helloworld.pc

# exec

helloworld_helloworld_CPPFLAGS=-I. -I$(srcdir)/helloworld/include
helloworld_helloworld_LDFLAGS=
helloworld_helloworld_LDADD=helloworld/libhelloworld.la
helloworld_helloworld_SOURCES=\
			      helloworld/helloworld.cpp

bin_PROGRAMS+=helloworld/helloworld

There’s a couple things going on there as we’re defining both a shared library and an executable that depends on it. The first variable, INCNAME, is just a helper that prevents us from having to duplicate a value in multiple places. The lib_LTLIBRARIES line adds a new shared library to the set of things we’re going to build and the next set of lines tell automake about the shared library. I don’t want to get too far in to what’s going on here or else I’ll end up (re-)writing a book, but I do want to point out the use of named and versioned include directories as it’s a useful best-practice. In this case helloworld’s headers will be placed in the directory $(includedir)/helloworld-1.0/ and thus will be included by apps that need them with directives like “#include <helloworld-1.0/parser.h>.” This allows multiple major versions of your library to co-exist on a single system. The final piece of the library section tells automake where to find our pkg-config file and where to install it (more later.)

Ok the exec section is more straightforward, to anyone familiar with automake anyway, and just defines an executable that depends on libhelloworld.so that we defined above and makes sure that the app can get at the headers when it is compiling (before they’re installed or more correctly make sure that it uses the source versions, not installed ones.) The final line bin_PROGRAMS adds our exec to the list of executables that automake should build and install.

Now we’ll move on to the include.am file in the tests directory. It’s similar to the one we just created, but doesn’t create (shared) libraries or installed executables. It instead creates check_PROGRAMS, executables that are built and run with make check.

# vim:ft=automake

TESTS+=\
      tests/phrase_test

check_PROGRAMS+=$(TESTS)

tests_phrase_test_CPPFLAGS=$(CPPUNIT_CFLAGS) -I$(srcdir)/helloworld/include
tests_phrase_test_LDFLAGS=$(CPPUNIT_LIBS) helloworld/libhelloworld.la
tests_phrase_test_SOURCES=tests/phrase_test.cpp

We have one more “infrastructure” file to deal with for now which will add pkg-config functionality to our shared library. The following needs to be placed in helloworld/helloworld.pc.in

prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@

Name: helloworld
Description: Hello World Pandora Build Example
Version: @VERSION@
Libs: -L${libdir} -lhelloworld
Cflags: -I${includedir}

autoconf/configure will take the above file and create helloworld.pc substituting all of the actual values in place of their variables and automake will install it to the appropriate directory thanks to the lines we added to helloworld/include.am’s library section.

That leaves us with the code. We won’t spend too much time on it as that’s not the purpose of the post. I’ll just tell you the file name and provide the contents to place in it. Here we go.

helloworld/include/helloworld-1.0/phrase.h:

#ifndef _HELLOWORLD_1_0_PHRASE_H_
#define _HELLOWORLD_1_0_PHRASE_H_

#include <string>

namespace helloworld
{
    class Phrase
    {
    private:
        std::string _text;

    public:
        Phrase (const std::string & text);
        virtual ~Phrase ();

        const std::string & getText() const
        {
            return this->_text;
        }

        void setText(const std::string & text)
        {
            this->_text = text;
        }

    protected:
        Phrase (const Phrase & rhs);

        Phrase & operator= (const Phrase & rhs);

    };
}

#endif // _HELLOWORLD_1_0_PHRASE_H_

helloworld/phrase.cpp:

#include "config.h"

#include "helloworld-1.0/phrase.h"

using namespace helloworld;

Phrase::Phrase (const std::string & text) : _text (text)
{
}

Phrase::~Phrase ()
{
}

Phrase::Phrase (const Phrase & rhs) : _text (rhs._text)
{
}

Phrase & Phrase::operator= (const Phrase & rhs)
{
    this->_text = rhs._text;

    return *this;
}

helloworld/helloworld.cpp:

#include "config.h"

#include <stdio.h>

#include "helloworld-1.0/phrase.h"

int main (int argc, char ** argv)
{
    (void)argc;
    (void)argv;

    helloworld::Phrase phrase ("Hello World!");

    fprintf (stdout, "%s\n", phrase.getText().c_str());

    return 0;
}

tests/phrase_test.cpp:

#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TestRunner.h>
#include <cppunit/TestResult.h>
#include <cppunit/ui/text/TestRunner.h>

#include <helloworld-1.0/phrase.h>

class PhraseTest : public CPPUNIT_NS::TestFixture
{
    CPPUNIT_TEST_SUITE (PhraseTest);
    CPPUNIT_TEST (testPhrase);
    CPPUNIT_TEST_SUITE_END ();

public:
    void setUp ();
    void tearDown ();

    void testPhrase ();
};

CPPUNIT_TEST_SUITE_REGISTRATION (PhraseTest);

void PhraseTest::setUp ()
{
}

void PhraseTest::tearDown ()
{
}

void PhraseTest::testPhrase ()
{
    std::string str = "Hello World!";
    helloworld::Phrase phrase (str);
    CPPUNIT_ASSERT_EQUAL (str, phrase.getText ());
    CPPUNIT_ASSERT ("" != phrase.getText ());

    std::string empty = "";
    phrase.setText (empty);
    CPPUNIT_ASSERT_EQUAL (std::string (empty), phrase.getText ());
    CPPUNIT_ASSERT (str != phrase.getText ());
}

int main (int argc, char ** argv)
{
    (void)argc;
    (void)argv;

    // informs test-listener about testresults
    CPPUNIT_NS::TestResult testresult;

    // register listener for collecting the test-results
    CPPUNIT_NS::TestResultCollector collectedresults;
    testresult.addListener (&collectedresults);

    // register listener for per-test progress output
    CPPUNIT_NS::BriefTestProgressListener progress;
    testresult.addListener (&progress);

    // insert test-suite at test-runner by registry
    CPPUNIT_NS::TestRunner testrunner;
    testrunner.addTest
        (CPPUNIT_NS::TestFactoryRegistry::getRegistry ().makeTest ());
    testrunner.run (testresult);

    // output results in compiler-format, with a custom error format that works
    // with a top-level Makefile.am and include.am's
    CPPUNIT_NS::CompilerOutputter compileroutputter (&collectedresults,
                                                     std::cerr,
                                                     "%p:%l:");
    compileroutputter.write ();

    // return 0 if tests were successful
    return collectedresults.wasSuccessful () ? 0 : 1;
}

Ok that’s it. You can now run autorun.sh, configure, and make and you “should” end up with a working shared library, pkg-config file, and executable. To test it all out do:

    $ ./config/autorun.sh
    $ ./configure --prefix=/tmp/helloworld-test
    $ make
    $ make check
    $ make install

Congrats, you now have a skeletal pandora-build based system. You can go in and add/remove shared libraries, headers, execs, tests, … as needed mostly by copy-n-pasting the above code and stuff you can find in other projects (both libdrizzle and drizzle are good, albeit it complicated, examples.) Feel free to ask questions if you have them and be sure to subscribe as I plan to make this a series of posts on the subject. Some of the planned topics include what needs to be in my repository (.gitignores,) integrating valgrind and other code checking/debugging utilities, logging, distribution/tarring things up, and maybe even building debian and redhat packages.

My Latest Project – SF Pizza

April 4th, 2010

I like pizza, a lot, and I enjoy exploring new pizza places and options. I also bought a cool domain a while back, thebestinsf.com and was looking for something to do with it. I decided to combine those two things and write about my exploration of San Francisco Pizza Places. I’m also throwing in posts about options for making pizza at home with store bought dough and sooner or later will get around to writing up some posts on making your own from scratch as I feel like I’ve tried enough recipes and techniques to have something useful to share. Check it out and let me know what you think.

Sourdough No Knead Bread

February 1st, 2010

It was just over a year ago when I wrote about my experimentation with No Knead Bread. I’ve made it a handful of times since then, the most recent of which was a couple weeks ago. It turned so well that we decided to make it a regular thing, at least initially planning to do it weekly. And all of two weeks in, so far so good.

It really is that easy; forget about bread machines, spend $45 on an enamaled cast iron dutch oven and 15 minutes measuring and mixing flour and water (you don’t even have to be precise, it will still turn out fine.

Sourdough No-Knead Bread

Sourdough No-Knead Bread

On to the sourdough part. About the same time I decided to make the bread I started to see things taking about sourdough (more preferment/poolish than what people think about when they hear sourdough.) First it was in the context of pizza, which I plan to try soon and then it was a blog post I ran across about doing your own starter from scratch. Living in San Francisco I have no excuse not to give it a try so try I did. The process went really well, I wish I’d taken pictures so that I could blog about it. The starter finished up and went in to the fridge Tuesday night and I had been looking for an excuse to use it since putting it in there. About 11:30 last night I thought of a good one, a sourdough adaptation of the no-knead-bread. As mentioned above the hydration ratio is pretty forgiving with this bread so it’s a great place to play around. After you’ve done it a few times you get a feel for what it should look like and if you change things up all you have to do is get it to look roughly that way. (In reality this is always the case with bread/dough making, the look and feel has to be “right” more than you have to put in X grams of flour and Y grams of water, …) Anyway, I threw about a half a cup of starter in to the flour and then added a cup of water and played around adding a bit more until it looked right and then covered it and went to bed. I made it home about 6:00 tonight and turned on the oven when I walked in the door, about an hour later I pulled out a great loaf of tasty bread. It’s not a strong sourdough, as in what you’d expect from San Francisco Sourdough, but there’s a greater depth of flavor than comes from the overnight ferment of the base recipe. The next time around I plan to up the starter to a full cup to punch up the flavor a bit, regardless I’ll be doing this a lot, probably every time I make the stuff from now on. mmmmmmmmmm

301 Redirects – Getting Old Feed URLs to Work With Wordpress

April 21st, 2009

If you have an established blog and have readers who subscribe to your feed you’ll likely loose them when you migrate to Wordpress and your RSS feed URL changes. Wordpress feed look like http://www.mysite.com/blog/feed/ if you’re blog is at http://www.mysite.com/blog/. My previous blog software’s RSS feed url looked like http://www.mysite.com/blog/?wl_mode=rss2. I didn’t have too many subscribers, but there were a few and I didn’t want to leave them hanging so I set about using a 301 permanent redirect to solve this problem.

Fixing this is pretty straightforward, just a couple of lines of code. For me this the following placed near the top of index.php does the trick.

if ($_GET['wl_mode'] == 'rss') {
        header("HTTP/1.1 301 Moved Permanently");
        header("Location: http://" . $_SERVER['SERVER_NAME'] .  "/blog/feed");
        exit();
}

It looks for the get parameter wl_mode to be ‘rss’. If wl_mode is defined and equal to ‘rss’ it sets two headers in the response and then exits. The first tells the client to redirect and that the redirect is permanent. The second gives the location to redirect to, the server name of the request, from the variable so that it matches whatever hostname the request was made to and the path of Wordpress’s RSS feed, ‘/feed’. The ‘/blog’ is where Wordpress is installed on my site, if your root is Wordpress you’d just have ‘/feed’.

What if your old url wasn’t wl_mode=rss. If it’s a different parameter or set of parameters you’d just swap them out. What if the old feed is not a parameter, but a URL/path? Something like the snippet below should be useful there.

if ($_SERVER['REQUEST_URI'] == '/blog/old/feed/path') {
        header("HTTP/1.1 301 Moved Permanently");
        header("Location: http://" . $_SERVER['SERVER_NAME'] .  "/blog/feed");
        exit();
}

5 Minute Custom Wordpress Theme

April 18th, 2009

Creating a custom wordpress theme is really easy especially if you’re starting with a template (a site design you want to use.) This is often the case when you’re trying to add a blog to an existing site or convert an existing website you’re happy with to use wordpress for blogging/content management. I won’t go in to details about how to install wordpress, there’s already a great guide for that. I’ll just outline the steps involved in creating a custom them to get wordpress to look & feel the way you want it to.

Laying the Foundation – Creating the Theme Directory

We’ll start out creating a directory to house our theme files (there’s only going to be 2 of them.) To do that we’ll log on to our server and execute the following:

$ cd /whereever/wordpress/is/installed/wp-content/themes
$ mkdir custom

If you don’t have shell access to you server use whatever mechanism you’ve uploaded/edited the sites files with in the past.

Step One – HTML – index.php

There’s only two files required to create a template for wordpress, index.php and style.css. We’ll start with index.php. To create an initial version of this file we’ll pick up where we left off a minute ago and do the following. If you’re familiar with another editor, feel free to use it, choices include vi, emacs, … but pico is one of the simplest to use (ctrl-O to save, ctrl-X to exit, more commands are listed across the bottom.)

$ cd custom
$ pico index.php

That will start up pico editing a file named index.php, the main template file for you new custom theme. We’ll start with a simple html page you can copy-n-paste in to this file.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
  <head>
    <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>;
      charset=<?php bloginfo('charset'); ?>" />
    <title>
      <?php wp_title('«', true, 'right'); ?> <?php bloginfo('name'); ?>
    </title>
    <link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>"
      type="text/css" media="screen" />
    <link rel="alternate" type="application/rss+xml"
      title="<?php bloginfo('name'); ?> RSS Feed"
      href="<?php bloginfo('rss2_url'); ?>" />
    <link rel="alternate" type="application/atom+xml"
      title="<?php bloginfo('name'); ?> Atom Feed"
      href="<?php bloginfo('atom_url'); ?>" />
    <link rel="pingback" href="<?php bloginfo('pingback_url'); ?>" />
  </head>
  <body>
    <div id='header'>
      Insert Your Header HTML here
    </div>
    <div id='content' class='span-16 prepend-1'>
        <?php if (have_posts()) : ?>
          <?php while (have_posts()) : the_post(); ?>
            <div <?php post_class() ?> id="post-<?php the_ID(); ?>">
              <h2><a href="<?php the_permalink() ?>" rel="bookmark"
                title="Permanent Link to <?php the_title_attribute();
                ?>"><?php the_title(); ?></a></h2>
              <small>
                <?php the_time('F jS, Y') ?>
                <!-- by <?php the_author() ?> -->
              </small>
              <div class="entry">
                <?php the_content('Read the rest of this entry »'); ?>
              </div>
              <p class="postmetadata"><?php the_tags('Tags: ', ', ', '<br />');
                ?> Posted in <?php the_category(', ') ?> |
                <?php edit_post_link('Edit', '', ' | '); ?>
                <?php comments_popup_link('No Comments »',
                                          '1 Comment »',
                                          '% Comments »'); ?>
              </p>
            </div>
          <?php endwhile; ?>
            <div class="navigation">
              <div class="alignleft"><?php
                next_posts_link('« Older Entries') ?></div>
              <div class="alignright"><?php
                previous_posts_link('Newer Entries »') ?></div>
            </div>
        <?php else : ?>
          <h2 class="center">Not Found</h2>
          <p class="center">Sorry, but you are looking for something that isn't
            here.</p>
          <?php get_search_form(); ?>
        <?php endif; ?>
      </div>
      <div id='sidebar' class='span-6 last'>
        <?php get_sidebar(); ?>
      </div>
    <div id='footer'>
      Insert Your Footer HTML here
    </div>
  </body>
</html>

Don’t worry if that looks like a mass of gibberish, there’s only a small portion of it that you’ll have to worry about, the two sections in red. In them you will place your header and footer HTML, whatever logos and/or text you’d like to see at the top of the page. If you’d like to have a navagation bar across the page you can create a second div following the header dive and put links to the various sections of you site there. The footer is a good place to put a copyright notice, links to email you or any other information you’d like to have appear at the bottom of all of your pages.

If you’re working with an existing template you want to insert wordpress into, you’ll take the section in blue and place it in the content section of your template. You may have to mess around with it a bit to get exactly what you’re looking for, but keep at it it shouldn’t take too long.

Step Two – CSS – style.css

We’re half the way to a new custom Wordpress theme. The next thing we’ll need to do is create style.css.

$ pico style.css

At this point if you want to save the file you can go to the admin section for you blog and click on the ‘Appearance’ link and you should see your new ‘custom’ theme. Clicking on it should pop up a preview of what your blog will look like using this theme. It probably won’t look like much yet, but it’s a nice clean workspace in which you’ll be able to mold things to your liking. If you don’t have visitors to your blog yet, or don’t mind them seeing the work in progress you may go head and apply your new theme. If you’re not ready for that you’ll need to continue to use the preview feature to view your work.

So one of the biggest problems with this theme is the sidebar is way down at the bottom below all of the content. We’ll need to add some css to address this issue, luckily there’s not much to it, at least to move the sidebar up. You’ll just need to add the following to style.css and refresh.

#header
{
}

#content
{
  float: left;
  width: 600px;
}

#sidebar
{
  float: left;
  width: 200px;
}

#footer
{
  clear: both;
}

The css above makes both #content and #sidebar float left and then limits #content’s width to 600 pixels and the sidebar to 200. So the blog will be 800 pixles wide. The only other thing going on is that we’ve asked the footer to clear both, which essentially means that it should go below any floating divs before it. This is obviously pretty rudimentary and doesn’t do much for the ascetic appeal of our blog, but everything “works” from here it’s just fiddling with css (which is way beyond the scope of this post.) Take a look at the HTML generated by this theme using view source and you should be able to track down the id’s and class’s you need to address to shape things up. Web developer Tool-bar can be really helpful for this work, check it out.

Conclusions

So we’ve created a simple, although still ugly, wordpress theme from scratch. It uses lots of defaults that can be customized to your liking, but it’s a good start. If you have any questions feel free to hit me up at rwmcfa1 <at> neces.com. Don’t have the time and/or desire to mess with custom wordpress instalation/development get in touch.