diff --git a/historic/jam/src/expand.c b/historic/jam/src/expand.c index 1aa8c1545..0f54674d6 100644 --- a/historic/jam/src/expand.c +++ b/historic/jam/src/expand.c @@ -6,6 +6,11 @@ # include "newstr.h" # include +# ifdef OS_CYGWIN +# include +# include +# endif + /* * expand.c - expand a buffer, given variable values * @@ -30,7 +35,8 @@ typedef struct { char filemods; /* one of the above applied */ char downshift; /* :L -- downshift result */ char upshift; /* :U -- upshift result */ - char to_slashes; /* :T -- convert "\" to "/" */ + char to_slashes; /* :T -- convert "\" to "/" */ + char to_windows; /* :W -- convert cygwin to native paths */ PATHPART empty; /* :E -- default for empties */ PATHPART join; /* :J -- join list with char */ } VAR_EDITS ; @@ -63,51 +69,51 @@ var_expand( LOL *lol, int cancopyin ) { - char out_buf[ MAXSYM ]; + char out_buf[ MAXSYM ]; string buf[1]; - string out1; /* Temporary buffer */ + string out1[1]; /* Temporary buffer */ size_t prefix_length; char *out; - char *inp = in; - char *ov; /* for temp copy of variable in outbuf */ - int depth; + char *inp = in; + char *ov; /* for temp copy of variable in outbuf */ + int depth; - if( DEBUG_VAREXP ) - printf( "expand '%.*s'\n", end - in, in ); + if( DEBUG_VAREXP ) + printf( "expand '%.*s'\n", end - in, in ); - /* This gets alot of cases: $(<) and $(>) */ + /* This gets alot of cases: $(<) and $(>) */ - if( in[0] == '$' && in[1] == '(' && in[3] == ')' && !in[4] ) - { - switch( in[2] ) - { - case '1': - case '<': - return list_copy( l, lol_get( lol, 0 ) ); - - case '2': - case '>': - return list_copy( l, lol_get( lol, 1 ) ); - } - } - - /* Just try simple copy of in to out. */ - - while( in < end ) - if( *in++ == '$' && *in == '(' ) - goto expand; - - /* No variables expanded - just add copy of input string to list. */ - - /* Cancopyin is an optimization: if the input was already a list */ - /* item, we can use the copystr() to put it on the new list. */ - /* Otherwise, we use the slower newstr(). */ - - if( cancopyin ) + if( in[0] == '$' && in[1] == '(' && in[3] == ')' && !in[4] ) { - return list_new( l, copystr( inp ) ); + switch( in[2] ) + { + case '1': + case '<': + return list_copy( l, lol_get( lol, 0 ) ); + + case '2': + case '>': + return list_copy( l, lol_get( lol, 1 ) ); + } } - else + + /* Just try simple copy of in to out. */ + + while( in < end ) + if( *in++ == '$' && *in == '(' ) + goto expand; + + /* No variables expanded - just add copy of input string to list. */ + + /* Cancopyin is an optimization: if the input was already a list */ + /* item, we can use the copystr() to put it on the new list. */ + /* Otherwise, we use the slower newstr(). */ + + if( cancopyin ) + { + return list_new( l, copystr( inp ) ); + } + else { LIST* r; string_new( buf ); @@ -118,342 +124,342 @@ var_expand( return r; } - expand: +expand: string_new( buf ); string_append_range( buf, inp, in - 1); /* copy the part before '$'. */ - /* - * Input so far (ignore blanks): - * - * stuff-in-outbuf $(variable) remainder - * ^ ^ - * in end - * Output so far: - * - * stuff-in-outbuf $ - * ^ ^ - * out_buf out - * - * - * We just copied the $ of $(...), so back up one on the output. - * We now find the matching close paren, copying the variable and - * modifiers between the $( and ) temporarily into out_buf, so that - * we can replace :'s with MAGIC_COLON. This is necessary to avoid - * being confused by modifier values that are variables containing - * :'s. Ugly. - */ + /* + * Input so far (ignore blanks): + * + * stuff-in-outbuf $(variable) remainder + * ^ ^ + * in end + * Output so far: + * + * stuff-in-outbuf $ + * ^ ^ + * out_buf out + * + * + * We just copied the $ of $(...), so back up one on the output. + * We now find the matching close paren, copying the variable and + * modifiers between the $( and ) temporarily into out_buf, so that + * we can replace :'s with MAGIC_COLON. This is necessary to avoid + * being confused by modifier values that are variables containing + * :'s. Ugly. + */ - depth = 1; + depth = 1; inp = ++in; /* skip over the '(' */ - while( in < end && depth ) - { - switch( *in++ ) - { - case '(': depth++; break; - case ')': depth--; break; - } - } + while( in < end && depth ) + { + switch( *in++ ) + { + case '(': depth++; break; + case ')': depth--; break; + } + } - /* - * Input so far (ignore blanks): - * - * stuff-in-outbuf $(variable) remainder - * ^ ^ ^ - * inp in end - */ - prefix_length = buf->size; - string_append_range( buf, inp, in - 1 ); + /* + * Input so far (ignore blanks): + * + * stuff-in-outbuf $(variable) remainder + * ^ ^ ^ + * inp in end + */ + prefix_length = buf->size; + string_append_range( buf, inp, in - 1 ); - out = buf->value + prefix_length; - for ( ov = out; ov < buf->value + buf->size; ++ov ) - { - switch( *ov ) - { - case ':': *ov = MAGIC_COLON; break; - case '[': *ov = MAGIC_LEFT; break; - case ']': *ov = MAGIC_RIGHT; break; - } - } + out = buf->value + prefix_length; + for ( ov = out; ov < buf->value + buf->size; ++ov ) + { + switch( *ov ) + { + case ':': *ov = MAGIC_COLON; break; + case '[': *ov = MAGIC_LEFT; break; + case ']': *ov = MAGIC_RIGHT; break; + } + } - /* - * Input so far (ignore blanks): - * - * stuff-in-outbuf $(variable) remainder - * ^ ^ - * in end - * Output so far: - * - * stuff-in-outbuf variable - * ^ ^ ^ - * out_buf out ov - * - * Later we will overwrite 'variable' in out_buf, but we'll be - * done with it by then. 'variable' may be a multi-element list, - * so may each value for '$(variable element)', and so may 'remainder'. - * Thus we produce a product of three lists. - */ + /* + * Input so far (ignore blanks): + * + * stuff-in-outbuf $(variable) remainder + * ^ ^ + * in end + * Output so far: + * + * stuff-in-outbuf variable + * ^ ^ ^ + * out_buf out ov + * + * Later we will overwrite 'variable' in out_buf, but we'll be + * done with it by then. 'variable' may be a multi-element list, + * so may each value for '$(variable element)', and so may 'remainder'. + * Thus we produce a product of three lists. + */ - { - LIST *variables = 0; - LIST *remainder = 0; - LIST *vars; + { + LIST *variables = 0; + LIST *remainder = 0; + LIST *vars; - /* Recursively expand variable name & rest of input */ + /* Recursively expand variable name & rest of input */ - if( out < ov ) - variables = var_expand( L0, out, ov, lol, 0 ); - if( in < end ) - remainder = var_expand( L0, in, end, lol, 0 ); + if( out < ov ) + variables = var_expand( L0, out, ov, lol, 0 ); + if( in < end ) + remainder = var_expand( L0, in, end, lol, 0 ); - /* Now produce the result chain */ + /* Now produce the result chain */ - /* For each variable name */ + /* For each variable name */ - for( vars = variables; vars; vars = list_next( vars ) ) - { - LIST *value, *evalue = 0; - char *colon; - char *bracket; - string variable; - char *varname; - int sub1 = 0, sub2 = -1; - VAR_EDITS edits; + for( vars = variables; vars; vars = list_next( vars ) ) + { + LIST *value, *evalue = 0; + char *colon; + char *bracket; + string variable[1]; + char *varname; + int sub1 = 0, sub2 = -1; + VAR_EDITS edits; - /* Look for a : modifier in the variable name */ - /* Must copy into varname so we can modify it */ + /* Look for a : modifier in the variable name */ + /* Must copy into varname so we can modify it */ - string_copy( &variable, vars->string ); - varname = variable.value; + string_copy( variable, vars->string ); + varname = variable->value; - if( colon = strchr( varname, MAGIC_COLON ) ) - { - string_truncate( &variable, colon - varname ); - var_edit_parse( colon + 1, &edits ); - } + if( colon = strchr( varname, MAGIC_COLON ) ) + { + string_truncate( variable, colon - varname ); + var_edit_parse( colon + 1, &edits ); + } - /* Look for [x-y] subscripting */ - /* sub1 and sub2 are x and y. */ + /* Look for [x-y] subscripting */ + /* sub1 and sub2 are x and y. */ - if ( bracket = strchr( varname, MAGIC_LEFT ) ) + if ( bracket = strchr( varname, MAGIC_LEFT ) ) + { + /* + ** Make all syntax errors in [] subscripting + ** result in the same behavior: silenty return an empty + ** expansion (by setting sub2 = 0). Brute force parsing; + ** May get moved into yacc someday. + */ + + char *s = bracket + 1; + + string_truncate( variable, bracket - varname ); + + do /* so we can use "break" */ { - /* - ** Make all syntax errors in [] subscripting - ** result in the same behavior: silenty return an empty - ** expansion (by setting sub2 = 0). Brute force parsing; - ** May get moved into yacc someday. - */ - - char *s = bracket + 1; - - string_truncate( &variable, bracket - varname ); - - do /* so we can use "break" */ + /* Allow negative indexes. */ + if (! isdigit( *s ) && ! ( *s == '-') ) { - /* Allow negative indexes. */ - if (! isdigit( *s ) && ! ( *s == '-') ) - { - sub2 = 0; - break; - } - sub1 = atoi(s); + sub2 = 0; + break; + } + sub1 = atoi(s); - /* Skip over the first symbol, which is either a digit or dash. */ - s++; - while ( isdigit( *s ) ) s++; + /* Skip over the first symbol, which is either a digit or dash. */ + s++; + while ( isdigit( *s ) ) s++; - if ( *s == MAGIC_RIGHT ) - { - sub2 = sub1; - break; - } + if ( *s == MAGIC_RIGHT ) + { + sub2 = sub1; + break; + } - if ( *s != '-') - { - sub2 = 0; - break; - } + if ( *s != '-') + { + sub2 = 0; + break; + } - s++; + s++; - if ( *s == MAGIC_RIGHT ) - { - sub2 = -1; - break; - } + if ( *s == MAGIC_RIGHT ) + { + sub2 = -1; + break; + } - if (! isdigit( *s ) && ! ( *s == '-') ) - { - sub2 = 0; - break; - } + if (! isdigit( *s ) && ! ( *s == '-') ) + { + sub2 = 0; + break; + } - /* First, compute the index of the last element. */ - sub2 = atoi(s); - s++; - while ( isdigit( *s ) ) s++; + /* First, compute the index of the last element. */ + sub2 = atoi(s); + s++; + while ( isdigit( *s ) ) s++; - if ( *s != MAGIC_RIGHT) - sub2 = 0; - - } while (0); - - /* - ** Anything but the end of the string, or the colon - ** introducing a modifier is a syntax error. - */ - - s++; - if (*s && *s != MAGIC_COLON) + if ( *s != MAGIC_RIGHT) sub2 = 0; - *bracket = '\0'; + } while (0); + + /* + ** Anything but the end of the string, or the colon + ** introducing a modifier is a syntax error. + */ + + s++; + if (*s && *s != MAGIC_COLON) + sub2 = 0; + + *bracket = '\0'; + } + + /* Get variable value, specially handling $(<), $(>), $(n) */ + + if( varname[0] == '<' && !varname[1] ) + value = lol_get( lol, 0 ); + else if( varname[0] == '>' && !varname[1] ) + value = lol_get( lol, 1 ); + else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] ) + value = lol_get( lol, varname[0] - '1' ); + else + value = var_get( varname ); + + /* Handle negitive indexes: part two. */ + { + int length = list_length( value ); + + if (sub1 < 0) + sub1 = length + sub1; + else + sub1 -= 1; + + if (sub2 < 0) + sub2 = length + 1 + sub2 - sub1; + else + sub2 -= sub1; + /* + ** The "sub2 < 0" test handles the semantic error + ** of sub2 < sub1. + */ + if ( sub2 < 0 ) + sub2 = 0; + } + + + + /* The fast path: $(x) - just copy the variable value. */ + /* This is only an optimization */ + + if( out == out_buf && !bracket && !colon && in == end ) + { + string_free( variable ); + l = list_copy( l, value ); + continue; + } + + /* Handle start subscript */ + + while( sub1 > 0 && value ) + --sub1, value = list_next( value ); + + /* Empty w/ :E=default? */ + + if( !value && colon && edits.empty.ptr ) + evalue = value = list_new( L0, newstr( edits.empty.ptr ) ); + + /* For each variable value */ + + string_new( out1 ); + for( ; value; value = list_next( value ) ) + { + LIST *rem; + size_t postfix_start; + + /* Handle end subscript (length actually) */ + + if( sub2 >= 0 && --sub2 < 0 ) + break; + + string_truncate( buf, prefix_length ); + + /* Apply : mods, if present */ + + if( colon && edits.filemods ) + var_edit_file( value->string, out1, &edits ); + else + string_append( out1, value->string ); + + if( colon && ( edits.upshift || edits.downshift || edits.to_slashes || edits.to_windows ) ) + var_edit_shift( out1, &edits ); + + /* Handle :J=joinval */ + /* If we have more values for this var, just */ + /* keep appending them (with the join value) */ + /* rather than creating separate LIST elements. */ + + if( colon && edits.join.ptr && + ( list_next( value ) || list_next( vars ) ) ) + { + string_append( out1, edits.join.ptr ); + continue; } - /* Get variable value, specially handling $(<), $(>), $(n) */ - - if( varname[0] == '<' && !varname[1] ) - value = lol_get( lol, 0 ); - else if( varname[0] == '>' && !varname[1] ) - value = lol_get( lol, 1 ); - else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] ) - value = lol_get( lol, varname[0] - '1' ); - else - value = var_get( varname ); + string_append( buf, out1->value ); + string_free( out1 ); + string_new( out1 ); - /* Handle negitive indexes: part two. */ - { - int length = list_length( value ); + /* If no remainder, append result to output chain. */ - if (sub1 < 0) - sub1 = length + sub1; - else - sub1 -= 1; + if( in == end ) + { + l = list_new( l, newstr( buf->value ) ); + continue; + } - if (sub2 < 0) - sub2 = length + 1 + sub2 - sub1; - else - sub2 -= sub1; - /* - ** The "sub2 < 0" test handles the semantic error - ** of sub2 < sub1. - */ - if ( sub2 < 0 ) - sub2 = 0; + /* For each remainder, append the complete string */ + /* to the output chain. */ + /* Remember the end of the variable expansion so */ + /* we can just tack on each instance of 'remainder' */ + + postfix_start = buf->size; + + for( rem = remainder; rem; rem = list_next( rem ) ) + { + string_truncate( buf, postfix_start ); + string_append( buf, rem->string ); + l = list_new( l, newstr( buf->value ) ); + } + } + string_free( out1 ); + + /* Toss used empty */ + + if( evalue ) + list_free( evalue ); + + string_free( variable ); } + /* variables & remainder were gifts from var_expand */ + /* and must be freed */ + if( variables ) + list_free( variables ); + if( remainder) + list_free( remainder ); - /* The fast path: $(x) - just copy the variable value. */ - /* This is only an optimization */ - - if( out == out_buf && !bracket && !colon && in == end ) - { - string_free( &variable ); - l = list_copy( l, value ); - continue; - } - - /* Handle start subscript */ - - while( sub1 > 0 && value ) - --sub1, value = list_next( value ); - - /* Empty w/ :E=default? */ - - if( !value && colon && edits.empty.ptr ) - evalue = value = list_new( L0, newstr( edits.empty.ptr ) ); - - /* For each variable value */ - - string_new( &out1 ); - for( ; value; value = list_next( value ) ) - { - LIST *rem; - size_t postfix_start; - - /* Handle end subscript (length actually) */ - - if( sub2 >= 0 && --sub2 < 0 ) - break; - - string_truncate( buf, prefix_length ); - - /* Apply : mods, if present */ - - if( colon && edits.filemods ) - var_edit_file( value->string, &out1, &edits ); - else - string_append( &out1, value->string ); - - if( colon && ( edits.upshift || edits.downshift || edits.to_slashes ) ) - var_edit_shift( &out1, &edits ); - - /* Handle :J=joinval */ - /* If we have more values for this var, just */ - /* keep appending them (with the join value) */ - /* rather than creating separate LIST elements. */ - - if( colon && edits.join.ptr && - ( list_next( value ) || list_next( vars ) ) ) - { - string_append( &out1, edits.join.ptr ); - continue; - } - - string_append( buf, out1.value ); - string_free( &out1 ); - string_new( &out1 ); - - /* If no remainder, append result to output chain. */ - - if( in == end ) - { - l = list_new( l, newstr( buf->value ) ); - continue; - } - - /* For each remainder, append the complete string */ - /* to the output chain. */ - /* Remember the end of the variable expansion so */ - /* we can just tack on each instance of 'remainder' */ - - postfix_start = buf->size; - - for( rem = remainder; rem; rem = list_next( rem ) ) - { - string_truncate( buf, postfix_start ); - string_append( buf, rem->string ); - l = list_new( l, newstr( buf->value ) ); - } - } - string_new( &out1 ); - - /* Toss used empty */ - - if( evalue ) - list_free( evalue ); - - string_free( &variable ); - } - - /* variables & remainder were gifts from var_expand */ - /* and must be freed */ - - if( variables ) - list_free( variables ); - if( remainder) - list_free( remainder ); - - if( DEBUG_VAREXP ) - { - printf( "expanded to " ); - list_print( l ); - printf( "\n" ); - } + if( DEBUG_VAREXP ) + { + printf( "expanded to " ); + list_print( l ); + printf( "\n" ); + } string_free( buf ); - return l; - } + return l; + } } /* @@ -517,7 +523,8 @@ var_edit_parse( case 'B': fp = &edits->f.f_base; goto fileval; case 'S': fp = &edits->f.f_suffix; goto fileval; case 'M': fp = &edits->f.f_member; goto fileval; - case 'T': edits->to_slashes = 1; continue; + case 'T': edits->to_slashes = 1; continue; + case 'W': edits->to_windows = 1; continue; default: return; /* should complain, but so what... */ } @@ -644,6 +651,16 @@ var_edit_shift( if ( *p == '\\') *p = '/'; } +# ifdef OS_CYGWIN + if ( edits->to_windows ) + { + char result[MAX_PATH + 1]; + cygwin_conv_to_win32_path(out->value, result); + assert(strlen(result) <= MAX_PATH); + string_free( out ); + string_copy( out, result ); + } +# endif } out->size = p - out->value; } @@ -657,19 +674,33 @@ void var_expand_unit_test() LIST *e2; char axyb[] = "a$(xy)b"; char azb[] = "a$($(z))b"; - + char path[] = "$(p:W)"; + lol_init(lol); var_set("xy", list_new( list_new( L0, newstr( "x" ) ), newstr( "y" ) ), VAR_SET ); var_set("z", list_new( L0, newstr( "xy" ) ), VAR_SET ); - + var_set("p", list_new( L0, newstr( "/cygdrive/c/foo/bar" ) ), VAR_SET ); + l = var_expand( 0, axyb, axyb + sizeof(axyb) - 1, lol, 0 ); for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next(l2), e2 = list_next(e2) ) assert( !strcmp( e2->string, l2->string ) ); + assert(l2 == 0 && e2 == 0); list_free(l); l = var_expand( 0, azb, azb + sizeof(azb) - 1, lol, 0 ); for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next(l2), e2 = list_next(e2) ) assert( !strcmp( e2->string, l2->string ) ); + assert(l2 == 0 && e2 == 0); + list_free(l); + + l = var_expand( 0, path, path + sizeof(path) - 1, lol, 0 ); + assert(l != 0); + assert(list_next(l) == 0); +# ifdef OS_CYGWIN + assert( !strcmp( l->string, "c:\\foo\\bar" ) ); +# else + assert( !strcmp( l->string, "/cygdrive/c/foo/bar" ) ); +# endif list_free(l); list_free(expected); diff --git a/historic/jam/src/index.html b/historic/jam/src/index.html index 71333e5f4..8cd31972d 100644 --- a/historic/jam/src/index.html +++ b/historic/jam/src/index.html @@ -1,15 +1,18 @@ + + "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org"> + Boost.Jam + @@ -19,8 +22,10 @@

