diff --git a/build/configure.jam b/build/configure.jam index 66b81b3..9b26e04 100644 --- a/build/configure.jam +++ b/build/configure.jam @@ -123,76 +123,87 @@ rule print-configure-checks-summary ( ) } } - -# Attempt to build a metatarget named by 'metatarget-reference' in context of -# 'project' with properties 'ps'. Returns non-empty value if build is OK. -# -rule builds-raw ( metatarget-reference : project : ps : what : retry ? ) +# Attempts to build a set of virtual targets +rule try-build ( targets * : ps : what : retry ? ) { + local cache-name = $(what) [ $(ps).raw ] ; + cache-name = $(cache-name:J=-) ; + local value = [ config-cache.get $(cache-name) ] ; + local result ; + local jam-targets ; - if ! $(retry) && ! $(.$(what)-tested.$(ps)) + for local t in $(targets[2-]) { - .$(what)-tested.$(ps) = true ; - - local cache-name = $(what) [ $(ps).raw ] ; - cache-name = $(cache-name:J=-) ; - local value = [ config-cache.get $(cache-name) ] ; - - local targets = [ targets.generate-from-reference - $(metatarget-reference) : $(project) : $(ps) ] ; - - local jam-targets ; - for local t in $(targets[2-]) + jam-targets += [ $(t).actualize ] ; + } + + if $(value) + { + local x = [ PAD " - $(what)" : $(.width) ] ; + if $(value) = true { - jam-targets += [ $(t).actualize ] ; + .$(what)-supported.$(ps) = yes ; + result = true ; + log-check-result "$(x) : yes (cached)" ; } - - if $(value) + else { - local x = [ PAD " - $(what)" : $(.width) ] ; - if $(value) = true - { - .$(what)-supported.$(ps) = yes ; - result = true ; - log-check-result "$(x) : yes (cached)" ; - } - else - { - log-check-result "$(x) : no (cached)" ; - } - } - else if ! UPDATE_NOW in [ RULENAMES ] + log-check-result "$(x) : no (cached)" ; + } + } + else if ! UPDATE_NOW in [ RULENAMES ] + { + # Cannot determine. Assume existance. + } + else + { + local x = [ PAD " - $(what)" : $(.width) ] ; + if [ UPDATE_NOW $(jam-targets) : + $(.log-fd) : ignore-minus-n : ignore-minus-q ] { - # Cannot determine. Assume existance. + .$(what)-supported.$(ps) = yes ; + result = true ; + log-check-result "$(x) : yes" ; } else { - local x = [ PAD " - $(what)" : $(.width) ] ; - if [ UPDATE_NOW $(jam-targets) : - $(.log-fd) : ignore-minus-n : ignore-minus-q ] - { - .$(what)-supported.$(ps) = yes ; - result = true ; - log-check-result "$(x) : yes" ; - } - else - { - log-check-result "$(x) : no" ; - } + log-check-result "$(x) : no" ; + } + } + if ! $(value) + { + if $(result) + { + config-cache.set $(cache-name) : true ; } - if ! $(value) + else { - if $(result) - { - config-cache.set $(cache-name) : true ; - } - else - { - config-cache.set $(cache-name) : false ; - } - } + config-cache.set $(cache-name) : false ; + } + } + return $(result) ; +} + +# Attempt to build a metatarget named by 'metatarget-reference' +# in context of 'project' with properties 'ps'. +# Returns non-empty value if build is OK. +rule builds-raw ( metatarget-reference : project : ps : what : retry ? ) +{ + local result ; + + if ! $(retry) && ! $(.$(what)-tested.$(ps)) + { + .$(what)-tested.$(ps) = true ; + + local targets = [ targets.generate-from-reference + $(metatarget-reference) : $(project) : $(ps) ] ; + + result = [ try-build $(targets[2-]) : $(ps) : $(what) : $(retry) ] ; + .$(what)-supported.$(ps) = $(result) ; + return $(result) ; + } else { diff --git a/build/virtual-target.jam b/build/virtual-target.jam index f62eadb..44a706d 100644 --- a/build/virtual-target.jam +++ b/build/virtual-target.jam @@ -1324,8 +1324,9 @@ class subvariant for local t in $(self.created-targets) { # Skip targets of the wrong type. + local type = [ $(t).type ] ; if ! $(target-type) || - [ type.is-derived [ $(t).type ] $(target-type) ] + ( $(type) && [ type.is-derived $(type) $(target-type) ] ) { result = [ sequence.merge $(result) : [ $(t).path ] ] ; } diff --git a/engine/builtins.c b/engine/builtins.c index e4130bb..28ff753 100644 --- a/engine/builtins.c +++ b/engine/builtins.c @@ -29,6 +29,10 @@ #include +#ifdef NT +#include +#endif + #if defined(USE_EXECUNIX) # include # include @@ -426,6 +430,11 @@ void load_builtins() bind_builtin( "MAKEDIR", builtin_makedir, 0, args ); } + { + const char * args [] = { "path", 0 }; + bind_builtin( "READLINK", builtin_readlink, 0, args ); + } + /* Initialize builtin modules. */ init_set(); init_path(); @@ -1828,6 +1837,94 @@ LIST * builtin_makedir( FRAME * frame, int flags ) } +LIST *builtin_readlink( FRAME * frame, int flags ) +{ + const char * path = object_str( list_front( lol_get( frame->args, 0 ) ) ); +#ifdef NT + + /* This struct is declared in ntifs.h which is + * part of the Windows Driver Kit. + */ + typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[ 1 ]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[ 1 ]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[ 1 ]; + } GenericReparseBuffer; + }; + } REPARSE_DATA_BUFFER; + + HANDLE hLink = CreateFileA( path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL ); + DWORD n; + union { + REPARSE_DATA_BUFFER reparse; + char data[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + } buf; + int okay = DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, &buf, sizeof(buf), &n, NULL); + + CloseHandle( hLink ); + + if (okay && buf.reparse.ReparseTag == IO_REPARSE_TAG_SYMLINK ) + { + int index = buf.reparse.SymbolicLinkReparseBuffer.SubstituteNameOffset / 2; + int length = buf.reparse.SymbolicLinkReparseBuffer.SubstituteNameLength / 2; + char cbuf[MAX_PATH + 1]; + int numchars = WideCharToMultiByte( CP_ACP, 0, buf.reparse.SymbolicLinkReparseBuffer.PathBuffer + index, length, cbuf, sizeof(cbuf), NULL, NULL ); + if( numchars >= sizeof(cbuf) ) + { + return 0; + } + cbuf[numchars] = '\0'; + return list_new( object_new( cbuf ) ); + } + return 0; +#else + char static_buf[256]; + char * buf = static_buf; + size_t bufsize = 256; + LIST * result = 0; + while (1) { + ssize_t len = readlink( path, buf, bufsize ); + if ( len < 0 ) + { + break; + } + else if ( len < bufsize ) + { + buf[ len ] = '\0'; + result = list_new( object_new( buf ) ); + break; + } + if ( buf != static_buf ) + BJAM_FREE( buf ); + bufsize *= 2; + buf = BJAM_MALLOC( bufsize ); + } + + if ( buf != static_buf ) + BJAM_FREE( buf ); + + return result; +#endif +} + #ifdef HAVE_PYTHON LIST * builtin_python_import_rule( FRAME * frame, int flags ) diff --git a/engine/builtins.h b/engine/builtins.h index b7a967c..6d0c873 100644 --- a/engine/builtins.h +++ b/engine/builtins.h @@ -63,6 +63,7 @@ LIST *builtin_pad( FRAME * frame, int flags ); LIST *builtin_precious( FRAME * frame, int flags ); LIST *builtin_self_path( FRAME * frame, int flags ); LIST *builtin_makedir( FRAME * frame, int flags ); +LIST *builtin_readlink( FRAME * frame, int flags ); void backtrace( FRAME *frame ); extern int last_update_now_status;