This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Conditional compilation

Hi,

I am currently trying to get my code support two different type of LCD display, the only difference is the hardware level driver, so condional compilation directive has to be introduced.

#ifdef DISPLAY_1
void display_driver()
{
// do one thing
}
#else
void display_driver()
{
// do another thing
}
#endif

However I don't want change the directive in the code, I would like to do it in the IDE,
I guess it should be under project\option\C51, any one know how to do it ? Thanks in advance.

Daniel

  • Options for Target ==> C51 ==> Preprocessor Symbols ==> 'Display_1'

  • to reduce the amount of repeated typing, you could consider:

    void display_driver()
    {
    
    #ifdef DISPLAY_1
    // do one thing
    #else
    // do another thing
    #endif
    
    }

  • An alternative to conditional compilation would be to have two separate source files, each of which defines one version of display_driver().

    You then use the 'Include in Build' file option to choose which one actually gets compiled...

    You could create two Targets for your project to manage this (you could also control the conditional-compilation with multiple Project Targets).

  • to reduce the amount of repeated typing, you could consider:

    even easier re typing
    in main .h file

    #define DISPLAY_1 // comment out if not display 1

  • "even easier re typing"

    No - you miss the point.

    I was talking about the amount of typing in the two definitions of his driver - not the amount of typing to set the #define !!

  • Oh, well. I usually "get excited" when reducing typing is mentioned. It gives you more time to type comments.

    Erik

  • It's often useful to have a positive check to be sure that someone actually selected a driver option, rather than just falling into an else clause due to lack of a choice.

    #if defined(DRIVER_1)
    #elif defined(DRIVER_2)
    #else
    #error "DRIVER_? must be defined"
    #endif

    It's tempting to try to define a "variable" for this sort of thing, but unfortunately the preprocessor doesn't really allow "strings":

    #if LCD_DRIVER == LCD_TYPE_0
    #elif LCD_DRIVER == LCD_TYPE_1
    #else
    #error "LCD_DRIVER must be defined"
    #endif

    You can do this if you're sure to include some #defines everwhere LCD_DRIVER might be used:

    #define LCD_TYPE_0 0
    #define LCD_TYPE_1 1

    Otherwise, all the undefined symbols just devolve to 0 and you get unexpected results.

    For this sort of job I personally would be more likely to bind at link time. That is, write two driver.c files and add the correct one to the project, as was mentioned earlier. Conditional compilation rapidly leads to unreadable preprocessor spaghetti, and also tends to degrade the usefulness of search / diff / merge tools.

  • For this sort of job I personally would be more likely to bind at link time. That is, write two driver.c files and add the correct one to the project, as was mentioned earlier. Conditional compilation rapidly leads to unreadable preprocessor spaghetti, and also tends to degrade the usefulness of search / diff / merge tools.

    This is not pantyhose (one size does not fit all)

    I have files with conditional compile and I have "parallel files".

    The trouble with "parallel files" is that, if they are very similar, they are likely to have the same bugs. The risk with "parallel files" is that you may miss a global fix in one of them. That said, if you end up an awful lot of #ifdefs your code will be flearidden for that reason.



    One way I have found to be very effective is using macros.

    One example:
    In a program I "inherited" there was 113 #ifdefs for kicking the watchdog since the software drove 2 different hardwares. Replacing all this with a macro KICK_THE_PUPPY reduced the #ifdefs to ONE (in the macro).

    one methgod I have usewd for handling "parallel files" is to include them all in the library.
    function for sign 1:
    (void) fusgn1(void)
    function for sign 2:
    (void) fusgn2(void)
    ....

    then, in module I oddly enough have named "select" I have
    #if (SIGNTYPE == 1)
    #define fusgn fusgn1
    #elif (SIGNTYPE == 1)
    #define fusgn fusgn2
    ....

    and main() call fusgn

    Erik

    just some ways to do it.

  • The trouble with "parallel files" is that, if they are very similar

    If the files are very similar, I agree. Drivers for two different devices, on the other hand, aren't likely to have any similarities other than the names and parameters of the API.

    Often in such a case, you've discovered a natural interface in the design. The one file that originally seemed to be a single coherent module really has subcomponents. You can then factor the two parallel files into one common file, plus a few helper / utility functions that encapsulate the true differences. You'd have one common file with the common code and two auxiliary files, of which you link one.

    At some point, the changes are so minor or the granularity of the change so small that it's easier to do conditional compilation rather than refactor the code.

  • "It's often useful to have a positive check to be sure that someone actually selected a driver option, rather than just falling into an else clause due to lack of a choice."

    Very good advice.

    #define LCD_TYPE_0 0
    #define LCD_TYPE_1 1


    While we're on the subject of Defensive Programming, values 0 and 1 are best avoided - as these are prime candidates for default values if something is just defined without actually being assigned a proper value (eg, on a command line).

  • Good point.

    Zero is particularly bad since undefined symbols evaluate to zero.

  • "Otherwise, all the undefined symbols just devolve to 0 and you get unexpected results."

    Although, unlike some other compilers I have used, Keil does issue a diagnostic in this situation.