C++ Boost

+ @@ -28,64 +33,108 @@

Boost.Jam

+



+
Introduction
+
Features
+
Contents
+
Installing
+
Core Jam Extensions
+
Command-line and Environment Variable Quoting
+
Startup Behavior
+
Rule Indirection
+
Argument Lists
+
Module Support
+
Declaration
+
Variable Scope
+
Local Rules
+
The RULENAMES rule
+ +
The VARNAMES + rule
+
The IMPORT rule
+
The EXPORT rule
-
The CALLER_MODULE + +
The + CALLER_MODULE
+ +
The DELETE_MODULE rule
+
Local for Loop Variables
+
Negative Indexing
+ +
Support for Cygwin
+
Target Binding Detection
+
Return Code Inversion
+
Ignoring Return Codes
+
Removing outdated targets
+
The SUBST Rule
+
The JAM_VERSION global variable
+
Debugging Support
+
The BACKTRACE rule
+
Profiling
+
Parser Debugging
+
Dependency Graph Output
+
The UPDATE rule and changes to command line handling
+
Semaphores
+
Jam Fundamentals
+

Introduction

+

Boost.Jam (BJam)  is a build tool based on FTJam, which in turn is based on Perforce Jam. It contains significant improvements made to facilitate its use in the Boost Build System, but should be backward compatible with Perforce Jam.

+

This is version 3.1.4 of BJam and is based on version 2.4 of Jam/MR:

@@ -98,9 +147,12 @@ freely, as long as this copyright notice is retained and modifications
 are clearly marked.
 ALL WARRANTIES ARE HEREBY DISCLAIMED.
 
+

Features

+

Jam is a make(1) replacement that makes building simple things simple and building complicated things manageable.

+

Jam's language is expressive, making Jamfiles (c.f. Makefiles) compact.  Here's a sample:

@@ -108,44 +160,62 @@ Main smail : main.c map.c resolve.c deliver.c
      misc.c parser.y alias.c pw.c headers.c
      scanner.l getpath.c str.c ;
 
+

This builds "smail" from a dozen source files.  Jam handles header file dependencies automatically and on-the-fly.

+

Jam is very portable: it runs on UNIX, VMS, Mac, and NT. Most Jamfiles themselves are portable, like the sample above.

+

Jam is unintrusive: it is small, it has negligible CPU overhead, and it doesn't create any of its own funny files (c.f. Odin, nmake, SunOS make).

+

Jam can build large projects spread across many directories in one pass, without recursing, tracking the relationships among all files. Jam can do this with multiple, concurrent processes.

+

Jam isn't under the blinkin GNU copyright, so you can incorporate it into commercial products.

+

Contents

+ + + + + + + + + +
Jam.htmlJam and language reference.
Jambase.htmlReference for the Jambase boilerplate file.
Jamfile.htmlEasy reading on creating a Jamfile and using jam.
RELNOTESRelease 2.4 release notes.
PortingNotes on porting jam to wildcat platforms.
+

Installing

+

Installing BJam after building it is simply a matter of copying the generated executables someplace in your PATH. For building the executables there are a set of build bootstrap scripts to @@ -156,162 +226,215 @@ Main smail : main.c map.c resolve.c deliver.c

 <build script name> [toolset]
 
+

Running the scripts without arguments will give you the best chance of success. On Windows platforms from a command console do:

 cd <jam source location>
 .\build.bat
 
+

On Unix type platforms do:

 cd <jam source location>
 sh ./build.sh
 
+

If the scripts fail to detect an appropriate toolset to build with your particular toolset may not be auto-detectable. In that case, you can specify the toolset as the first argument, this assumes that the toolset is readily available in the PATH. The supported toolsets, and wether they are auto-detected, are:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ScriptPlatformsToolsetsDetection
build.batWindows NT, 2000, and XPcomo, Comeau.Computing C/C++ 
borland, Borland C++Builder (BCC 5.5)* Common install location: "C:\Borland\BCC55"
* BCC32.EXE in PATH
gcc, GNU GCC 
gcc-nocygwin, GNU GCC 
intel-win32, Intel C++ Compiler for Windows* ICL.EXE in PATH
metrowerks, MetroWerks CodeWarrior C/C++ 7.x, 8.x* CWFolder variable configured
* MWCC.EXE in PATH
mingw, GNU GCC as the MinGW configuration 
msvc, Microsoft Visual C++ 6.x* VCVARS32.BAT already configured
* Common install locations: "C:\Program Files\Microsoft Visual Studio", "C:\Program Files\Microsoft Visual C++"
* CL.EXE in PATH
vc7, Microsoft Visual C++ 7.x* Common install location: "C:\Program Files\Microsoft Visual Studio .NET"
build.shUnix, Linux, Cygwin, etc.acc, HP-UX aCC* aCC in PATH
* uname is "HP-UX"
como, Comeau.Computing C/C++* como in PATH
gcc, GNU GCC* gcc in PATH
intel-linux, Intel C++ for Linux* icc in PATH
* Common install locations: "/opt/intel/compiler70", "/opt/intel/compiler60", "/opt/intel/compiler50"
kcc, Intel KAI C++* KCC in PATH
kylix, Borland C++Builder* bc++ in PATH
mipspro, SGI MIPSpro C 
sunpro, Sun Workshop 6 C++ 
true64cxx, Compaq C++ Compiler for True64 UNIX 
vacpp, IBM VisualAge C++* xlc in PATH
MacOS X
darwin, Apple MacOS X GCC* uname is "Darwin"
+

The built executables are placed in a subdirectory specific to your platform. For example, in Linux running on an Intel x86 compatible chip, the executables are placed in: "bin.linuxx86". There are two @@ -319,6 +442,7 @@ sh ./build.sh are the same binary but with different names. The "jam" invocation is used for compatability with the Perforce Jam/MR functionality, whereas "bjam" is used for the extended Boost.Build functionality.

+

