X-Git-Url: https://git.hcoop.net/bpt/guile.git/blobdiff_plain/31ab99de563027fe2bceb60bbd712407fcaf868e..284019a2a5cfd7c7734701671f6a1776f11211eb:/libguile/load.c diff --git a/libguile/load.c b/libguile/load.c index 50af25643..8cc08e89b 100644 --- a/libguile/load.c +++ b/libguile/load.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1995,1996,1998,1999,2000,2001, 2004, 2006, 2008, 2009 Free Software Foundation, Inc. +/* Copyright (C) 1995,1996,1998,1999,2000,2001, 2004, 2006, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -27,6 +27,7 @@ #include #include "libguile/_scm.h" +#include "libguile/private-gc.h" /* scm_getenv_int */ #include "libguile/libpath.h" #include "libguile/fports.h" #include "libguile/read.h" @@ -37,7 +38,6 @@ #include "libguile/root.h" #include "libguile/strings.h" #include "libguile/modules.h" -#include "libguile/lang.h" #include "libguile/chars.h" #include "libguile/srfi-13.h" @@ -62,6 +62,8 @@ #define R_OK 4 #endif +#include + /* Loading a file, given an absolute filename. */ @@ -98,15 +100,15 @@ SCM_DEFINE (scm_primitive_load, "primitive-load", 1, 0, 0, SCM port = scm_open_file (filename, scm_from_locale_string ("r")); scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE); scm_i_dynwind_current_load_port (port); - encoding = scm_scan_for_encoding (port); + + encoding = scm_i_scan_for_encoding (port); if (encoding) - { - scm_i_set_port_encoding_x (port, encoding); - free (encoding); - } + scm_i_set_port_encoding_x (port, encoding); else - /* The file has no encoding declaraed. We'll presume Latin-1. */ - scm_i_set_port_encoding_x (port, NULL); + /* The file has no encoding declared. We'll presume UTF-8, like + compile-file does. */ + scm_i_set_port_encoding_x (port, "UTF-8"); + while (1) { SCM reader, form; @@ -114,7 +116,7 @@ SCM_DEFINE (scm_primitive_load, "primitive-load", 1, 0, 0, /* Lookup and use the current reader to read the next expression. */ reader = scm_fluid_ref (the_reader); - if (reader == SCM_BOOL_F) + if (scm_is_false (reader)) form = scm_read (port); else form = scm_call_1 (reader, port); @@ -168,8 +170,9 @@ SCM_DEFINE (scm_sys_library_dir, "%library-dir", 0,0,0, #ifdef SCM_SITE_DIR SCM_DEFINE (scm_sys_site_dir, "%site-dir", 0,0,0, (), - "Return the directory where the Guile site files are installed.\n" - "E.g., may return \"/usr/share/guile/site\".") + "Return the directory where users should install Scheme code for use\n" + "with this version of Guile.\n\n" + "E.g., may return \"/usr/share/guile/site/" SCM_EFFECTIVE_VERSION "\".") #define FUNC_NAME s_scm_sys_site_dir { return scm_from_locale_string (SCM_SITE_DIR); @@ -177,6 +180,18 @@ SCM_DEFINE (scm_sys_site_dir, "%site-dir", 0,0,0, #undef FUNC_NAME #endif /* SCM_SITE_DIR */ +#ifdef SCM_GLOBAL_SITE_DIR +SCM_DEFINE (scm_sys_global_site_dir, "%global-site-dir", 0,0,0, + (), + "Return the directory where users should install Scheme code for use\n" + "with all versions of Guile.\n\n" + "E.g., may return \"/usr/share/guile/site\".") +#define FUNC_NAME s_scm_sys_global_site_dir +{ + return scm_from_locale_string (SCM_GLOBAL_SITE_DIR); +} +#undef FUNC_NAME +#endif /* SCM_GLOBAL_SITE_DIR */ @@ -193,9 +208,12 @@ static SCM *scm_loc_load_compiled_path; static SCM *scm_loc_load_compiled_extensions; /* Whether we should try to auto-compile. */ -static SCM *scm_loc_load_should_autocompile; +static SCM *scm_loc_load_should_auto_compile; + +/* Whether to treat all auto-compiled files as stale. */ +static SCM *scm_loc_fresh_auto_compile; -/* The fallback path for autocompilation */ +/* The fallback path for auto-compilation */ static SCM *scm_loc_compile_fallback_path; SCM_DEFINE (scm_parse_path, "parse-path", 1, 1, 0, @@ -240,8 +258,9 @@ scm_init_load_path () else if (env) path = scm_parse_path (scm_from_locale_string (env), path); else - path = scm_list_3 (scm_from_locale_string (SCM_SITE_DIR), - scm_from_locale_string (SCM_LIBRARY_DIR), + path = scm_list_4 (scm_from_locale_string (SCM_LIBRARY_DIR), + scm_from_locale_string (SCM_SITE_DIR), + scm_from_locale_string (SCM_GLOBAL_SITE_DIR), scm_from_locale_string (SCM_PKGDATA_DIR)); env = getenv ("GUILE_SYSTEM_COMPILED_PATH"); @@ -274,6 +293,12 @@ scm_init_load_path () snprintf (cachedir, sizeof(cachedir), "%s/.cache/" FALLBACK_DIR, pwd->pw_dir); #endif /* HAVE_GETPWENT */ +#ifdef __MINGW32__ + else if ((e = getenv ("LOCALAPPDATA"))) + snprintf (cachedir, sizeof (cachedir), "%s/.cache/" FALLBACK_DIR, e); + else if ((e = getenv ("APPDATA"))) + snprintf (cachedir, sizeof (cachedir), "%s/.cache/" FALLBACK_DIR, e); +#endif /* __MINGW32__ */ else cachedir[0] = 0; @@ -391,8 +416,8 @@ scm_c_string_has_an_ext (char *str, size_t len, SCM extensions) If FILENAME is absolute, return it unchanged. If given, EXTENSIONS is a list of strings; for each directory in PATH, we search for FILENAME concatenated with each EXTENSION. */ -SCM_DEFINE (scm_search_path, "search-path", 2, 2, 0, - (SCM path, SCM filename, SCM extensions, SCM require_exts), +SCM_DEFINE (scm_search_path, "search-path", 2, 0, 1, + (SCM path, SCM filename, SCM rest), "Search @var{path} for a directory containing a file named\n" "@var{filename}. The file must be readable, and not a directory.\n" "If we find one, return its full filename; otherwise, return\n" @@ -405,11 +430,47 @@ SCM_DEFINE (scm_search_path, "search-path", 2, 2, 0, struct stringbuf buf; char *filename_chars; size_t filename_len; + SCM extensions, require_exts; SCM result = SCM_BOOL_F; + if (SCM_UNBNDP (rest) || scm_is_null (rest)) + { + /* Called either by Scheme code that didn't provide the optional + arguments, or C code that used the Guile 1.8 signature (2 required, + 1 optional arg) and passed '() or nothing as the EXTENSIONS + argument. */ + extensions = SCM_EOL; + require_exts = SCM_UNDEFINED; + } + else + { + if (scm_is_null (SCM_CAR (rest)) || scm_is_pair (SCM_CAR (rest))) + { + /* Called by Scheme code written for 1.9. */ + extensions = SCM_CAR (rest); + if (scm_is_null (SCM_CDR (rest))) + require_exts = SCM_UNDEFINED; + else + { + require_exts = SCM_CADR (rest); + if (SCM_UNLIKELY (!scm_is_null (SCM_CDDR (rest)))) + scm_wrong_num_args (scm_from_locale_string (FUNC_NAME)); + } + } + else + { + /* Called by C code that uses the 1.8 signature, i.e., which + expects the 3rd argument to be EXTENSIONS. */ + extensions = rest; + require_exts = SCM_UNDEFINED; + } + } + if (SCM_UNBNDP (extensions)) extensions = SCM_EOL; + SCM_VALIDATE_LIST (3, extensions); + if (SCM_UNBNDP (require_exts)) require_exts = SCM_BOOL_F; @@ -565,46 +626,64 @@ SCM_DEFINE (scm_sys_search_load_path, "%search-load-path", 1, 0, 0, SCM_MISC_ERROR ("%load-path is not a proper list", SCM_EOL); if (scm_ilength (exts) < 0) SCM_MISC_ERROR ("%load-extension list is not a proper list", SCM_EOL); - return scm_search_path (path, filename, exts, SCM_UNDEFINED); + return scm_search_path (path, filename, exts); } #undef FUNC_NAME +/* Return true if COMPILED_FILENAME is newer than source file + FULL_FILENAME, false otherwise. Also return false if one of the + files cannot be stat'd. */ static int compiled_is_fresh (SCM full_filename, SCM compiled_filename) { char *source, *compiled; struct stat stat_source, stat_compiled; - int res; + int compiled_is_newer; source = scm_to_locale_string (full_filename); compiled = scm_to_locale_string (compiled_filename); - + if (stat (source, &stat_source) == 0 - && stat (compiled, &stat_compiled) == 0 - && stat_source.st_mtime == stat_compiled.st_mtime) + && stat (compiled, &stat_compiled) == 0) { - res = 1; + struct timespec source_mtime, compiled_mtime; + + source_mtime = get_stat_mtime (&stat_source); + compiled_mtime = get_stat_mtime (&stat_compiled); + + if (source_mtime.tv_sec < compiled_mtime.tv_sec + || (source_mtime.tv_sec == compiled_mtime.tv_sec + && source_mtime.tv_nsec <= compiled_mtime.tv_nsec)) + compiled_is_newer = 1; + else + { + compiled_is_newer = 0; + scm_puts (";;; note: source file ", scm_current_error_port ()); + scm_puts (source, scm_current_error_port ()); + scm_puts ("\n;;; newer than compiled ", scm_current_error_port ()); + scm_puts (compiled, scm_current_error_port ()); + scm_puts ("\n", scm_current_error_port ()); + } } else - { - scm_puts (";;; note: source file ", scm_current_error_port ()); - scm_puts (source, scm_current_error_port ()); - scm_puts ("\n;;; newer than compiled ", scm_current_error_port ()); - scm_puts (compiled, scm_current_error_port ()); - scm_puts ("\n", scm_current_error_port ()); - res = 0; - } + /* At least one of the files isn't accessible. */ + compiled_is_newer = 0; free (source); free (compiled); - return res; + + return compiled_is_newer; } SCM_KEYWORD (kw_env, "env"); +SCM_KEYWORD (kw_opts, "opts"); + +SCM_SYMBOL (sym_compile_file, "compile-file"); +SCM_SYMBOL (sym_auto_compilation_options, "%auto-compilation-options"); static SCM -do_try_autocompile (void *data) +do_try_auto_compile (void *data) { SCM source = PTR2SCM (data); SCM comp_mod, compile_file; @@ -614,14 +693,30 @@ do_try_autocompile (void *data) scm_newline (scm_current_error_port ()); comp_mod = scm_c_resolve_module ("system base compile"); - compile_file = scm_module_variable - (comp_mod, scm_from_locale_symbol ("compile-file")); + compile_file = scm_module_variable (comp_mod, sym_compile_file); if (scm_is_true (compile_file)) { /* Auto-compile in the context of the current module. */ - SCM res = scm_call_3 (scm_variable_ref (compile_file), source, - kw_env, scm_current_module ()); + SCM res, opts; + SCM args[5]; + + opts = scm_module_variable (scm_the_root_module (), + sym_auto_compilation_options); + if (SCM_VARIABLEP (opts)) + opts = SCM_VARIABLE_REF (opts); + else + opts = SCM_EOL; + + args[0] = source; + args[1] = kw_opts; + args[2] = opts; + args[3] = kw_env; + args[4] = scm_current_module (); + + /* Assume `*current-warning-prefix*' has an appropriate value. */ + res = scm_call_n (scm_variable_ref (compile_file), args, 5); + scm_puts (";;; compiled ", scm_current_error_port ()); scm_display (res, scm_current_error_port ()); scm_newline (scm_current_error_port ()); @@ -631,14 +726,14 @@ do_try_autocompile (void *data) { scm_puts (";;; it seems ", scm_current_error_port ()); scm_display (source, scm_current_error_port ()); - scm_puts ("\n;;; is part of the compiler; skipping autocompilation\n", + scm_puts ("\n;;; is part of the compiler; skipping auto-compilation\n", scm_current_error_port ()); return SCM_BOOL_F; } } static SCM -autocompile_catch_handler (void *data, SCM tag, SCM throw_args) +auto_compile_catch_handler (void *data, SCM tag, SCM throw_args) { SCM source = PTR2SCM (data); scm_puts (";;; WARNING: compilation of ", scm_current_error_port ()); @@ -652,16 +747,16 @@ autocompile_catch_handler (void *data, SCM tag, SCM throw_args) return SCM_BOOL_F; } -SCM_DEFINE (scm_sys_warn_autocompilation_enabled, "%warn-autocompilation-enabled", 0, 0, 0, +SCM_DEFINE (scm_sys_warn_auto_compilation_enabled, "%warn-auto-compilation-enabled", 0, 0, 0, (void), "") -#define FUNC_NAME s_scm_sys_warn_autocompilation_enabled +#define FUNC_NAME s_scm_sys_warn_auto_compilation_enabled { static int message_shown = 0; if (!message_shown) { - scm_puts (";;; note: autocompilation is enabled, set GUILE_AUTO_COMPILE=0\n" - ";;; or pass the --no-autocompile argument to disable.\n", + scm_puts (";;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0\n" + ";;; or pass the --no-auto-compile argument to disable.\n", scm_current_error_port ()); message_shown = 1; } @@ -671,16 +766,16 @@ SCM_DEFINE (scm_sys_warn_autocompilation_enabled, "%warn-autocompilation-enabled #undef FUNC_NAME static SCM -scm_try_autocompile (SCM source) +scm_try_auto_compile (SCM source) { - if (scm_is_false (*scm_loc_load_should_autocompile)) + if (scm_is_false (*scm_loc_load_should_auto_compile)) return SCM_BOOL_F; - scm_sys_warn_autocompilation_enabled (); + scm_sys_warn_auto_compilation_enabled (); return scm_c_catch (SCM_BOOL_T, - do_try_autocompile, + do_try_auto_compile, SCM2PTR (source), - autocompile_catch_handler, + auto_compile_catch_handler, SCM2PTR (source), NULL, NULL); } @@ -726,14 +821,19 @@ SCM_DEFINE (scm_primitive_load_path, "primitive-load-path", 0, 0, 1, exception_on_not_found = SCM_BOOL_T; full_filename = scm_sys_search_load_path (filename); - compiled_filename = scm_search_path (*scm_loc_load_compiled_path, - filename, - *scm_loc_load_compiled_extensions, - SCM_BOOL_T); - + if (scm_is_string (full_filename)) + full_filename = scm_canonicalize_path (full_filename); + + compiled_filename = + scm_search_path (*scm_loc_load_compiled_path, + filename, + scm_list_2 (*scm_loc_load_compiled_extensions, + SCM_BOOL_T)); + if (scm_is_false (compiled_filename) && scm_is_true (full_filename) && scm_is_true (*scm_loc_compile_fallback_path) + && scm_is_false (*scm_loc_fresh_auto_compile) && scm_is_pair (*scm_loc_load_compiled_extensions) && scm_is_string (scm_car (*scm_loc_load_compiled_extensions))) { @@ -767,6 +867,7 @@ SCM_DEFINE (scm_primitive_load_path, "primitive-load-path", 0, 0, 1, if (!compiled_is_fallback && scm_is_true (*scm_loc_compile_fallback_path) + && scm_is_false (*scm_loc_fresh_auto_compile) && scm_is_pair (*scm_loc_load_compiled_extensions) && scm_is_string (scm_car (*scm_loc_load_compiled_extensions))) { @@ -786,7 +887,7 @@ SCM_DEFINE (scm_primitive_load_path, "primitive-load-path", 0, 0, 1, /* Otherwise, we bottom out here. */ { - SCM freshly_compiled = scm_try_autocompile (full_filename); + SCM freshly_compiled = scm_try_auto_compile (full_filename); if (scm_is_true (freshly_compiled)) return scm_load_compiled_with_vm (freshly_compiled); @@ -802,6 +903,25 @@ scm_c_primitive_load_path (const char *filename) return scm_primitive_load_path (scm_from_locale_string (filename)); } +void +scm_init_eval_in_scheme (void) +{ + SCM eval_scm, eval_go; + eval_scm = scm_search_path (*scm_loc_load_path, + scm_from_locale_string ("ice-9/eval.scm"), + SCM_EOL); + eval_go = scm_search_path (*scm_loc_load_compiled_path, + scm_from_locale_string ("ice-9/eval.go"), + SCM_EOL); + + if (scm_is_true (eval_scm) && scm_is_true (eval_go) + && compiled_is_fresh (eval_scm, eval_go)) + scm_load_compiled_with_vm (eval_go); + else + /* if we have no eval.go, we shouldn't load any compiled code at all */ + *scm_loc_load_compiled_path = SCM_EOL; +} + /* Information about the build environment. */ @@ -824,13 +944,28 @@ init_build_info () SCM val = scm_from_locale_string (info[i].value); *loc = scm_acons (key, val, *loc); } +#ifdef PACKAGE_PACKAGER + *loc = scm_acons (scm_from_latin1_symbol ("packager"), + scm_from_latin1_string (PACKAGE_PACKAGER), + *loc); +#endif +#ifdef PACKAGE_PACKAGER_VERSION + *loc = scm_acons (scm_from_latin1_symbol ("packager-version"), + scm_from_latin1_string (PACKAGE_PACKAGER_VERSION), + *loc); +#endif +#ifdef PACKAGE_PACKAGER_BUG_REPORTS + *loc = scm_acons (scm_from_latin1_symbol ("packager-bug-reports"), + scm_from_latin1_string (PACKAGE_PACKAGER_BUG_REPORTS), + *loc); +#endif } void scm_init_load () { - scm_listofnullstr = scm_permanent_object (scm_list_1 (scm_nullstr)); + scm_listofnullstr = scm_list_1 (scm_nullstr); scm_loc_load_path = SCM_VARIABLE_LOC (scm_c_define ("%load-path", SCM_EOL)); scm_loc_load_extensions = SCM_VARIABLE_LOC (scm_c_define ("%load-extensions", @@ -845,19 +980,49 @@ scm_init_load () scm_loc_compile_fallback_path = SCM_VARIABLE_LOC (scm_c_define ("%compile-fallback-path", SCM_BOOL_F)); - - scm_loc_load_should_autocompile - = SCM_VARIABLE_LOC (scm_c_define ("%load-should-autocompile", SCM_BOOL_F)); + scm_loc_load_should_auto_compile + = SCM_VARIABLE_LOC (scm_c_define ("%load-should-auto-compile", SCM_BOOL_F)); + scm_loc_fresh_auto_compile + = SCM_VARIABLE_LOC (scm_c_define ("%fresh-auto-compile", SCM_BOOL_F)); the_reader = scm_make_fluid (); scm_fluid_set_x (the_reader, SCM_BOOL_F); scm_c_define("current-reader", the_reader); + scm_c_define ("load-compiled", + scm_c_make_gsubr ("load-compiled/vm", 1, 0, 0, + scm_load_compiled_with_vm)); + init_build_info (); #include "libguile/load.x" } +void +scm_init_load_should_auto_compile () +{ + char *auto_compile = getenv ("GUILE_AUTO_COMPILE"); + + if (auto_compile && strcmp (auto_compile, "0") == 0) + { + *scm_loc_load_should_auto_compile = SCM_BOOL_F; + *scm_loc_fresh_auto_compile = SCM_BOOL_F; + } + /* Allow "freshen" also. */ + else if (auto_compile && strncmp (auto_compile, "fresh", 5) == 0) + { + *scm_loc_load_should_auto_compile = SCM_BOOL_T; + *scm_loc_fresh_auto_compile = SCM_BOOL_T; + } + else + { + *scm_loc_load_should_auto_compile = SCM_BOOL_T; + *scm_loc_fresh_auto_compile = SCM_BOOL_F; + } +} + + + /* Local Variables: c-file-style: "gnu"