Search code examples
cgccheader-fileslibraries

Weak functions with single-file header libraries


I maintain rawdraw, and rawdraw uses global symbols to callback, for creation, input, and closure. I would like automatically use one copy of a symbol, say, a no-op if the user has not defined one, or if the user has defined one, I would want to use it.

This isn't a problem for most platforms, but for Android it's incredibly annoying because you can't identify linker issues until the app is running on-device.

The issue is this is in the header. So what I want is a way to, from the same C file, allow a function call to be overridden, but not require it.

I've tried both weak and weak,aliasof(...) attributes and neither seem to allow overriding of a symbol in the same C file.

For example, in this case, a user wants to allow detection of window termination, but many users of this library don't care.

cnfg.h

void HandleWindowTermination();

...

    case APP_CMD_TERM_WINDOW:
              ...
        HandleWindowTermination();
        break;

Would require the user to implement HandleWindowTermination() - but I would like to have an optional implementation of it.

void DefaultHandleWindowTermination() { } // Do nothing

That is only used if HandleWindowTermination() is never defined.


Solution

  • GCC "weak" attribute is not available for all targets. From the GCC manual:

    This attribute requires assembler and object file support, and may not be available on all targets.

    Hence you may need to use a work-around. One possibility could be to define a function pointer to an optional implementation:

       typedef void (* HandleWindowTerminationFuncType) ();
       HandleWindowTerminationFuncType HandleWindowTerminationFunction = NULL;
    
       static void HandleWindowTermination()
       {
           if(HandleWindowTerminationFunction != NULL)
           {
               HandleWindowTerminationFunction();
           }
           else
           {
               // Default action
           }
       }
    

    Another module may then implement a HandleWindowTermination() function and set the HandleWindowTerminationFunction pointer to point at that implementation (you may implement a "setter" function to do that).