The build scripts support additional invocation arguments for use by developers of Boost.Jam. The extra arguments come after the toolset, and can take the form of "--options" or targets for the @@ -326,19 +450,25 @@ sh ./build.sh

 <build script name> [toolset] [--options* [targets]*]
 
+

There is current only one available option, "--debug", which builds debugging versions of the executable. When built they are placed in their own directory "bin.<platform>.debug".

+

Currently there are two targets supported: dist, and clean. Respectively they: generate packages (compressed archives) as appropriate for distribution in the platform, or remove all the built executables and objects.

+

Core Jam Extensions

+

A number of enhancements have been made to the core language of Classic Jam. These changes were aimed primarily at making it easier to manage the complexity of a large system such as Boost.Build.

+

Command-line and Environment Variable Quoting

+

Classic Jam had an odd behavior with respect to command-line variable ( -s...) and environment variable settings which made it impossible to define an arbitrary @@ -350,6 +480,7 @@ sh ./build.sh

 jam -sMSVCNT="\"\"C:\Program Files\Microsoft Visual C++\VC98\"\"" ...
 
+

The outer quote is for the shell. The middle quote is for Jam, to tell it to take everything within those quotes literally, and the inner quotes are for the shell again when paths are passed as arguments to build @@ -358,19 +489,24 @@ jam -sMSVCNT="\"\"C:\Program Files\Microsoft Visual C++\VC98\"\"" ...

 set MSVCNT=""C:\Program Files\Microsoft Visual C++\VC98\""
 
+

Startup Behavior

+

The Boost.Build v2 initialization behavior has been implemented. This behavior only applies when the executable being invoked is called "bjam" or, for backward-compatibility, when the BOOST_ROOT variable is set.

+
  1. We attempt to load "boost-build.jam" by searching from the current invocation directory up to the root of the file-system. This file is expected to invoke the boost-build rule to indicate where the Boost.Build system files are, and to load them.
  2. +
  3. If boost-build.jam is not found we error and exit, giving brief instructions on possible errors. +
    As a backward-compatibility measure for older versions of Boost.Build, when the BOOST_ROOT variable is set, we @@ -380,15 +516,19 @@ set MSVCNT=""C:\Program Files\Microsoft Visual C++\VC98\"" initialization is complete.
  4. +
  5. The boost-build rule adds its (optional) argument to the front of BOOST_BUILD_PATH, and attempts to load bootstrap.jam from those directories. If a relative path is specified as an argument, it is treated as though it was relative to the boost-build.jam file.
  6. +
  7. If the bootstrap.jam file was not found, we print a likely error message and exit.
+

Rule Indirection

+

Boost Jam allows you to call a rule whose name is held in a variable or computed as the result of an expression:

@@ -396,6 +536,7 @@ x = foo ;
 rule foobar { ECHO foobar ; }   # a trivial rule
 $(x)bar ;                       # invokes foobar
 
+

Furthermore, if the first expression expands to more than one list item, everything after the first item becomes part of the first argument. This allows a crude form of argument binding:

@@ -418,7 +559,9 @@ rule equal ( x y ) # bind 3 to the first argument of equal ECHO [ filter 1 2 3 4 5 4 3 : equal 3 ] ; # prints "3 3" +

Argument lists

+

You can now describe the arguments accepted by a rule, and refer to them by name within the rule. For example, the following prints ``I'm sorry, Dave'' to the console:

@@ -432,31 +575,41 @@ rule report ( pronoun index ? : state : names + ) } report I 2 : sorry : Joe Dave Pete ; +

Each name in a list of formal arguments (separated by ``:'' in the rule declaration) is bound to a single element of the corresponding actual argument unless followed by one of these modifiers:

+ + + + + + + +
SymbolSemantics of preceding symbol
?optional
*Bind to zero or more unbound elements of the actual argument. When ``*'' appears where an argument name is expected, any number of additional arguments are accepted. This feature can be used to implement "varargs" rules.
+Bind to one or more unbound elements of the actual argument.
+

The actual and formal arguments are checked for inconsistencies, which cause Jam to exit with an error code:

@@ -469,21 +622,26 @@ report I 2 : sorry : Joe Dave Pete ;
 # called with: ( I 2  : sorry )
 # missing argument names
 
+

If you omit the list of formal arguments, all checking is bypassed as in ``classic'' Jam. Argument lists drastically improve the reliability and readability of your rules, however, and are strongly recommended for any new Jam code you write.

+

Module Support

+

Boost Jam introduces support for modules, which provide some rudimentary namespace protection for rules and variables. A new keyword, ``module'' was also introduced. The features described in this section are primitives, meaning that they are meant to provide the operations needed to write Jam rules which provide a more elegant module interface.

+

Declaration

 module expression { ... }
 
+

Code within the ... } executes within the module named by evaluating expression. Rule definitions can be found in the module's own namespace, and in the namespace of the global @@ -499,6 +657,7 @@ module expression { ... } } my_module.salute goodbye ; +

When an invoked rule is not found in the current module's namespace, it is looked up in the namespace of the global module, so qualified calls work across modules:

@@ -508,7 +667,9 @@ module your_module rule bedtime ( ) { my_module.salute goodnight ; } } +

Variable Scope

+

Each module has its own set of dynamically nested variable scopes. When execution passes from module A to module B, all the variable bindings from A become unavailable, and are replaced by the bindings that @@ -537,6 +698,7 @@ module B } } +

The only way to access another module's variables is by entering that module:

@@ -551,29 +713,47 @@ rule peek ( module-name ? : variables + )
     Note that because existing variable bindings change whenever a new module
     scope is entered, argument bindings become unavailable. That explains the
     use of "$(>)" in the peek rule above. 
+
     

Local Rules

 local rule rulename...
 
+

The rule is declared locally to the current module. It is not entered in the global module with qualification, and its name will not appear in the result of:

 [ RULENAMES module-name ]
 
+

The RULENAMES Rule

 rule RULENAMES ( module ? )
 
+

Returns a list of the names of all non-local rules in the given module. If module is omitted, the names of all non-local rules in the global module are returned.

+ +

The VARNAMES Rule

+
+rule VARNAMES ( module ? )
+
+ +

Returns a list of the names of all variable bindings in the given + module. If module is omitted, the names of all variable bindings + in the global module are returned. Note:this includes any local + variables in rules from the call stack which have not returned at the + time of the VARNAMES invocation.

+

The IMPORT Rule

+

IMPORT allows rule name aliasing across modules:

 rule IMPORT ( source_module ? : source_rules *
             : target_module ? : target_rules * )
 
+

The IMPORT rule copies rules from the source_module into the target_module as local rules. If either source_module or target_module is not supplied, it @@ -589,11 +769,14 @@ IMPORT m1 : rule1 : m2 : m1-rule1 ; # import all non-local rules from m1 into m2 IMPORT m1 : [ RULENAMES m1 ] : m2 : [ RULENAMES m1 ] ;

+

The EXPORT Rule

+

EXPORT allows rule name aliasing across modules:

 rule EXPORT ( module ? : rules * )
 
+

The EXPORT rule marks rules from the source_module as non-local (and thus exportable). If an element of rules does not name a rule in module, an error is @@ -606,10 +789,12 @@ IMPORT X : r : : r ; # error - r is local in X EXPORT X : r ; IMPORT X : r : : r ; # OK. +

The CALLER_MODULE Rule

 rule CALLER_MODULE ( levels ? )
 
+

