diff options
author | Andy Wingo <wingo@pobox.com> | 2016-06-11 22:43:50 +0200 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2016-06-12 10:32:45 +0200 |
commit | 7142005a055432f0d261c294c8cef012651a1899 (patch) | |
tree | 42940a78ac3326d746fa10d68fe7663ddf2546da /libguile/load.c | |
parent | 2cb7c4c4d7e6e6e5df9746c2582c49a8234d6103 (diff) |
Skip incompatible .go files
* libguile/load.c (load_thunk_from_path, try_load_thunk_from_file): New
functions.
(search_path): Simplify.
(scm_primitive_load_path, scm_init_eval_in_scheme): Use the new
functions to load compiled files.
* module/ice-9/boot-9.scm (load-in-vicinity): Skip invalid .go files.
Inspired by a patch from Jan Nieuwenhuizen <janneke@gnu.org>.
Diffstat (limited to 'libguile/load.c')
-rw-r--r-- | libguile/load.c | 302 |
1 files changed, 240 insertions, 62 deletions
diff --git a/libguile/load.c b/libguile/load.c index 897541490..7ad9a754d 100644 --- a/libguile/load.c +++ b/libguile/load.c @@ -28,18 +28,19 @@ #include <stdio.h> #include "libguile/_scm.h" -#include "libguile/libpath.h" -#include "libguile/fports.h" -#include "libguile/read.h" -#include "libguile/eval.h" -#include "libguile/throw.h" #include "libguile/alist.h" +#include "libguile/chars.h" #include "libguile/dynwind.h" -#include "libguile/root.h" -#include "libguile/strings.h" +#include "libguile/eval.h" +#include "libguile/fports.h" +#include "libguile/libpath.h" +#include "libguile/loader.h" #include "libguile/modules.h" -#include "libguile/chars.h" +#include "libguile/read.h" +#include "libguile/root.h" #include "libguile/srfi-13.h" +#include "libguile/strings.h" +#include "libguile/throw.h" #include "libguile/validate.h" #include "libguile/load.h" @@ -570,34 +571,85 @@ compiled_is_fresh (SCM full_filename, SCM compiled_filename, return compiled_is_newer; } -/* Search PATH for a directory containing a file named FILENAME. - The file must be readable, and not a directory. - If we find one, return its full pathname; otherwise, return #f. - If FILENAME is absolute, return it unchanged. - We also fill *stat_buf corresponding to the returned pathname. - If given, EXTENSIONS is a list of strings; for each directory - in PATH, we search for FILENAME concatenated with each EXTENSION. +static SCM +do_load_thunk_from_file (void *data) +{ + return scm_load_thunk_from_file (SCM_PACK_POINTER (data)); +} - If SOURCE_FILE_NAME is SCM_BOOL_F, then return the first matching - file name that we find in the path. Otherwise only return a file if - it is newer than SOURCE_STAT_BUF, otherwise issuing a warning if we - see a stale file earlier in the path, setting *FOUND_STALE_FILE to 1. +static SCM +load_thunk_from_file_catch_handler (void *data, SCM tag, SCM throw_args) +{ + SCM filename = SCM_PACK_POINTER (data); + SCM oport, lines; + + oport = scm_open_output_string (); + scm_print_exception (oport, SCM_BOOL_F, tag, throw_args); + + scm_puts (";;; WARNING: loading compiled file ", + scm_current_warning_port ()); + scm_display (filename, scm_current_warning_port ()); + scm_puts (" failed:\n", scm_current_warning_port ()); + + lines = scm_string_split (scm_get_output_string (oport), + SCM_MAKE_CHAR ('\n')); + for (; scm_is_pair (lines); lines = scm_cdr (lines)) + if (scm_c_string_length (scm_car (lines))) + { + scm_puts (";;; ", scm_current_warning_port ()); + scm_display (scm_car (lines), scm_current_warning_port ()); + scm_newline (scm_current_warning_port ()); + } + + scm_close_port (oport); + + return SCM_BOOL_F; +} + +static SCM +try_load_thunk_from_file (SCM filename) +{ + return scm_c_catch (SCM_BOOL_T, + do_load_thunk_from_file, + SCM_UNPACK_POINTER (filename), + load_thunk_from_file_catch_handler, + SCM_UNPACK_POINTER (filename), + NULL, NULL); +} + +/* Search the %load-compiled-path for a directory containing a file + named FILENAME. The file must be readable, and not a directory. If + we don't find one, return #f. If we do fine one, treat it as a + compiled file and try to load it as a thunk. If that fails, continue + looking in the path. + + If given, EXTENSIONS is a list of strings; for each directory in + PATH, we search for FILENAME concatenated with each EXTENSION. + + If SOURCE_FILE_NAME is true, then only try to load compiled files + that are newer than SOURCE_STAT_BUF. If they are older, otherwise issuing a warning if + we see a stale file earlier in the path, setting *FOUND_STALE_FILE to + 1. */ static SCM -search_path (SCM path, SCM filename, SCM extensions, SCM require_exts, - struct stat *stat_buf, - SCM source_file_name, struct stat *source_stat_buf, - int *found_stale_file) +load_thunk_from_path (SCM filename, SCM source_file_name, + struct stat *source_stat_buf, + int *found_stale_file) { struct stringbuf buf; + struct stat stat_buf; char *filename_chars; size_t filename_len; + SCM path, extensions; SCM result = SCM_BOOL_F; char initial_buffer[256]; + path = *scm_loc_load_compiled_path; if (scm_ilength (path) < 0) scm_misc_error ("%search-path", "path is not a proper list: ~a", scm_list_1 (path)); + + extensions = *scm_loc_load_compiled_extensions; if (scm_ilength (extensions) < 0) scm_misc_error ("%search-path", "bad extensions list: ~a", scm_list_1 (extensions)); @@ -611,11 +663,10 @@ search_path (SCM path, SCM filename, SCM extensions, SCM require_exts, /* If FILENAME is absolute and is still valid, return it unchanged. */ if (is_absolute_file_name (filename)) { - if ((scm_is_false (require_exts) || - string_has_an_ext (filename, extensions)) - && stat (filename_chars, stat_buf) == 0 - && !(stat_buf->st_mode & S_IFDIR)) - result = filename; + if (string_has_an_ext (filename, extensions) + && stat (filename_chars, &stat_buf) == 0 + && !(stat_buf.st_mode & S_IFDIR)) + result = scm_load_thunk_from_file (filename); goto end; } @@ -629,8 +680,7 @@ search_path (SCM path, SCM filename, SCM extensions, SCM require_exts, { if (*endp == '.') { - if (scm_is_true (require_exts) && - !string_has_an_ext (filename, extensions)) + if (!string_has_an_ext (filename, extensions)) { /* This filename has an extension, but not one of the right ones... */ @@ -687,21 +737,26 @@ search_path (SCM path, SCM filename, SCM extensions, SCM require_exts, /* If the file exists at all, we should return it. If the file is inaccessible, then that's an error. */ - if (stat (buf.buf, stat_buf) == 0 - && ! (stat_buf->st_mode & S_IFDIR)) + if (stat (buf.buf, &stat_buf) == 0 + && ! (stat_buf.st_mode & S_IFDIR)) { SCM found = scm_from_locale_string (scm_i_mirror_backslashes (buf.buf)); if (scm_is_true (source_file_name) && !compiled_is_fresh (source_file_name, found, - source_stat_buf, stat_buf)) + source_stat_buf, &stat_buf)) { if (found_stale_file) *found_stale_file = 1; continue; } + result = try_load_thunk_from_file (found); + if (scm_is_false (result)) + /* Already warned. */ + continue; + if (found_stale_file && *found_stale_file) { scm_puts (";;; found fresh compiled file at ", @@ -710,7 +765,137 @@ search_path (SCM path, SCM filename, SCM extensions, SCM require_exts, scm_newline (scm_current_warning_port ()); } - result = found; + goto end; + } + } + + if (!SCM_NULL_OR_NIL_P (exts)) + scm_wrong_type_arg_msg (NULL, 0, extensions, "proper list"); + } + + if (!SCM_NULL_OR_NIL_P (path)) + scm_wrong_type_arg_msg (NULL, 0, path, "proper list"); + + end: + scm_dynwind_end (); + return result; +} + +/* Search PATH for a directory containing a file named FILENAME. + The file must be readable, and not a directory. + If we find one, return its full pathname; otherwise, return #f. + If FILENAME is absolute, return it unchanged. + We also fill *stat_buf corresponding to the returned pathname. + If given, EXTENSIONS is a list of strings; for each directory + in PATH, we search for FILENAME concatenated with each EXTENSION. + */ +static SCM +search_path (SCM path, SCM filename, SCM extensions, SCM require_exts, + struct stat *stat_buf) +{ + struct stringbuf buf; + char *filename_chars; + size_t filename_len; + SCM result = SCM_BOOL_F; + char initial_buffer[256]; + + if (scm_ilength (path) < 0) + scm_misc_error ("%search-path", "path is not a proper list: ~a", + scm_list_1 (path)); + if (scm_ilength (extensions) < 0) + scm_misc_error ("%search-path", "bad extensions list: ~a", + scm_list_1 (extensions)); + + scm_dynwind_begin (0); + + filename_chars = scm_to_locale_string (filename); + filename_len = strlen (filename_chars); + scm_dynwind_free (filename_chars); + + /* If FILENAME is absolute and is still valid, return it unchanged. */ + if (is_absolute_file_name (filename)) + { + if ((scm_is_false (require_exts) || + string_has_an_ext (filename, extensions)) + && stat (filename_chars, stat_buf) == 0 + && !(stat_buf->st_mode & S_IFDIR)) + result = filename; + goto end; + } + + /* If FILENAME has an extension, don't try to add EXTENSIONS to it. */ + { + char *endp; + + for (endp = filename_chars + filename_len - 1; + endp >= filename_chars; + endp--) + { + if (*endp == '.') + { + if (scm_is_true (require_exts) && + !string_has_an_ext (filename, extensions)) + { + /* This filename has an extension, but not one of the right + ones... */ + goto end; + } + /* This filename already has an extension, so cancel the + list of extensions. */ + extensions = SCM_EOL; + break; + } + else if (is_file_name_separator (SCM_MAKE_CHAR (*endp))) + /* This filename has no extension, so keep the current list + of extensions. */ + break; + } + } + + /* This simplifies the loop below a bit. + */ + if (scm_is_null (extensions)) + extensions = scm_listofnullstr; + + buf.buf_len = sizeof initial_buffer; + buf.buf = initial_buffer; + + /* Try every path element. + */ + for (; scm_is_pair (path); path = SCM_CDR (path)) + { + SCM dir = SCM_CAR (path); + SCM exts; + size_t sans_ext_len; + + buf.ptr = buf.buf; + stringbuf_cat_locale_string (&buf, dir); + + /* Concatenate the path name and the filename. */ + + if (buf.ptr > buf.buf + && !is_file_name_separator (SCM_MAKE_CHAR (buf.ptr[-1]))) + stringbuf_cat (&buf, FILE_NAME_SEPARATOR_STRING); + + stringbuf_cat (&buf, filename_chars); + sans_ext_len = buf.ptr - buf.buf; + + /* Try every extension. */ + for (exts = extensions; scm_is_pair (exts); exts = SCM_CDR (exts)) + { + SCM ext = SCM_CAR (exts); + + buf.ptr = buf.buf + sans_ext_len; + stringbuf_cat_locale_string (&buf, ext); + + /* If the file exists at all, we should return it. If the + file is inaccessible, then that's an error. */ + + if (stat (buf.buf, stat_buf) == 0 + && ! (stat_buf->st_mode & S_IFDIR)) + { + result = + scm_from_locale_string (scm_i_mirror_backslashes (buf.buf)); goto end; } } @@ -780,8 +965,7 @@ SCM_DEFINE (scm_search_path, "search-path", 2, 0, 1, if (SCM_UNBNDP (require_exts)) require_exts = SCM_BOOL_F; - return search_path (path, filename, extensions, require_exts, &stat_buf, - SCM_BOOL_F, NULL, NULL); + return search_path (path, filename, extensions, require_exts, &stat_buf); } #undef FUNC_NAME @@ -806,7 +990,7 @@ SCM_DEFINE (scm_sys_search_load_path, "%search-load-path", 1, 0, 0, SCM_VALIDATE_STRING (1, filename); return search_path (*scm_loc_load_path, filename, *scm_loc_load_extensions, - SCM_BOOL_F, &stat_buf, SCM_BOOL_F, NULL, NULL); + SCM_BOOL_F, &stat_buf); } #undef FUNC_NAME @@ -973,7 +1157,7 @@ SCM_DEFINE (scm_primitive_load_path, "primitive-load-path", 0, 0, 1, #define FUNC_NAME s_scm_primitive_load_path { SCM filename, exception_on_not_found; - SCM full_filename, compiled_filename; + SCM full_filename, compiled_thunk; SCM hook = *scm_loc_load_hook; struct stat stat_source, stat_compiled; int found_stale_compiled_file = 0; @@ -1010,15 +1194,12 @@ SCM_DEFINE (scm_primitive_load_path, "primitive-load-path", 0, 0, 1, full_filename = search_path (*scm_loc_load_path, filename, *scm_loc_load_extensions, SCM_BOOL_F, - &stat_source, SCM_BOOL_F, NULL, NULL); + &stat_source); - compiled_filename = - search_path (*scm_loc_load_compiled_path, filename, - *scm_loc_load_compiled_extensions, SCM_BOOL_T, - &stat_compiled, full_filename, &stat_source, - &found_stale_compiled_file); + compiled_thunk = load_thunk_from_path (filename, full_filename, &stat_source, + &found_stale_compiled_file); - if (scm_is_false (compiled_filename) + if (scm_is_false (compiled_thunk) && scm_is_true (full_filename) && scm_is_true (*scm_loc_compile_fallback_path) && scm_is_false (*scm_loc_fresh_auto_compile) @@ -1045,12 +1226,12 @@ SCM_DEFINE (scm_primitive_load_path, "primitive-load-path", 0, 0, 1, scm_display (fallback, scm_current_warning_port ()); scm_newline (scm_current_warning_port ()); } - compiled_filename = fallback; + compiled_thunk = try_load_thunk_from_file (fallback); } free (fallback_chars); } - if (scm_is_false (full_filename) && scm_is_false (compiled_filename)) + if (scm_is_false (full_filename) && scm_is_false (compiled_thunk)) { if (scm_is_true (scm_procedure_p (exception_on_not_found))) return scm_call_0 (exception_on_not_found); @@ -1062,17 +1243,16 @@ SCM_DEFINE (scm_primitive_load_path, "primitive-load-path", 0, 0, 1, } if (!scm_is_false (hook)) - scm_call_1 (hook, (scm_is_true (full_filename) - ? full_filename : compiled_filename)); + scm_call_1 (hook, full_filename); - if (scm_is_true (compiled_filename)) - return scm_load_compiled_with_vm (compiled_filename); + if (scm_is_true (compiled_thunk)) + return scm_call_0 (compiled_thunk); else { SCM freshly_compiled = scm_try_auto_compile (full_filename); if (scm_is_true (freshly_compiled)) - return scm_load_compiled_with_vm (freshly_compiled); + return scm_call_0 (scm_load_thunk_from_file (freshly_compiled)); else return scm_primitive_load (full_filename); } @@ -1088,21 +1268,19 @@ scm_c_primitive_load_path (const char *filename) void scm_init_eval_in_scheme (void) { - SCM eval_scm, eval_go; - struct stat stat_source, stat_compiled; + SCM eval_scm, eval_thunk; + struct stat stat_source; int found_stale_eval_go = 0; eval_scm = search_path (*scm_loc_load_path, scm_from_locale_string ("ice-9/eval.scm"), - SCM_EOL, SCM_BOOL_F, &stat_source, - SCM_BOOL_F, NULL, NULL); - eval_go = search_path (*scm_loc_load_compiled_path, - scm_from_locale_string ("ice-9/eval.go"), - SCM_EOL, SCM_BOOL_F, &stat_compiled, - eval_scm, &stat_source, &found_stale_eval_go); + SCM_EOL, SCM_BOOL_F, &stat_source); + eval_thunk = + load_thunk_from_path (scm_from_locale_string ("ice-9/eval.go"), + eval_scm, &stat_source, &found_stale_eval_go); - if (scm_is_true (eval_go)) - scm_load_compiled_with_vm (eval_go); + if (scm_is_true (eval_thunk)) + scm_call_0 (eval_thunk); else /* If we have no eval.go, we shouldn't load any compiled code at all because we can't guarantee that tail calls will work. */ |