C global variables in Eiffel

by Larry Liu (modified: 2007 Dec 07)

Per Module C Global Variables

If we write a C header file for a Eiffel application (not for Eiffel runtime), there are C variables in C header file which we use for interactive with Eiffel language. We should take care about the global C variables. They are not application level global variables if they are included several times. Note static C global variables of the same case.

Precisely speaking, the C global variables are per Module global (each generated C big file is a module). The C global here is the outmost level of C variable in a C header file.

Workbench and Finalize Differences

The global C variable problem only happens in finalized Eiffel application. This is caused by different header including strategy between finalized mode and workbench mode in Eiffel compiler.

  • For workbench mode, one header file only included for one time.
  • For finalized mode, if a header file referenced by other modules (generated C big file), such as call other Eiffel class feature which use a C header file, the header file will be included one time.

Solution

One simple solution is compiling the C header file into one lib file. In this way, we can get a real application level C global variable which declared in C file. Because the lib file only included once for an executable, so we don’t need care about multi-time including problem.

Example

For Eiffel Software bug# 13671 (Cannot login when trying to automatic report crash), it’s caused by global C variable problem.

Before revision#71399, we implement the C global eiffel_function_object’ in $EIFFEL_SRC\library\cURL\spec\include\ eiffel_curl.h’. All C implementations are written in eiffel_curl.h. There is NO eiffel_curl.c before. (In this way, we want avoid to compile a new eiffel_curl.lib for Eiffel Studio.) It will be used by { CURL_FUNCTION }. In workbench mode, it works fine because the eiffel_curl.h’ only included one time. But in finalize mode, the bug happens. It because we call { CURL_FUNCTION }. c_set_object’ to initialize the C global variable in one module (the C big file generated from {CURL_FUNCTION}). Later cURL callback use the eiffel_function_object’ C variable in another module (the C big file generated from {CURL_EASY_EXTERNALS}), the eiffel_function_object’ is not initialized, the value is 0. It makes sense, because they are two global variables in two modules. Eiffel class {CURL_EASY_EXTERNALS} not use eiffel_curl.h’ directly, but in {CURL_EASY_EXTERNALS}. set_write_function’ it calls {CURL_FUNCTION}. c_set_write_function’. This will trigger Eiffel compiler include ANOTER eiffel_curl.h’ for class {CURL_EASY_EXTERNALS}.

Manu fixed it in the way that providing a cURL lib file for eiffel_curl.h’ and move the C global variable into a new C file eiffel_curl.c’ (in $EIFFEL_SRC\library\cURL\Clib\ eiffel_curl.c after revision#71399). In this way, the C global variable `eiffel_function_object’ is a real application level global since it only included one time.