# New Ticket Created by Mike Mattie # Please include the string: [perl #41908] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=41908 >
Hello, This patch begins the feature enhancement phase of the Parrot_locate_runtime_str. based on: rev 17631 two new static functions are introduced. * try_load_path: this helper combines the path_finalization with the stat check for file existence. it is also a good debug point so I have left the bread-crumbs ifdef'd out. * try_bytecode_extensions this new function uses an array of extensions trying each one with the try_load_path call. compatibility is preserved by trying the path as given before attempting to guess an extension. *Parrot_locate_runtime_str: updated to use the new try_bytecode_extensions whenever the requested type is not PARROT_RUNTIME_FT_DYNEXT. Also some tabs that leaked into the file have been removed. I will be more vigilant in the future in regards to this. status: compile tested, full test-suite ran w/o new failures. At this point the extension guessing code is functional. I should in all likely-hood code a test file for the extension guessing as it exists. If this is necessary simply hold this ticket. [phase 2] At this point a real discussion is needed with the parrot developer community. The ultimate purpose of these patches is to enable developers to write code that will work the same way in both their working-copies and the install tree. To do this the parrot development process will need to be modified. I have thought up a solution that I believe is extremely un-obtrusive , and possibly a unique feature. background: If the developers begin removing extensions from their requested files the work-cycle will change to a full-compilation cycle, as the loader will prefer a .pbc file over a .pasm or a .pir. In discussions on IRC there was a reluctance to switch to this cycle. It does take some of the dynamic flavor out of the development process. There are two solutions. 1. do a clean during development. only the source files will remain and there should not be any problems. There could be collisions with a installed tree, however the second option is a step towards a complete solution. 2. introduce a environment variable, for example: PARROT_LOAD_PREFER this variable when set would have two valid values: source|compile. if no variable was set, or it was incorrectly set it would default to the compile value, giving typical (perl5 for example) behavior where a compiled version is always loaded over the source version. when the variable would be set to "source" then the reverse would happen, and the ".pir" files would be loaded over a .pbc. This allows developers to simply export PARROT_LOAD_PREFER="source" when developing to guarantee that the loaded files will be the source files with their most recent changes. by looking at the diff I think you will see the code changes subsequent to this patch to implement this will be nearly trivial at this point. [phase 3] the big win assuming that environment variables are a suitable way for parrot developers to maintain their current behavior a big step forward is now possible. the last remaining issue is the difference between the layout in the working-copy and the install tree. ie: parrot/library vs. runtime/parrot/library I have been developing a perl5 program in my spare time meant to address this very problem for my own purposes. but either the idea or an adapted version of the code can solve this neatly. the idea is that markers are placed in the working-copy tree marking installation paths. so in runtime/ some sort of file (MANIFEST ?) would indicate that the paths below runtime/ are to be preserved in the install tree. [if those files listed what needed to be installed writing the install target would be a snap, with language-hackers having control over their installed files.] With this information a perl program can recursively traverse the tree and create and add each of these directories with a MANIFEST file to the load path ( PARROT_INC ? , I am not sure ) so if you have your source code in ${HOME}/parrot/ , and there is a MANIFEST file in runtime/ , the code would add an environment variable like this: PARROT_INC="${HOME}/parrot/runtime" the perl program can simply dump out this list of environment variables on stdout. when a perl developer is ready to hack in the tree , he runs the program, and source's the output, updating his environment for that session. now his path "Digest/MD5" automatically gets a ".pir" tried first because of PARROT_LOAD_PREFER="source", and the prefix is the exact same in both the working copy and the install tree. when the perl developer installs his code, and the environment variables are cleared .pbc files are loaded as they should be and the path prefixes are the same. Extensive release testing is not necessary to maintain the install target because things break in the working-copy in the same way they would break in the install-tree. This is extremely powerful for development. [leftovers] there is a insignificant race, but still a race in the code. This needs to be addressed later as a part of fully insulating the src/library.c API. Ultimately a struct like this is needed. struct load_file { FILE* handle, parrot_runtime_ft type } 1. Parrot_runtime_locate_runtime_str would be renamed to parrot_locate_runtime_file, it would return the struct with the handle, the type value would be a null/unkown value. this closes the race by getting rid of a pointless stat() introduced by the string return value, a result of the poor API insulation. dynext.c replicates much of Parrot_locate_runtime_str in it's own fashion. also this should be opened on unix with O_NOCTTY | O_NOFOLLOW btw. maybe even fsat for block/char devices too. 2. a a hueristic routine for detecting parrot_runtime_ft it would take the load_file struct, and do the magic number/heuristic checks on the first chunk of the file and determine what runtime_ft_type it is, setting the value in the load_file struct. At this point the appropriate loader/infrastructure can be chosen to load the file. also the handling of shared object extensions can be done in the same way of try_bytecode_extensions now. That's all for now. Thanks again for answering all my questions, and I look forward to any comments or suggestions. Cheers, Mike Mattie ([EMAIL PROTECTED])
--- HEAD/src/library.c 2007-03-19 02:35:50.000000000 -0700 +++ parrot-0.4.9.test/src/library.c 2007-03-19 02:32:26.000000000 -0700 @@ -256,6 +256,78 @@ return join; } +#define LOAD_EXT_CODE_LAST 3 + +static const char* load_ext_code[ LOAD_EXT_CODE_LAST + 1 ] = { + ".pbc", + + /* source level files */ + + ".pasm", + ".past", + ".pir", +}; + +static STRING* +try_load_path(Interp *interp, STRING* path) { + STRING *final; + + final = string_copy(interp, path); + +#if 0 + printf("path is \"%s\"\n", + string_to_cstring(interp, final )); +#endif + + final = path_finalize(interp, final ); + + if (Parrot_stat_info_intval(interp, final , STAT_EXISTS)) { + return final; + } + + return NULL; +} + +/* + guess extensions, so that the user can drop the extensions + leaving it up to the build process/install wether or not + a .pbc or a .pir file is used. + */ + +static STRING* +try_bytecode_extensions (Interp *interp, STRING* path ) +{ + STRING *with_ext, *result; + + int guess; + + /* + first try the path without guessing ensure compatability with existing code. + */ + + with_ext = string_copy(interp, path); + + if ( (result = try_load_path(interp, with_ext) ) ) + return result; + + /* + start guessing now. this version tries to find the lowest form of the + code, starting with bytecode and working up to PIR. note the atypical + loop control. This is so the array can easily be processed in reverse. + */ + + for( guess = 0 ; guess <= LOAD_EXT_CODE_LAST ; guess++ ) { + with_ext = string_copy(interp, path); + with_ext = string_append(interp, + with_ext, const_string(interp, load_ext_code[guess])); + + if ( (result = try_load_path(interp, with_ext)) ) + return result; + } + + return NULL; +} + /* =item C<char* Parrot_locate_runtime_file(Interp *, const char *file_name, @@ -288,6 +360,11 @@ INTVAL i, n; PMC *paths; +#if 0 + printf("requesting path: \"%s\"\n", + string_to_cstring(interp, file )); +#endif + /* if this is an absolute path return it as is */ if (is_abs_path(interp, file)) return file; @@ -305,23 +382,27 @@ path = VTABLE_get_string_keyed_int(interp, paths, i); if (string_length(interp, prefix) && !is_abs_path(interp,path)) { - full_name = path_concat(interp, prefix , path ); + full_name = path_concat(interp, prefix , path ); } else full_name = string_copy(interp, path); - full_name = path_append(interp, full_name , file ); + full_name = path_append(interp, full_name , file ); + + full_name = ( type & PARROT_RUNTIME_FT_DYNEXT ) + ? try_load_path(interp, full_name ) + : try_bytecode_extensions(interp, full_name ); - full_name = path_finalize(interp, full_name ); - if (Parrot_stat_info_intval(interp, full_name, STAT_EXISTS)) { + if ( full_name ) return full_name; - } } - full_name = path_finalize( interp, file ); - if (Parrot_stat_info_intval(interp, full_name, STAT_EXISTS)) { - return full_name; - } + full_name = ( type & PARROT_RUNTIME_FT_DYNEXT ) + ? try_load_path(interp, file ) + : try_bytecode_extensions(interp, file ); + + if ( full_name ) + return full_name; return NULL; }
signature.asc
Description: PGP signature