0

I have been reading the on-line book Basics of libuv and trying to rewrite them to work with both a static link and a dynamic link to the libuv library. I rewrote the watchers example (code below), but I had to "rename" the functions I retrieved from libuv.dylib to make it work, which means I had to write an entirely separate code path for the dynamic linking case. Can I somehow keep the same function names?

I want my code to look like this.

#include <stdio.h>
#include <uv.h>
#ifdef DYNAMIC
#include <dlfcn.h>
#endif

int64_t counter = 0;

void wait_for_a_while(uv_idle_t *handle, int status) {
  counter++;
  if (counter >= 10e6)
    uv_idle_stop(handle); // This function pointer must be a global variable
}

int main(int argc, char **argv) {
  uv_idle_t idler;

// Initialize code needed for dynamically-linked library
#ifdef DYNAMIC
  void *lib_handle = dlopen("libuv.dylib", RTLD_LOCAL|RTLD_LAZY);
  // Set up pointers to functions defined in libuv.dyld ...
#endif

  uv_idle_init(uv_default_loop(), &idler);
  uv_idle_start(&idler, wait_for_a_while);

  printf("Idling...\n");
  uv_run(uv_default_loop(), UV_RUN_DEFAULT);

// Clean up dynamically linked code
#ifdef DYNAMIC
  dlclose(lib_handle);
#endif
  return 0;
}

Currently, it looks like this.

#include <stdio.h>
#include <uv.h>
#ifdef DYNAMIC
#include <dlfcn.h>
// Currently, I need to define function pointers with different names
// than the functions they call
uv_loop_t* (*uln)(void);
int (*ur)(uv_loop_t*, uv_run_mode);
uv_loop_t* (*udl)(void);
int (*uii)(uv_loop_t*, uv_idle_t*);
int (*uist)(uv_idle_t*, uv_idle_cb);
int (*uisp)(uv_idle_t*);
#endif

int64_t counter = 0;

void wait_for_a_while(uv_idle_t *handle, int status) {
  counter++;
  if (counter >= 10e6)
#ifdef DYNAMIC
    uisp(handle);
#else
    uv_idle_stop(handle); // This should be the only line remaining
#endif
}

int main(int argc, char **argv) {
  uv_idle_t idler;

// Code path for dynamic linking case
#ifdef DYNAMIC
  void *lib_handle = dlopen("libuv.dylib", RTLD_LOCAL|RTLD_LAZY);
  // Retrieve symbol names from libuv.dylib
  *(void **)(&uln) = dlsym(lib_handle, "uv_loop_new");
  *(void **)(&ur) = dlsym(lib_handle, "uv_run");
  *(void **)(&udl) = dlsym(lib_handle, "uv_default_loop");
  *(void **)(&uii) = dlsym(lib_handle, "uv_idle_init");
  *(void **)(&uist) = dlsym(lib_handle, "uv_idle_start");
  *(void **)(&uisp) = dlsym(lib_handle, "uv_idle_stop");

  uii(udl(), &idler);
  uist(&idler, wait_for_a_while);

  printf("Idling...\n");
  ur(udl(), UV_RUN_DEFAULT);

  dlclose(lib_handle);

// Code for static linking case
#else
  uv_idle_init(uv_default_loop(), &idler);
  uv_idle_start(&idler, wait_for_a_while);

  printf("Idling...\n");
  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
#endif
  return 0;
}
Elzair
  • 452
  • 1
  • 4
  • 11
  • Please extract the essence (that's independent of this `libuv`) of your issue, and show a minimum of code (probably just a few lines). – meaning-matters Jul 22 '13 at 18:09
  • Your intent appears to be the ability to dynamically or statically link to the libuv library, but you don't describe why you're not able to do this. Normally, this is nothing more than a change to the compiler command line. – Ioan Jul 22 '13 at 18:35
  • I want to be able to dynamically link to libuv.dylib and be able to use the same function names as if I had statically linked to libuv.a. I want to use uv_loop_new() instead of uln(), uv_idle_init() instead of uii(), etc. – Elzair Jul 22 '13 at 21:09
  • The function names are the same whether you're statically or dynamically linking. Unless you have a reason for linking via `dlopen()` at runtime yourself, you shouldn't be (re)defining function pointers; just use them after including the header. Dynamic linking can refer to two things: automatic linking to a shared library at runtime (done by linker for you), explicit linking by you at runtime (via `dlopen()`). Generally, you don't expect to statically link if you're using `dlopen()`. – Ioan Jul 23 '13 at 15:51

1 Answers1

2

Change:

#include <uv.h>
#ifdef DYNAMIC
#include <dlfcn.h>
/*...*/

into:

#ifndef DYNAMIC
#include <uv.h>
#else
#include <dlfcn.h>
/*...*/

Now, you can name your function pointer variables the same as the interfaces you want to call them as.

However, it is unclear why you need to do this at all. Normally, you just link your application with the dynamic library. You would only need to do what you are doing if you are experimentally changing the implementation of the dynamic library (treating it like a plugin).


In a comment, you mention that you need the definitions of structures in <uv.h>. Then to make my original proposal work, you would need to redefine those structures in the case of DYNAMIC, since you would not be using the header file. But, if the uv library ever changes, you would lose those changes and be forced to update your DYNAMIC version to match, which is an undesirable situation.

Another work around is to follow your original approach of defining different function pointer names, but then define macros to map the original function names to the function pointer names.

#include <uv.h>
#ifdef DYNAMIC
#include <dlfcn.h>
uv_loop_t* (*uln)(void);
int (*ur)(uv_loop_t*, uv_run_mode);
//...
#define uv_loop_new uln 
#defin uv_run ur
//...
#endif
jxh
  • 69,070
  • 8
  • 110
  • 193
  • Thanks. That would clear up the function errors, but the library also defines some structs that I need, and two of those functions return a pointer to a struct defined in that library. Do I need to add the struct definition to my code or include a pointer to that struct as well (and would I then run into type issues)? – Elzair Jul 23 '13 at 14:50
  • I get an error when I give my function pointer variable the same name as the function **watcher.c:5:14: error: redefinition of** **'uv_loop_new' as different kind of symbol** **uv_loop_t* (*uv_loop_new)(void);** This is the line where I define the pointer to uv_loop_new: **uv_loop_t* (*uv_loop_new)(void);** – Elzair Jul 23 '13 at 14:51
  • You probably have some other header file that is including `` and you are running into that. Let me propose another solution given that you need data structures inside ``. – jxh Jul 23 '13 at 15:24