Chapter 27. Opaque Wrappers

Table of Contents

27.1. Opaque Wrapper Example

One of the most important features of abuild is that a given build item automatically inherits the interfaces of not only all of its direct dependencies but of its indirect dependencies as well. There may be instances, however, in which this is undesirable. We present such a case here.

27.1. Opaque Wrapper Example

This example shows how we can create a C/C++ build item that implements an “opaque wrapper” around some other interface. In the doc/example/opaque-wrapper directory, there are three directories: hidden, public, and client. The hidden item implements some interface. The public item implements a wrapper around hidden's interface, but uses hidden privately: only its source files, not its header files, access files from hidden:

opaque-wrapper/public/Public.hh

#ifndef __PUBLIC_HH__
#define __PUBLIC_HH__

class Public
{
  public:
    void performOperation();
};

#endif // __PUBLIC_HH__

opaque-wrapper/public/Public.cc

#include "Public.hh"
#include <Hidden.hh>

void
Public::performOperation()
{
    Hidden h;
    h.doSomething();
    h.doSomethingElse();
}

The intention is that users of public should not be able to access any parts of hidden at all. The client directory contains an example of a build item that uses public. It doesn't include any files from hidden, and if it were to try, it would get an error since the hidden directory is not in its include path. However, it still must link against the hidden library. The public build item achieves this by resetting the INCLUDES interface variable in an after-build file:

opaque-wrapper/public/Abuild.interface

INCLUDES = .
LIBDIRS = $(ABUILD_OUTPUT_DIR)
LIBS = opaque-public

after-build hide-hidden.interface

opaque-wrapper/public/hide-hidden.interface

# Prevent those that depend upon us from seeing the INCLUDES that we saw
reset INCLUDES
# Re-insert our own include directory into the public interface
INCLUDES = .

This way, items that depend on public will see only this item's includes and not those of the items it depends on. Here is the output of abuild ccxx_debug when run from the client directory:

opaque-wrapper-ccxx_debug.out

abuild: build starting
abuild: opaque-client (abuild-<native>): ccxx_debug
make: Entering directory `--topdir--/opaque-wrapper/client/abuild-<native>'
INCLUDES = ../../public
LIBDIRS = ../../public/abuild-<native> ../../hidden/abuild-<native>
LIBS = opaque-public opaque-hidden
make: Leaving directory `--topdir--/opaque-wrapper/client/abuild-<native>'
abuild: build complete

As you can see, there is no reference to the hidden/include directory even though its library and library directory are present in opaque-client's compilation environment.