CALLER_MODULE returns the name of the module scope enclosing the call to its caller (if levels is supplied, it is interpreted as an integer number of additional levels of call stack to traverse to locate @@ -629,7 +814,24 @@ module Y { callers = [ X.get-caller ] [ Y.call-X ] [ X.call-Y ] ; ECHO {$(callers)} ; + +

The DELETE_MODULE Rule

+
+rule DELETE_MODULE ( module ? )
+
+ +

DELETE_MODULE removes all of the variable bindings and + otherwise-unreferenced rules from the given module (or the global module, + if no module is supplied), and returns their memory to the system. + Note: though it won't affect rules that are currently executing + until they complete, DELETE_MODULE should be used with + extreme care because it will wipe out any others and all variable + (including locals in that module) immediately. Because of the way dynamic + binding works, variables which are shadowed by locals will not be + destroyed, so the results can be really unpredictable.

+

Local For Loop Variables

+

Boost Jam allows you to declare a local for loop control variable right in the loop:

@@ -641,7 +843,9 @@ for local y in $(x)
 }
 ECHO $(y) ;     # prints "4 5 6"
 
+

Negative Indexing

+

Classic Jam supplies 1-based list indexing, and slicing on a closed (inclusive) range:

@@ -650,6 +854,7 @@ ECHO $(x[3]) ;   # prints "3"
 ECHO $(x[2-4]) ; # prints "2 3 4"
 ECHO $(x[2-]) ;  # prints "2 3 4 5"
 
+

Boost Jam adds Python-style negative indexing to access locations relative to the end of the list.

@@ -658,10 +863,28 @@ ECHO $(x[-3--1]) ;       # prints "3 4 5"
 ECHO $(x[-3-4]) ;        # prints "3 4"
 ECHO $(x[2--2]) ;        # prints "2 3 4"       
 
+

Consistency with the 1-based, inclusive indexing of Classic Jam and the use of ``-'' as the range separator make this feature a bit clumsier than it would otherwise need to be, but it does work.

+ +

Support for Cygwin

+ +

When invoking Windows-based tools from Cygwin it can be important to pass them true + windows-style paths. Boost.Jam supplies the :W modifier + which, under Cygwin only, turns a cygwin path into a Win32 path + using the + cygwin_conv_to_win32_path function. On other platforms, the + string is unchanged.

+
+x = /cygdrive/c/Program Files/Borland ;
+ECHO $(x:W) ; # prints "c:\Program Files\Borland" on Cygwin
+
+

Target Binding Detection

+

Whenever a target is bound to a location in the filesystem, Boost Jam will look for a variable called BINDRULE (first ``on'' the target being bound, then in the global @@ -672,11 +895,14 @@ ECHO $(x[2--2]) ; # prints "2 3 4"

 rule bind-rule ( target : path )
 
+

This facility is useful for correct header file scanning, since many compilers will search for #included files first in the directory containing the file doing the #include directive. $(BINDRULE) can be used to make a record of that directory.

+

Return Code Inversion

+

For handling targets whose build actions are expected to fail (e.g. when testing that assertions or compile-time type checkin work properly), Boost Jam supplies a FAIL_EXPECTED rule in the same style as @@ -684,29 +910,37 @@ rule bind-rule ( target : path ) build actions for arguments to FAIL_EXPECTED is inverted: if it fails, building of dependent targets continues as though it succeeded. If it succeeds, dependent targets are skipped.

+

Ignoring Return Codes

+

Perforce Jam supplied a NOCARE rule which is typically used for header files to indicate that if they are not found, the dependent targets should be built anyway. Boost Jam extends NOCARE to apply to targets with build actions: if their build actions exit with a nonzero return code, dependent targets will still be built.

+

Removing Outdated Targets

 rule RMOLD ( targets * )
 
+

Perforce Jam removes any target files that may exist on disk when the rule used to build those targets fails. However, targets whose dependencies fail to build are not removed by default. The RMOLD rule causes its arguments to be removed if any of their dependencies fail to build.

+

The SUBST Rule

+

Note: the SUBST rule is deprecated in favor of Perforce Jam's built-in MATCH rule, which has been rolled into Boost.Jam.

+

The behavior of the SUBST rule for regular-expression matching and replacement (originally added in FTJam) has been modified:

+
  • One or more replacement patterns may be supplied. The new signature @@ -721,43 +955,56 @@ SUBST ( source pattern replacements + ) ECHO [ SUBST xyz (.)(.)(.) [$1] ($2) {$3} ] ;
  • +
  • If there is no match, SUBST now returns an empty list. In FTJam, the original source string was returned, making it awkward to check whether a pattern was matched.
  • +
  • Compiled regular expressions are now internally cached, making it much faster to use SUBST multiple times with the same string.
+

The JAM_VERSION global variable

+

A predefined global variable with two elements indicates the version number of Boost Jam. Boost Jam versions start at "03" "00". Earlier versions of Jam do not automatically define JAM_VERSION.

+

Debugging Support

+

The BACKTRACE rule

 rule BACKTRACE ( )
 
+

Returns a list of quadruples: filename line module rulename..., describing each shallower level of the call stack. This rule can be used to generate useful diagnostic messages from Jam rules.

+

The -d command-line option admits new arguments:

+
  • -d+10 - enables profiling of rule invocations. When Jam exits, it dumps all rules invoked, their gross and net times in platform-dependent units, and the number of times the rule was invoked.
  • +
  • -d+11 - enables parser debugging, if Jam has been compiled with the "--debug" option to the parser generator named by $(YACC).
  • +
  • -d+12 - enables dependency graph output . This feature was ``stolen'' from a version of Jam modified by Craig McPheeters.
+

The UPDATE rule and changes to command line handling

+

Classic jam treats any non-option element of command line as a name of target to be updated. This prevented more sophisticated handling of command line. This is now enabled again but with additional changes to @@ -766,6 +1013,7 @@ rule BACKTRACE ( )

 rule UPDATE ( targets * )
 
+

The rule has two effects: 1. it clears the list of targets to update, and 2. causes the specified targets to be updated. If no target was specified with the UPDATE rule, no targets will be updated. To @@ -776,25 +1024,33 @@ rule UPDATE ( targets * ) local previous-updates = [ UPDATE ] ; UPDATE $(previous-updates) a-new-target ; +

Semaphores

+

It is sometimes desirable to disallow parallel execution of some actions. For example:

+
  • Old versions of yacc use files with fixed names. So, running two yacc actions is dangerous.
  • +
  • One might want to perform parallel compiling, but not do parallel linking, because linking is i/o bound and only gets slower.
Craig McPeeters has extended Perforce Jam to solve such problems, and that extension was integrated in Boost.Jam. +

Any target can be assigned a semaphore, by setting a variable called SEMAPHORE on that target. The value of the variable is the semaphore name. It must be different from names of any declared target, but is arbitrary otherwise.

+

The semantic of semaphores is that in a group of targets which have the same semaphore, only one can be updated at the moment, regardless of "-j" option.

+

Jam Fundamentals

+

This section is derived from the official Jam documentation and from my experience using it and reading the Jambase rules. I repeat the information here mostly because it is essential to understanding and @@ -802,11 +1058,14 @@ UPDATE $(previous-updates) a-new-target ; missing from the official documentation altogether. I hope it will be useful to anyone wishing to become familiar with Jam and the Boost build system.

+

· Jam ``rules'' are actually simple procedural entities. Think of them as functions. Arguments are separated by colons.

+

· A Jam target is an abstract entity identified by an arbitrary string. The build-in DEPENDS rule creates a link in the dependency graph between the named targets.

+

· Note that the documentation for the built-in INCLUDES rule is incorrect: INCLUDES targets1 : targets2 causes everything @@ -816,21 +1075,25 @@ UPDATE $(previous-updates) a-new-target ; targets1. It seems to be OK to create circular dependencies this way; in fact, it appears to be the ``right thing to do'' when a single build action produces both targets1 and targets2.

+

· When a rule is invoked, if there are actions declared with the same name as the rule, the actions are added to the updating actions for the target identified by the rule's first argument. It is actually possible to invoke an undeclared rule if corresponding actions are declared: the rule is treated as empty.

+

· Targets (other than NOTFILE targets) are associated with paths in the file system through a process called binding. Binding is a process of searching for a file with the same name as the target (sans grist), based on the settings of the target-specific SEARCH and LOCATE variables.

+

· In addition to local and global variables, jam allows you to set a variable on a target. Target-specific variable values can usually not be read, and take effect only in the following contexts:

+
  • In updating actions, variable values are first looked up on the target named by the first argument (the target @@ -838,20 +1101,24 @@ UPDATE $(previous-updates) a-new-target ; executing actions, Jam rules make target-specific variable settings as a way of supplying parameters to the corresponding actions.
  • +
  • Binding is controlled entirely by the target-specific setting of the SEARCH and LOCATE variables, as described here.
  • +
  • In the special rule used for header file scanning, variable values are first looked up on the target named by the rule's first argument (the source file being scanned).
+

· The ``bound value'' of a variable is the path associated with the target named by the variable. In build actions, the first two arguments are automatically replaced with their bound values. Target-specific variables can be selectively replaced by their bound values using the bind action modifier.

+

· Note that the term ``binding'' as used in the Jam documentation indicates a phase of processing that includes three sub-phases: binding (yes!), update determination, and header file @@ -859,6 +1126,7 @@ UPDATE $(previous-updates) a-new-target ; confusion. In particular, the Modifying Binding section in the Jam documentation should probably be titled ``Modifying Update Determination''.

+

· ``Grist'' is just a string prefix of the form <characters>. It is used in Jam to create unique target names based on simpler names. For example, the file name @@ -870,15 +1138,18 @@ UPDATE $(previous-updates) a-new-target ; concatenating multiple gristed elements at the beginning of a string. Grist is used instead of identifying targets with absolute paths for two reasons:

+
  1. The location of targets cannot always be derived solely from what the user puts in a Jamfile, but sometimes depends also on the binding process. Some mechanism to distinctly identify targets with the same name is still needed.
  2. +
  3. Grist allows us to use a uniform abstract identifier for each built target, regardless of target file location (as allowed by setting ALL_LOCATE_TARGET.
+

When grist is extracted from a name with $(var:G), the result includes the leading and trailing angle brackets. When grist is added to a name with @@ -887,6 +1158,7 @@ UPDATE $(previous-updates) a-new-target ; and trailing >s are added if necessary to form an expression of the form <expr2>; <expr2> is then prepended.

+

· When Jam is invoked it imports all environment variable settings into corresponding Jam variables, followed by all command-line (-s...) variable @@ -896,6 +1168,7 @@ UPDATE $(previous-updates) a-new-target ; Windows). All other variables are split on space (" ") boundaries. Boost Jam modifies that behavior by allowing variables to be quoted.

+

· A variable whose value is an empty list or which consists entirely of empty strings has a negative logical value. Thus, for example, code like the following allows a sensible non-empty default @@ -904,17 +1177,22 @@ UPDATE $(previous-updates) a-new-target ; MESSAGE ?= starting jam... ; if $(MESSAGE) { ECHO The message is: $(MESSAGE) ; } +

If the user wants a specific message, he invokes jam with "-sMESSAGE=message text". If he wants no message, he invokes jam with -sMESSAGE= and nothing at all is printed.

+

· The parsing of command line options in Jam can be rather unintuitive, with regards to how other Unix programs accept options. There are two variants accepted as valid for an option:

+
  1. -xvalue, and
  2. +
  3. -x value.
+

Please also read The Jam language reference for the additional details, and the Jam release notes for a brief description of recent, but fundamental changes @@ -922,11 +1200,13 @@ if $(MESSAGE) { ECHO The message is: $(MESSAGE) ; } any of the build system code. In particular, note that the return statement does not affect control flow.


+

Revised 2 February, 2003

+

© Copyright René Rivera, David Abrahams, Vladimir Prus 2003. All Rights Reserved. Permission to copy, use, modify, sell and distribute this document is @@ -935,3 +1215,4 @@ if $(MESSAGE) { ECHO The message is: $(MESSAGE) ; } with no claim as to its suitability for any purpose.

+ diff --git a/jam_src/expand.c b/jam_src/expand.c index 1aa8c1545..0f54674d6 100644 --- a/jam_src/expand.c +++ b/jam_src/expand.c @@ -6,6 +6,11 @@ # include "newstr.h" # include +# ifdef OS_CYGWIN +# include +# include +# endif + /* * expand.c - expand a buffer, given variable values * @@ -30,7 +35,8 @@ typedef struct { char filemods; /* one of the above applied */ char downshift; /* :L -- downshift result */ char upshift; /* :U -- upshift result */ - char to_slashes; /* :T -- convert "\" to "/" */ + char to_slashes; /* :T -- convert "\" to "/" */ + char to_windows; /* :W -- convert cygwin to native paths */ PATHPART empty; /* :E -- default for empties */ PATHPART join; /* :J -- join list with char */ } VAR_EDITS ; @@ -63,51 +69,51 @@ var_expand( LOL *lol, int cancopyin ) { - char out_buf[ MAXSYM ]; + char out_buf[ MAXSYM ]; string buf[1]; - string out1; /* Temporary buffer */ + string out1[1]; /* Temporary buffer */ size_t prefix_length; char *out; - char *inp = in; - char *ov; /* for temp copy of variable in outbuf */ - int depth; + char *inp = in; + char *ov; /* for temp copy of variable in outbuf */ + int depth; - if( DEBUG_VAREXP ) - printf( "expand '%.*s'\n", end - in, in ); + if( DEBUG_VAREXP ) + printf( "expand '%.*s'\n", end - in, in ); - /* This gets alot of cases: $(<) and $(>) */ + /* This gets alot of cases: $(<) and $(>) */ - if( in[0] == '$' && in[1] == '(' && in[3] == ')' && !in[4] ) - { - switch( in[2] ) - { - case '1': - case '<': - return list_copy( l, lol_get( lol, 0 ) ); - - case '2': - case '>': - return list_copy( l, lol_get( lol, 1 ) ); - } - } - - /* Just try simple copy of in to out. */ - - while( in < end ) - if( *in++ == '$' && *in == '(' ) - goto expand; - - /* No variables expanded - just add copy of input string to list. */ - - /* Cancopyin is an optimization: if the input was already a list */ - /* item, we can use the copystr() to put it on the new list. */ - /* Otherwise, we use the slower newstr(). */ - - if( cancopyin ) + if( in[0] == '$' && in[1] == '(' && in[3] == ')' && !in[4] ) { - return list_new( l, copystr( inp ) ); + switch( in[2] ) + { + case '1': + case '<': + return list_copy( l, lol_get( lol, 0 ) ); + + case '2': + case '>': + return list_copy( l, lol_get( lol, 1 ) ); + } } - else + + /* Just try simple copy of in to out. */ + + while( in < end ) + if( *in++ == '$' && *in == '(' ) + goto expand; + + /* No variables expanded - just add copy of input string to list. */ + + /* Cancopyin is an optimization: if the input was already a list */ + /* item, we can use the copystr() to put it on the new list. */ + /* Otherwise, we use the slower newstr(). */ + + if( cancopyin ) + { + return list_new( l, copystr( inp ) ); + } + else { LIST* r; string_new( buf ); @@ -118,342 +124,342 @@ var_expand( return r; } - expand: +expand: string_new( buf ); string_append_range( buf, inp, in - 1); /* copy the part before '$'. */ - /* - * Input so far (ignore blanks): - * - * stuff-in-outbuf $(variable) remainder - * ^ ^ - * in end - * Output so far: - * - * stuff-in-outbuf $ - * ^ ^ - * out_buf out - * - * - * We just copied the $ of $(...), so back up one on the output. - * We now find the matching close paren, copying the variable and - * modifiers between the $( and ) temporarily into out_buf, so that - * we can replace :'s with MAGIC_COLON. This is necessary to avoid - * being confused by modifier values that are variables containing - * :'s. Ugly. - */ + /* + * Input so far (ignore blanks): + * + * stuff-in-outbuf $(variable) remainder + * ^ ^ + * in end + * Output so far: + * + * stuff-in-outbuf $ + * ^ ^ + * out_buf out + * + * + * We just copied the $ of $(...), so back up one on the output. + * We now find the matching close paren, copying the variable and + * modifiers between the $( and ) temporarily into out_buf, so that + * we can replace :'s with MAGIC_COLON. This is necessary to avoid + * being confused by modifier values that are variables containing + * :'s. Ugly. + */ - depth = 1; + depth = 1; inp = ++in; /* skip over the '(' */ - while( in < end && depth ) - { - switch( *in++ ) - { - case '(': depth++; break; - case ')': depth--; break; - } - } + while( in < end && depth ) + { + switch( *in++ ) + { + case '(': depth++; break; + case ')': depth--; break; + } + } - /* - * Input so far (ignore blanks): - * - * stuff-in-outbuf $(variable) remainder - * ^ ^ ^ - * inp in end - */ - prefix_length = buf->size; - string_append_range( buf, inp, in - 1 ); + /* + * Input so far (ignore blanks): + * + * stuff-in-outbuf $(variable) remainder + * ^ ^ ^ + * inp in end + */ + prefix_length = buf->size; + string_append_range( buf, inp, in - 1 ); - out = buf->value + prefix_length; - for ( ov = out; ov < buf->value + buf->size; ++ov ) - { - switch( *ov ) - { - case ':': *ov = MAGIC_COLON; break; - case '[': *ov = MAGIC_LEFT; break; - case ']': *ov = MAGIC_RIGHT; break; - } - } + out = buf->value + prefix_length; + for ( ov = out; ov < buf->value + buf->size; ++ov ) + { + switch( *ov ) + { + case ':': *ov = MAGIC_COLON; break; + case '[': *ov = MAGIC_LEFT; break; + case ']': *ov = MAGIC_RIGHT; break; + } + } - /* - * Input so far (ignore blanks): - * - * stuff-in-outbuf $(variable) remainder - * ^ ^ - * in end - * Output so far: - * - * stuff-in-outbuf variable - * ^ ^ ^ - * out_buf out ov - * - * Later we will overwrite 'variable' in out_buf, but we'll be - * done with it by then. 'variable' may be a multi-element list, - * so may each value for '$(variable element)', and so may 'remainder'. - * Thus we produce a product of three lists. - */ + /* + * Input so far (ignore blanks): + * + * stuff-in-outbuf $(variable) remainder + * ^ ^ + * in end + * Output so far: + * + * stuff-in-outbuf variable + * ^ ^ ^ + * out_buf out ov + * + * Later we will overwrite 'variable' in out_buf, but we'll be + * done with it by then. 'variable' may be a multi-element list, + * so may each value for '$(variable element)', and so may 'remainder'. + * Thus we produce a product of three lists. + */ - { - LIST *variables = 0; - LIST *remainder = 0; - LIST *vars; + { + LIST *variables = 0; + LIST *remainder = 0; + LIST *vars; - /* Recursively expand variable name & rest of input */ + /* Recursively expand variable name & rest of input */ - if( out < ov ) - variables = var_expand( L0, out, ov, lol, 0 ); - if( in < end ) - remainder = var_expand( L0, in, end, lol, 0 ); + if( out < ov ) + variables = var_expand( L0, out, ov, lol, 0 ); + if( in < end ) + remainder = var_expand( L0, in, end, lol, 0 ); - /* Now produce the result chain */ + /* Now produce the result chain */ - /* For each variable name */ + /* For each variable name */ - for( vars = variables; vars; vars = list_next( vars ) ) - { - LIST *value, *evalue = 0; - char *colon; - char *bracket; - string variable; - char *varname; - int sub1 = 0, sub2 = -1; - VAR_EDITS edits; + for( vars = variables; vars; vars = list_next( vars ) ) + { + LIST *value, *evalue = 0; + char *colon; + char *bracket; + string variable[1]; + char *varname; + int sub1 = 0, sub2 = -1; + VAR_EDITS edits; - /* Look for a : modifier in the variable name */ - /* Must copy into varname so we can modify it */ + /* Look for a : modifier in the variable name */ + /* Must copy into varname so we can modify it */ - string_copy( &variable, vars->string ); - varname = variable.value; + string_copy( variable, vars->string ); + varname = variable->value; - if( colon = strchr( varname, MAGIC_COLON ) ) - { - string_truncate( &variable, colon - varname ); - var_edit_parse( colon + 1, &edits ); - } + if( colon = strchr( varname, MAGIC_COLON ) ) + { + string_truncate( variable, colon - varname ); + var_edit_parse( colon + 1, &edits ); + } - /* Look for [x-y] subscripting */ - /* sub1 and sub2 are x and y. */ + /* Look for [x-y] subscripting */ + /* sub1 and sub2 are x and y. */ - if ( bracket = strchr( varname, MAGIC_LEFT ) ) + if ( bracket = strchr( varname, MAGIC_LEFT ) ) + { + /* + ** Make all syntax errors in [] subscripting + ** result in the same behavior: silenty return an empty + ** expansion (by setting sub2 = 0). Brute force parsing; + ** May get moved into yacc someday. + */ + + char *s = bracket + 1; + + string_truncate( variable, bracket - varname ); + + do /* so we can use "break" */ { - /* - ** Make all syntax errors in [] subscripting - ** result in the same behavior: silenty return an empty - ** expansion (by setting sub2 = 0). Brute force parsing; - ** May get moved into yacc someday. - */ - - char *s = bracket + 1; - - string_truncate( &variable, bracket - varname ); - - do /* so we can use "break" */ + /* Allow negative indexes. */ + if (! isdigit( *s ) && ! ( *s == '-') ) { - /* Allow negative indexes. */ - if (! isdigit( *s ) && ! ( *s == '-') ) - { - sub2 = 0; - break; - } - sub1 = atoi(s); + sub2 = 0; + break; + } + sub1 = atoi(s); - /* Skip over the first symbol, which is either a digit or dash. */ - s++; - while ( isdigit( *s ) ) s++; + /* Skip over the first symbol, which is either a digit or dash. */ + s++; + while ( isdigit( *s ) ) s++; - if ( *s == MAGIC_RIGHT ) - { - sub2 = sub1; - break; - } + if ( *s == MAGIC_RIGHT ) + { + sub2 = sub1; + break; + } - if ( *s != '-') - { - sub2 = 0; - break; - } + if ( *s != '-') + { + sub2 = 0; + break; + } - s++; + s++; - if ( *s == MAGIC_RIGHT ) - { - sub2 = -1; - break; - } + if ( *s == MAGIC_RIGHT ) + { + sub2 = -1; + break; + } - if (! isdigit( *s ) && ! ( *s == '-') ) - { - sub2 = 0; - break; - } + if (! isdigit( *s ) && ! ( *s == '-') ) + { + sub2 = 0; + break; + } - /* First, compute the index of the last element. */ - sub2 = atoi(s); - s++; - while ( isdigit( *s ) ) s++; + /* First, compute the index of the last element. */ + sub2 = atoi(s); + s++; + while ( isdigit( *s ) ) s++; - if ( *s != MAGIC_RIGHT) - sub2 = 0; - - } while (0); - - /* - ** Anything but the end of the string, or the colon - ** introducing a modifier is a syntax error. - */ - - s++; - if (*s && *s != MAGIC_COLON) + if ( *s != MAGIC_RIGHT) sub2 = 0; - *bracket = '\0'; + } while (0); + + /* + ** Anything but the end of the string, or the colon + ** introducing a modifier is a syntax error. + */ + + s++; + if (*s && *s != MAGIC_COLON) + sub2 = 0; + + *bracket = '\0'; + } + + /* Get variable value, specially handling $(<), $(>), $(n) */ + + if( varname[0] == '<' && !varname[1] ) + value = lol_get( lol, 0 ); + else if( varname[0] == '>' && !varname[1] ) + value = lol_get( lol, 1 ); + else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] ) + value = lol_get( lol, varname[0] - '1' ); + else + value = var_get( varname ); + + /* Handle negitive indexes: part two. */ + { + int length = list_length( value ); + + if (sub1 < 0) + sub1 = length + sub1; + else + sub1 -= 1; + + if (sub2 < 0) + sub2 = length + 1 + sub2 - sub1; + else + sub2 -= sub1; + /* + ** The "sub2 < 0" test handles the semantic error + ** of sub2 < sub1. + */ + if ( sub2 < 0 ) + sub2 = 0; + } + + + + /* The fast path: $(x) - just copy the variable value. */ + /* This is only an optimization */ + + if( out == out_buf && !bracket && !colon && in == end ) + { + string_free( variable ); + l = list_copy( l, value ); + continue; + } + + /* Handle start subscript */ + + while( sub1 > 0 && value ) + --sub1, value = list_next( value ); + + /* Empty w/ :E=default? */ + + if( !value && colon && edits.empty.ptr ) + evalue = value = list_new( L0, newstr( edits.empty.ptr ) ); + + /* For each variable value */ + + string_new( out1 ); + for( ; value; value = list_next( value ) ) + { + LIST *rem; + size_t postfix_start; + + /* Handle end subscript (length actually) */ + + if( sub2 >= 0 && --sub2 < 0 ) + break; + + string_truncate( buf, prefix_length ); + + /* Apply : mods, if present */ + + if( colon && edits.filemods ) + var_edit_file( value->string, out1, &edits ); + else + string_append( out1, value->string ); + + if( colon && ( edits.upshift || edits.downshift || edits.to_slashes || edits.to_windows ) ) + var_edit_shift( out1, &edits ); + + /* Handle :J=joinval */ + /* If we have more values for this var, just */ + /* keep appending them (with the join value) */ + /* rather than creating separate LIST elements. */ + + if( colon && edits.join.ptr && + ( list_next( value ) || list_next( vars ) ) ) + { + string_append( out1, edits.join.ptr ); + continue; } - /* Get variable value, specially handling $(<), $(>), $(n) */ - - if( varname[0] == '<' && !varname[1] ) - value = lol_get( lol, 0 ); - else if( varname[0] == '>' && !varname[1] ) - value = lol_get( lol, 1 ); - else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] ) - value = lol_get( lol, varname[0] - '1' ); - else - value = var_get( varname ); + string_append( buf, out1->value ); + string_free( out1 ); + string_new( out1 ); - /* Handle negitive indexes: part two. */ - { - int length = list_length( value ); + /* If no remainder, append result to output chain. */ - if (sub1 < 0) - sub1 = length + sub1; - else - sub1 -= 1; + if( in == end ) + { + l = list_new( l, newstr( buf->value ) ); + continue; + } - if (sub2 < 0) - sub2 = length + 1 + sub2 - sub1; - else - sub2 -= sub1; - /* - ** The "sub2 < 0" test handles the semantic error - ** of sub2 < sub1. - */ - if ( sub2 < 0 ) - sub2 = 0; + /* For each remainder, append the complete string */ + /* to the output chain. */ + /* Remember the end of the variable expansion so */ + /* we can just tack on each instance of 'remainder' */ + + postfix_start = buf->size; + + for( rem = remainder; rem; rem = list_next( rem ) ) + { + string_truncate( buf, postfix_start ); + string_append( buf, rem->string ); + l = list_new( l, newstr( buf->value ) ); + } + } + string_free( out1 ); + + /* Toss used empty */ + + if( evalue ) + list_free( evalue ); + + string_free( variable ); } + /* variables & remainder were gifts from var_expand */ + /* and must be freed */ + if( variables ) + list_free( variables ); + if( remainder) + list_free( remainder ); - /* The fast path: $(x) - just copy the variable value. */ - /* This is only an optimization */ - - if( out == out_buf && !bracket && !colon && in == end ) - { - string_free( &variable ); - l = list_copy( l, value ); - continue; - } - - /* Handle start subscript */ - - while( sub1 > 0 && value ) - --sub1, value = list_next( value ); - - /* Empty w/ :E=default? */ - - if( !value && colon && edits.empty.ptr ) - evalue = value = list_new( L0, newstr( edits.empty.ptr ) ); - - /* For each variable value */ - - string_new( &out1 ); - for( ; value; value = list_next( value ) ) - { - LIST *rem; - size_t postfix_start; - - /* Handle end subscript (length actually) */ - - if( sub2 >= 0 && --sub2 < 0 ) - break; - - string_truncate( buf, prefix_length ); - - /* Apply : mods, if present */ - - if( colon && edits.filemods ) - var_edit_file( value->string, &out1, &edits ); - else - string_append( &out1, value->string ); - - if( colon && ( edits.upshift || edits.downshift || edits.to_slashes ) ) - var_edit_shift( &out1, &edits ); - - /* Handle :J=joinval */ - /* If we have more values for this var, just */ - /* keep appending them (with the join value) */ - /* rather than creating separate LIST elements. */ - - if( colon && edits.join.ptr && - ( list_next( value ) || list_next( vars ) ) ) - { - string_append( &out1, edits.join.ptr ); - continue; - } - - string_append( buf, out1.value ); - string_free( &out1 ); - string_new( &out1 ); - - /* If no remainder, append result to output chain. */ - - if( in == end ) - { - l = list_new( l, newstr( buf->value ) ); - continue; - } - - /* For each remainder, append the complete string */ - /* to the output chain. */ - /* Remember the end of the variable expansion so */ - /* we can just tack on each instance of 'remainder' */ - - postfix_start = buf->size; - - for( rem = remainder; rem; rem = list_next( rem ) ) - { - string_truncate( buf, postfix_start ); - string_append( buf, rem->string ); - l = list_new( l, newstr( buf->value ) ); - } - } - string_new( &out1 ); - - /* Toss used empty */ - - if( evalue ) - list_free( evalue ); - - string_free( &variable ); - } - - /* variables & remainder were gifts from var_expand */ - /* and must be freed */ - - if( variables ) - list_free( variables ); - if( remainder) - list_free( remainder ); - - if( DEBUG_VAREXP ) - { - printf( "expanded to " ); - list_print( l ); - printf( "\n" ); - } + if( DEBUG_VAREXP ) + { + printf( "expanded to " ); + list_print( l ); + printf( "\n" ); + } string_free( buf ); - return l; - } + return l; + } } /* @@ -517,7 +523,8 @@ var_edit_parse( case 'B': fp = &edits->f.f_base; goto fileval; case 'S': fp = &edits->f.f_suffix; goto fileval; case 'M': fp = &edits->f.f_member; goto fileval; - case 'T': edits->to_slashes = 1; continue; + case 'T': edits->to_slashes = 1; continue; + case 'W': edits->to_windows = 1; continue; default: return; /* should complain, but so what... */ } @@ -644,6 +651,16 @@ var_edit_shift( if ( *p == '\\') *p = '/'; } +# ifdef OS_CYGWIN + if ( edits->to_windows ) + { + char result[MAX_PATH + 1]; + cygwin_conv_to_win32_path(out->value, result); + assert(strlen(result) <= MAX_PATH); + string_free( out ); + string_copy( out, result ); + } +# endif } out->size = p - out->value; } @@ -657,19 +674,33 @@ void var_expand_unit_test() LIST *e2; char axyb[] = "a$(xy)b"; char azb[] = "a$($(z))b"; - + char path[] = "$(p:W)"; + lol_init(lol); var_set("xy", list_new( list_new( L0, newstr( "x" ) ), newstr( "y" ) ), VAR_SET ); var_set("z", list_new( L0, newstr( "xy" ) ), VAR_SET ); - + var_set("p", list_new( L0, newstr( "/cygdrive/c/foo/bar" ) ), VAR_SET ); + l = var_expand( 0, axyb, axyb + sizeof(axyb) - 1, lol, 0 ); for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next(l2), e2 = list_next(e2) ) assert( !strcmp( e2->string, l2->string ) ); + assert(l2 == 0 && e2 == 0); list_free(l); l = var_expand( 0, azb, azb + sizeof(azb) - 1, lol, 0 ); for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next(l2), e2 = list_next(e2) ) assert( !strcmp( e2->string, l2->string ) ); + assert(l2 == 0 && e2 == 0); + list_free(l); + + l = var_expand( 0, path, path + sizeof(path) - 1, lol, 0 ); + assert(l != 0); + assert(list_next(l) == 0); +# ifdef OS_CYGWIN + assert( !strcmp( l->string, "c:\\foo\\bar" ) ); +# else + assert( !strcmp( l->string, "/cygdrive/c/foo/bar" ) ); +# endif list_free(l); list_free(expected); diff --git a/jam_src/index.html b/jam_src/index.html index 71333e5f4..8cd31972d 100644 --- a/jam_src/index.html +++ b/jam_src/index.html @@ -1,15 +1,18 @@ + + "HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org"> + Boost.Jam + @@ -19,8 +22,10 @@

C++ Boost

+ @@ -28,64 +33,108 @@

Boost.Jam

+



+
Introduction
+
Features
+
Contents
+
Installing
+
Core Jam Extensions
+
Command-line and Environment Variable Quoting
+
Startup Behavior
+
Rule Indirection
+
Argument Lists
+
Module Support
+
Declaration
+
Variable Scope
+
Local Rules
+
The RULENAMES rule
+ +
The VARNAMES + rule
+
The IMPORT rule
+
The EXPORT rule
-
The CALLER_MODULE + +
The + CALLER_MODULE
+ +
The DELETE_MODULE rule
+
Local for Loop Variables
+
Negative Indexing
+ +
Support for Cygwin
+
Target Binding Detection
+
Return Code Inversion
+
Ignoring Return Codes
+
Removing outdated targets
+
The SUBST Rule
+
The JAM_VERSION global variable
+
Debugging Support
+
The BACKTRACE rule
+
Profiling
+
Parser Debugging
+
Dependency Graph Output
+
The UPDATE rule and changes to command line handling
+
Semaphores
+
Jam Fundamentals
+

Introduction

+

Boost.Jam (BJam)  is a build tool based on FTJam, which in turn is based on Perforce Jam. It contains significant improvements made to facilitate its use in the Boost Build System, but should be backward compatible with Perforce Jam.

+

This is version 3.1.4 of BJam and is based on version 2.4 of Jam/MR:

@@ -98,9 +147,12 @@ freely, as long as this copyright notice is retained and modifications
 are clearly marked.
 ALL WARRANTIES ARE HEREBY DISCLAIMED.
 
+

Features

+

Jam is a make(1) replacement that makes building simple things simple and building complicated things manageable.

+

Jam's language is expressive, making Jamfiles (c.f. Makefiles) compact.  Here's a sample:

@@ -108,44 +160,62 @@ Main smail : main.c map.c resolve.c deliver.c
      misc.c parser.y alias.c pw.c headers.c
      scanner.l getpath.c str.c ;
 
+

This builds "smail" from a dozen source files.  Jam handles header file dependencies automatically and on-the-fly.

+

Jam is very portable: it runs on UNIX, VMS, Mac, and NT. Most Jamfiles themselves are portable, like the sample above.

+

Jam is unintrusive: it is small, it has negligible CPU overhead, and it doesn't create any of its own funny files (c.f. Odin, nmake, SunOS make).

+

Jam can build large projects spread across many directories in one pass, without recursing, tracking the relationships among all files. Jam can do this with multiple, concurrent processes.

+

Jam isn't under the blinkin GNU copyright, so you can incorporate it into commercial products.

+

Contents

+ + + + + + + + + +
Jam.htmlJam and language reference.
Jambase.htmlReference for the Jambase boilerplate file.
Jamfile.htmlEasy reading on creating a Jamfile and using jam.
RELNOTESRelease 2.4 release notes.
PortingNotes on porting jam to wildcat platforms.
+

Installing

+

Installing BJam after building it is simply a matter of copying the generated executables someplace in your PATH. For building the executables there are a set of build bootstrap scripts to @@ -156,162 +226,215 @@ Main smail : main.c map.c resolve.c deliver.c

 <build script name> [toolset]
 
+

Running the scripts without arguments will give you the best chance of success. On Windows platforms from a command console do:

 cd <jam source location>
 .\build.bat
 
+

On Unix type platforms do:

 cd <jam source location>
 sh ./build.sh
 
+

If the scripts fail to detect an appropriate toolset to build with your particular toolset may not be auto-detectable. In that case, you can specify the toolset as the first argument, this assumes that the toolset is readily available in the PATH. The supported toolsets, and wether they are auto-detected, are:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ScriptPlatformsToolsetsDetection
build.batWindows NT, 2000, and XPcomo, Comeau.Computing C/C++ 
borland, Borland C++Builder (BCC 5.5)* Common install location: "C:\Borland\BCC55"
* BCC32.EXE in PATH
gcc, GNU GCC 
gcc-nocygwin, GNU GCC 
intel-win32, Intel C++ Compiler for Windows* ICL.EXE in PATH
metrowerks, MetroWerks CodeWarrior C/C++ 7.x, 8.x* CWFolder variable configured
* MWCC.EXE in PATH
mingw, GNU GCC as the MinGW configuration 
msvc, Microsoft Visual C++ 6.x* VCVARS32.BAT already configured
* Common install locations: "C:\Program Files\Microsoft Visual Studio", "C:\Program Files\Microsoft Visual C++"
* CL.EXE in PATH
vc7, Microsoft Visual C++ 7.x* Common install location: "C:\Program Files\Microsoft Visual Studio .NET"
build.shUnix, Linux, Cygwin, etc.acc, HP-UX aCC* aCC in PATH
* uname is "HP-UX"
como, Comeau.Computing C/C++* como in PATH
gcc, GNU GCC* gcc in PATH
intel-linux, Intel C++ for Linux* icc in PATH
* Common install locations: "/opt/intel/compiler70", "/opt/intel/compiler60", "/opt/intel/compiler50"
kcc, Intel KAI C++* KCC in PATH
kylix, Borland C++Builder* bc++ in PATH
mipspro, SGI MIPSpro C 
sunpro, Sun Workshop 6 C++ 
true64cxx, Compaq C++ Compiler for True64 UNIX 
vacpp, IBM VisualAge C++* xlc in PATH
MacOS X
darwin, Apple MacOS X GCC* uname is "Darwin"
+

The built executables are placed in a subdirectory specific to your platform. For example, in Linux running on an Intel x86 compatible chip, the executables are placed in: "bin.linuxx86". There are two @@ -319,6 +442,7 @@ sh ./build.sh are the same binary but with different names. The "jam" invocation is used for compatability with the Perforce Jam/MR functionality, whereas "bjam" is used for the extended Boost.Build functionality.

+

The build scripts support additional invocation arguments for use by developers of Boost.Jam. The extra arguments come after the toolset, and can take the form of "--options" or targets for the @@ -326,19 +450,25 @@ sh ./build.sh

 <build script name> [toolset] [--options* [targets]*]
 
+

There is current only one available option, "--debug", which builds debugging versions of the executable. When built they are placed in their own directory "bin.<platform>.debug".

+

Currently there are two targets supported: dist, and clean. Respectively they: generate packages (compressed archives) as appropriate for distribution in the platform, or remove all the built executables and objects.

+

Core Jam Extensions

+

A number of enhancements have been made to the core language of Classic Jam. These changes were aimed primarily at making it easier to manage the complexity of a large system such as Boost.Build.

+

Command-line and Environment Variable Quoting

+

Classic Jam had an odd behavior with respect to command-line variable ( -s...) and environment variable settings which made it impossible to define an arbitrary @@ -350,6 +480,7 @@ sh ./build.sh

 jam -sMSVCNT="\"\"C:\Program Files\Microsoft Visual C++\VC98\"\"" ...
 
+

The outer quote is for the shell. The middle quote is for Jam, to tell it to take everything within those quotes literally, and the inner quotes are for the shell again when paths are passed as arguments to build @@ -358,19 +489,24 @@ jam -sMSVCNT="\"\"C:\Program Files\Microsoft Visual C++\VC98\"\"" ...

 set MSVCNT=""C:\Program Files\Microsoft Visual C++\VC98\""
 
+

Startup Behavior

+

The Boost.Build v2 initialization behavior has been implemented. This behavior only applies when the executable being invoked is called "bjam" or, for backward-compatibility, when the BOOST_ROOT variable is set.

+
  1. We attempt to load "boost-build.jam" by searching from the current invocation directory up to the root of the file-system. This file is expected to invoke the boost-build rule to indicate where the Boost.Build system files are, and to load them.
  2. +
  3. If boost-build.jam is not found we error and exit, giving brief instructions on possible errors. +
    As a backward-compatibility measure for older versions of Boost.Build, when the BOOST_ROOT variable is set, we @@ -380,15 +516,19 @@ set MSVCNT=""C:\Program Files\Microsoft Visual C++\VC98\"" initialization is complete.
  4. +
  5. The boost-build rule adds its (optional) argument to the front of BOOST_BUILD_PATH, and attempts to load bootstrap.jam from those directories. If a relative path is specified as an argument, it is treated as though it was relative to the boost-build.jam file.
  6. +
  7. If the bootstrap.jam file was not found, we print a likely error message and exit.
+

Rule Indirection

+

Boost Jam allows you to call a rule whose name is held in a variable or computed as the result of an expression:

@@ -396,6 +536,7 @@ x = foo ;
 rule foobar { ECHO foobar ; }   # a trivial rule
 $(x)bar ;                       # invokes foobar
 
+

Furthermore, if the first expression expands to more than one list item, everything after the first item becomes part of the first argument. This allows a crude form of argument binding:

@@ -418,7 +559,9 @@ rule equal ( x y ) # bind 3 to the first argument of equal ECHO [ filter 1 2 3 4 5 4 3 : equal 3 ] ; # prints "3 3" +

Argument lists

+

You can now describe the arguments accepted by a rule, and refer to them by name within the rule. For example, the following prints ``I'm sorry, Dave'' to the console:

@@ -432,31 +575,41 @@ rule report ( pronoun index ? : state : names + ) } report I 2 : sorry : Joe Dave Pete ; +

Each name in a list of formal arguments (separated by ``:'' in the rule declaration) is bound to a single element of the corresponding actual argument unless followed by one of these modifiers:

+ + + + + + + +
SymbolSemantics of preceding symbol
?optional
*Bind to zero or more unbound elements of the actual argument. When ``*'' appears where an argument name is expected, any number of additional arguments are accepted. This feature can be used to implement "varargs" rules.
+Bind to one or more unbound elements of the actual argument.
+

The actual and formal arguments are checked for inconsistencies, which cause Jam to exit with an error code:

@@ -469,21 +622,26 @@ report I 2 : sorry : Joe Dave Pete ;
 # called with: ( I 2  : sorry )
 # missing argument names
 
+

If you omit the list of formal arguments, all checking is bypassed as in ``classic'' Jam. Argument lists drastically improve the reliability and readability of your rules, however, and are strongly recommended for any new Jam code you write.

+

Module Support

+

Boost Jam introduces support for modules, which provide some rudimentary namespace protection for rules and variables. A new keyword, ``module'' was also introduced. The features described in this section are primitives, meaning that they are meant to provide the operations needed to write Jam rules which provide a more elegant module interface.

+

Declaration

 module expression { ... }
 
+

Code within the ... } executes within the module named by evaluating expression. Rule definitions can be found in the module's own namespace, and in the namespace of the global @@ -499,6 +657,7 @@ module expression { ... } } my_module.salute goodbye ; +

When an invoked rule is not found in the current module's namespace, it is looked up in the namespace of the global module, so qualified calls work across modules:

@@ -508,7 +667,9 @@ module your_module rule bedtime ( ) { my_module.salute goodnight ; } } +

