Platform dependencies

Similar to how compiler/linker/assembler/archiver names and flags are part of the redo build system proper, so too are platform dependencies.

The simplest form of platform dependency is something like a program module that only should be part of the program on certain platforms. This is just a question of a case statement in a (shell script) .do program using the output of uname. For example:

# In mylib.a.do:
case "`uname`" in
(Linux)	platform_objects='object/kqueue_linux.o';;
(*)	platform_objects='';;
esac
redo-ifchange ./archive ${objects} ${platform_objects}
./archive "$3" ${objects} ${platform_objects}

A similar test can be used to choose one of several source code file implementations to use for something according to platform, by treating the source code file as a redo target file, that is "built" by copying or linking one of a selection of source files into place. For example:

# In myheader.h.do:
case "`uname`" in
(Linux)	ext="linux" ;;
(NetBSD)	ext="netbsd" ;;
(*BSD)	ext="bsd" ;;
(*)	ext="unknown" ;;
esac
redo-ifchange "$1.${ext}"
ln -s -f "`basename \"$1\"`.${ext}" "$3"

Commonly, platform dependencies involve conditional compilation across multiple source code files, controlled by a macro. The redo way of doing this is an adaptation of one of Bernstein's pre-redo mechanisms:

The platform feature is designated by a macro, such as (for example) HAS_READ_TSC. This is not set via compiler flags but by the inclusion of a header named "has_read_tsc.h", which is included in the source code files that need to be conditionally compiled according to the macro.

// In some_module.cpp:
#include "has_read_tsc.h"
…
#if defined(HAS_READ_TSC)
…
#else
…
#endif

This header is not a redo source file, but is a redo target file, generated by a has_read_tsc.h.do program, which is along the lines of:

# In has_read_tsc.h.do:
redo-ifchange try_read_tsc.c compile link
if ./compile object/try_read_tsc.o try_read_tsc.c object/try_read_tsc.d &&
   ./link command/try_read_tsc object/try_read_tsc.o
then
	echo '#define HAS_READ_TSC 1' > "$3"
else
	echo '/* sysdep: -read_tsc */' > "$3"
fi

The try_read_tsc.c program is a test program that only successfully compiles and links (and, perhaps, if necessary for the test, runs and exits success) if the feature is available on the platform:

# In has_read_tsc.h.do:
int main(void)
{
  …
  asm volatile("rdtsc" : "=a"(x[0]),"=d"(x[1]) );
  asm volatile("rdtsc" : "=a"(y[0]),"=d"(y[1]) );
  …
}

The final part of the mechanism is ensuring that has_read_tsc.h is actually built before any program that tries to #include it is compiled. This is done by simply declaring a dependency at the start of the top‐level .do program:

# In all.do:
redo-ifchange has_read_tsc.h