One of my XS-based modules requires some feature flags to be set up
before it can be compiled.  I seek advice on how best to do this under
Module::Build.

The module is Time::UTC::Now, and it needs to know about the existence
of certain time-related library functions and the presence of certain
members of related structs.  These are tested for by attempting to
compile and link short test programs.  (The test programs are never
run; success of linking is what determines the feature flag setting.)
The test results are supplied to the XS code in the form of preprocessor
definitions that are added to the compiler command line.

In my attempt at this so far, I've overridded M::B::compile_c (in a
subclass), so that it'll run the tests, add the feature definitions
to its arguments, and pass the modified arguments on to the original
compile_c method.  I also have it cache the test results in a file,
and this file along with all the test files are subject to cleanup.
This bit works fine.  The compilation part of the tests also goes well:
I call $self->compile_c on the test file, with an extra flag to bypass
the feature testing.

I have a problem with the linking part of the test.  I can't use
M::B::link_c, because that insists on putting the result under blib,
which I don't want.  I don's see a way to override where the resulting
library goes.  Instead I'm cheating a bit: I call $self->_cbuilder
to get the ExtUtils::CBuilder object, then call ->link_executable on
that.  (Generating an executable is simpler than generating a library,
anyway.)  This works, but obviously I'm relying on an internal method
of Module::Build.

I also have a problem with the dependency of the main object file on
the feature definition cache file.  M::B generally manages dependencies
by having the code to build a file check whether it's up to date, and
not generate it if it is.  By this means I have the feature definition
cache file depend on the feature test code (which is in a separate file).
But with the object file the up-to-date-ness is tested by M::B::compile_c,
which doesn't know about any dependency other than the source file.
There's no way to tell compile_c that the compilation is influenced by,
say, a header file, or (in this case) the cache file that is read by
the overridden part of compile_c.  I have temporarily resolved this by
having the overridden compile_c delete the object file if it detects
that it is out-of-date with respect to the cache file.  However,
to find the name of the object file I had to cheat again, by calling
$self->_cbuilder->object_file.

Is there a cleaner way to incorporate these tests into the build process?
Have I missed some bits of M::B that I could override to greater effect?

My development version of the module in question is at
<http://www.fysh.org/~zefram/tmp/Time-UTC-Now-0.006001.tar.gz>.

-zefram

Reply via email to