Variable Scope

+

Each module has its own set of dynamically nested variable scopes. When execution passes from module A to module B, all the variable bindings from A become unavailable, and are replaced by the bindings that @@ -537,6 +698,7 @@ module B } } +

The only way to access another module's variables is by entering that module:

@@ -551,29 +713,47 @@ rule peek ( module-name ? : variables + )
     Note that because existing variable bindings change whenever a new module
     scope is entered, argument bindings become unavailable. That explains the
     use of "$(>)" in the peek rule above. 
+
     

Local Rules

 local rule rulename...
 
+

The rule is declared locally to the current module. It is not entered in the global module with qualification, and its name will not appear in the result of:

 [ RULENAMES module-name ]
 
+

The RULENAMES Rule

 rule RULENAMES ( module ? )
 
+

Returns a list of the names of all non-local rules in the given module. If module is omitted, the names of all non-local rules in the global module are returned.

+ +

The VARNAMES Rule

+
+rule VARNAMES ( module ? )
+
+ +

Returns a list of the names of all variable bindings in the given + module. If module is omitted, the names of all variable bindings + in the global module are returned. Note:this includes any local + variables in rules from the call stack which have not returned at the + time of the VARNAMES invocation.

+

The IMPORT Rule

+

IMPORT allows rule name aliasing across modules:

 rule IMPORT ( source_module ? : source_rules *
             : target_module ? : target_rules * )
 
