L
luser- -droog
I've avoided learning about dynamic loading for a long time, but
found that I need to learn to do it for things like multiple output
devices and running the whole program as a library call instead of
standalone. (This is all in the context of my Postscript Interpreter,
code.google.com/p/xpost)
So I read http://en.wikipedia.org/wiki/Dynamic_loading
and followed a link to a Linux page, and whipped up this little
example/test. And it works!
But it can't be that easy, right? I've got to be missing something.
Please comment on the following code. (Ignore for the moment
the lack of error handling in the stack implementation; I'm mostly
interested in the interfacing.)
test.c:
/*
Dynamic Loading test
ref.
http://en.wikipedia.org/wiki/Dynamic_loading
http://linux4u.jinr.ru/usoft/WWW/www_debian.org/Documentation/elf/node7.html
*/
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
void fatal(char *msg) {
fprintf(stderr, "Fatal Error: %s\n", msg);
exit(EXIT_FAILURE);
}
struct Stack_interface *si;
void loadplugins (void) {
void *stack_library = dlopen("stack.so", RTLD_LAZY);
if (stack_library == NULL) fatal("unable to load stack");
si = dlsym(stack_library, "interface");
if (si == NULL) fatal("unable to load stack interface");
}
int main() {
loadplugins();
void *stack;
char *a = "A";
char *b = "B";
void *c;
stack = si->stack_init();
stack = si->push(stack, a);
stack = si->push(stack, b);
stack = si->pop(stack, &c);
printf("%s\n", (char *)c);
stack = si->pop(stack, &c);
printf("%s\n", (char *)c);
return 0;
}
stack.h:
struct Stack_interface {
void *(*stack_init) (void);
void *(*push) (void *stack, void *item);
void *(*pop) (void *stack, void **item);
};
stack.c:
#include <stdlib.h>
#include <string.h>
#include "stack.h"
/*
struct Stack_interface {
void *(*stack_init) (void);
void *(*push) (void *stack, void *item);
void *(*pop) (void *stack, void **item);
};
*/
void *stack_init (void);
void *push(void *stack, void *item);
void *pop(void *stack, void **item);
struct Stack_interface interface = {
stack_init,
push,
pop
};
typedef struct stack {
void *item;
struct stack *next;
} Stack;
void *stack_init (void) {
Stack *s;
s = malloc(sizeof*s);
if (s) {
s->item = NULL;
s->next = NULL;
}
return s;
}
void *push (void *stack, void *item) {
Stack *s = stack;
Stack *n = stack_init();
n->item = item;
n->next = s;
return n;
}
void *pop (void *stack, void **item) {
Stack *s = stack;
Stack *n = s->next;
*item = s->item;
free(s);
return n;
}
makefile:
CC=gcc
LDFLAGS=
#LDFLAGS=-rdynamic #Cygwin doesn't need
SHLDFLAGS=
all: test
stack.o: stack.c
$(CC) -c -fPIC $<
stack.so: stack.o
$(CC) $(SHLDFLAGS) -shared -o $@ $^
test: test.o stack.so
$(CC) $(LDFLAGS) -o $@ test.o -ldl
clean:
$(RM) stack.o stack.so test.o test.exe
found that I need to learn to do it for things like multiple output
devices and running the whole program as a library call instead of
standalone. (This is all in the context of my Postscript Interpreter,
code.google.com/p/xpost)
So I read http://en.wikipedia.org/wiki/Dynamic_loading
and followed a link to a Linux page, and whipped up this little
example/test. And it works!
But it can't be that easy, right? I've got to be missing something.
Please comment on the following code. (Ignore for the moment
the lack of error handling in the stack implementation; I'm mostly
interested in the interfacing.)
test.c:
/*
Dynamic Loading test
ref.
http://en.wikipedia.org/wiki/Dynamic_loading
http://linux4u.jinr.ru/usoft/WWW/www_debian.org/Documentation/elf/node7.html
*/
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
void fatal(char *msg) {
fprintf(stderr, "Fatal Error: %s\n", msg);
exit(EXIT_FAILURE);
}
struct Stack_interface *si;
void loadplugins (void) {
void *stack_library = dlopen("stack.so", RTLD_LAZY);
if (stack_library == NULL) fatal("unable to load stack");
si = dlsym(stack_library, "interface");
if (si == NULL) fatal("unable to load stack interface");
}
int main() {
loadplugins();
void *stack;
char *a = "A";
char *b = "B";
void *c;
stack = si->stack_init();
stack = si->push(stack, a);
stack = si->push(stack, b);
stack = si->pop(stack, &c);
printf("%s\n", (char *)c);
stack = si->pop(stack, &c);
printf("%s\n", (char *)c);
return 0;
}
stack.h:
struct Stack_interface {
void *(*stack_init) (void);
void *(*push) (void *stack, void *item);
void *(*pop) (void *stack, void **item);
};
stack.c:
#include <stdlib.h>
#include <string.h>
#include "stack.h"
/*
struct Stack_interface {
void *(*stack_init) (void);
void *(*push) (void *stack, void *item);
void *(*pop) (void *stack, void **item);
};
*/
void *stack_init (void);
void *push(void *stack, void *item);
void *pop(void *stack, void **item);
struct Stack_interface interface = {
stack_init,
push,
pop
};
typedef struct stack {
void *item;
struct stack *next;
} Stack;
void *stack_init (void) {
Stack *s;
s = malloc(sizeof*s);
if (s) {
s->item = NULL;
s->next = NULL;
}
return s;
}
void *push (void *stack, void *item) {
Stack *s = stack;
Stack *n = stack_init();
n->item = item;
n->next = s;
return n;
}
void *pop (void *stack, void **item) {
Stack *s = stack;
Stack *n = s->next;
*item = s->item;
free(s);
return n;
}
makefile:
CC=gcc
LDFLAGS=
#LDFLAGS=-rdynamic #Cygwin doesn't need
SHLDFLAGS=
all: test
stack.o: stack.c
$(CC) -c -fPIC $<
stack.so: stack.o
$(CC) $(SHLDFLAGS) -shared -o $@ $^
test: test.o stack.so
$(CC) $(LDFLAGS) -o $@ test.o -ldl
clean:
$(RM) stack.o stack.so test.o test.exe