complex relationship between header and source

Hi, I'm interested in making my avr crypto lib available to Arduino users.

The problem is that there is no simple relationship between the header files which include the declarations and the sources which include the actual implementation. Often there are multiple implementations with different characteristics (for example different optimizations and C and assembly versions which use the same header files).

If I understand the available documentation correctly there is currently now way the user can add a header file and specify which source object should be build and linked. The name of the source object is always taken from the name of the included header file. Maybe the feature I would like to have would need an extension to the programming language of the Arduino system.

best regards, bg

There should be a one-to-one mapping between the header file and source file. If the output from the source code differs based on where it is to be used, conditional compiling is used (#ifdef/#elif/#else/#endif) to control what code is passed to the compiler.

Do you have some need to not follow this standard?

The problem is that there is no simple relationship between the header files which include the declarations and the sources which include the actual implementation. Often there are multiple implementations with different characteristics (for example different optimizations and C and assembly versions which use the same header files).

Can you give an example?

A simple example we could take a look at the SHA-256 implementation, which consits of the following components:

  • sha256.h which contains the declaration for the functions and the types used for SHA-256 hashing
  • sha256.c which contains the implementation of the functions used for hashing in the C-language
  • sha256-asm.S which contains an optimized implementation in AVR-Assembler (for gas)

I would call this simple because the user would most likely want to use the assembly version, but there are alos cases where multiple assembly versions for the same component are available (some optimized for speed some optimized for size or even more complex scenarios) and the user wants to make a choice we can not predict. But even this simple case has two problems:

  • Assembly files seem to be not supported currently (but this is discussed somewhere else on this board)
  • we might add a C++ wrapper, but it is required to build and link sha256-asm.o (from sha256-asm.S). Creating a header file sha256-asm.h seems to be quite odd for this.

As a more complex example we could take a look at the AES implementation, which consits of the following components:

  • aes.h includes all other header file (for easy usage)
  • aes_types.h defines the types used
  • aes_enc.h defines the prototype for a generic aes encryptions
  • aes_enc.c implements generic aes-encryption (C)
  • aes_enc-asm.S implements generic aes-encryption (ASM)
  • aes_dec.h defines prototype for generic aes-decryption
  • aes_dec.c implements generic aes-decryption (C)
  • aes_dec-asm.S implements generic aes-decryption (ASM)
  • aes_dec-asm_faster.S implements generic aes-decryption (ASM, faster but larger)
  • aes_sbox.h
  • aes_sbox.c
  • aes_sbox-asm.S
  • aes_invsbox.h
  • aes_invsbox.c
  • aes_invsbox-asm.S
  • aes_keyschedule.h
  • aes_keyschedule.c
  • aes_keyschedule-asm.S
  • gf256mul.h
  • gf256mul.S
  • aes128_enc.h
  • aes128_enc.c
  • aes128_dec.h
  • aes128_dec.c
  • ... there are even more files for 192/128 encrypting/decrypting

(for those who are interested in a more verbose description, take a look at the corresponding wiki page)

This of course also need a C++ wrapper but the decision if for example the fast decryption or normal description should be used should be made by the application developer and not by the library (Serpent has even more alternatives). Also I am considering putting all header files in a single one (aes.h) which would reduce the complexity for normal users and would not bring additional cost because declarations do not go into the binary.

  • Assembly files seem to be not supported currently (but this is discussed somewhere else on this board)

Yeah, this support is currently in SVN.

As to your other issue it sounds similar to what I've encountered with my V-USB wrapping. Essentially, it boils down to the fact that you can't AFAICT control how a library is compiled from a sketch.

In your case it sounds like the only way to implement a choice would be a separate header for each type which sounds like it could be complex. Given the target audience of Arduino users may not be familiar with all the factors in choosing a variation it might well be good to make that choice for them.

--Philip;

My quick reaction is: encapsulate the complexity of having multiple libraries in the header files. Go ahead and build lots of different header files for different versions (possibly even using different subdirectories in the hardware/libraries tree), and control which is linked using the top-level include file.

Examples:

#define AES_OPTIMIZE_SPEED
#include <aes.h>

would cause the aes.h file to include the headers for the speed-optimized assembler version, while a plain:

#include <aes.h>

would use the C++ implementation. Inside the aes.h file you’d have something like:

#if defined(AES_OPTIMIZE_SPEED)
#include <aes-asm-speed.h>
#elif  defined(AES_OPTIMIZE_SPACE)
#include <aes-opt-space.h>
#else
#include <aes-cpp.h>
#endif

It doesn’t solve the problem of automagically building your assembler libraries (although it sounds from follower’s comment like that solution may be forthcoming), but someone who wanted the “basic”, cpp-coded functionality could still just install a .zip, avoid using the #define’s for optimization, and still have everything work, even in the current version of the code.

Ran