Table of Contents

Example
 

This procedure will demonstrate how to start, build and install two libraries
and an executable tree. It assumes RPSL has been set up as described in 
Install RPSL and a developer sandbox has been set up as described in 
Set up an RPSL Project.  The red command line commands can be pasted into a 
terminal to try the example.

|Step 1|2|3|4|5|6|7|8|9|10|11|12|


STEP 1.next|top
-------
Start up a new library module in your developer sandbox. Each new library starts 
with major, minor, and micro versions 0.0.0. Make a new library called "bar" 
with a namespace "testrpsl" that will be the default namespace for any new classes 
in the library via rpslNewClass or rpslNewTClass.
 
% cd $RPSL_USER/build
% rpslNewLibTree bar testrpsl

This generates a standard, simple autotools tree except for few RPSL files. The 
user-edited file rpslParams defines the name of the target, the release and shared 
version of the current library, and dependencies. If a library has dependencies on 
other libraries, there are pkg-config dependency entries of the form mylibname >= 0.1.0 
(library spec, relation, version spec).  Also the file runConfigure is a script that 
runs configure with user-editable default compiler flags and target locations. The hidden 
file .rpsl_libtree is empty and only used as a marker for the pwd.  The hidden 
file .namespace contains the default namespace to use when generating source 
code skeletons.  None of these RPSL files are used directly by the autotools and 
could be deleted for a conventional autotools distribution.

The rpslParams file just created defaults to the folloing:

name = bar
release = 0.0.0
shared = 0:1:0


STEP 2.next|top
-------
The top level and main source directory of a library have the library target root 
name. This name is used in the include statements of dependent code. Use the form 
#include <mylibname/header.h> when linking. The source files for the "bar" 
library that we just started are thus in the following directory (RPSL also 
supports one additional level of subdirectories below this directory):
 
% cd bar/bar

This will eventually contain the source files and the automatically-generated 
"include the whole library" files bar.cpp and bar.h. Do not edit these.  The 
directory also will have the Makefile.am that will be updated when new code files 
are added.

Now make a new non-template class "barClass":
 
% rpslNewClass barClass

This will generate barClass.cpp and barClass.h using a skeleton class structure, 
user name, and creation date.  Recall that if there is an .rpslauthor file 
in your home directory its contents will be substituted everywhere there is an 
@author@ field in the skeleton.


STEP 3.next|top
-------
Edit barClass.cpp and barClass.h to add a method "msg()". 

In barClass.h add:

      // includes
      #include <iostream>
      #include <string>



      // operations
      //!  Summary description of the msg method. 
      void msg( string st );



In barClass.cpp add the implementation:

      // operations
      void barClass::msg( string st )
      {
           cout << "(barClass::msg): " << st << endl;
      }




STEP 4.next|top
-------
Now make a unit test that uses the autotools "make check" feature. All source
implementation files in the test directory are assumed to contain one main() 
and are added automatically to the "check_PROGRAMS" target.
 	
% cd $RPSL_USER/build/bar/tests

Create and edit test1.cpp to include bar/barClass.h and call barClass::msg():

     #include <bar/barClass.h>

     using namespace testrpsl;
     using namespace std;

     int main(void)
     {
        barClass bc;
        bc.msg(string("test1"));
        return 0;
     }

Now synchronize the build to include the new class and test main and configure.
Note that rpslSyncBuild must be run in the top-level library directory.
	
% cd $RPSL_USER/build/bar 
% rpslSyncBuild
% ./runConfigure


STEP 5.next|top
-------
Now that the library is ready for building go to the top-level module directory
and run a local build.  Then run the unit tests with make check to see if they
all pass (return 0). Finally, install the library into the target tree:

% make
% make check  (should see the test compile, run, and pass)
% make install

This installs the library to the location specified by the prefix in the local 
file runConfigure. That file starts out with a default prefix for installing to
usr/local in the current development tree.  This puts the pc.in file in the search 
path of pkg-config. And that means the library will be found and included and linked
correctly by dependent library and executable modules. 


STEP 6.next|top
-------
Now make another library called "foo" in the same namespace and add one class:
	
% cd $RPSL_USER/build
% rpslNewLibTree foo testrpsl
% cd foo/foo
% rpslNewClass fooClass


STEP 7.next|top
-------
Next, edit fooClass to add a method "show":

In fooClass.h add the include files:


      // includes
      #include <iostream>
      #include <string>
      #include <bar/barClass.h>


      // operations
      //!  Summary description of the show method. 
      void show( string st );


In fooClass.cpp add the implementation:

      // operations
      void fooClass::show( string st )
      {
         barClass bc;
         bc.msg(string("(fooClass::show): ")+st);
      }

Because the foo library depends on bar we must add a pkgconfig dependency
statement to the rpslParams file in the top-level library directory and
re-synchronize the build to incorporate the new dependency:
 
% cd $RPSL_USER/build/foo
% echo "bar >= 0.0.0" >> rpslParams	
% rpslSyncBuild

This triggers a search for a library "bar" with a version that satisfies the
given relation (here, any version).  Behind the scenes, pkg-config is searching
for the pc file in the pkg-config subdirectory usr/lib/pkgconfig in each
of the three RPSL levels.  That pc file (here bar.pc) tells the system how to 
include and link to the library.


STEP 8.next|top
-------
Now build and install the foo library.:
 
% ./runConfigure
% make
% make install

Now we are ready to make an executable project that uses these two libraries. 
Although it isn't particularly efficient, a non-test executable occupies its
own autotools module tree.


STEP 9.next|top
-------
Set up the executable project in the developer sandbox and go to the source
directory:

% cd $RPSL_USER/build
% rpslNewExecTree baz
% cd baz/baz

Unlike a library it is okay to call the executable source directory "src" or
the name of the executable. Executable source trees always include exactly 
one file with a main() and possibly a few related classes for files.


STEP 10.next|top
-------
Edit main.cpp to include foo/fooClass.h; and call fooClass::show();

     #include <foo/fooClass.h>

     using namespace testrpsl;
     using namespace std;

     int main(void)
     {
   
        fooClass fc;
        fc.show(string("(main) Hello, world!"));

        return 0;
     }


STEP 11.next|top
-------
Modify the rpslParams file with the line "foo >= 0.0.0" in the 
top-level "baz" directory and synchronize the build:

% cd $RPSL_USER/build/baz
% echo "foo >= 0.0.0" >> rpslParams
% rpslSyncBuild

Notice that we don't have to specify the transitive dependency on bar.  If you 
inspect $RPSL_USER/usr/local/lib/pkgconfig/foo.pc you will see that it shows 
its dependence on "bar" in the "Requires:" line.  This will be checked for, and 
linked into, the executable by the pkg-config macros. A nice feature indeed.


STEP 12.top
-------
The executable baz is ready to make:

% ./runConfigure
% make install
% rehash

(try it)

% baz
(barClass::msg): (fooClass::show): (main): Hello, world!

That's it!

top

Table of Contents
William Snyder
Last modified: Sun Aug 28 21:50:06 EDT 2005