Boost logo

Boost-Build :

Subject: [Boost-build] Compiling header files independently as a test.
From: Thomas Brown (tabsoftwareconsulting_at_[hidden])
Date: 2018-03-16 20:13:41


Boost.Build team,

I have found it useful to (and there are some that require) test
header file independence by including it by itself in a source file
and checking that it compiles. For example, the Bloomberg BDE
project states that the ".h file of each component should contain only
those #include directives (and forward class declarations) necessary
to ensure that the header file can compile in isolation."
(https://github.com/bloomberg/bde/wiki/physical-code-organization).

I have been exploring doing this with Boost.Build and while I've
figured out a way to get it done, it is not nearly as nice as I'd like
it to be. Does anyone have a better approach? if not, could we add
something to testing.jam to support this directly?

I've cobbled together some code that works for me but has several
limitations that I don't like and don't know how to fix.

1. I implement the tests in the library's Jamfile since that is where
the actual header file names are known. I actually put all required
files (headers, sources, etc.) in the sources list of the alias or
lib. Is that something others are doing? This forces me to put the
source file names and header file names into separate variables so I
can iterate over them. I also do this in order to specify the sources
for a doxygen target within Boost.Build.

  I have a separate Jamfile for tests to simplify using just the
library with other Boost.Build-based projects. I'd prefer to have all
the tests together, but I don't want to repeat the headers nor use a
glob.

  I might consider using a glob, but that would again be in the
library definition, not the test file.

2. I'd really prefer to iterate through the sources of any target (at
least any alias or lib) to run the compile-header tests in the test
Jamfile without knowing what they are named. This would actually make
it possible to have a separate Jamfile to generate doxygen as well.

3. The "compile-header" target might require more information if the
library has dependencies, which have to be specified in both the
library and the compile-header targets. This seems to usually be
handled by depending on the library itself in the compile-header
target, so maybe it's not a big deal, but it is a bit strange to say
that compiling the header that is part of libx depends on libx.

I've included inline some code that reflects what I am currently
doing. It is extremely preliminary. I could see, at the minimum,
adding a "compile-header" and maybe "compile-header-fail" (not
implemented here) that generates a source file and attempts to compile
it to testing.jam. However, this approach still leaves a lot of
boilerplate to the user and requires the tests are in the same Jamfile
as the alias / lib target definition.

I would not mind doing the work to get something in if others agree on
the concept and an approach to implement it.

Best regards,
Tom

1. I have a local testing-additions.jam file that adds a "compile-header" rule

```
# testing-additions.jam
import testing ;

# generate a source file and check for compile success
rule compile-header ( sources : requirements * : target-name ? )
{
  local s ;
  local t ;

  if ! $(target-name)
  {
    target-name = compile_test_$(sources:D=:S=) ;
  }

  s = $(target-name).cpp ;

  make $(s) : $(sources) : @testing-additions.generate-source-for-header ;

  compile $(s) : $(requirements) : $(target-name) ;
}

actions generate-source-for-header
{
  echo "" > $(<)
  echo "#include \"$(>)\"" >> $(<)
  echo "int main () { return 0; }" >> $(<)
  echo "" >> $(<)
}
```

2. Wherever I have header files in my projects (in an alias or a lib,
etc). I do something like the following.

```
# a Jamfile for the header-only library libx
import testing-additions ;

# other header-only libraries that libx depends on
alias dep0 ;
alias dep1 ;

local headers =
  x0.hpp
  x1.hpp
  x2.h
  ;

alias libx
  : # sources
    $(headers)

    dep0
    dep1

  : # requirements
  : # default-build
  : # usage-requirements
    <include>src
  ;

for h in $(headers)
{
  compile-header $(h) : <dependency>libx ;
}
```


Boost-Build list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk