From e206f0d6026ced853e90ab645b807c8d3ed3dfb8 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sun, 13 Dec 2020 21:30:03 -0600 Subject: [PATCH] Initial implementation of dynamic response files. This implements the ability for response file "@()" substitution to dynamically adjust to either expand the content or create the response file depending on the possible command line length. This should reduce the create of such response temp files improving build performance. --- src/engine/constants.cpp | 7 + src/engine/constants.h | 2 + src/engine/execcmd.h | 4 + src/engine/execnt.cpp | 7 +- src/engine/execunix.cpp | 7 +- src/engine/execvms.cpp | 7 +- src/engine/function.cpp | 565 ++++++++++------ src/engine/jamgram.cpp | 667 +++++++------------ src/engine/jamgram.hpp | 2 +- src/tools/clang-linux.jam | 88 +-- src/tools/features/response-file-feature.jam | 26 + src/tools/gcc.jam | 8 +- test/core_at_file.py | 16 +- test/toolset-mock/src/MockProgram.py | 12 + test/toolset-mock/src/ar.py | 2 + test/toolset-mock/src/clang-linux-3.9.0.py | 72 +- test/toolset-mock/src/ranlib.py | 2 + test/toolset_clang_linux.py | 9 + 18 files changed, 785 insertions(+), 718 deletions(-) create mode 100644 src/tools/features/response-file-feature.jam diff --git a/src/engine/constants.cpp b/src/engine/constants.cpp index ce4e3d7e4..c64ea3b63 100644 --- a/src/engine/constants.cpp +++ b/src/engine/constants.cpp @@ -1,5 +1,6 @@ /* * Copyright 2011 Steven Watanabe + * Copyright 2020 René Ferdinand Rivera Morell * * This file is part of Jam - see jam.c for Copyright information. */ @@ -74,6 +75,8 @@ void constants_init( void ) constant_MAIN_PYTHON = object_new( "MAIN_PYTHON" ); constant_BUILTIN_GLOB_ARCHIVE_BACK= object_new( "BUILTIN_GLOB_ARCHIVE_BACK" ); constant_FILE_ARCHIVESCAN = object_new( "FILE_ARCHIVESCAN" ); + + constant_RESPONSE_FILE_SUB = object_new( "RESPONSE_FILE_SUB" ); } void constants_done( void ) @@ -133,6 +136,8 @@ void constants_done( void ) object_free( constant_MAIN_PYTHON ); object_free( constant_FILE_ARCHIVESCAN ); object_free( constant_BUILTIN_GLOB_ARCHIVE_BACK ); + + object_free( constant_RESPONSE_FILE_SUB ); } OBJECT * constant_empty; @@ -190,3 +195,5 @@ OBJECT * constant_extra_pythonpath; OBJECT * constant_MAIN_PYTHON; OBJECT * constant_FILE_ARCHIVESCAN; OBJECT * constant_BUILTIN_GLOB_ARCHIVE_BACK; + +OBJECT * constant_RESPONSE_FILE_SUB; diff --git a/src/engine/constants.h b/src/engine/constants.h index ec112080d..675b66579 100644 --- a/src/engine/constants.h +++ b/src/engine/constants.h @@ -73,4 +73,6 @@ extern OBJECT * constant_MAIN_PYTHON; /* "MAIN_PYTHON" */ extern OBJECT * constant_FILE_ARCHIVESCAN; /* "FILE_ARCHIVESCAN" */ extern OBJECT * constant_BUILTIN_GLOB_ARCHIVE_BACK; /* "BUILTIN_GLOB_ARCHIVE_BACK" */ +extern OBJECT * constant_RESPONSE_FILE_SUB; // "RESPONSE_FILE_SUB" + #endif diff --git a/src/engine/execcmd.h b/src/engine/execcmd.h index fa24e432d..293822b30 100644 --- a/src/engine/execcmd.h +++ b/src/engine/execcmd.h @@ -112,4 +112,8 @@ int is_raw_command_request( LIST * shell ); int check_cmd_for_too_long_lines( char const * command, int32_t max, int32_t * const error_length, int32_t * const error_max_length ); +/* Maximum shell command line length. + */ +int32_t shell_maxline(); + #endif diff --git a/src/engine/execnt.cpp b/src/engine/execnt.cpp index be0a57a9b..e365d7396 100644 --- a/src/engine/execnt.cpp +++ b/src/engine/execnt.cpp @@ -318,7 +318,7 @@ int32_t exec_check */ /* Check for too long command lines. */ - return check_cmd_for_too_long_lines( command->value, maxline(), + return check_cmd_for_too_long_lines( command->value, shell_maxline(), error_length, error_max_length ); } @@ -1376,5 +1376,10 @@ static void reportWindowsError( char const * const apiName, int32_t slot ) string_renew( cmdtab[ slot ].buffer_err ); } +int32_t shell_maxline() +{ + return maxline(); +} + #endif /* USE_EXECNT */ diff --git a/src/engine/execunix.cpp b/src/engine/execunix.cpp index 9b6ee0fc9..5cd5139ff 100644 --- a/src/engine/execunix.cpp +++ b/src/engine/execunix.cpp @@ -154,7 +154,7 @@ int exec_check return is_raw_cmd ? EXEC_CHECK_OK - : check_cmd_for_too_long_lines( command->value, MAXLINE, error_length, + : check_cmd_for_too_long_lines( command->value, shell_maxline(), error_length, error_max_length ); } @@ -603,4 +603,9 @@ static int get_free_cmdtab_slot() exit( EXITBAD ); } +int32_t shell_maxline() +{ + return MAXLINE; +} + # endif /* USE_EXECUNIX */ diff --git a/src/engine/execvms.cpp b/src/engine/execvms.cpp index e5a12bc62..2c516326c 100644 --- a/src/engine/execvms.cpp +++ b/src/engine/execvms.cpp @@ -89,7 +89,7 @@ int exec_check return is_raw_cmd ? EXEC_CHECK_OK - : check_cmd_for_too_long_lines( command->value, MAXLINE, error_length, + : check_cmd_for_too_long_lines( command->value, shell_maxline(), error_length, error_max_length ); } @@ -415,6 +415,11 @@ clock_t get_cpu_time() return result; } +int32_t shell_maxline() +{ + return MAXLINE; +} + # endif /* VMS */ diff --git a/src/engine/function.cpp b/src/engine/function.cpp index 357f331c3..101fd1a13 100644 --- a/src/engine/function.cpp +++ b/src/engine/function.cpp @@ -13,6 +13,7 @@ #include "compile.h" #include "constants.h" #include "debugger.h" +#include "execcmd.h" #include "filesys.h" #include "frames.h" #include "lists.h" @@ -29,6 +30,8 @@ #include #include +#include + /* #define FUNCTION_DEBUG_PROFILE */ @@ -628,9 +631,17 @@ typedef struct char to_windows; /* :W -- convert cygwin to native paths */ PATHPART empty; /* :E -- default for empties */ PATHPART join; /* :J -- join list with char */ + PATHPART prefix; /* :< */ + PATHPART postfix; /* :> */ } VAR_EDITS; -static LIST * apply_modifiers_impl( LIST * result, string * buf, +struct VAR_EXPANDED +{ + LIST * value = L0; + LIST * inner = L0; +}; + +static VAR_EXPANDED apply_modifiers_impl( LIST * result, string * buf, VAR_EDITS * edits, int32_t n, LISTITER iter, LISTITER end ); static void get_iters( subscript_t const subscript, LISTITER * const first, LISTITER * const last, int32_t const length ); @@ -693,6 +704,8 @@ static int32_t var_edit_parse( char const * mods, VAR_EDITS * edits, int32_t hav case 'M': fp = &edits->f.f_member; goto fileval; case 'T': edits->to_slashes = 1; continue; case 'W': edits->to_windows = 1; continue; + case '<': fp = &edits->prefix; goto strval; + case '>': fp = &edits->postfix; goto strval; default: continue; /* Should complain, but so what... */ } @@ -873,19 +886,37 @@ static int32_t expand_modifiers( STACK * s, int32_t n ) return total; } -static LIST * apply_modifiers( STACK * s, int32_t n ) +static VAR_EXPANDED apply_modifiers( STACK * s, int32_t n ) { LIST * value = stack_top( s ); - LIST * result = L0; + VAR_EXPANDED result; VAR_EDITS * const edits = (VAR_EDITS *)( (LIST * *)stack_get( s ) + 1 ); string buf[ 1 ]; string_new( buf ); - result = apply_modifiers_impl( result, buf, edits, n, list_begin( value ), + result = apply_modifiers_impl( L0, buf, edits, n, list_begin( value ), list_end( value ) ); string_free( buf ); return result; } +// STACK: LIST * modifiers[modifier_count] +static VAR_EXPANDED eval_modifiers( STACK * s, LIST * value, int32_t modifier_count ) +{ + // Convert modifiers to value edits. + int32_t edits = expand_modifiers( s, modifier_count ); + // Edit the value on the stack. + stack_push( s, value ); + VAR_EXPANDED result = apply_modifiers( s, edits ); + list_free( stack_pop( s ) ); + // Clean up the value edits on the stack. + stack_deallocate( s, edits * sizeof( VAR_EDITS ) ); + // Clean up the filename modifiers. + for ( int32_t i = 0; i < modifier_count; ++i ) + list_free( stack_pop( s ) ); + // Done. + return result; +} + /* * Parse a string of the form "1-2", "-2--1", "2-" and return the two @@ -1027,6 +1058,32 @@ static void get_iters( subscript_t const subscript, LISTITER * const first, *last = end; } +static LIST * apply_modifiers_prepost( LIST * result, string * buf, + VAR_EDITS * edits, int32_t n, LISTITER begin, LISTITER end ) +{ + for ( LISTITER iter = begin; iter != end; iter = list_next( iter ) ) + { + for ( int32_t i = 0; i < n; ++i ) + { + if ( edits[ i ].prefix.ptr ) + { + string_append( buf, edits[ i ].prefix.ptr ); + } + } + string_append( buf, object_str( list_item( iter ) ) ); + for ( int32_t i = 0; i < n; ++i ) + { + if ( edits[ i ].postfix.ptr ) + { + string_append( buf, edits[ i ].postfix.ptr ); + } + } + result = list_push_back( result, object_new( buf->value ) ); + string_truncate( buf, 0 ); + } + return result; +} + static LIST * apply_modifiers_empty( LIST * result, string * buf, VAR_EDITS * edits, int32_t n ) { @@ -1083,12 +1140,17 @@ static LIST * apply_modifiers_non_empty( LIST * result, string * buf, return result; } -static LIST * apply_modifiers_impl( LIST * result, string * buf, +static VAR_EXPANDED apply_modifiers_impl( LIST * result, string * buf, VAR_EDITS * edits, int32_t n, LISTITER iter, LISTITER end ) { - return iter == end + LIST * modified = iter == end ? apply_modifiers_empty( result, buf, edits, n ) : apply_modifiers_non_empty( result, buf, edits, n, iter, end ); + VAR_EXPANDED expanded; + expanded.value = apply_modifiers_prepost( + L0, buf, edits, n, list_begin( modified ), list_end( modified ) ); + expanded.inner = modified; + return expanded; } static LIST * apply_subscript_and_modifiers( STACK * s, int32_t n ) @@ -1110,7 +1172,10 @@ static LIST * apply_subscript_and_modifiers( STACK * s, int32_t n ) subscript_t const sub = parse_subscript( object_str( list_item( indices_iter ) ) ); get_iters( sub, &iter, &end, length ); - result = apply_modifiers_impl( result, buf, edits, n, iter, end ); + VAR_EXPANDED modified + = apply_modifiers_impl( result, buf, edits, n, iter, end ); + result = modified.value; + list_free( modified.inner ); } string_free( buf ); return result; @@ -1256,6 +1321,7 @@ struct dynamic_array { int32_t size; int32_t capacity; + int32_t unit_size; void * data; }; @@ -1263,6 +1329,7 @@ static void dynamic_array_init( struct dynamic_array * array ) { array->size = 0; array->capacity = 0; + array->unit_size = 0; array->data = 0; } @@ -1274,6 +1341,14 @@ static void dynamic_array_free( struct dynamic_array * array ) static void dynamic_array_push_impl( struct dynamic_array * const array, void const * const value, int32_t const unit_size ) { + if ( array->unit_size == 0 ) + { + array->unit_size = unit_size; + } + else + { + assert( array->unit_size == unit_size ); + } if ( array->capacity == 0 ) { array->capacity = 2; @@ -1293,7 +1368,7 @@ static void dynamic_array_push_impl( struct dynamic_array * const array, } #define dynamic_array_push( array, value ) (dynamic_array_push_impl(array, &value, sizeof(value))) -#define dynamic_array_at( type, array, idx ) (((type *)(array)->data)[idx]) +#define dynamic_array_at( type, array, idx ) ( (assert( array->unit_size == sizeof(type) )) , (((type *)(array)->data)[idx]) ) #define dynamic_array_pop( array ) (--(array)->size) /* @@ -1611,15 +1686,51 @@ typedef struct OBJECT * s; } VAR_PARSE_STRING; -typedef struct -{ - VAR_PARSE base; - struct dynamic_array filename[ 1 ]; - struct dynamic_array contents[ 1 ]; -} VAR_PARSE_FILE; - static void var_parse_free( VAR_PARSE * ); +static std::string var_parse_to_string( VAR_PARSE_STRING * string, bool debug = false ); +static std::string var_parse_to_string( VAR_PARSE_GROUP * group, bool debug = false ); +static std::string var_parse_to_string( VAR_PARSE_VAR const * parse, bool debug = false ); + +static std::string var_parse_to_string( VAR_PARSE_STRING * string, bool debug ) +{ + std::string result; + if ( debug ) result += "'"; + result += object_str( string->s ) ? object_str( string->s ) : ""; + if ( debug ) result += "'"; + return result; +} +static std::string var_parse_to_string( VAR_PARSE_GROUP * group, bool debug ) +{ + std::string result; + if ( debug ) result += "["; + for ( int32_t i = 0; i < group->elems->size; ++i ) + { + switch ( dynamic_array_at( VAR_PARSE *, group->elems, i )->type ) + { + case VAR_PARSE_TYPE_VAR: + result += var_parse_to_string( dynamic_array_at( VAR_PARSE_VAR *, group->elems, i ), debug ); + break; + + case VAR_PARSE_TYPE_STRING: + result += var_parse_to_string( dynamic_array_at( VAR_PARSE_STRING *, group->elems, i ), debug ); + break; + } + } + if ( debug ) result += "["; + return result; +} +static std::string var_parse_to_string( VAR_PARSE_VAR const * parse, bool debug ) +{ + std::string result = "$("; + result += var_parse_to_string( parse->name, debug ); + for ( int32_t i = 0; i < parse->modifiers->size; ++i ) + { + result += ":" + var_parse_to_string( dynamic_array_at( VAR_PARSE_GROUP *, parse->modifiers, i ), debug ); + } + return result + ")"; +} + /* * VAR_PARSE_GROUP @@ -1732,6 +1843,21 @@ static VAR_PARSE_GROUP * var_parse_var_new_modifier( VAR_PARSE_VAR * var ) return result; } +static int32_t var_parse_var_mod_index( VAR_PARSE_VAR const * var , char m) +{ + for ( int32_t i = 0; i < var->modifiers->size; ++i ) + { + VAR_PARSE_GROUP * mod = dynamic_array_at( VAR_PARSE_GROUP *, var->modifiers, i ); + VAR_PARSE_STRING * mod_val = dynamic_array_at( VAR_PARSE_STRING *, mod->elems, 0 ); + const char * mod_str = object_str(mod_val->s); + if (mod_str && mod_str[0] == m) + { + return i; + } + } + return -1; +} + /* * VAR_PARSE_STRING @@ -1744,35 +1870,6 @@ static void var_parse_string_free( VAR_PARSE_STRING * string ) } -/* - * VAR_PARSE_FILE - */ - -static VAR_PARSE_FILE * var_parse_file_new( void ) -{ - VAR_PARSE_FILE * const result = (VAR_PARSE_FILE *)BJAM_MALLOC( sizeof( - VAR_PARSE_FILE ) ); - result->base.type = VAR_PARSE_TYPE_FILE; - dynamic_array_init( result->filename ); - dynamic_array_init( result->contents ); - return result; -} - -static void var_parse_file_free( VAR_PARSE_FILE * file ) -{ - int32_t i; - for ( i = 0; i < file->filename->size; ++i ) - var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, - file->filename, i ) ); - dynamic_array_free( file->filename ); - for ( i = 0; i < file->contents->size; ++i ) - var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, - file->contents, i ) ); - dynamic_array_free( file->contents ); - BJAM_FREE( file ); -} - - /* * VAR_PARSE */ @@ -1782,6 +1879,7 @@ static void var_parse_free( VAR_PARSE * parse ) switch ( parse->type ) { case VAR_PARSE_TYPE_VAR: + case VAR_PARSE_TYPE_FILE: var_parse_var_free( (VAR_PARSE_VAR *)parse ); break; @@ -1789,10 +1887,6 @@ static void var_parse_free( VAR_PARSE * parse ) var_parse_string_free( (VAR_PARSE_STRING *)parse ); break; - case VAR_PARSE_TYPE_FILE: - var_parse_file_free( (VAR_PARSE_FILE *)parse ); - break; - default: assert( !"Invalid type" ); } @@ -1898,17 +1992,53 @@ static void var_parse_string_compile( VAR_PARSE_STRING const * parse, ); } -static void var_parse_file_compile( VAR_PARSE_FILE const * parse, compiler * c ) +static void parse_var_string( char const * first, char const * last, + struct dynamic_array * out ); + +static void var_parse_file_compile( VAR_PARSE_VAR const * parse, compiler * c ) { - int32_t i; - for ( i = 0; i < parse->filename->size; ++i ) - var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, - parse->filename, parse->filename->size - i - 1 ), c ); - compile_emit( c, INSTR_APPEND_STRINGS, parse->filename->size ); - for ( i = 0; i < parse->contents->size; ++i ) - var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, - parse->contents, parse->contents->size - i - 1 ), c ); - compile_emit( c, INSTR_WRITE_FILE, parse->contents->size ); + std::string var = var_parse_to_string( parse, true ); + int32_t empty_mod_index = var_parse_var_mod_index( parse, 'E' ); + int32_t grist_mod_index = var_parse_var_mod_index( parse, 'G' ); + int32_t modifier_count = 0; + // Push the contents, aka the edit modifier value. + { + assert( empty_mod_index >= 0 ); + // We reparse the edit modifier as we do teh expansion differently than + // regular var expansion. + std::string contents_val = var_parse_to_string( + dynamic_array_at( + VAR_PARSE_GROUP *, parse->modifiers, empty_mod_index ), false ); + dynamic_array contents_dyn_array; + dynamic_array_init( &contents_dyn_array ); + parse_var_string( + contents_val.c_str() + 2, contents_val.c_str() + contents_val.size(), + &contents_dyn_array ); + for ( int32_t i = contents_dyn_array.size - 1; i >= 0; --i ) + { + var_parse_group_compile( dynamic_array_at( + VAR_PARSE_GROUP *, ( &contents_dyn_array ), i ), c ); + } + dynamic_array_free( &contents_dyn_array ); + compile_emit( c, INSTR_APPEND_STRINGS, contents_dyn_array.size ); + } + // If there are modifiers, emit them in reverse order. + if ( parse->modifiers->size > 0 ) + { + for ( int32_t i = parse->modifiers->size - 1; i >= 0; --i ) + { + // Skip special modifiers. + if ( i == empty_mod_index || i == grist_mod_index ) continue; + modifier_count += 1; + var_parse_group_compile( + dynamic_array_at( VAR_PARSE_GROUP *, parse->modifiers, i ), c ); + } + } + // Push the filename, aka var name. + var_parse_group_compile( parse->name, c ); + // This instruction applies the modifiers and writes out the file and fills + // in the file name. + compile_emit( c, INSTR_WRITE_FILE, modifier_count ); } static void var_parse_compile( VAR_PARSE const * parse, compiler * c ) @@ -1924,7 +2054,7 @@ static void var_parse_compile( VAR_PARSE const * parse, compiler * c ) break; case VAR_PARSE_TYPE_FILE: - var_parse_file_compile( (VAR_PARSE_FILE const *)parse, c ); + var_parse_file_compile( (VAR_PARSE_VAR const *)parse, c ); break; default: @@ -1964,8 +2094,6 @@ static void var_parse_actions_compile( VAR_PARSE_ACTIONS const * actions, * Parse VAR_PARSE_VAR */ -static VAR_PARSE * parse_at_file( char const * start, char const * mid, - char const * end ); static VAR_PARSE * parse_variable( char const * * string ); static int32_t try_parse_variable( char const * * s_, char const * * string, VAR_PARSE_GROUP * out ); @@ -2026,36 +2154,18 @@ static int32_t try_parse_variable( char const * * s_, char const * * string, } if ( s[ 0 ] == '@' && s[ 1 ] == '(' ) { - int32_t depth = 1; - char const * ine; - char const * split = 0; var_parse_group_maybe_add_constant( out, *string, s ); s += 2; - ine = s; - - /* Scan the content of the response file @() section. */ - while ( *ine && ( depth > 0 ) ) + VAR_PARSE_VAR *vp = (VAR_PARSE_VAR*)parse_variable( &s ); + /* We at least need the empty (:E) modifier. */ + if (var_parse_var_mod_index(vp, 'E') >= 0) { - switch ( *ine ) - { - case '(': ++depth; break; - case ')': --depth; break; - case ':': - if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '=' - ) ) - split = ine; - break; - } - ++ine; + vp->base.type = VAR_PARSE_TYPE_FILE; + var_parse_group_add( out, (VAR_PARSE*)vp ); + *string = s; + *s_ = s; + return 1; } - - if ( !split || depth ) - return 0; - - var_parse_group_add( out, parse_at_file( s, split, ine - 1 ) ); - *string = ine; - *s_ = ine; - return 1; } return 0; } @@ -2221,20 +2331,6 @@ static void parse_var_string( char const * first, char const * last, } } -/* - * start should point to the character immediately following the opening "@(", - * mid should point to the ":E=", and end should point to the closing ")". - */ - -static VAR_PARSE * parse_at_file( char const * start, char const * mid, - char const * end ) -{ - VAR_PARSE_FILE * result = var_parse_file_new(); - parse_var_string( start, mid, result->filename ); - parse_var_string( mid + 3, end, result->contents ); - return (VAR_PARSE *)result; -} - /* * Given that *s_ points to the character after a "(", parses up to the matching * ")". *string should point to the first unemitted character before *s_. @@ -3859,6 +3955,146 @@ void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s, stack_deallocate( s, sizeof( string * ) ); } +// Result is either the filename or contents depending on: +// 1. If the RESPONSE_FILE_SUB == f or not set (it's filename) +// 2. If the RESPONSE_FILE_SUB == c (it's contents) +// 3. If the RESPONSE_FILE_SUB == a (depends on the length of contents) +// Note, returns a *copy* of the filename or contents. +LIST * function_execute_write_file( + JAM_FUNCTION * function, FRAME * frame, STACK * s, + VAR_EXPANDED filename, LIST * contents ) +{ + LIST * filename_or_contents_result = nullptr; + + LIST * response_file_sub = function_get_named_variable( + function, frame, constant_RESPONSE_FILE_SUB ); + char response_file_sub_c + = response_file_sub && list_front( response_file_sub ) + ? object_str( list_front( response_file_sub ) )[0] + : 'f'; + list_free( response_file_sub ); + const char * contents_str = object_str( list_front( contents ) ); + if ( response_file_sub_c == 'a' ) + { + if ( int32_t( strlen( contents_str ) + 256 ) > shell_maxline() ) + response_file_sub_c = 'f'; + else + response_file_sub_c = 'c'; + } + if ( response_file_sub_c == 'c' ) + { + filename_or_contents_result = list_copy( contents ); + } + else + { + char const * out = object_str( list_front( filename.inner ) ); + OBJECT * tmp_filename = nullptr; + FILE * out_file = nullptr; + bool out_debug = DEBUG_EXEC; + + /* For stdout/stderr we will create a temp file and generate a + * command that outputs the content as needed. + */ + if ( ( strcmp( "STDOUT", out ) == 0 ) || + ( strcmp( "STDERR", out ) == 0 ) ) + { + int32_t err_redir = strcmp( "STDERR", out ) == 0; + string result[ 1 ]; + + tmp_filename = path_tmpfile(); + + /* Construct os-specific cat command. */ + { + const char * command = "cat"; + const char * quote = "\""; + const char * redirect = "1>&2"; + + #ifdef OS_NT + command = "type"; + quote = "\""; + #elif defined( OS_VMS ) + command = "pipe type"; + quote = ""; + + /* Get tmp file name in os-format. */ + { + string os_filename[ 1 ]; + + string_new( os_filename ); + path_translate_to_os( object_str( tmp_filename ), os_filename ); + object_free( tmp_filename ); + tmp_filename = object_new( os_filename->value ); + string_free( os_filename ); + } + #endif + + string_new( result ); + string_append( result, command ); + string_append( result, " " ); + string_append( result, quote ); + string_append( result, object_str( tmp_filename ) ); + string_append( result, quote ); + if ( err_redir ) + { + string_append( result, " " ); + string_append( result, redirect ); + } + } + + /* Replace STDXXX with the temporary file. */ + filename_or_contents_result = list_new( object_new( result->value ) ); + out = object_str( tmp_filename ); + + string_free( result ); + + /* Make sure temp files created by this get nuked eventually. */ + file_remove_atexit( tmp_filename ); + } + else + { + filename_or_contents_result = list_copy( filename.value ); + } + + if ( !globs.noexec ) + { + string out_name[ 1 ]; + /* Handle "path to file" filenames. */ + if ( ( out[ 0 ] == '"' ) && ( out[ strlen( out ) - 1 ] == '"' ) + ) + { + string_copy( out_name, out + 1 ); + string_truncate( out_name, out_name->size - 1 ); + } + else + string_copy( out_name, out ); + out_file = fopen( out_name->value, "w" ); + + if ( !out_file ) + { + err_printf( "[errno %d] failed to write output file '%s': %s", + errno, out_name->value, strerror(errno) ); + exit( EXITBAD ); + } + string_free( out_name ); + } + + if ( out_debug ) out_printf( "\nfile %s\n", out ); + if ( out_file ) fputs( object_str( list_front( contents ) ), out_file ); + if ( out_debug ) out_puts( object_str( list_front( contents ) ) ); + if ( out_file ) + { + fflush( out_file ); + fclose( out_file ); + } + if ( tmp_filename ) + object_free( tmp_filename ); + + if ( out_debug ) out_putc( '\n' ); + } + + return filename_or_contents_result; +} + /* * WARNING: The instruction set is tuned for Jam and is not really generic. Be * especially careful about stack push/pop. @@ -4660,7 +4896,9 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) l = stack_pop( s ); n = expand_modifiers( s, code->arg ); stack_push( s, l ); - l = apply_modifiers( s, n ); + VAR_EXPANDED m = apply_modifiers( s, n ); + l = m.value; + list_free( m.inner ); list_free( stack_pop( s ) ); stack_deallocate( s, n * sizeof( VAR_EDITS ) ); for ( i = 0; i < code->arg; ++i ) @@ -4715,7 +4953,9 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) { stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) ); - result = list_append( result, apply_modifiers( s, n ) ); + VAR_EXPANDED m = apply_modifiers( s, n ); + result = m.value; + list_free( m.inner ); list_free( stack_pop( s ) ); } list_free( vars ); @@ -4932,114 +5172,27 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) break; } + // WRITE_FILE( LIST*1 filename, LIST*1 modifiers[N], LIST*1 contents ) case INSTR_WRITE_FILE: { PROFILE_ENTER_LOCAL(function_run_INSTR_WRITE_FILE); - string buf[ 1 ]; - char const * out; - OBJECT * tmp_filename = 0; - int32_t out_debug = DEBUG_EXEC ? 1 : 0; - FILE * out_file = 0; - string_new( buf ); - combine_strings( s, code->arg, buf ); - out = object_str( list_front( stack_top( s ) ) ); - - /* For stdout/stderr we will create a temp file and generate a - * command that outputs the content as needed. - */ - if ( ( strcmp( "STDOUT", out ) == 0 ) || - ( strcmp( "STDERR", out ) == 0 ) ) + // Get expanded filename. + LIST * filename = nullptr; { - int32_t err_redir = strcmp( "STDERR", out ) == 0; - string result[ 1 ]; - - tmp_filename = path_tmpfile(); - - /* Construct os-specific cat command. */ - { - const char * command = "cat"; - const char * quote = "\""; - const char * redirect = "1>&2"; - - #ifdef OS_NT - command = "type"; - quote = "\""; - #elif defined( OS_VMS ) - command = "pipe type"; - quote = ""; - - /* Get tmp file name is os-format. */ - { - string os_filename[ 1 ]; - - string_new( os_filename ); - path_translate_to_os( object_str( tmp_filename ), os_filename ); - object_free( tmp_filename ); - tmp_filename = object_new( os_filename->value ); - string_free( os_filename ); - } - #endif - - string_new( result ); - string_append( result, command ); - string_append( result, " " ); - string_append( result, quote ); - string_append( result, object_str( tmp_filename ) ); - string_append( result, quote ); - if ( err_redir ) - { - string_append( result, " " ); - string_append( result, redirect ); - } - } - - /* Replace STDXXX with the temporary file. */ - list_free( stack_pop( s ) ); - stack_push( s, list_new( object_new( result->value ) ) ); - out = object_str( tmp_filename ); - - string_free( result ); - - /* Make sure temp files created by this get nuked eventually. */ - file_remove_atexit( tmp_filename ); + expansion_item ei = { stack_pop( s ) }; + filename = expand( &ei, 1 ); } - - if ( !globs.noexec ) - { - string out_name[ 1 ]; - /* Handle "path to file" filenames. */ - if ( ( out[ 0 ] == '"' ) && ( out[ strlen( out ) - 1 ] == '"' ) - ) - { - string_copy( out_name, out + 1 ); - string_truncate( out_name, out_name->size - 1 ); - } - else - string_copy( out_name, out ); - out_file = fopen( out_name->value, "w" ); - - if ( !out_file ) - { - err_printf( "[errno %d] failed to write output file '%s': %s", - errno, out_name->value, strerror(errno) ); - exit( EXITBAD ); - } - string_free( out_name ); - } - - if ( out_debug ) out_printf( "\nfile %s\n", out ); - if ( out_file ) fputs( buf->value, out_file ); - if ( out_debug ) out_puts( buf->value ); - if ( out_file ) - { - fflush( out_file ); - fclose( out_file ); - } - string_free( buf ); - if ( tmp_filename ) - object_free( tmp_filename ); - - if ( out_debug ) out_putc( '\n' ); + // Apply modifiers to "raw" filename. + VAR_EXPANDED filename_mod = eval_modifiers( s, filename, code->arg ); + // Get contents. + LIST * contents = stack_pop( s ); + // Write out the contents file, or expand the contents, as needed. + LIST * filename_or_contents = function_execute_write_file( function, frame, s, filename_mod, contents ); + // The result that gets replaced into the @() space. + stack_push( s, filename_or_contents ); + list_free( filename_mod.value ); + list_free( filename_mod.inner ); + list_free( contents ); PROFILE_EXIT_LOCAL(function_run_INSTR_WRITE_FILE); break; } diff --git a/src/engine/jamgram.cpp b/src/engine/jamgram.cpp index 2f7382dfa..4f3de0615 100644 --- a/src/engine/jamgram.cpp +++ b/src/engine/jamgram.cpp @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.6.4. */ +/* A Bison parser, made by GNU Bison 3.7.2. */ /* Bison implementation for Yacc-like parsers in C @@ -49,7 +49,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.6.4" +#define YYBISON_VERSION "3.7.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -135,144 +135,7 @@ # endif # endif -/* Use api.header.include to #include this header - instead of duplicating it here. */ -#ifndef YY_YY_SRC_ENGINE_JAMGRAM_HPP_INCLUDED -# define YY_YY_SRC_ENGINE_JAMGRAM_HPP_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int yydebug; -#endif - -/* Token kinds. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - YYEMPTY = -2, - YYEOF = 0, /* "end of file" */ - YYerror = 256, /* error */ - YYUNDEF = 257, /* "invalid token" */ - _BANG_t = 258, /* _BANG_t */ - _BANG_EQUALS_t = 259, /* _BANG_EQUALS_t */ - _AMPER_t = 260, /* _AMPER_t */ - _AMPERAMPER_t = 261, /* _AMPERAMPER_t */ - _LPAREN_t = 262, /* _LPAREN_t */ - _RPAREN_t = 263, /* _RPAREN_t */ - _PLUS_EQUALS_t = 264, /* _PLUS_EQUALS_t */ - _COLON_t = 265, /* _COLON_t */ - _SEMIC_t = 266, /* _SEMIC_t */ - _LANGLE_t = 267, /* _LANGLE_t */ - _LANGLE_EQUALS_t = 268, /* _LANGLE_EQUALS_t */ - _EQUALS_t = 269, /* _EQUALS_t */ - _RANGLE_t = 270, /* _RANGLE_t */ - _RANGLE_EQUALS_t = 271, /* _RANGLE_EQUALS_t */ - _QUESTION_EQUALS_t = 272, /* _QUESTION_EQUALS_t */ - _LBRACKET_t = 273, /* _LBRACKET_t */ - _RBRACKET_t = 274, /* _RBRACKET_t */ - ACTIONS_t = 275, /* ACTIONS_t */ - BIND_t = 276, /* BIND_t */ - BREAK_t = 277, /* BREAK_t */ - CASE_t = 278, /* CASE_t */ - CLASS_t = 279, /* CLASS_t */ - CONTINUE_t = 280, /* CONTINUE_t */ - DEFAULT_t = 281, /* DEFAULT_t */ - ELSE_t = 282, /* ELSE_t */ - EXISTING_t = 283, /* EXISTING_t */ - FOR_t = 284, /* FOR_t */ - IF_t = 285, /* IF_t */ - IGNORE_t = 286, /* IGNORE_t */ - IN_t = 287, /* IN_t */ - INCLUDE_t = 288, /* INCLUDE_t */ - LOCAL_t = 289, /* LOCAL_t */ - MODULE_t = 290, /* MODULE_t */ - ON_t = 291, /* ON_t */ - PIECEMEAL_t = 292, /* PIECEMEAL_t */ - QUIETLY_t = 293, /* QUIETLY_t */ - RETURN_t = 294, /* RETURN_t */ - RULE_t = 295, /* RULE_t */ - SWITCH_t = 296, /* SWITCH_t */ - TOGETHER_t = 297, /* TOGETHER_t */ - UPDATED_t = 298, /* UPDATED_t */ - WHILE_t = 299, /* WHILE_t */ - _LBRACE_t = 300, /* _LBRACE_t */ - _BAR_t = 301, /* _BAR_t */ - _BARBAR_t = 302, /* _BARBAR_t */ - _RBRACE_t = 303, /* _RBRACE_t */ - ARG = 304, /* ARG */ - STRING = 305 /* STRING */ - }; - typedef enum yytokentype yytoken_kind_t; -#endif -/* Token kinds. */ -#define YYEOF 0 -#define YYerror 256 -#define YYUNDEF 257 -#define _BANG_t 258 -#define _BANG_EQUALS_t 259 -#define _AMPER_t 260 -#define _AMPERAMPER_t 261 -#define _LPAREN_t 262 -#define _RPAREN_t 263 -#define _PLUS_EQUALS_t 264 -#define _COLON_t 265 -#define _SEMIC_t 266 -#define _LANGLE_t 267 -#define _LANGLE_EQUALS_t 268 -#define _EQUALS_t 269 -#define _RANGLE_t 270 -#define _RANGLE_EQUALS_t 271 -#define _QUESTION_EQUALS_t 272 -#define _LBRACKET_t 273 -#define _RBRACKET_t 274 -#define ACTIONS_t 275 -#define BIND_t 276 -#define BREAK_t 277 -#define CASE_t 278 -#define CLASS_t 279 -#define CONTINUE_t 280 -#define DEFAULT_t 281 -#define ELSE_t 282 -#define EXISTING_t 283 -#define FOR_t 284 -#define IF_t 285 -#define IGNORE_t 286 -#define IN_t 287 -#define INCLUDE_t 288 -#define LOCAL_t 289 -#define MODULE_t 290 -#define ON_t 291 -#define PIECEMEAL_t 292 -#define QUIETLY_t 293 -#define RETURN_t 294 -#define RULE_t 295 -#define SWITCH_t 296 -#define TOGETHER_t 297 -#define UPDATED_t 298 -#define WHILE_t 299 -#define _LBRACE_t 300 -#define _BAR_t 301 -#define _BARBAR_t 302 -#define _RBRACE_t 303 -#define ARG 304 -#define STRING 305 - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef int YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - - -extern YYSTYPE yylval; - -int yyparse (void); - -#endif /* !YY_YY_SRC_ENGINE_JAMGRAM_HPP_INCLUDED */ +#include "jamgram.hpp" /* Symbol kind. */ enum yysymbol_kind_t { @@ -716,6 +579,7 @@ union yyalloc /* YYNSTATES -- Number of states. */ #define YYNSTATES 207 +/* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 305 @@ -1258,7 +1122,7 @@ yydestruct (const char *yymsg, } -/* The lookahead symbol. */ +/* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ @@ -1276,34 +1140,30 @@ int yynerrs; int yyparse (void) { - yy_state_fast_t yystate; + yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; + int yyerrstatus = 0; - /* The stacks and their tools: - 'yyss': related to states. - 'yyvs': related to semantic values. - - Refer to the stacks through separate pointers, to allow yyoverflow + /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ - YYPTRDIFF_T yystacksize; + YYPTRDIFF_T yystacksize = YYINITDEPTH; - /* The state stack. */ + /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; - yy_state_t *yyss; - yy_state_t *yyssp; + yy_state_t *yyss = yyssa; + yy_state_t *yyssp = yyss; - /* The semantic value stack. */ + /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; - /* Lookahead token as an internal (translated) token number. */ + /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ @@ -1317,15 +1177,6 @@ yyparse (void) Keep to zero when no symbol should be popped. */ int yylen = 0; - yynerrs = 0; - yystate = 0; - yyerrstatus = 0; - - yystacksize = YYINITDEPTH; - yyssp = yyss = yyssa; - yyvsp = yyvs = yyvsa; - - YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ @@ -1526,722 +1377,722 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 3: + case 3: /* run: rules */ #line 148 "src/engine/jamgram.y" { parse_save( yyvsp[0].parse ); } -#line 1533 "src/engine/jamgram.cpp" +#line 1384 "src/engine/jamgram.cpp" break; - case 4: + case 4: /* block: null */ #line 159 "src/engine/jamgram.y" { yyval.parse = yyvsp[0].parse; } -#line 1539 "src/engine/jamgram.cpp" +#line 1390 "src/engine/jamgram.cpp" break; - case 5: + case 5: /* block: rules */ #line 161 "src/engine/jamgram.y" { yyval.parse = yyvsp[0].parse; } -#line 1545 "src/engine/jamgram.cpp" +#line 1396 "src/engine/jamgram.cpp" break; - case 6: + case 6: /* rules: rule */ #line 165 "src/engine/jamgram.y" { yyval.parse = yyvsp[0].parse; } -#line 1551 "src/engine/jamgram.cpp" +#line 1402 "src/engine/jamgram.cpp" break; - case 7: + case 7: /* rules: rule rules */ #line 167 "src/engine/jamgram.y" { yyval.parse = prules( yyvsp[-1].parse, yyvsp[0].parse ); } -#line 1557 "src/engine/jamgram.cpp" +#line 1408 "src/engine/jamgram.cpp" break; - case 8: + case 8: /* $@1: %empty */ #line 168 "src/engine/jamgram.y" { yymode( SCAN_ASSIGN ); } -#line 1563 "src/engine/jamgram.cpp" +#line 1414 "src/engine/jamgram.cpp" break; - case 9: + case 9: /* $@2: %empty */ #line 168 "src/engine/jamgram.y" { yymode( SCAN_NORMAL ); } -#line 1569 "src/engine/jamgram.cpp" +#line 1420 "src/engine/jamgram.cpp" break; - case 10: + case 10: /* rules: LOCAL_t $@1 list assign_list_opt _SEMIC_t $@2 block */ #line 169 "src/engine/jamgram.y" { yyval.parse = plocal( yyvsp[-4].parse, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 1575 "src/engine/jamgram.cpp" +#line 1426 "src/engine/jamgram.cpp" break; - case 11: + case 11: /* null: %empty */ #line 173 "src/engine/jamgram.y" { yyval.parse = pnull(); } -#line 1581 "src/engine/jamgram.cpp" +#line 1432 "src/engine/jamgram.cpp" break; - case 12: + case 12: /* $@3: %empty */ #line 176 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1587 "src/engine/jamgram.cpp" +#line 1438 "src/engine/jamgram.cpp" break; - case 13: + case 13: /* assign_list_opt: _EQUALS_t $@3 list */ #line 177 "src/engine/jamgram.y" { yyval.parse = yyvsp[0].parse; yyval.number = ASSIGN_SET; } -#line 1593 "src/engine/jamgram.cpp" +#line 1444 "src/engine/jamgram.cpp" break; - case 14: + case 14: /* assign_list_opt: null */ #line 179 "src/engine/jamgram.y" { yyval.parse = yyvsp[0].parse; yyval.number = ASSIGN_APPEND; } -#line 1599 "src/engine/jamgram.cpp" +#line 1450 "src/engine/jamgram.cpp" break; - case 15: + case 15: /* arglist_opt: _LPAREN_t lol _RPAREN_t */ #line 183 "src/engine/jamgram.y" { yyval.parse = yyvsp[-1].parse; } -#line 1605 "src/engine/jamgram.cpp" +#line 1456 "src/engine/jamgram.cpp" break; - case 16: + case 16: /* arglist_opt: %empty */ #line 185 "src/engine/jamgram.y" { yyval.parse = P0; } -#line 1611 "src/engine/jamgram.cpp" +#line 1462 "src/engine/jamgram.cpp" break; - case 17: + case 17: /* local_opt: LOCAL_t */ #line 189 "src/engine/jamgram.y" { yyval.number = 1; } -#line 1617 "src/engine/jamgram.cpp" +#line 1468 "src/engine/jamgram.cpp" break; - case 18: + case 18: /* local_opt: %empty */ #line 191 "src/engine/jamgram.y" { yyval.number = 0; } -#line 1623 "src/engine/jamgram.cpp" +#line 1474 "src/engine/jamgram.cpp" break; - case 19: + case 19: /* else_opt: ELSE_t rule */ #line 195 "src/engine/jamgram.y" { yyval.parse = yyvsp[0].parse; } -#line 1629 "src/engine/jamgram.cpp" +#line 1480 "src/engine/jamgram.cpp" break; - case 20: + case 20: /* else_opt: %empty */ #line 197 "src/engine/jamgram.y" { yyval.parse = pnull(); } -#line 1635 "src/engine/jamgram.cpp" +#line 1486 "src/engine/jamgram.cpp" break; - case 21: + case 21: /* rule: _LBRACE_t block _RBRACE_t */ #line 200 "src/engine/jamgram.y" { yyval.parse = yyvsp[-1].parse; } -#line 1641 "src/engine/jamgram.cpp" +#line 1492 "src/engine/jamgram.cpp" break; - case 22: + case 22: /* $@4: %empty */ #line 201 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1647 "src/engine/jamgram.cpp" +#line 1498 "src/engine/jamgram.cpp" break; - case 23: + case 23: /* rule: INCLUDE_t $@4 list _SEMIC_t */ #line 202 "src/engine/jamgram.y" { yyval.parse = pincl( yyvsp[-1].parse ); yymode( SCAN_NORMAL ); } -#line 1653 "src/engine/jamgram.cpp" +#line 1504 "src/engine/jamgram.cpp" break; - case 24: + case 24: /* $@5: %empty */ #line 203 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1659 "src/engine/jamgram.cpp" +#line 1510 "src/engine/jamgram.cpp" break; - case 25: + case 25: /* rule: ARG $@5 lol _SEMIC_t */ #line 204 "src/engine/jamgram.y" { yyval.parse = prule( yyvsp[-3].string, yyvsp[-1].parse ); yymode( SCAN_NORMAL ); } -#line 1665 "src/engine/jamgram.cpp" +#line 1516 "src/engine/jamgram.cpp" break; - case 26: + case 26: /* $@6: %empty */ #line 205 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1671 "src/engine/jamgram.cpp" +#line 1522 "src/engine/jamgram.cpp" break; - case 27: + case 27: /* rule: arg assign $@6 list _SEMIC_t */ #line 206 "src/engine/jamgram.y" { yyval.parse = pset( yyvsp[-4].parse, yyvsp[-1].parse, yyvsp[-3].number ); yymode( SCAN_NORMAL ); } -#line 1677 "src/engine/jamgram.cpp" +#line 1528 "src/engine/jamgram.cpp" break; - case 28: + case 28: /* $@7: %empty */ #line 207 "src/engine/jamgram.y" { yymode( SCAN_ASSIGN ); } -#line 1683 "src/engine/jamgram.cpp" +#line 1534 "src/engine/jamgram.cpp" break; - case 29: + case 29: /* $@8: %empty */ #line 207 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1689 "src/engine/jamgram.cpp" +#line 1540 "src/engine/jamgram.cpp" break; - case 30: + case 30: /* rule: arg ON_t $@7 list assign $@8 list _SEMIC_t */ #line 208 "src/engine/jamgram.y" { yyval.parse = pset1( yyvsp[-7].parse, yyvsp[-4].parse, yyvsp[-1].parse, yyvsp[-3].number ); yymode( SCAN_NORMAL ); } -#line 1695 "src/engine/jamgram.cpp" +#line 1546 "src/engine/jamgram.cpp" break; - case 31: + case 31: /* $@9: %empty */ #line 209 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1701 "src/engine/jamgram.cpp" +#line 1552 "src/engine/jamgram.cpp" break; - case 32: + case 32: /* rule: RETURN_t $@9 list _SEMIC_t */ #line 210 "src/engine/jamgram.y" { yyval.parse = preturn( yyvsp[-1].parse ); yymode( SCAN_NORMAL ); } -#line 1707 "src/engine/jamgram.cpp" +#line 1558 "src/engine/jamgram.cpp" break; - case 33: + case 33: /* rule: BREAK_t _SEMIC_t */ #line 212 "src/engine/jamgram.y" { yyval.parse = pbreak(); } -#line 1713 "src/engine/jamgram.cpp" +#line 1564 "src/engine/jamgram.cpp" break; - case 34: + case 34: /* rule: CONTINUE_t _SEMIC_t */ #line 214 "src/engine/jamgram.y" { yyval.parse = pcontinue(); } -#line 1719 "src/engine/jamgram.cpp" +#line 1570 "src/engine/jamgram.cpp" break; - case 35: + case 35: /* $@10: %empty */ #line 215 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1725 "src/engine/jamgram.cpp" +#line 1576 "src/engine/jamgram.cpp" break; - case 36: + case 36: /* $@11: %empty */ #line 215 "src/engine/jamgram.y" { yymode( SCAN_NORMAL ); } -#line 1731 "src/engine/jamgram.cpp" +#line 1582 "src/engine/jamgram.cpp" break; - case 37: + case 37: /* rule: FOR_t local_opt ARG IN_t $@10 list _LBRACE_t $@11 block _RBRACE_t */ #line 216 "src/engine/jamgram.y" { yyval.parse = pfor( yyvsp[-7].string, yyvsp[-4].parse, yyvsp[-1].parse, yyvsp[-8].number ); } -#line 1737 "src/engine/jamgram.cpp" +#line 1588 "src/engine/jamgram.cpp" break; - case 38: + case 38: /* $@12: %empty */ #line 217 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1743 "src/engine/jamgram.cpp" +#line 1594 "src/engine/jamgram.cpp" break; - case 39: + case 39: /* $@13: %empty */ #line 217 "src/engine/jamgram.y" { yymode( SCAN_NORMAL ); } -#line 1749 "src/engine/jamgram.cpp" +#line 1600 "src/engine/jamgram.cpp" break; - case 40: + case 40: /* rule: SWITCH_t $@12 list _LBRACE_t $@13 cases _RBRACE_t */ #line 218 "src/engine/jamgram.y" { yyval.parse = pswitch( yyvsp[-4].parse, yyvsp[-1].parse ); } -#line 1755 "src/engine/jamgram.cpp" +#line 1606 "src/engine/jamgram.cpp" break; - case 41: + case 41: /* $@14: %empty */ #line 219 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 1761 "src/engine/jamgram.cpp" +#line 1612 "src/engine/jamgram.cpp" break; - case 42: + case 42: /* $@15: %empty */ #line 219 "src/engine/jamgram.y" { yymode( SCAN_NORMAL ); } -#line 1767 "src/engine/jamgram.cpp" +#line 1618 "src/engine/jamgram.cpp" break; - case 43: + case 43: /* rule: IF_t $@14 expr _LBRACE_t $@15 block _RBRACE_t else_opt */ #line 220 "src/engine/jamgram.y" { yyval.parse = pif( yyvsp[-5].parse, yyvsp[-2].parse, yyvsp[0].parse ); } -#line 1773 "src/engine/jamgram.cpp" +#line 1624 "src/engine/jamgram.cpp" break; - case 44: + case 44: /* $@16: %empty */ #line 221 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1779 "src/engine/jamgram.cpp" +#line 1630 "src/engine/jamgram.cpp" break; - case 45: + case 45: /* $@17: %empty */ #line 221 "src/engine/jamgram.y" { yymode( SCAN_NORMAL ); } -#line 1785 "src/engine/jamgram.cpp" +#line 1636 "src/engine/jamgram.cpp" break; - case 46: + case 46: /* rule: MODULE_t $@16 list _LBRACE_t $@17 block _RBRACE_t */ #line 222 "src/engine/jamgram.y" { yyval.parse = pmodule( yyvsp[-4].parse, yyvsp[-1].parse ); } -#line 1791 "src/engine/jamgram.cpp" +#line 1642 "src/engine/jamgram.cpp" break; - case 47: + case 47: /* $@18: %empty */ #line 223 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1797 "src/engine/jamgram.cpp" +#line 1648 "src/engine/jamgram.cpp" break; - case 48: + case 48: /* $@19: %empty */ #line 223 "src/engine/jamgram.y" { yymode( SCAN_NORMAL ); } -#line 1803 "src/engine/jamgram.cpp" +#line 1654 "src/engine/jamgram.cpp" break; - case 49: + case 49: /* rule: CLASS_t $@18 lol _LBRACE_t $@19 block _RBRACE_t */ #line 224 "src/engine/jamgram.y" { yyval.parse = pclass( yyvsp[-4].parse, yyvsp[-1].parse ); } -#line 1809 "src/engine/jamgram.cpp" +#line 1660 "src/engine/jamgram.cpp" break; - case 50: + case 50: /* $@20: %empty */ #line 225 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 1815 "src/engine/jamgram.cpp" +#line 1666 "src/engine/jamgram.cpp" break; - case 51: + case 51: /* $@21: %empty */ #line 225 "src/engine/jamgram.y" { yymode( SCAN_NORMAL ); } -#line 1821 "src/engine/jamgram.cpp" +#line 1672 "src/engine/jamgram.cpp" break; - case 52: + case 52: /* rule: WHILE_t $@20 expr $@21 _LBRACE_t block _RBRACE_t */ #line 226 "src/engine/jamgram.y" { yyval.parse = pwhile( yyvsp[-4].parse, yyvsp[-1].parse ); } -#line 1827 "src/engine/jamgram.cpp" +#line 1678 "src/engine/jamgram.cpp" break; - case 53: + case 53: /* $@22: %empty */ #line 227 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 1833 "src/engine/jamgram.cpp" +#line 1684 "src/engine/jamgram.cpp" break; - case 54: + case 54: /* $@23: %empty */ #line 227 "src/engine/jamgram.y" { yymode( SCAN_PARAMS ); } -#line 1839 "src/engine/jamgram.cpp" +#line 1690 "src/engine/jamgram.cpp" break; - case 55: + case 55: /* $@24: %empty */ #line 227 "src/engine/jamgram.y" { yymode( SCAN_NORMAL ); } -#line 1845 "src/engine/jamgram.cpp" +#line 1696 "src/engine/jamgram.cpp" break; - case 56: + case 56: /* rule: local_opt RULE_t $@22 ARG $@23 arglist_opt $@24 rule */ #line 228 "src/engine/jamgram.y" { yyval.parse = psetc( yyvsp[-4].string, yyvsp[0].parse, yyvsp[-2].parse, yyvsp[-7].number ); } -#line 1851 "src/engine/jamgram.cpp" +#line 1702 "src/engine/jamgram.cpp" break; - case 57: + case 57: /* rule: ON_t arg rule */ #line 230 "src/engine/jamgram.y" { yyval.parse = pon( yyvsp[-1].parse, yyvsp[0].parse ); } -#line 1857 "src/engine/jamgram.cpp" +#line 1708 "src/engine/jamgram.cpp" break; - case 58: + case 58: /* $@25: %empty */ #line 232 "src/engine/jamgram.y" { yymode( SCAN_STRING ); } -#line 1863 "src/engine/jamgram.cpp" +#line 1714 "src/engine/jamgram.cpp" break; - case 59: + case 59: /* $@26: %empty */ #line 234 "src/engine/jamgram.y" { yymode( SCAN_NORMAL ); } -#line 1869 "src/engine/jamgram.cpp" +#line 1720 "src/engine/jamgram.cpp" break; - case 60: + case 60: /* rule: ACTIONS_t eflags ARG bindlist _LBRACE_t $@25 STRING $@26 _RBRACE_t */ #line 236 "src/engine/jamgram.y" { yyval.parse = psete( yyvsp[-6].string,yyvsp[-5].parse,yyvsp[-2].string,yyvsp[-7].number ); } -#line 1875 "src/engine/jamgram.cpp" +#line 1726 "src/engine/jamgram.cpp" break; - case 61: + case 61: /* assign: _EQUALS_t */ #line 244 "src/engine/jamgram.y" { yyval.number = ASSIGN_SET; } -#line 1881 "src/engine/jamgram.cpp" +#line 1732 "src/engine/jamgram.cpp" break; - case 62: + case 62: /* assign: _PLUS_EQUALS_t */ #line 246 "src/engine/jamgram.y" { yyval.number = ASSIGN_APPEND; } -#line 1887 "src/engine/jamgram.cpp" +#line 1738 "src/engine/jamgram.cpp" break; - case 63: + case 63: /* assign: _QUESTION_EQUALS_t */ #line 248 "src/engine/jamgram.y" { yyval.number = ASSIGN_DEFAULT; } -#line 1893 "src/engine/jamgram.cpp" +#line 1744 "src/engine/jamgram.cpp" break; - case 64: + case 64: /* assign: DEFAULT_t _EQUALS_t */ #line 250 "src/engine/jamgram.y" { yyval.number = ASSIGN_DEFAULT; } -#line 1899 "src/engine/jamgram.cpp" +#line 1750 "src/engine/jamgram.cpp" break; - case 65: + case 65: /* expr: arg */ #line 257 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_EXISTS, yyvsp[0].parse, pnull() ); yymode( SCAN_COND ); } -#line 1905 "src/engine/jamgram.cpp" +#line 1756 "src/engine/jamgram.cpp" break; - case 66: + case 66: /* $@27: %empty */ #line 258 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 1911 "src/engine/jamgram.cpp" +#line 1762 "src/engine/jamgram.cpp" break; - case 67: + case 67: /* expr: expr _EQUALS_t $@27 expr */ #line 259 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_EQUALS, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 1917 "src/engine/jamgram.cpp" +#line 1768 "src/engine/jamgram.cpp" break; - case 68: + case 68: /* $@28: %empty */ #line 260 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 1923 "src/engine/jamgram.cpp" +#line 1774 "src/engine/jamgram.cpp" break; - case 69: + case 69: /* expr: expr _BANG_EQUALS_t $@28 expr */ #line 261 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_NOTEQ, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 1929 "src/engine/jamgram.cpp" +#line 1780 "src/engine/jamgram.cpp" break; - case 70: + case 70: /* $@29: %empty */ #line 262 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 1935 "src/engine/jamgram.cpp" +#line 1786 "src/engine/jamgram.cpp" break; - case 71: + case 71: /* expr: expr _LANGLE_t $@29 expr */ #line 263 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_LESS, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 1941 "src/engine/jamgram.cpp" +#line 1792 "src/engine/jamgram.cpp" break; - case 72: + case 72: /* $@30: %empty */ #line 264 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 1947 "src/engine/jamgram.cpp" +#line 1798 "src/engine/jamgram.cpp" break; - case 73: + case 73: /* expr: expr _LANGLE_EQUALS_t $@30 expr */ #line 265 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_LESSEQ, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 1953 "src/engine/jamgram.cpp" +#line 1804 "src/engine/jamgram.cpp" break; - case 74: + case 74: /* $@31: %empty */ #line 266 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 1959 "src/engine/jamgram.cpp" +#line 1810 "src/engine/jamgram.cpp" break; - case 75: + case 75: /* expr: expr _RANGLE_t $@31 expr */ #line 267 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_MORE, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 1965 "src/engine/jamgram.cpp" +#line 1816 "src/engine/jamgram.cpp" break; - case 76: + case 76: /* $@32: %empty */ #line 268 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 1971 "src/engine/jamgram.cpp" +#line 1822 "src/engine/jamgram.cpp" break; - case 77: + case 77: /* expr: expr _RANGLE_EQUALS_t $@32 expr */ #line 269 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_MOREEQ, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 1977 "src/engine/jamgram.cpp" +#line 1828 "src/engine/jamgram.cpp" break; - case 78: + case 78: /* $@33: %empty */ #line 270 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 1983 "src/engine/jamgram.cpp" +#line 1834 "src/engine/jamgram.cpp" break; - case 79: + case 79: /* expr: expr _AMPER_t $@33 expr */ #line 271 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_AND, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 1989 "src/engine/jamgram.cpp" +#line 1840 "src/engine/jamgram.cpp" break; - case 80: + case 80: /* $@34: %empty */ #line 272 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 1995 "src/engine/jamgram.cpp" +#line 1846 "src/engine/jamgram.cpp" break; - case 81: + case 81: /* expr: expr _AMPERAMPER_t $@34 expr */ #line 273 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_AND, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 2001 "src/engine/jamgram.cpp" +#line 1852 "src/engine/jamgram.cpp" break; - case 82: + case 82: /* $@35: %empty */ #line 274 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 2007 "src/engine/jamgram.cpp" +#line 1858 "src/engine/jamgram.cpp" break; - case 83: + case 83: /* expr: expr _BAR_t $@35 expr */ #line 275 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_OR, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 2013 "src/engine/jamgram.cpp" +#line 1864 "src/engine/jamgram.cpp" break; - case 84: + case 84: /* $@36: %empty */ #line 276 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 2019 "src/engine/jamgram.cpp" +#line 1870 "src/engine/jamgram.cpp" break; - case 85: + case 85: /* expr: expr _BARBAR_t $@36 expr */ #line 277 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_OR, yyvsp[-3].parse, yyvsp[0].parse ); } -#line 2025 "src/engine/jamgram.cpp" +#line 1876 "src/engine/jamgram.cpp" break; - case 86: + case 86: /* $@37: %empty */ #line 278 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 2031 "src/engine/jamgram.cpp" +#line 1882 "src/engine/jamgram.cpp" break; - case 87: + case 87: /* expr: arg IN_t $@37 list */ #line 279 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_IN, yyvsp[-3].parse, yyvsp[0].parse ); yymode( SCAN_COND ); } -#line 2037 "src/engine/jamgram.cpp" +#line 1888 "src/engine/jamgram.cpp" break; - case 88: + case 88: /* $@38: %empty */ #line 280 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 2043 "src/engine/jamgram.cpp" +#line 1894 "src/engine/jamgram.cpp" break; - case 89: + case 89: /* expr: _BANG_t $@38 expr */ #line 281 "src/engine/jamgram.y" { yyval.parse = peval( EXPR_NOT, yyvsp[0].parse, pnull() ); } -#line 2049 "src/engine/jamgram.cpp" +#line 1900 "src/engine/jamgram.cpp" break; - case 90: + case 90: /* $@39: %empty */ #line 282 "src/engine/jamgram.y" { yymode( SCAN_CONDB ); } -#line 2055 "src/engine/jamgram.cpp" +#line 1906 "src/engine/jamgram.cpp" break; - case 91: + case 91: /* expr: _LPAREN_t $@39 expr _RPAREN_t */ #line 283 "src/engine/jamgram.y" { yyval.parse = yyvsp[-1].parse; } -#line 2061 "src/engine/jamgram.cpp" +#line 1912 "src/engine/jamgram.cpp" break; - case 92: + case 92: /* cases: %empty */ #line 294 "src/engine/jamgram.y" { yyval.parse = P0; } -#line 2067 "src/engine/jamgram.cpp" +#line 1918 "src/engine/jamgram.cpp" break; - case 93: + case 93: /* cases: case cases */ #line 296 "src/engine/jamgram.y" { yyval.parse = pnode( yyvsp[-1].parse, yyvsp[0].parse ); } -#line 2073 "src/engine/jamgram.cpp" +#line 1924 "src/engine/jamgram.cpp" break; - case 94: + case 94: /* $@40: %empty */ #line 299 "src/engine/jamgram.y" { yymode( SCAN_CASE ); } -#line 2079 "src/engine/jamgram.cpp" +#line 1930 "src/engine/jamgram.cpp" break; - case 95: + case 95: /* $@41: %empty */ #line 299 "src/engine/jamgram.y" { yymode( SCAN_NORMAL ); } -#line 2085 "src/engine/jamgram.cpp" +#line 1936 "src/engine/jamgram.cpp" break; - case 96: + case 96: /* case: CASE_t $@40 ARG _COLON_t $@41 block */ #line 300 "src/engine/jamgram.y" { yyval.parse = psnode( yyvsp[-3].string, yyvsp[0].parse ); } -#line 2091 "src/engine/jamgram.cpp" +#line 1942 "src/engine/jamgram.cpp" break; - case 97: + case 97: /* lol: list */ #line 309 "src/engine/jamgram.y" { yyval.parse = pnode( P0, yyvsp[0].parse ); } -#line 2097 "src/engine/jamgram.cpp" +#line 1948 "src/engine/jamgram.cpp" break; - case 98: + case 98: /* lol: list _COLON_t lol */ #line 311 "src/engine/jamgram.y" { yyval.parse = pnode( yyvsp[0].parse, yyvsp[-2].parse ); } -#line 2103 "src/engine/jamgram.cpp" +#line 1954 "src/engine/jamgram.cpp" break; - case 99: + case 99: /* list: listp */ #line 321 "src/engine/jamgram.y" { yyval.parse = yyvsp[0].parse; } -#line 2109 "src/engine/jamgram.cpp" +#line 1960 "src/engine/jamgram.cpp" break; - case 100: + case 100: /* listp: %empty */ #line 325 "src/engine/jamgram.y" { yyval.parse = pnull(); } -#line 2115 "src/engine/jamgram.cpp" +#line 1966 "src/engine/jamgram.cpp" break; - case 101: + case 101: /* listp: listp arg */ #line 327 "src/engine/jamgram.y" { yyval.parse = pappend( yyvsp[-1].parse, yyvsp[0].parse ); } -#line 2121 "src/engine/jamgram.cpp" +#line 1972 "src/engine/jamgram.cpp" break; - case 102: + case 102: /* arg: ARG */ #line 331 "src/engine/jamgram.y" { yyval.parse = plist( yyvsp[0].string ); } -#line 2127 "src/engine/jamgram.cpp" +#line 1978 "src/engine/jamgram.cpp" break; - case 103: + case 103: /* @42: %empty */ #line 332 "src/engine/jamgram.y" { yyval.number = yymode( SCAN_CALL ); } -#line 2133 "src/engine/jamgram.cpp" +#line 1984 "src/engine/jamgram.cpp" break; - case 104: + case 104: /* arg: _LBRACKET_t @42 func _RBRACKET_t */ #line 333 "src/engine/jamgram.y" { yyval.parse = yyvsp[-1].parse; yymode( yyvsp[-2].number ); } -#line 2139 "src/engine/jamgram.cpp" +#line 1990 "src/engine/jamgram.cpp" break; - case 105: + case 105: /* $@43: %empty */ #line 341 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 2145 "src/engine/jamgram.cpp" +#line 1996 "src/engine/jamgram.cpp" break; - case 106: + case 106: /* func: ARG $@43 lol */ #line 342 "src/engine/jamgram.y" { yyval.parse = prule( yyvsp[-2].string, yyvsp[0].parse ); } -#line 2151 "src/engine/jamgram.cpp" +#line 2002 "src/engine/jamgram.cpp" break; - case 107: + case 107: /* $@44: %empty */ #line 343 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 2157 "src/engine/jamgram.cpp" +#line 2008 "src/engine/jamgram.cpp" break; - case 108: + case 108: /* func: ON_t arg ARG $@44 lol */ #line 344 "src/engine/jamgram.y" { yyval.parse = pon( yyvsp[-3].parse, prule( yyvsp[-2].string, yyvsp[0].parse ) ); } -#line 2163 "src/engine/jamgram.cpp" +#line 2014 "src/engine/jamgram.cpp" break; - case 109: + case 109: /* $@45: %empty */ #line 345 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 2169 "src/engine/jamgram.cpp" +#line 2020 "src/engine/jamgram.cpp" break; - case 110: + case 110: /* func: ON_t arg RETURN_t $@45 list */ #line 346 "src/engine/jamgram.y" { yyval.parse = pon( yyvsp[-3].parse, yyvsp[0].parse ); } -#line 2175 "src/engine/jamgram.cpp" +#line 2026 "src/engine/jamgram.cpp" break; - case 111: + case 111: /* eflags: %empty */ #line 356 "src/engine/jamgram.y" { yyval.number = 0; } -#line 2181 "src/engine/jamgram.cpp" +#line 2032 "src/engine/jamgram.cpp" break; - case 112: + case 112: /* eflags: eflags eflag */ #line 358 "src/engine/jamgram.y" { yyval.number = yyvsp[-1].number | yyvsp[0].number; } -#line 2187 "src/engine/jamgram.cpp" +#line 2038 "src/engine/jamgram.cpp" break; - case 113: + case 113: /* eflag: UPDATED_t */ #line 362 "src/engine/jamgram.y" { yyval.number = EXEC_UPDATED; } -#line 2193 "src/engine/jamgram.cpp" +#line 2044 "src/engine/jamgram.cpp" break; - case 114: + case 114: /* eflag: TOGETHER_t */ #line 364 "src/engine/jamgram.y" { yyval.number = EXEC_TOGETHER; } -#line 2199 "src/engine/jamgram.cpp" +#line 2050 "src/engine/jamgram.cpp" break; - case 115: + case 115: /* eflag: IGNORE_t */ #line 366 "src/engine/jamgram.y" { yyval.number = EXEC_IGNORE; } -#line 2205 "src/engine/jamgram.cpp" +#line 2056 "src/engine/jamgram.cpp" break; - case 116: + case 116: /* eflag: QUIETLY_t */ #line 368 "src/engine/jamgram.y" { yyval.number = EXEC_QUIETLY; } -#line 2211 "src/engine/jamgram.cpp" +#line 2062 "src/engine/jamgram.cpp" break; - case 117: + case 117: /* eflag: PIECEMEAL_t */ #line 370 "src/engine/jamgram.y" { yyval.number = EXEC_PIECEMEAL; } -#line 2217 "src/engine/jamgram.cpp" +#line 2068 "src/engine/jamgram.cpp" break; - case 118: + case 118: /* eflag: EXISTING_t */ #line 372 "src/engine/jamgram.y" { yyval.number = EXEC_EXISTING; } -#line 2223 "src/engine/jamgram.cpp" +#line 2074 "src/engine/jamgram.cpp" break; - case 119: + case 119: /* bindlist: %empty */ #line 381 "src/engine/jamgram.y" { yyval.parse = pnull(); } -#line 2229 "src/engine/jamgram.cpp" +#line 2080 "src/engine/jamgram.cpp" break; - case 120: + case 120: /* $@46: %empty */ #line 382 "src/engine/jamgram.y" { yymode( SCAN_PUNCT ); } -#line 2235 "src/engine/jamgram.cpp" +#line 2086 "src/engine/jamgram.cpp" break; - case 121: + case 121: /* bindlist: BIND_t $@46 list */ #line 383 "src/engine/jamgram.y" { yyval.parse = yyvsp[0].parse; } -#line 2241 "src/engine/jamgram.cpp" +#line 2092 "src/engine/jamgram.cpp" break; -#line 2245 "src/engine/jamgram.cpp" +#line 2096 "src/engine/jamgram.cpp" default: break; } @@ -2401,13 +2252,13 @@ yyabortlab: yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; - /* Fall through. */ + goto yyreturn; #endif -/*-----------------------------------------------------. -| yyreturn -- parsing is finished, return the result. | -`-----------------------------------------------------*/ +/*-------------------------------------------------------. +| yyreturn -- parsing is finished, clean up and return. | +`-------------------------------------------------------*/ yyreturn: if (yychar != YYEMPTY) { diff --git a/src/engine/jamgram.hpp b/src/engine/jamgram.hpp index 325bbe141..48e84c194 100644 --- a/src/engine/jamgram.hpp +++ b/src/engine/jamgram.hpp @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.6.4. */ +/* A Bison parser, made by GNU Bison 3.7.2. */ /* Bison interface for Yacc-like parsers in C diff --git a/src/tools/clang-linux.jam b/src/tools/clang-linux.jam index 28ddcde7b..aaeb2dc71 100644 --- a/src/tools/clang-linux.jam +++ b/src/tools/clang-linux.jam @@ -20,6 +20,7 @@ import type ; import numbers ; import os ; import property ; +import set ; feature.extend-subfeature toolset clang : platform : linux ; @@ -112,6 +113,8 @@ rule init ( version ? : command * : options * ) { ############################################################################### # Flags +local all-os = [ feature.values ] ; + # note: clang silently ignores some of these inlining options # For clang, 'on' and 'full' are identical. toolset.flags clang-linux.compile OPTIONS full : -Wno-inline ; @@ -133,6 +136,11 @@ toolset.flags clang-linux.link OPTIONS gnu gnu11 : -stdlib=libst toolset.flags clang-linux.compile OPTIONS libc++ : -stdlib=libc++ ; toolset.flags clang-linux.link OPTIONS libc++ : -stdlib=libc++ ; +# Enable response file control +toolset.flags clang-linux RESPONSE_FILE_SUB auto : a ; +toolset.flags clang-linux RESPONSE_FILE_SUB file : f ; +toolset.flags clang-linux RESPONSE_FILE_SUB contents : c ; + ############################################################################### # C and C++ compilation @@ -203,85 +211,21 @@ actions compile.c.pch ############################################################################### # Linking -SPACE = " " ; +local soname-os = [ set.difference $(all-os) : windows ] ; +toolset.flags clang-linux.link SONAME_OPT $(soname-os) : "-Wl,-soname -Wl," ; rule link ( targets * : sources * : properties * ) { - SPACE on $(targets) = " " ; - - local tosw ; - local pselect = [ property.select : $(properties) ] ; - - if $(pselect) - { - - local tosv = [ feature.get-values : $(pselect) ] ; - - if $(tosv) = windows - { - tosw = 1 ; - } - } - else if [ os.name ] in NT - { - tosw = 1 ; - } - if $(tosw) - { - link-w $(targets) : $(sources) ; - } - else - { - link-o $(targets) : $(sources) ; - } + _ on $(targets) = " " ; } rule link.dll ( targets * : sources * : properties * ) { - SPACE on $(targets) = " " ; - - local tosw ; - local pselect = [ property.select : $(properties) ] ; - - if $(pselect) - { - - local tosv = [ feature.get-values : $(pselect) ] ; - - if $(tosv) = windows - { - tosw = 1 ; - } - } - else if [ os.name ] in NT - { - tosw = 1 ; - } - if $(tosw) - { - link.dll-w $(targets) : $(sources) ; - } - else - { - link.dll-o $(targets) : $(sources) ; - } + _ on $(targets) = " " ; } -# Target OS is not Windows, needs the RPATH stuff -actions link-o bind LIBRARIES { - "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -o "$(<)" @"@($(<[1]:T).rsp:E=-Wl,-R$(SPACE)-Wl,"$(RPATH)" -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" $(START-GROUP) "$(>:T)" "$(LIBRARIES:T)" $(FINDLIBS-ST-PFX:T) -l$(FINDLIBS-ST:T) $(FINDLIBS-SA-PFX:T) -l$(FINDLIBS-SA:T) $(END-GROUP))" $(OPTIONS) $(USER_OPTIONS) +actions link bind LIBRARIES { + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -o "$(<)" @($(<[1]:T).rsp:<=@":>=":E=-Wl,-R$(_)-Wl,"$(RPATH)" -Wl,-rpath-link$(_)-Wl,"$(RPATH_LINK)" $(START-GROUP) "$(>:T)" "$(LIBRARIES:T)" $(FINDLIBS-ST-PFX:T) -l$(FINDLIBS-ST:T) $(FINDLIBS-SA-PFX:T) -l$(FINDLIBS-SA:T) $(END-GROUP)) $(OPTIONS) $(USER_OPTIONS) } -# Target OS is not Windows, needs the RPATH and SONAME stuff -actions link.dll-o bind LIBRARIES { - "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -o "$(<)" @"@($(<[1]:T).rsp:E=-Wl,-R$(SPACE)-Wl,"$(RPATH)" -Wl,-soname$(SPACE)-Wl,$(<[1]:D=) -shared $(START-GROUP) "$(>:T)" "$(LIBRARIES:T)" $(FINDLIBS-ST-PFX:T) -l$(FINDLIBS-ST:T) $(FINDLIBS-SA-PFX:T) -l$(FINDLIBS-SA:T) $(END-GROUP))" $(OPTIONS) $(USER_OPTIONS) -} - -# Target OS is Windows, does not need the RPATH stuff -actions link-w bind LIBRARIES { - "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -o "$(<)" @"@($(<[1]:T).rsp:E=$(START-GROUP) "$(>:T)" "$(LIBRARIES:T)" $(FINDLIBS-ST-PFX:T) -l$(FINDLIBS-ST:T) $(FINDLIBS-SA-PFX:T) -l$(FINDLIBS-SA:T) $(END-GROUP))" $(OPTIONS) $(USER_OPTIONS) -} - -# Target OS is Windows, does not need the RPATH and SONAME stuff -actions link.dll-w bind LIBRARIES { - "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -o "$(<)" -shared @"@($(<[1]:T).rsp:E=$(START-GROUP) "$(>:T)" "$(LIBRARIES:T)" $(FINDLIBS-ST-PFX:T) -l$(FINDLIBS-ST:T) $(FINDLIBS-SA-PFX:T) -l$(FINDLIBS-SA:T) $(END-GROUP))" $(OPTIONS) $(USER_OPTIONS) - +actions link.dll bind LIBRARIES { + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -o "$(<)" @($(<[1]:T).rsp:<=@":>=":E=-Wl,-R$(_)-Wl,"$(RPATH)" $(SONAME_OPT)$(<[1]:D=) -shared $(START-GROUP) "$(>:T)" "$(LIBRARIES:T)" $(FINDLIBS-ST-PFX:T) -l$(FINDLIBS-ST:T) $(FINDLIBS-SA-PFX:T) -l$(FINDLIBS-SA:T) $(END-GROUP)) $(OPTIONS) $(USER_OPTIONS) } diff --git a/src/tools/features/response-file-feature.jam b/src/tools/features/response-file-feature.jam new file mode 100644 index 000000000..de910d55b --- /dev/null +++ b/src/tools/features/response-file-feature.jam @@ -0,0 +1,26 @@ +# Copyright 2020 René Ferdinand Rivera Morell +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import feature ; + +#| tag::doc[] + +[[bbv2.builtin.features.response-file]]`response-file`:: +*Allowed values:* `file`, `contents`, `auto`. ++ +Controls whether a response file is used, or not, during the build of the +applicable target. For `file` a response file is created and the filename +replaced in the action. For `contents` the contents (`:E=`) is replaced +in the action and no response file is created. For `auto` either a response +file is created, or the contents replaced, based on the length of the +contents such that if the contents fits within the limits of the command +execution line length limits the contents is replaced. Otherwise a +response file is created and the filename is replaced in the actions. + +|# # end::doc[] + +feature.feature response-file + : auto file contents + : incidental ; diff --git a/src/tools/gcc.jam b/src/tools/gcc.jam index 3d65128e5..6f298e755 100644 --- a/src/tools/gcc.jam +++ b/src/tools/gcc.jam @@ -968,13 +968,15 @@ toolset.flags gcc.link.dll .IMPLIB-COMMAND cygwin : "-Wl,--out-implib # support -s. toolset.flags gcc.link OPTIONS $(generic-os)/on : -Wl,--strip-all ; - toolset.flags gcc.link RPATH $(generic-os) : ; - toolset.flags gcc.link RPATH_OPTION $(generic-os) : -rpath ; - toolset.flags gcc.link RPATH_LINK $(generic-os) : ; toolset.flags gcc.link START-GROUP $(generic-os) : -Wl,--start-group ; toolset.flags gcc.link END-GROUP $(generic-os) : -Wl,--end-group ; + local rpath-os = [ set.difference $(all-os) : aix darwin vxworks solaris osf hpux windows ] ; + toolset.flags gcc.link RPATH $(rpath-os) : ; + toolset.flags gcc.link RPATH_OPTION $(rpath-os) : -rpath ; + toolset.flags gcc.link RPATH_LINK $(rpath-os) : ; + # gnu ld has the ability to change the search behaviour for libraries # referenced by the -l switch. These modifiers are -Bstatic and # -Bdynamic and change search for -l switches that follow them. The diff --git a/test/core_at_file.py b/test/core_at_file.py index 50fa51220..0a321f4c9 100755 --- a/test/core_at_file.py +++ b/test/core_at_file.py @@ -13,27 +13,27 @@ t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0) t.write("file.jam", """\ name = n1 n2 ; contents = M1 M2 ; -EXIT "file:" "@(o$(name) .txt:E= test -D$(contents))" : 0 ; +EXIT "file:" "@(o$(name:J=) .txt:E= test -D$(contents))" : 0 ; """) t.run_build_system() -t.expect_output_lines("file: on1 on2 .txt"); -t.expect_addition("on1 on2 .txt") -t.expect_content("on1 on2 .txt", " test -DM1 -DM2", True) +t.expect_output_lines("file: on1n2 .txt"); +t.expect_addition("on1n2 .txt") +t.expect_content("on1n2 .txt", " test -DM1 -DM2", True) t.rm(".") t.write("file.jam", """\ name = n1 n2 ; contents = M1 M2 ; -actions run { echo file: "@(o$(name) .txt:E= test -D$(contents))" } +actions run { echo file: "@(o$(name:J=) .txt:E= test -D$(contents))" } run all ; """) t.run_build_system(["-d2"]) -t.expect_output_lines(' echo file: "on1 on2 .txt" '); -t.expect_addition("on1 on2 .txt") -t.expect_content("on1 on2 .txt", " test -DM1 -DM2", True) +t.expect_output_lines(' echo file: "on1n2 .txt" '); +t.expect_addition("on1n2 .txt") +t.expect_content("on1n2 .txt", " test -DM1 -DM2", True) t.rm(".") diff --git a/test/toolset-mock/src/MockProgram.py b/test/toolset-mock/src/MockProgram.py index 795b8676d..e6f46af94 100644 --- a/test/toolset-mock/src/MockProgram.py +++ b/test/toolset-mock/src/MockProgram.py @@ -1,4 +1,5 @@ # Copyright 2017 Steven Watanabe +# Copyright 2020 René Ferdinand Rivera Morell # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at @@ -120,6 +121,17 @@ class arg(object): if s.startswith(self.prefix) and try_match([s[len(self.prefix):]], 0, self.a, outputs) == 1: return pos + 1 +# +class opt(object): + def __init__(self, *args): + self.args = args + def match(self, command_line, pos, outputs): + for p in self.args: + res = try_match_one(command_line, pos, p, outputs) + if res is not None: + pos = res + return pos + # Given a file id, returns a string that will be # written to the file to allow it to be recognized. def make_file_contents(id): diff --git a/test/toolset-mock/src/ar.py b/test/toolset-mock/src/ar.py index 853fe1dd8..9fb681eef 100644 --- a/test/toolset-mock/src/ar.py +++ b/test/toolset-mock/src/ar.py @@ -1,6 +1,7 @@ #!/usr/bin/python # # Copyright 2017-2018 Steven Watanabe +# Copyright 2020 René Ferdinand Rivera Morell # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at @@ -20,5 +21,6 @@ command('ar', 'rc', output_file('bin/clang-linux-3.9.0/debug/link-static/libl1.a command('ar', 'rc', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/libl1.a'), input_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/lib.o')) command('ar', 'rcu', output_file('bin/clang-vxworks-4.0.1/debug/link-static/libl1.a'), input_file('bin/clang-vxworks-4.0.1/debug/link-static/lib.o')) command('ar', 'rcu', output_file('bin/clang-vxworks-4.0.1/debug/link-static/runtime-link-static/libl1.a'), input_file('bin/clang-vxworks-4.0.1/debug/link-static/runtime-link-static/lib.o')) +command('ar', 'rc', output_file('bin/clang-linux-3.9.0/debug/link-static/target-os-windows/libl1.lib'), input_file('bin/clang-linux-3.9.0/debug/link-static/target-os-windows/lib.obj')) main() diff --git a/test/toolset-mock/src/clang-linux-3.9.0.py b/test/toolset-mock/src/clang-linux-3.9.0.py index 02d28db54..0194818c8 100644 --- a/test/toolset-mock/src/clang-linux-3.9.0.py +++ b/test/toolset-mock/src/clang-linux-3.9.0.py @@ -1,7 +1,7 @@ #!/usr/bin/python # # Copyright 2017 Steven Watanabe -# Copyright 2020 Rene Rivera +# Copyright 2020 René Ferdinand Rivera Morell # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at @@ -12,38 +12,76 @@ from MockProgram import * command('clang++', '-print-prog-name=ar', stdout=script('ar.py')) command('clang++', '-print-prog-name=ranlib', stdout=script('ranlib.py')) -if allow_properties('variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared'): +# target-os=linux .. + +if allow_properties('target-os=linux', 'variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared'): command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/lib.o'), input_file(source='lib.cpp')) - command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/libl1.so'), arg_file('@bin/clang-linux-3.9.0/debug*/libl1.so.rsp'), unordered('-g', '-fPIC')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/libl1.so'), '-Wl,-soname', '-Wl,libl1.so', '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/lib.o'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-fPIC')) command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/main.o'), input_file(source='main.cpp')) - command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/test'), arg_file('@bin/clang-linux-3.9.0/debug*/test.rsp'), unordered('-g', '-fPIC')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/test'), '-Wl,-R', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/libl1.so')), '-Wl,-rpath-link', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/libl1.so')), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/main.o'), input_file('bin/clang-linux-3.9.0/debug/libl1.so'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-fPIC')) -if allow_properties('variant=release', 'link=shared', 'threading=single', 'runtime-link=shared', 'strip=on'): +if allow_properties('target-os=linux', 'variant=release', 'link=shared', 'threading=single', 'runtime-link=shared', 'strip=on'): command('clang++', unordered(ordered('-x', 'c++'), '-O3', '-Wno-inline', '-Wall', '-fPIC', '-DNDEBUG', '-c'), '-o', output_file('bin/clang-linux-3.9.0/release/lib.o'), input_file(source='lib.cpp')) - command('clang++', '-o', output_file('bin/clang-linux-3.9.0/release/strip-on/libl1.so'), arg_file('@bin/clang-linux-3.9.0/release/strip-on*/libl1.so.rsp'), unordered('-fPIC', '-Wl,--strip-all')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/release/libl1.so'), '-Wl,-soname', '-Wl,libl1.so', '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/release/lib.o'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-fPIC', '-Wl,--strip-all')) command('clang++', unordered(ordered('-x', 'c++'), '-O3', '-Wno-inline', '-Wall', '-fPIC', '-DNDEBUG', '-c'), '-o', output_file('bin/clang-linux-3.9.0/release/main.o'), input_file(source='main.cpp')) - command('clang++', '-o', output_file('bin/clang-linux-3.9.0/release/test'), arg_file('@bin/clang-linux-3.9.0/release/strip-on*/test.rsp'), unordered('-fPIC', '-Wl,--strip-all')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/release/test'), '-Wl,-R', arg('-Wl,', target_path('bin/clang-linux-3.9.0/release/libl1.so')), '-Wl,-rpath-link', arg('-Wl,', target_path('bin/clang-linux-3.9.0/release/libl1.so')), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/release/main.o'), input_file('bin/clang-linux-3.9.0/release/libl1.so'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-fPIC', '-Wl,--strip-all')) -if allow_properties('variant=debug', 'link=shared', 'threading=multi', 'runtime-link=shared'): +if allow_properties('target-os=linux', 'variant=debug', 'link=shared', 'threading=multi', 'runtime-link=shared'): command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-pthread', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/lib.o'), input_file(source='lib.cpp')) - command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/libl1.so'), arg_file('@bin/clang-linux-3.9.0/debug*/threading-multi/libl1.so.rsp'), unordered('-g', '-pthread', '-fPIC')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/libl1.so'), '-Wl,-soname', '-Wl,libl1.so', '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/threading-multi/lib.o'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-lrt', '-Wl,--end-group', unordered('-g', '-pthread', '-fPIC')) command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-pthread', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/main.o'), input_file(source='main.cpp')) - command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/test'), arg_file('@bin/clang-linux-3.9.0/debug*/threading-multi/test.rsp'), unordered('-g', '-pthread', '-fPIC')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/test'), '-Wl,-R', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/threading-multi/libl1.so')), '-Wl,-rpath-link', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/threading-multi/libl1.so')), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/threading-multi/main.o'), input_file('bin/clang-linux-3.9.0/debug/threading-multi/libl1.so'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-lrt', '-Wl,--end-group', unordered('-g', '-pthread', '-fPIC')) -if allow_properties('variant=debug', 'link=static', 'threading=single', 'runtime-link=shared'): +if allow_properties('target-os=linux', 'variant=debug', 'link=static', 'threading=single', 'runtime-link=shared'): command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/lib.o'), input_file(source='lib.cpp')) command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/main.o'), input_file(source='main.cpp')) - command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/test'), arg_file('@bin/clang-linux-3.9.0/debug/link-static*/test.rsp'), '-g') + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/test'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/link-static/main.o'), input_file('bin/clang-linux-3.9.0/debug/link-static/libl1.a'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', '-g') -if allow_properties('variant=debug', 'link=static', 'threading=single', 'runtime-link=static'): +if allow_properties('target-os=linux', 'variant=debug', 'link=static', 'threading=single', 'runtime-link=static'): command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/lib.o'), input_file(source='lib.cpp')) command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/main.o'), input_file(source='main.cpp')) - command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/test'), arg_file('@bin/clang-linux-3.9.0/debug/link-static/runtime-link-static*/test.rsp'), unordered('-g', '-static')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/test'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/main.o'), input_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/libl1.a'), '-Wl,--end-group', unordered('-g', '-static')) -if allow_properties('variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared', 'architecture=x86', 'address-model=32'): +if allow_properties('target-os=linux', 'variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared', 'architecture=x86', 'address-model=32'): command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-march=i686', '-m32', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/lib.o'), input_file(source='lib.cpp')) - command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/libl1.so'), arg_file('@bin/clang-linux-3.9.0/debug/address-model-32/architecture-x86*/libl1.so.rsp'), unordered('-g', '-march=i686', '-fPIC', '-m32')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/libl1.so'), '-Wl,-soname', '-Wl,libl1.so', '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/lib.o'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-march=i686', '-fPIC', '-m32')) command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-march=i686', '-m32', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/main.o'), input_file(source='main.cpp')) - command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/test'), arg_file('@bin/clang-linux-3.9.0/debug/address-model-32/architecture-x86*/test.rsp'), unordered('-g', '-march=i686', '-fPIC', '-m32')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/test'), '-Wl,-R', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/libl1.so')), '-Wl,-rpath-link', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/libl1.so')), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/main.o'), input_file('bin/clang-linux-3.9.0/debug/libl1.so'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-march=i686', '-fPIC', '-m32')) + +# target-os=windows .. + +if allow_properties('target-os=windows', 'variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/target-os-windows/lib.obj'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/target-os-windows/l1.dll'), '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/target-os-windows/lib.obj'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/target-os-windows/main.obj'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/target-os-windows/test.exe'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/target-os-windows/main.obj'), input_file('bin/clang-linux-3.9.0/debug/target-os-windows/l1.dll'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g')) + +if allow_properties('target-os=windows', 'variant=release', 'link=shared', 'threading=single', 'runtime-link=shared', 'strip=on'): + command('clang++', unordered(ordered('-x', 'c++'), '-O3', '-Wno-inline', '-Wall', '-DNDEBUG', '-c'), '-o', output_file('bin/clang-linux-3.9.0/release/target-os-windows/lib.obj'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/release/strip-on/target-os-windows/l1.dll'), '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/release/target-os-windows/lib.obj'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-Wl,--strip-all')) + command('clang++', unordered(ordered('-x', 'c++'), '-O3', '-Wno-inline', '-Wall', '-DNDEBUG', '-c'), '-o', output_file('bin/clang-linux-3.9.0/release/strip-on/target-os-windows/main.obj'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/release/test'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/release/strip-on/target-os-windows/main.obj'), input_file('bin/clang-linux-3.9.0/release/strip-on/target-os-windows/l1.dll'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-Wl,--strip-all')) + +if allow_properties('target-os=windows', 'variant=debug', 'link=shared', 'threading=multi', 'runtime-link=shared'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-pthread', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/target-os-windows/threading-multi/lib.obj'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/target-os-windows/threading-multi/l1.dll'), '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/target-os-windows/threading-multi/lib.obj'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-pthread')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-pthread', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/target-os-windows/threading-multi/main.obj'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/test'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/target-os-windows/threading-multi/main.obj'), input_file('bin/clang-linux-3.9.0/debug/target-os-windows/threading-multi/l1.dll'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-pthread')) + +if allow_properties('target-os=windows', 'variant=debug', 'link=static', 'threading=single', 'runtime-link=shared'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/target-os-windows/lib.obj'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/target-os-windows/main.obj'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/target-os-windows/test.exe'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/link-static/target-os-windows/main.obj'), input_file('bin/clang-linux-3.9.0/debug/link-static/target-os-windows/libl1.lib'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', '-g') + +if allow_properties('target-os=windows', 'variant=debug', 'link=static', 'threading=single', 'runtime-link=static'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/target-os-windows/lib.obj'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/target-os-windows/main.obj'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/target-os-windows/test.exe'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/link-static/target-os-windows/main.obj'), input_file('bin/clang-linux-3.9.0/debug/link-static/target-os-windows/libl1.lib'), '-Wl,--end-group', unordered('-g', '-static')) + +if allow_properties('target-os=windows', 'variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared', 'architecture=x86', 'address-model=32'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-march=i686', '-m32', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/address-model-32/architecture-x86/target-os-windows/lib.obj'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/address-model-32/architecture-x86/target-os-windows/l1.dll'), '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/address-model-32/architecture-x86/target-os-windows/lib.obj'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-march=i686', '-m32')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-march=i686', '-m32', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/address-model-32/architecture-x86/target-os-windows/main.obj'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/address-model-32/architecture-x86/target-os-windows/test.exe'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/address-model-32/architecture-x86/target-os-windows/main.obj'), input_file('bin/clang-linux-3.9.0/debug/address-model-32/architecture-x86/target-os-windows/l1.dll'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-march=i686', '-m32')) main() diff --git a/test/toolset-mock/src/ranlib.py b/test/toolset-mock/src/ranlib.py index 4abe21ed0..6a3e9b63c 100644 --- a/test/toolset-mock/src/ranlib.py +++ b/test/toolset-mock/src/ranlib.py @@ -1,6 +1,7 @@ #!/usr/bin/python # # Copyright 2017 Steven Watanabe +# Copyright 2020 René Ferdinand Rivera Morell # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at @@ -18,5 +19,6 @@ command('ranlib', '-cs', input_file('bin/intel-darwin-10.2/debug/link-static/tar command('ranlib', '-cs', input_file('bin/intel-darwin-10.2/debug/link-static/runtime-link-static/target-os-darwin/libl1.a')) command('ranlib', input_file('bin/clang-linux-3.9.0/debug/link-static/libl1.a')) command('ranlib', input_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/libl1.a')) +command('ranlib', input_file('bin/clang-linux-3.9.0/debug/link-static/target-os-windows/libl1.lib')) main() diff --git a/test/toolset_clang_linux.py b/test/toolset_clang_linux.py index 2fbf84b6d..b4fe0d5a1 100644 --- a/test/toolset_clang_linux.py +++ b/test/toolset_clang_linux.py @@ -1,6 +1,7 @@ #!/usr/bin/python # # Copyright 2017 Steven Watanabe +# Copyright 2020 René Ferdinand Rivera Morell # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at @@ -17,3 +18,11 @@ test_toolset("clang-linux", "3.9.0", [ ["target-os=linux", "link=static"], ["target-os=linux", "link=static", "runtime-link=static"], ["target-os=linux", "architecture=x86", "address-model=32"]]) + +test_toolset("clang-linux", "3.9.0", [ + ["target-os=windows"], + ["target-os=windows", "release", "strip=on"], + ["target-os=windows", "threading=multi"], + ["target-os=windows", "link=static"], + ["target-os=windows", "architecture=x86", "address-model=32"] + ])