+

The IMPORT rule copies rules from the source_module into the target_module as local rules. If either source_module or target_module is not supplied, it @@ -589,11 +769,14 @@ IMPORT m1 : rule1 : m2 : m1-rule1 ; # import all non-local rules from m1 into m2 IMPORT m1 : [ RULENAMES m1 ] : m2 : [ RULENAMES m1 ] ;

+

The EXPORT Rule

+

EXPORT allows rule name aliasing across modules:

 rule EXPORT ( module ? : rules * )
 
+

The EXPORT rule marks rules from the source_module as non-local (and thus exportable). If an element of rules does not name a rule in module, an error is @@ -606,10 +789,12 @@ IMPORT X : r : : r ; # error - r is local in X EXPORT X : r ; IMPORT X : r : : r ; # OK. +

The CALLER_MODULE Rule

 rule CALLER_MODULE ( levels ? )
 
+

CALLER_MODULE returns the name of the module scope enclosing the call to its caller (if levels is supplied, it is interpreted as an integer number of additional levels of call stack to traverse to locate @@ -629,7 +814,24 @@ module Y { callers = [ X.get-caller ] [ Y.call-X ] [ X.call-Y ] ; ECHO {$(callers)} ; + +

The DELETE_MODULE Rule

+
+rule DELETE_MODULE ( module ? )
+
+ +

DELETE_MODULE removes all of the variable bindings and + otherwise-unreferenced rules from the given module (or the global module, + if no module is supplied), and returns their memory to the system. + Note: though it won't affect rules that are currently executing + until they complete, DELETE_MODULE should be used with + extreme care because it will wipe out any others and all variable + (including locals in that module) immediately. Because of the way dynamic + binding works, variables which are shadowed by locals will not be + destroyed, so the results can be really unpredictable.

+

Local For Loop Variables

+

Boost Jam allows you to declare a local for loop control variable right in the loop:

@@ -641,7 +843,9 @@ for local y in $(x)
 }
 ECHO $(y) ;     # prints "4 5 6"
 
+

Negative Indexing

+

Classic Jam supplies 1-based list indexing, and slicing on a closed (inclusive) range:

@@ -650,6 +854,7 @@ ECHO $(x[3]) ;   # prints "3"
 ECHO $(x[2-4]) ; # prints "2 3 4"
 ECHO $(x[2-]) ;  # prints "2 3 4 5"
 
+

Boost Jam adds Python-style negative indexing to access locations relative to the end of the list.

@@ -658,10 +863,28 @@ ECHO $(x[-3--1]) ;       # prints "3 4 5"
 ECHO $(x[-3-4]) ;        # prints "3 4"
 ECHO $(x[2--2]) ;        # prints "2 3 4"       
 
+

Consistency with the 1-based, inclusive indexing of Classic Jam and the use of ``-'' as the range separator make this feature a bit clumsier than it would otherwise need to be, but it does work.

+ +

Support for Cygwin

+ +

When invoking Windows-based tools from Cygwin it can be important to pass them true + windows-style paths. Boost.Jam supplies the :W modifier + which, under Cygwin only, turns a cygwin path into a Win32 path + using the + cygwin_conv_to_win32_path function. On other platforms, the + string is unchanged.

+
+x = /cygdrive/c/Program Files/Borland ;
+ECHO $(x:W) ; # prints "c:\Program Files\Borland" on Cygwin
+
+

Target Binding Detection

+

Whenever a target is bound to a location in the filesystem, Boost Jam will look for a variable called BINDRULE (first ``on'' the target being bound, then in the global @@ -672,11 +895,14 @@ ECHO $(x[2--2]) ; # prints "2 3 4"

 rule bind-rule ( target : path )
 
+

This facility is useful for correct header file scanning, since many compilers will search for #included files first in the directory containing the file doing the #include directive. $(BINDRULE) can be used to make a record of that directory.

+

Return Code Inversion

+

For handling targets whose build actions are expected to fail (e.g. when testing that assertions or compile-time type checkin work properly), Boost Jam supplies a FAIL_EXPECTED rule in the same style as @@ -684,29 +910,37 @@ rule bind-rule ( target : path ) build actions for arguments to FAIL_EXPECTED is inverted: if it fails, building of dependent targets continues as though it succeeded. If it succeeds, dependent targets are skipped.

+

Ignoring Return Codes

+

Perforce Jam supplied a NOCARE rule which is typically used for header files to indicate that if they are not found, the dependent targets should be built anyway. Boost Jam extends NOCARE to apply to targets with build actions: if their build actions exit with a nonzero return code, dependent targets will still be built.

+

Removing Outdated Targets

 rule RMOLD ( targets * )
 
+

Perforce Jam removes any target files that may exist on disk when the rule used to build those targets fails. However, targets whose dependencies fail to build are not removed by default. The RMOLD rule causes its arguments to be removed if any of their dependencies fail to build.

+

The SUBST Rule

+

Note: the SUBST rule is deprecated in favor of Perforce Jam's built-in MATCH rule, which has been rolled into Boost.Jam.

+

The behavior of the SUBST rule for regular-expression matching and replacement (originally added in FTJam) has been modified:

+
  • One or more replacement patterns may be supplied. The new signature @@ -721,43 +955,56 @@ SUBST ( source pattern replacements + ) ECHO [ SUBST xyz (.)(.)(.) [$1] ($2) {$3} ] ;
  • +
  • If there is no match, SUBST now returns an empty list. In FTJam, the original source string was returned, making it awkward to check whether a pattern was matched.
  • +
  • Compiled regular expressions are now internally cached, making it much faster to use SUBST multiple times with the same string.
+

The JAM_VERSION global variable

+

A predefined global variable with two elements indicates the version number of Boost Jam. Boost Jam versions start at "03" "00". Earlier versions of Jam do not automatically define JAM_VERSION.

+

Debugging Support

+

The BACKTRACE rule

 rule BACKTRACE ( )
 
+

Returns a list of quadruples: filename line module rulename..., describing each shallower level of the call stack. This rule can be used to generate useful diagnostic messages from Jam rules.

+

The -d command-line option admits new arguments:

+
  • -d+10 - enables profiling of rule invocations. When Jam exits, it dumps all rules invoked, their gross and net times in platform-dependent units, and the number of times the rule was invoked.
  • +
  • -d+11 - enables parser debugging, if Jam has been compiled with the "--debug" option to the parser generator named by $(YACC).
  • +
  • -d+12 - enables dependency graph output . This feature was ``stolen'' from a version of Jam modified by Craig McPheeters.
+

The UPDATE rule and changes to command line handling

+

Classic jam treats any non-option element of command line as a name of target to be updated. This prevented more sophisticated handling of command line. This is now enabled again but with additional changes to @@ -766,6 +1013,7 @@ rule BACKTRACE ( )

 rule UPDATE ( targets * )
 
+

The rule has two effects: 1. it clears the list of targets to update, and 2. causes the specified targets to be updated. If no target was specified with the UPDATE rule, no targets will be updated. To @@ -776,25 +1024,33 @@ rule UPDATE ( targets * ) local previous-updates = [ UPDATE ] ; UPDATE $(previous-updates) a-new-target ; +

Semaphores

+

It is sometimes desirable to disallow parallel execution of some actions. For example:

+
  • Old versions of yacc use files with fixed names. So, running two yacc actions is dangerous.
  • +
  • One might want to perform parallel compiling, but not do parallel linking, because linking is i/o bound and only gets slower.
Craig McPeeters has extended Perforce Jam to solve such problems, and that extension was integrated in Boost.Jam. +

Any target can be assigned a semaphore, by setting a variable called SEMAPHORE on that target. The value of the variable is the semaphore name. It must be different from names of any declared target, but is arbitrary otherwise.

+

The semantic of semaphores is that in a group of targets which have the same semaphore, only one can be updated at the moment, regardless of "-j" option.

+

Jam Fundamentals

+

This section is derived from the official Jam documentation and from my experience using it and reading the Jambase rules. I repeat the information here mostly because it is essential to understanding and @@ -802,11 +1058,14 @@ UPDATE $(previous-updates) a-new-target ; missing from the official documentation altogether. I hope it will be useful to anyone wishing to become familiar with Jam and the Boost build system.

+

· Jam ``rules'' are actually simple procedural entities. Think of them as functions. Arguments are separated by colons.

+

· A Jam target is an abstract entity identified by an arbitrary string. The build-in DEPENDS rule creates a link in the dependency graph between the named targets.

+

· Note that the documentation for the built-in INCLUDES rule is incorrect: INCLUDES targets1 : targets2 causes everything @@ -816,21 +1075,25 @@ UPDATE $(previous-updates) a-new-target ; targets1. It seems to be OK to create circular dependencies this way; in fact, it appears to be the ``right thing to do'' when a single build action produces both targets1 and targets2.

+

· When a rule is invoked, if there are actions declared with the same name as the rule, the actions are added to the updating actions for the target identified by the rule's first argument. It is actually possible to invoke an undeclared rule if corresponding actions are declared: the rule is treated as empty.

+

· Targets (other than NOTFILE targets) are associated with paths in the file system through a process called binding. Binding is a process of searching for a file with the same name as the target (sans grist), based on the settings of the target-specific SEARCH and LOCATE variables.

+

· In addition to local and global variables, jam allows you to set a variable on a target. Target-specific variable values can usually not be read, and take effect only in the following contexts:

+
  • In updating actions, variable values are first looked up on the target named by the first argument (the target @@ -838,20 +1101,24 @@ UPDATE $(previous-updates) a-new-target ; executing actions, Jam rules make target-specific variable settings as a way of supplying parameters to the corresponding actions.
  • +
  • Binding is controlled entirely by the target-specific setting of the SEARCH and LOCATE variables, as described here.
  • +
  • In the special rule used for header file scanning, variable values are first looked up on the target named by the rule's first argument (the source file being scanned).
+

· The ``bound value'' of a variable is the path associated with the target named by the variable. In build actions, the first two arguments are automatically replaced with their bound values. Target-specific variables can be selectively replaced by their bound values using the bind action modifier.

+

· Note that the term ``binding'' as used in the Jam documentation indicates a phase of processing that includes three sub-phases: binding (yes!), update determination, and header file @@ -859,6 +1126,7 @@ UPDATE $(previous-updates) a-new-target ; confusion. In particular, the Modifying Binding section in the Jam documentation should probably be titled ``Modifying Update Determination''.

+

· ``Grist'' is just a string prefix of the form <characters>. It is used in Jam to create unique target names based on simpler names. For example, the file name @@ -870,15 +1138,18 @@ UPDATE $(previous-updates) a-new-target ; concatenating multiple gristed elements at the beginning of a string. Grist is used instead of identifying targets with absolute paths for two reasons:

+
  1. The location of targets cannot always be derived solely from what the user puts in a Jamfile, but sometimes depends also on the binding process. Some mechanism to distinctly identify targets with the same name is still needed.
  2. +
  3. Grist allows us to use a uniform abstract identifier for each built target, regardless of target file location (as allowed by setting ALL_LOCATE_TARGET.
+

When grist is extracted from a name with $(var:G), the result includes the leading and trailing angle brackets. When grist is added to a name with @@ -887,6 +1158,7 @@ UPDATE $(previous-updates) a-new-target ; and trailing >s are added if necessary to form an expression of the form <expr2>; <expr2> is then prepended.

+

· When Jam is invoked it imports all environment variable settings into corresponding Jam variables, followed by all command-line (-s...) variable @@ -896,6 +1168,7 @@ UPDATE $(previous-updates) a-new-target ; Windows). All other variables are split on space (" ") boundaries. Boost Jam modifies that behavior by allowing variables to be quoted.

+

· A variable whose value is an empty list or which consists entirely of empty strings has a negative logical value. Thus, for example, code like the following allows a sensible non-empty default @@ -904,17 +1177,22 @@ UPDATE $(previous-updates) a-new-target ; MESSAGE ?= starting jam... ; if $(MESSAGE) { ECHO The message is: $(MESSAGE) ; } +

If the user wants a specific message, he invokes jam with "-sMESSAGE=message text". If he wants no message, he invokes jam with -sMESSAGE= and nothing at all is printed.

+

· The parsing of command line options in Jam can be rather unintuitive, with regards to how other Unix programs accept options. There are two variants accepted as valid for an option:

+
  1. -xvalue, and
  2. +
  3. -x value.
+

Please also read The Jam language reference for the additional details, and the Jam release notes for a brief description of recent, but fundamental changes @@ -922,11 +1200,13 @@ if $(MESSAGE) { ECHO The message is: $(MESSAGE) ; } any of the build system code. In particular, note that the return statement does not affect control flow.


+

Revised 2 February, 2003

+

© Copyright René Rivera, David Abrahams, Vladimir Prus 2003. All Rights Reserved. Permission to copy, use, modify, sell and distribute this document is @@ -935,3 +1215,4 @@ if $(MESSAGE) { ECHO The message is: $(MESSAGE) ; } with no claim as to its suitability for any purpose.

+ diff --git a/new/borland.jam b/new/borland.jam index a37acc6f3..abd82cc6f 100644 --- a/new/borland.jam +++ b/new/borland.jam @@ -143,14 +143,23 @@ flags builtin.response-file LIBRARY_PATH_OPTION borland : -L : unchecke flags builtin.response-file LIBRARY_OPTION borland : -l : unchecked ; + # bcc32 needs to have ilink32 in the path in order to invoke it, so explicitly # specifying $(BCC_TOOL_PATH)bcc32 doesn't help. You need to add # $(BCC_TOOL_PATH) to the path # The NEED_IMPLIB variable controls whether we need to invoke implib. +# Declare action for archives. We don't use response file +# since it's hard to get "+-" there. +# CONSIDER: don't know what 'together' is for... +actions updated together piecemeal archive +{ + "$(.root)tlib" /P256 /u /a /C "$(<:W)" +-"$(>:W)" +} + + if [ os.name ] = CYGWIN { - .cygpath = "cygpath -w " ; rule link { if ! $(<[2]) @@ -158,16 +167,9 @@ if [ os.name ] = CYGWIN NEED_IMPLIB on $(<) = ; } } - .set-path = "cmd /S /C set \"PATH=" ; .old-path = ";%PATH%\" \"&&\"" ; - actions link bind LIBRARIES - { - $(.set-path)$(.root)$(.old-path) "$(.root)bcc32" -v -q $(OPTIONS) -L"$(LIBPATH)" -L"$(STDLIBPATH)" -e"`$(.cygpath)$(<[1]:D)`\\$(<[1]:D=)" @"`$(.cygpath)$(>)`" - $(NEED_IMPLIB)"$(.root)implib" $(NEED_IMPLIB)"`$(.cygpath)$(<[2]:D)`\\$(<[2]:D=)" $(NEED_IMPLIB)"`$(.cygpath)$(<[1]:D)`\\$(<[1]:D=)" - } - # Couldn't get TLIB to stop being confused about pathnames # containing dashes (it seemed to treat them as option separators # when passed through from bash), so we explicitly write the @@ -176,39 +178,29 @@ if [ os.name ] = CYGWIN # options. actions updated together piecemeal archive { - echo "\"$(.root)tlib\" /P256 /u /a /C \"`$(.cygpath)$(<:D)`\\$(<:D=)\" +-\"`$(.cygpath)$(>)`\"" > $(<:D)/tlib.bat + echo "\"$(.root)tlib\" /P256 /u /a /C \"$(<:W)\" +-\"$(>:W)\"" > $(<:D)/tlib.bat chmod +x $(<:D)/tlib.bat && $(<:D)/tlib.bat && rm $(<:D)/tlib.bat ; } } +else if [ os.name ] = NT +{ + .set-path = "set \"PATH=" ; + .old-path = ";%PATH%\" + " ; +} else { - if [ os.name ] = NT - { - .set-path = "set \"PATH=" ; - .old-path = ";%PATH%\" - " ; - } - else - { - .set-path = "PATH=\"" ; - .old-path = "\":$PATH - export PATH - " ; - } - - actions link bind LIBRARIES - { - $(.set-path)$(.root)$(.old-path) "$(.root)bcc32" -v -q $(OPTIONS) -L"$(LIBPATH)" -L"$(STDLIBPATH)" -e"$(<[1])" @"$(>)" - $(NEED_IMPLIB)"$(.root)implib" $(NEED_IMPLIB)$(<[2]) $(NEED_IMPLIB)$(<[1]) - } + .set-path = "PATH=\"" ; + .old-path = "\":$PATH + export PATH + " ; +} - # Declare action for archives. We don't use response file - # since it's hard to get "+-" there. - # CONSIDER: don't know what 'together' is for... - actions updated together piecemeal archive - { - "$(.root)tlib" /P256 /u /a /C "$(<)" +-"$(>)" - } +actions link bind LIBRARIES +{ + $(.set-path)$(.root:W)$(.old-path) "$(.root)bcc32" -v -q $(OPTIONS) -L"$(LIBPATH:W)" -L"$(STDLIBPATH:W)" -e"$(<[1]:W)" @"$(>:W)" + $(NEED_IMPLIB)"$(.root)implib" $(NEED_IMPLIB)"$(<[2]:W)" $(NEED_IMPLIB)"$(<[1]:W)" } + diff --git a/new/msvc.jam b/new/msvc.jam index 14c2c7d03..7a1e9ee5e 100755 --- a/new/msvc.jam +++ b/new/msvc.jam @@ -119,9 +119,9 @@ rule init ( version ? : path ? : vendor ? : setup ? compiler ? linker ? ) } else { - # When version is not specifying, we cannot form any usefull - # condition. Since subfeatures don't have default, we can't - # stick 'unspecified' as version. Therefore, just set global + # When version is not specified, we cannot form any useful + # condition. Since subfeatures don't have defaults, we can't + # use 'unspecified' as version. Therefore, just set global # variables in this module. .CC = $(prefix)$(compiler) ; .LD = $(prefix)$(linker) ; @@ -282,11 +282,6 @@ if [ os.name ] in NT { .implib = "/INCREMENTAL:NO /IMPLIB:" ; - actions link - { - $(.LD) $(LINKFLAGS) /out:"$(<[1])" $(.implib)"$(<[2])" /LIBPATH:"$(LINKPATH)" "$(FINDLIBS:S=.lib)" $(USER_LINKFLAGS) @"$(>)" - } - actions archive { if exist "$(<)" set _$(<:B)_="$(<)" @@ -304,18 +299,18 @@ else # CYGWIN .cygpath = "cygpath -d " ; } - actions link - { - $(.LD) $(LINKFLAGS) /out:"`$(.cygpath)$(<[1]:D)`/$(<[1]:D=)" $(.implib)"`$(.cygpath)$(<[2]:D)`/$(<[2]:D=)" /LIBPATH:"$(LINKPATH)" "$(FINDLIBS:S=.lib)" $(USER_LINKFLAGS) @`$(.cygpath)$(>)` ; - } - actions archive { - _bbv2_out_="`$(.cygpath)$(<:D)`/$(<:D=)" + _bbv2_out_="$(<)" if test -f "$_bbv2_out_" ; then - _bbv2_existing_="\"$_bbv2_out_\"" + _bbv2_existing_="$(<:W)" fi - $(.LD) /lib "/out:$_bbv2_out_" $_bbv2_existing_ @`$(.cygpath)$(>)` + $(.LD) /lib "/out:$(<:W)" $_bbv2_existing_ @"$(>:W)" } - } + +actions link +{ + $(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" $(.implib)"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" "$(FINDLIBS:S=.lib)" $(USER_LINKFLAGS) @"$(>:W)" +} + diff --git a/test/BoostBuild.py b/test/BoostBuild.py index 1648666cc..067b22472 100644 --- a/test/BoostBuild.py +++ b/test/BoostBuild.py @@ -410,8 +410,9 @@ class Tester(TestCmd.TestCmd): # not totally sure about this change, but I don't see a good alternative if windows: - self.ignore('*.pdb') - self.ignore('*.rsp') + self.ignore('*.ilk') # msvc incremental linking files + self.ignore('*.pdb') # msvc program database files + self.ignore('*.rsp') # response files # debug builds of bjam built with gcc produce this profiling data self.ignore('gmon.out') diff --git a/v2/borland.jam b/v2/borland.jam index a37acc6f3..abd82cc6f 100644 --- a/v2/borland.jam +++ b/v2/borland.jam @@ -143,14 +143,23 @@ flags builtin.response-file LIBRARY_PATH_OPTION borland : -L : unchecke flags builtin.response-file LIBRARY_OPTION borland : -l : unchecked ; + # bcc32 needs to have ilink32 in the path in order to invoke it, so explicitly # specifying $(BCC_TOOL_PATH)bcc32 doesn't help. You need to add # $(BCC_TOOL_PATH) to the path # The NEED_IMPLIB variable controls whether we need to invoke implib. +# Declare action for archives. We don't use response file +# since it's hard to get "+-" there. +# CONSIDER: don't know what 'together' is for... +actions updated together piecemeal archive +{ + "$(.root)tlib" /P256 /u /a /C "$(<:W)" +-"$(>:W)" +} + + if [ os.name ] = CYGWIN { - .cygpath = "cygpath -w " ; rule link { if ! $(<[2]) @@ -158,16 +167,9 @@ if [ os.name ] = CYGWIN NEED_IMPLIB on $(<) = ; } } - .set-path = "cmd /S /C set \"PATH=" ; .old-path = ";%PATH%\" \"&&\"" ; - actions link bind LIBRARIES - { - $(.set-path)$(.root)$(.old-path) "$(.root)bcc32" -v -q $(OPTIONS) -L"$(LIBPATH)" -L"$(STDLIBPATH)" -e"`$(.cygpath)$(<[1]:D)`\\$(<[1]:D=)" @"`$(.cygpath)$(>)`" - $(NEED_IMPLIB)"$(.root)implib" $(NEED_IMPLIB)"`$(.cygpath)$(<[2]:D)`\\$(<[2]:D=)" $(NEED_IMPLIB)"`$(.cygpath)$(<[1]:D)`\\$(<[1]:D=)" - } - # Couldn't get TLIB to stop being confused about pathnames # containing dashes (it seemed to treat them as option separators # when passed through from bash), so we explicitly write the @@ -176,39 +178,29 @@ if [ os.name ] = CYGWIN # options. actions updated together piecemeal archive { - echo "\"$(.root)tlib\" /P256 /u /a /C \"`$(.cygpath)$(<:D)`\\$(<:D=)\" +-\"`$(.cygpath)$(>)`\"" > $(<:D)/tlib.bat + echo "\"$(.root)tlib\" /P256 /u /a /C \"$(<:W)\" +-\"$(>:W)\"" > $(<:D)/tlib.bat chmod +x $(<:D)/tlib.bat && $(<:D)/tlib.bat && rm $(<:D)/tlib.bat ; } } +else if [ os.name ] = NT +{ + .set-path = "set \"PATH=" ; + .old-path = ";%PATH%\" + " ; +} else { - if [ os.name ] = NT - { - .set-path = "set \"PATH=" ; - .old-path = ";%PATH%\" - " ; - } - else - { - .set-path = "PATH=\"" ; - .old-path = "\":$PATH - export PATH - " ; - } - - actions link bind LIBRARIES - { - $(.set-path)$(.root)$(.old-path) "$(.root)bcc32" -v -q $(OPTIONS) -L"$(LIBPATH)" -L"$(STDLIBPATH)" -e"$(<[1])" @"$(>)" - $(NEED_IMPLIB)"$(.root)implib" $(NEED_IMPLIB)$(<[2]) $(NEED_IMPLIB)$(<[1]) - } + .set-path = "PATH=\"" ; + .old-path = "\":$PATH + export PATH + " ; +} - # Declare action for archives. We don't use response file - # since it's hard to get "+-" there. - # CONSIDER: don't know what 'together' is for... - actions updated together piecemeal archive - { - "$(.root)tlib" /P256 /u /a /C "$(<)" +-"$(>)" - } +actions link bind LIBRARIES +{ + $(.set-path)$(.root:W)$(.old-path) "$(.root)bcc32" -v -q $(OPTIONS) -L"$(LIBPATH:W)" -L"$(STDLIBPATH:W)" -e"$(<[1]:W)" @"$(>:W)" + $(NEED_IMPLIB)"$(.root)implib" $(NEED_IMPLIB)"$(<[2]:W)" $(NEED_IMPLIB)"$(<[1]:W)" } + diff --git a/v2/msvc.jam b/v2/msvc.jam index 14c2c7d03..7a1e9ee5e 100755 --- a/v2/msvc.jam +++ b/v2/msvc.jam @@ -119,9 +119,9 @@ rule init ( version ? : path ? : vendor ? : setup ? compiler ? linker ? ) } else { - # When version is not specifying, we cannot form any usefull - # condition. Since subfeatures don't have default, we can't - # stick 'unspecified' as version. Therefore, just set global + # When version is not specified, we cannot form any useful + # condition. Since subfeatures don't have defaults, we can't + # use 'unspecified' as version. Therefore, just set global # variables in this module. .CC = $(prefix)$(compiler) ; .LD = $(prefix)$(linker) ; @@ -282,11 +282,6 @@ if [ os.name ] in NT { .implib = "/INCREMENTAL:NO /IMPLIB:" ; - actions link - { - $(.LD) $(LINKFLAGS) /out:"$(<[1])" $(.implib)"$(<[2])" /LIBPATH:"$(LINKPATH)" "$(FINDLIBS:S=.lib)" $(USER_LINKFLAGS) @"$(>)" - } - actions archive { if exist "$(<)" set _$(<:B)_="$(<)" @@ -304,18 +299,18 @@ else # CYGWIN .cygpath = "cygpath -d " ; } - actions link - { - $(.LD) $(LINKFLAGS) /out:"`$(.cygpath)$(<[1]:D)`/$(<[1]:D=)" $(.implib)"`$(.cygpath)$(<[2]:D)`/$(<[2]:D=)" /LIBPATH:"$(LINKPATH)" "$(FINDLIBS:S=.lib)" $(USER_LINKFLAGS) @`$(.cygpath)$(>)` ; - } - actions archive { - _bbv2_out_="`$(.cygpath)$(<:D)`/$(<:D=)" + _bbv2_out_="$(<)" if test -f "$_bbv2_out_" ; then - _bbv2_existing_="\"$_bbv2_out_\"" + _bbv2_existing_="$(<:W)" fi - $(.LD) /lib "/out:$_bbv2_out_" $_bbv2_existing_ @`$(.cygpath)$(>)` + $(.LD) /lib "/out:$(<:W)" $_bbv2_existing_ @"$(>:W)" } - } + +actions link +{ + $(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" $(.implib)"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" "$(FINDLIBS:S=.lib)" $(USER_LINKFLAGS) @"$(>:W)" +} + diff --git a/v2/test/BoostBuild.py b/v2/test/BoostBuild.py index 1648666cc..067b22472 100644 --- a/v2/test/BoostBuild.py +++ b/v2/test/BoostBuild.py @@ -410,8 +410,9 @@ class Tester(TestCmd.TestCmd): # not totally sure about this change, but I don't see a good alternative if windows: - self.ignore('*.pdb') - self.ignore('*.rsp') + self.ignore('*.ilk') # msvc incremental linking files + self.ignore('*.pdb') # msvc program database files + self.ignore('*.rsp') # response files # debug builds of bjam built with gcc produce this profiling data self.ignore('gmon.out')