What is the correct way to handle optional public types / functions for a library using automake?

StackOverflow https://stackoverflow.com/questions/9440779

Pergunta

In a library I am maintaining, there are a few functions which depend on pthreads. The project uses automake. I want to create a configure option to disable the dependency on pthreads, which should simply not compile those functions. (The reason is for certain cross-compiling and embedded targets.)

Avoiding to compile the file containing these functions works okay so far, but now I realized that these functions and one struct they use are defined in the public headers.

  1. What is the correct approach here, from a library maintenance perspective?
  2. What's the correct way to make types or functions optional in public headers?

Initially I thought I should turn the headers into autoconf input (.in) files and generate the headers with these functions and types optionally removed.

But then, what about systems that might have different versions of the library installed simultaneously? Normally these should be able to share headers.

Should I make the headers use a preprocessor conditional to avoid these functions, and use pkg-config to specify it as a command-line option?

Another idea is to move these functions and types into their own header, and avoid installing this header when pthreads are disabled. This would mean messing up the organization of the headers slightly, but maybe is the best idea. I want your opinion though, what's the best way to deal with optional functionality in the public headers of a library?

Foi útil?

Solução

Another idea is to move these functions and types into their own header, and avoid installing this header when pthreads are disabled.

That'd be the cleanest choice. When you enable the option via AC_ARG_ENABLE you can bypass all the pthreads setup as well, of course. With this option, packages that depend on your library will be able to tell easily (via AC_TRY_COMPILE) that the pthread-optional functions are not there instead of AC_TRY_RUN to see if those functions work at runtime.

Outras dicas

One way is to have your thread-requiring functions to continue existing on the embedded platform, but returning an error code in case they are invoked. That way, the API remains the same across platforms, which is very much desirable for code using your library ("Program"), since Program does not need autoconf-like tests for the presence of functions in your library, but can just use them and utilize source-code level ifs to determine their functionality.

int mylib_thread_frenzy(void)
{
#ifdef HAVE_PTHREAD_CREATE
       int ret = pthread_create(...);
       if (ret < 0)
               return -errno;
       return 0;
#else
       return -ENOSYS;
#endif
}

.

/* Program */
int ret = mylib_thread_frenzy();
if (ret == -ENOSYS) {
    /* Hm, castrated platform. Try something else... */
    printf("Or just tell the user the platform is too weak.\n");
} else {
    printf("World domination acquired\n");
}

In any case, do not attempt to #include "config.h" in mylib.h, and do not ship this config.h either, since the defines set forth in your config.h may clash with those of another library and/or Program.

If you absolutely do want to remove functions from mylib.h, I guess this comes to mind:

/* mylib.h.in */
#if 0@HAVE_PTHREAD_CREATE@
extern int mylib_pthread_frenzy(void);
#endif

/* configure.ac */
AC_SEARCH_LIBS([pthread_create], [pthread],
  [HAVE_PTHREAD_CREATE=1
   AC_SUBST([HAVE_PTHREAD_CREATE])
  ])
AC_CONFIG_FILES([mylib.h.in])
AC_OUTPUT

I however dislike the second approach because it means configure has to rerun whenever mylib.h.in changes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top