On systems that support both C compiling and dynamic loading, we can speed up `realpath()` (where most time in rbenv is spent) by replacing it with a dynamically loaded bash builtin. When `make -C src` is called in the project's root, `libexec/rbenv-realpath.dylib` will be created. If it exists, rbenv will attempt to load it as a builtin command. If it fails, execution will fall back to the old `realpath()` shell function.pull/360/head^2
| @ -0,0 +1,10 @@ | |||||
| SHOBJ_LDFLAGS = -dynamiclib -current_version 1.0 | |||||
| .c.o: | |||||
| $(CC) $(CFLAGS) -c -o $@ $< | |||||
| ../libexec/rbenv-realpath.dylib: realpath.o | |||||
| $(CC) $(CFLAGS) $(SHOBJ_LDFLAGS) -o $@ realpath.o | |||||
| clean: | |||||
| rm -f *.o ../libexec/*.dylib | |||||
| @ -0,0 +1,31 @@ | |||||
| #ifndef __BASH_H__ | |||||
| #define __BASH_H__ | |||||
| #define EXECUTION_SUCCESS 0 | |||||
| #define EXECUTION_FAILURE 1 | |||||
| #define EX_USAGE 258 | |||||
| #define BUILTIN_ENABLED 1 | |||||
| typedef struct word_desc { | |||||
| char *word; | |||||
| int flags; | |||||
| } WORD_DESC; | |||||
| typedef struct word_list { | |||||
| struct word_list *next; | |||||
| WORD_DESC *word; | |||||
| } WORD_LIST; | |||||
| typedef int sh_builtin_func_t(WORD_LIST *); | |||||
| struct builtin { | |||||
| char *name; | |||||
| sh_builtin_func_t *function; | |||||
| int flags; | |||||
| char * const *long_doc; | |||||
| const char *short_doc; | |||||
| char *unused; | |||||
| }; | |||||
| #endif | |||||
| @ -0,0 +1,43 @@ | |||||
| #include "bash.h" | |||||
| #include <stdlib.h> | |||||
| #include <stdio.h> | |||||
| int realpath_builtin(list) | |||||
| WORD_LIST *list; | |||||
| { | |||||
| int es; | |||||
| char *realbuf, *p; | |||||
| if (list == 0) { | |||||
| // builtin_usage(); | |||||
| return (EX_USAGE); | |||||
| } | |||||
| for (es = EXECUTION_SUCCESS; list; list = list->next) { | |||||
| p = list->word->word; | |||||
| realbuf = realpath(p, NULL); | |||||
| if (realbuf == NULL) { | |||||
| es = EXECUTION_FAILURE; | |||||
| // builtin_error("%s: cannot resolve: %s", p, strerror(errno)); | |||||
| } else { | |||||
| printf("%s\n", realbuf); | |||||
| free(realbuf); | |||||
| } | |||||
| } | |||||
| return es; | |||||
| } | |||||
| char *realpath_doc[] = { | |||||
| "Display each PATHNAME argument, resolving symbolic links. The exit status", | |||||
| "is 0 if each PATHNAME was resolved; non-zero otherwise.", | |||||
| (char *)NULL | |||||
| }; | |||||
| struct builtin realpath_struct = { | |||||
| "realpath", | |||||
| realpath_builtin, | |||||
| BUILTIN_ENABLED, | |||||
| realpath_doc, | |||||
| "realpath pathname [pathname...]", | |||||
| 0 | |||||
| }; | |||||