Static version check of an un-versioned library

When you integrate an external partner delivery (Software Library), it is crucial to maintain version coherency. Say your partner is delivering library version 2.2.1, and you would integrate that together with your software from label Week30. You then need to make sure that:

  1. Proper header files are included for this library. Header files for V2.2.1 are probably different than for V1.2.3.
  2. The software would not even compile with an older version of the library. What I mean is that, you want the whole build system preventing you to build the software.
  3. At runtime, you want to make sure the proper library version is actually used. If not, your software would typically assert, or handle this in a way or another.

This sounds very basic requirements and any software engineer should be persuaded that these are the bare minimum requirements. However, more often than not, the reality is different (sounds familiar ?).

I had this situation on one project where we were receiving regular drops of an algorithm library. The library was named … “library.a” and the header file “library.h”. No provision was made for a runtime revision querying, and it took several successive deliveries to agree upon an “uint32 getVersion() ” entry point.

Most important for me was to solve point 2. as all the libraries had the same name, nearly the same size and a very similar interface …. but radically different behaviors.

So I ended doing the following:

1. Use the Librarian tool to add a specific function to the library. This function would be named after the library version. The function does not need to do anything, just to be there.

2. Call this function from our software.

Then the magic operates: if the wrong function is called, then the linker would complain. This is preventing linking the wrong library, and it is correctly detected at compile time.

Steps in more details

Use of the librarian

My environment was IAR for ARM, but it can be applied to a lot of others toolchains. In this toolchain, the compiler and librarian are

IAR_COMPILER="IAR Systems\Embedded Workbench 7.0\arm\bin\iccarm.exe"
IAR_LIBRARIAN="IAR Systems\Embedded Workbench 7.0\arm\bin\iarchive.exe"

Using a small batch file, we can pre-process the libray as follows:

@echo void IchBinV%VERSION%(void){} > %TEMPFILE%.c
%IAR_COMPILER% -o %TEMPFILE%.o -c %TEMPFILE%.c
%IAR_LIBRARIAN% -r %PARTNER_LIB% %TEMPFILE%.o

So I create an helper function named “IchBin<version-number>(void) ” where version-number would hold the actual version. For example, for V1.05

IchBinV105(void) {}

Client software side

The function is compiled “on-the-fly” and added to the partner library. Then, somewhere in my software, I would have

......
#ifdef LIBRARY_V105
int res = IchBinV105();
#elif defined(LIBRARY_V106)
int res = IchBinV106();
#endif
.....

(example with 2 different versions checked)

In term of process, a simple batch file can be used (or bash), which would automate all this. For example, mine was (sanitized):

set PARTNER_LIB=%2%

:process
if /I NOT "%1"=="105" if /I NOT "%1"=="201" if /I NOT "%1"=="202" goto wrong_rev

set IAR_COMPILER="C:\Program Files (x86)\IAR Systems\Embedded Workbench 7.0\arm\bin\iccarm.exe"
set IAR_LIBRARIAN="C:\Program Files (x86)\IAR Systems\Embedded Workbench 7.0\arm\bin\iarchive.exe"
set TEMPFILE=%TEMP%\libversion
set VERSION=%1%

:: Test the tools
:: 1. Test compiler
%IAR_COMPILER% 1>nul 2>nul
if "%ERRORLEVEL%"=="0" goto :compiler_ok

echo could not find ICCARM compiler.
goto :end
:compiler_ok
@echo Found compiler iccarm.exe

:: 2. Test librarian
%IAR_LIBRARIAN% 1>nul 2>nul
if "%ERRORLEVEL%"=="0" goto :librarian_ok
echo could not find Librarian compiler.
goto :end
:librarian_ok
@echo Found Librarian iarchive.exe
@echo.
@echo Processing library archiving process
pause

@echo void IchBinV%VERSION%(void){} > %TEMPFILE%.c
%IAR_COMPILER% -o %TEMPFILE%.o -c %TEMPFILE%.c
%IAR_LIBRARIAN% -r %PARTNER_LIB% %TEMPFILE%.o

:: Verification
@echo.
@echo Library contains now the following entries
%IAR_LIBRARIAN% --symbols %PARTNER_LIB%
goto :end

:wrong_rev
@echo Error: Bad revision
@echo.

:usage
@echo prepares a lib for archiving
@echo.
@echo syntax:
@echo "prep_lib <version> <lib_file_name>"
@echo "version = [105 | 201 | 202]"
@echo "lib_file_name = file name [default = library.a]"

The bulk of the script is checking the tools, the revs, the arguments, then runs the 2 lines described above.

That is a very simple trick but once in place, it can save hours of debugging and nervous conference calls !

PS: the strange name for the function “IchBin” was the result of a long running joke we had in the team, in relation with a famous ad at the french TV

( https://www.youtube.com/watch?v=6ZsPBgjITNs).

Leave a Reply

Your email address will not be published.