mirror of
https://github.com/pyenv/pyenv.git
synced 2024-12-22 10:23:32 +00:00
Speed up realpath()
with dynamically loaded C extension
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.
This commit is contained in:
parent
13a474c4e9
commit
16c7eb4135
5 changed files with 89 additions and 1 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -4,3 +4,5 @@
|
|||
/versions
|
||||
/sources
|
||||
/cache
|
||||
/libexec/*.dylib
|
||||
/src/*.o
|
||||
|
|
|
@ -19,6 +19,7 @@ if [ -z "$RBENV_COMMAND" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if ! enable -f "${BASH_SOURCE%/*}"/rbenv-realpath.dylib realpath 2>/dev/null; then
|
||||
READLINK=$(type -p greadlink readlink | head -1)
|
||||
if [ -z "$READLINK" ]; then
|
||||
echo "rbenv: cannot find readlink - are you missing GNU coreutils?" >&2
|
||||
|
@ -42,13 +43,14 @@ realpath() {
|
|||
echo "$(pwd)/$name"
|
||||
cd "$cwd"
|
||||
}
|
||||
fi
|
||||
|
||||
IFS=: hook_paths=($RBENV_HOOK_PATH)
|
||||
|
||||
shopt -s nullglob
|
||||
for path in "${hook_paths[@]}"; do
|
||||
for script in "$path/$RBENV_COMMAND"/*.bash; do
|
||||
echo $(realpath $script)
|
||||
realpath "$script"
|
||||
done
|
||||
done
|
||||
shopt -u nullglob
|
||||
|
|
10
src/Makefile
Normal file
10
src/Makefile
Normal file
|
@ -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
|
31
src/bash.h
Normal file
31
src/bash.h
Normal file
|
@ -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
|
43
src/realpath.c
Normal file
43
src/realpath.c
Normal file
|
@ -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
|
||||
};
|
Loading…
Reference in a new issue