Doubled up variable substitutions in msvc action

"Chambers, Matthew via Boost-build" <[email protected]> Wed, 24 Jun 2020 13:16:32 -0400
Newsgroups gmane.comp.lib.boost.build
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--===============5245480630400970436==
Content-Type: multipart/alternative;
 boundary="------------21CA42BC0987BD6EF846758C"
Content-Language: en-US

This is a multi-part message in MIME format.
--------------21CA42BC0987BD6EF846758C
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 8bit

I have hit an intermittent (hard to reproduce) issue when building a particular target with MSVC. I've added custom versions of msvc.link 
and msvc.compile for /clr and .NET support. They've been working fine for the few targets I originally developed them for. This problem 
started happening when I recently added another target using these custom versions. The symptom is that I get this link command with doubled 
up "link" and flags suggesting the $(.LD) and $(LINKFLAGS) variables are getting doubled up. It's so hard to reproduce I haven't managed to 
get any --debug-configuration output when it happens. I've only gotten it to happen on our AWS build agents. I was hoping one of the 
veterans would have a hunch about what's happening just from the symptom.

  link link /NOLOGO /NOLOGO /INCREMENTAL:NO /INCREMENTAL:NO /DLL /DEBUG /DEBUG /MACHINE:X64 /MACHINE:X64 /MANIFEST /MANIFEST 
/subsystem:console /subsystem:console /out:"Z:\path\to\PrmPasefScheduler.dll" /LIBPATH:"Z:\some\path\x64" /LIBPATH:"Z:\some\other\path\x64"  
/MACHINE:x64 /FIXED:No /MACHINE:x64 /FIXED:No @"Z:\path\to\PrmPasefScheduler.dll.rsp"

Just in case you want to dig deeper, here is the problematic target:

rule msvc-requirement ( properties * )
{
     if ! <toolset>msvc in $(properties) { return <build>no ; }
}
obj PrmScheduler       : PrmScheduler.cpp        : <conditional>@msvc-requirement <define>UNICODE <define>_UNICODE 
<toolset>msvc:<using-clr>true ;

rule prmscheduler-requirements ( properties * )
{
     if <address-model>64 in $(properties)
     {
         return <search>x64 ;
     }
     else
     {
         return <search>x86 ;
     }
}

rule prmscheduler-usage-requirements ( properties * )
{
     if <address-model>64 in $(properties)
     {
         return <assembly-dependency>$(PRMSCHEDULER_CLI_ROOT)/x64/prmscheduler.dll ;
     }
     else
     {
         return <assembly-dependency>$(PRMSCHEDULER_CLI_ROOT)/x86/prmscheduler.dll ;
     }
}

searched-lib prmscheduler : : <conditional>@prmscheduler-requirements : : <conditional>@prmscheduler-usage-requirements ;

constant PLATFORM : "x64" ;
lib PrmPasefScheduler
     : # sources
         PrmScheduler
     : # requirements
         <library>prmscheduler
         <link>shared
<library>$(PWIZ_ROOT_PATH)/pwiz/utility/misc//pwiz_utility_misc/<link>static/<using-clr>false
         <linkflags>"/MACHINE:$(PLATFORM) /FIXED:No"
         <cxxflags>/permissive
         <conditional>@msvc-requirement
        <define>UNICODE
        <define>_UNICODE
        <toolset>msvc:<using-clr>true
     : # default-build
     : # usage-requirements
         <library>prmscheduler
<library>$(PWIZ_ROOT_PATH)/pwiz/utility/misc//pwiz_utility_misc/<link>static/<using-clr>false
     ;

_
__Here are the custom rules/actions:_

actions compile-c++clr
{
     $(.SETUP) $(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -Fo"$(<[1]:W)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" /clr $(ASSEMBLY_INCLUDE_PATHS) 
$(ASSEMBLIES) $(CC_RSPLINE))" $(.CC.FILTER)" > "$(<[1]:W).out"
     set status=%ERRORLEVEL%
     findstr /V /X "$(>[1]:D=)" "$(<[1]:W).out"
     exit %status%
}

rule compile.c++clr ( targets + : sources * : properties * )
{
     set-setup-command $(targets) : $(properties) ;
     set-assemblies $(<[1]) : $(properties) ;
     get-rspline $(targets) : -TP ;
     compile-c++clr $(<) : $(>) [ on $(<) return $(PCH_FILE) ] [ on $(<) return $(PCH_HEADER) ] ;
}

actions link.clr.dll bind DEF_FILE LIBRARIES_MENTIONED_BY_FILE
{
     $(.SETUP) $(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) 
@"@($(<[1]:W).rsp:E=$(.nl)"$(>)" $(.nl)$(LIBRARIES_MENTIONED_BY_FILE) $(.nl)$(LIBRARIES) $(.nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" 
$(.nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")" $(MANIFEST_DEPENDENCIES)
     if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%
}

rule link.clr.dll ( targets + : sources * : properties * )
{
     set-setup-command $(targets) : $(properties) ;
     set-manifest-dependencies $(<[1]) : $(properties) ;
     DEPENDS $(<) : [ on $(<) return $(DEF_FILE) ] ;
     if <embed-manifest>on in $(properties)
     {
         msvc.manifest.dll $(targets) : $(sources) : $(properties) ;
     }
     copy-assemblies $(<[1]) : $(properties) ;
}

_
__Here are the custom features:_

feature.feature assembly            : : free dependency ;
feature.feature assembly-dependency : : free dependency ;
feature.feature assembly-dependency-ex : : free ;
feature.feature manifest-dependency : : free dependency ;
feature.feature configuration-file  : : free dependency ;
feature.feature using-clr           : false true : composite ;
feature.compose <using-clr>true     : <asynch-exceptions>on <runtime-link>shared ;

generators.register [ new msvc-linking-generator msvc.link.clr.dll : OBJ SEARCHED_LIB STATIC_LIB : SHARED_LIB : <toolset>msvc 
<using-clr>true ] ;
generators.override msvc.link.clr.dll : msvc.link.dll ;

generators.register-c-compiler msvc.compile.c++clr : CPP : OBJ : <toolset>msvc <using-clr>true ;

_
__Here are some utility functions used in the above actions:_

#
# Add /FU and /AI flags for targets using /clr
#
rule set-assemblies ( target : properties * )
{
     local assemblies-string ;
     local assemblies = [ feature.get-values <assembly> : $(properties) ] ;
     if $(assemblies)
     {
         for local assembly in $(assemblies)
         {
             local assembly-path = [ $(assembly).name ] ;
             if $(assembly-path:S) != ".pdb"
             {
                 if ! [ path.is-rooted $(assembly-path) ]
                 {
                     assembly-path = [ path.join [ $(assembly).path ] $(assembly-path:D=) ] ;
                 }
                 assembly-path = [ path.native $(assembly-path) ] ;
                 assemblies-string += " /FU\"$(assembly-path)\"" ;
             }
         }
     }
     ASSEMBLIES on $(target) = $(assemblies-string) ;

     # add /AI flags for each assembly-dependency's (unique) directory
     local assembly-include-string ;
     local assembly-dependencies = [ feature.get-values <assembly-dependency> : $(properties) ] ;
     if $(assembly-dependencies)
     {
         local assembly-include-paths ;
         for local dependency in $(assembly-dependencies)
         {
             local dependency-path = [ $(dependency).name ] ;
             if ! [ path.is-rooted $(dependency-path) ]
             {
                 dependency-path = [ path.join [ $(dependency).path ] $(dependency-path:D=) ] ;
             }
             dependency-path = [ path.native $(dependency-path) ] ;
             dependency-path = $(dependency-path:D) ;
             if ! $(dependency-path) in $(assembly-include-paths)
             {
                 assembly-include-paths += $(dependency-path) ;
                 assembly-include-string += " /AI\"$(dependency-path)\"" ;
             }
         }
     }
     ASSEMBLY_INCLUDE_PATHS on $(target) = $(assembly-include-string) ;
}

#
# Add /MANIFESTDEPENDENCY flags (primarily for side-by-side loading of COM DLLs)
#
local rule set-manifest-dependencies ( target : properties * )
{
     local manifest-dependencies-string ;
     local manifest-dependencies = [ feature.get-values <manifest-dependency> : $(properties) ] ;
     if $(manifest-dependencies)
     {
         # type='win32' name='<assembly_basename>' version='<assembly_version>'
         for local dependency in $(manifest-dependencies)
         {
             local dependency-path = [ path.native [ $(dependency).name ] ] ;
             local dependency-version = [ MATCH "FileVersion:     ([0-9\\.]+)" : [ SHELL "ShowVer.exe $(dependency-path)" ] ] ;

             # unknown version will cause a runtime-error; is there a better solution?
             dependency-version ?= "unknown" ;

             # the name of the manifest can not match the basename of the DLL because of a Windows XP loader bug
             manifest-dependencies-string += " /MANIFESTDEPENDENCY:\"type='win32' name='$(dependency-path:B).SxS' 
version='$(dependency-version)'\"" ;
         }
     }
     MANIFEST_DEPENDENCIES on $(target) = $(manifest-dependencies-string) ;
}

#
# Copy .NET assemblies and their native DLL dependencies to the target's directory;
# Also .NET applications may need a side-by-side configuration file that must be named like $(target).exe.config - copy that if necessary
#
rule copy-assemblies ( target : properties * )
{
     local assemblies = [ feature.get-values <assembly> : $(properties) ] ;
     assemblies += [ feature.get-values <assembly-dependency> : $(properties) ] ;
     if $(assemblies)
     {
         local target-path = [ on $(target) return $(LOCATE) ] ;
         for local assembly in $(assemblies)
         {
             local assembly-path = [ $(assembly).name ] ;
             if ! [ path.is-rooted $(assembly-path) ]
             {
                 assembly-path = [ path.join [ $(assembly).path ] $(assembly-path:D=) ] ;
             }
             assembly-path = [ path.native $(assembly-path) ] ;
             local assembly-at-target-filepath = [ path.native [ path.join $(target-path) $(assembly-path:D=) ] ] ;

             if $(assembly-at-target-filepath:L) != $(assembly-path:L) &&
                ! ( $(assembly-at-target-filepath:L) in $(.unique-targets) )
             {
                 .unique-targets += $(assembly-at-target-filepath:L) ;
                 if ! [ CHECK_IF_FILE $(assembly-at-target-filepath:L) ]
                 {
                     common.hard-link $(assembly-at-target-filepath) : $(assembly-path) ;
                     DEPENDS $(assembly-at-target-filepath) : $(target-path) [ $(assembly).actualize ] ;
                     DEPENDS $(target) : $(assembly-at-target-filepath) ;
                     #JAM_SEMAPHORE on $(target-filepath) = "dotNetSemaphore" ;
                     #JAM_SEMAPHORE on $(target) = "dotNetSemaphore" ;
                 }
             }
         }
     }

     # .NET applications may need a side-by-side configuration file that must be named like $(target).exe.config
     local configuration-file = [ feature.get-values <configuration-file> : $(properties) ] ;
     if $(configuration-file)
     {
         local target-path = [ on $(target) return $(LOCATE) ] ;
         local configuration-file-path = [ $(configuration-file).name ] ;
         if ! [ path.is-rooted $(configuration-file-path) ]
         {
             configuration-file-path = [ path.join [ $(configuration-file).path ] $(configuration-file-path:D=) ] ;
         }
         configuration-file-path = [ path.native $(configuration-file-path) ] ;
         local target-filepath = [ path.native [ path.join $(target-path) $(configuration-file-path:D=) ] ] ;
         if $(target-filepath) != $(configuration-file-path) &&
            ! ( $(configuration-file-path) in $(.unique-targets) )
         {
             .unique-targets += $(configuration-file-path) ;
             common.hard-link $(target-filepath) : $(configuration-file-path) ;
             DEPENDS $(target-filepath) : $(target-path) ;
             DEPENDS $(target) : $(target-filepath) ;
             #JAM_SEMAPHORE on $(target-filepath) = "dotNetSemaphore" ;
             #JAM_SEMAPHORE on $(target) = "dotNetSemaphore" ;
         }
     }
}

--------------21CA42BC0987BD6EF846758C
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 8bit

<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    I have hit an intermittent (hard to reproduce) issue when building a
    particular target with MSVC. I've added custom versions of msvc.link
    and msvc.compile for /clr and .NET support. They've been working
    fine for the few targets I originally developed them for. This
    problem started happening when I recently added another target using
    these custom versions. The symptom is that I get this link command
    with doubled up "link" and flags suggesting the $(.LD) and
    $(LINKFLAGS) variables are getting doubled up. It's so hard to
    reproduce I haven't managed to get any --debug-configuration output
    when it happens. I've only gotten it to happen on our AWS build
    agents. I was hoping one of the veterans would have a hunch about
    what's happening just from the symptom.<br>
    <br>
     link link /NOLOGO /NOLOGO /INCREMENTAL:NO /INCREMENTAL:NO /DLL
    /DEBUG /DEBUG /MACHINE:X64 /MACHINE:X64 /MANIFEST /MANIFEST
    /subsystem:console /subsystem:console
    /out:"Z:\path\to\PrmPasefScheduler.dll" /LIBPATH:"Z:\some\path\x64"
    /LIBPATH:"Z:\some\other\path\x64"  /MACHINE:x64 /FIXED:No
    /MACHINE:x64 /FIXED:No @"Z:\path\to\PrmPasefScheduler.dll.rsp" <br>
    <br>
    Just in case you want to dig deeper, here is the problematic target:<br>
    <tt><br>
    </tt><tt>rule msvc-requirement ( properties * )</tt><tt><br>
    </tt><tt>{</tt><tt><br>
    </tt><tt>    if ! &lt;toolset&gt;msvc in $(properties) { return
      &lt;build&gt;no ; }</tt><tt><br>
    </tt><tt>}</tt><tt><br>
    </tt><tt>obj PrmScheduler       : PrmScheduler.cpp        :
      &lt;conditional&gt;@msvc-requirement &lt;define&gt;UNICODE
      &lt;define&gt;_UNICODE &lt;toolset&gt;msvc:&lt;using-clr&gt;true ;</tt><tt><br>
    </tt><tt><br>
    </tt><tt>rule prmscheduler-requirements ( properties * )</tt><tt><br>
    </tt><tt>{</tt><tt><br>
    </tt><tt>    if &lt;address-model&gt;64 in $(properties)</tt><tt><br>
    </tt><tt>    {</tt><tt><br>
    </tt><tt>        return &lt;search&gt;x64 ;</tt><tt><br>
    </tt><tt>    }</tt><tt><br>
    </tt><tt>    else</tt><tt><br>
    </tt><tt>    {</tt><tt><br>
    </tt><tt>        return &lt;search&gt;x86 ;</tt><tt><br>
    </tt><tt>    }</tt><tt><br>
    </tt><tt>}</tt><tt><br>
    </tt><tt><br>
    </tt><tt>rule prmscheduler-usage-requirements ( properties * )</tt><tt><br>
    </tt><tt>{</tt><tt><br>
    </tt><tt>    if &lt;address-model&gt;64 in $(properties)</tt><tt><br>
    </tt><tt>    {</tt><tt><br>
    </tt><tt>        return
      &lt;assembly-dependency&gt;$(PRMSCHEDULER_CLI_ROOT)/x64/prmscheduler.dll
      ;</tt><tt><br>
    </tt><tt>    }</tt><tt><br>
    </tt><tt>    else</tt><tt><br>
    </tt><tt>    {</tt><tt><br>
    </tt><tt>        return
      &lt;assembly-dependency&gt;$(PRMSCHEDULER_CLI_ROOT)/x86/prmscheduler.dll
      ;</tt><tt><br>
    </tt><tt>    }</tt><tt><br>
    </tt><tt>}</tt><tt><br>
    </tt><tt><br>
    </tt><tt>searched-lib prmscheduler : :
      &lt;conditional&gt;@prmscheduler-requirements : :
      &lt;conditional&gt;@prmscheduler-usage-requirements ;</tt><tt><br>
    </tt><tt><br>
    </tt><tt>constant PLATFORM : "x64" ;</tt><tt><br>
    </tt><tt>lib PrmPasefScheduler</tt><tt><br>
    </tt><tt>    : # sources</tt><tt><br>
    </tt><tt>        PrmScheduler</tt><tt><br>
    </tt><tt>    : # requirements</tt><tt><br>
    </tt><tt>        &lt;library&gt;prmscheduler</tt><tt><br>
    </tt><tt>        &lt;link&gt;shared</tt><tt><br>
    </tt><tt>       
&lt;library&gt;$(PWIZ_ROOT_PATH)/pwiz/utility/misc//pwiz_utility_misc/&lt;link&gt;static/&lt;using-clr&gt;false</tt><tt><br>
    </tt><tt>        &lt;linkflags&gt;"/MACHINE:$(PLATFORM) /FIXED:No"</tt><tt><br>
    </tt><tt>        &lt;cxxflags&gt;/permissive</tt><tt><br>
    </tt><tt>        &lt;conditional&gt;@msvc-requirement</tt><tt><br>
    </tt><tt>       &lt;define&gt;UNICODE</tt><tt><br>
    </tt><tt>       &lt;define&gt;_UNICODE</tt><tt><br>
    </tt><tt>       &lt;toolset&gt;msvc:&lt;using-clr&gt;true</tt><tt><br>
    </tt><tt>    : # default-build</tt><tt><br>
    </tt><tt>    : # usage-requirements</tt><tt><br>
    </tt><tt>        &lt;library&gt;prmscheduler</tt><tt><br>
    </tt><tt>       
&lt;library&gt;$(PWIZ_ROOT_PATH)/pwiz/utility/misc//pwiz_utility_misc/&lt;link&gt;static/&lt;using-clr&gt;false</tt><tt><br>
    </tt><tt>    ;</tt><tt><br>
    </tt><tt>    </tt><br>
    <u><br>
    </u><u>Here are the custom rules/actions:</u><br>
    <br>
    <tt>actions compile-c++clr</tt><tt><br>
    </tt><tt>{</tt><tt><br>
    </tt><tt>    $(.SETUP) $(.CC) @"@($(&lt;[1]:W).rsp:E="$(&gt;[1]:W)"
      -Fo"$(&lt;[1]:W)" -Yu"$(&gt;[3]:D=)" -Fp"$(&gt;[2]:W)" /clr
      $(ASSEMBLY_INCLUDE_PATHS) $(ASSEMBLIES) $(CC_RSPLINE))"
      $(.CC.FILTER)" &gt; "$(&lt;[1]:W).out"</tt><tt><br>
    </tt><tt>    set status=%ERRORLEVEL%</tt><tt><br>
    </tt><tt>    findstr /V /X "$(&gt;[1]:D=)" "$(&lt;[1]:W).out"</tt><tt><br>
    </tt><tt>    exit %status%</tt><tt><br>
    </tt><tt>}</tt><tt><br>
    </tt><tt><br>
    </tt><tt>rule compile.c++clr ( targets + : sources * : properties *
      )</tt><tt><br>
    </tt><tt>{</tt><tt><br>
    </tt><tt>    set-setup-command $(targets) : $(properties) ;</tt><tt><br>
    </tt><tt>    set-assemblies $(&lt;[1]) : $(properties) ;</tt><tt><br>
    </tt><tt>    get-rspline $(targets) : -TP ;</tt><tt><br>
    </tt><tt>    compile-c++clr $(&lt;) : $(&gt;) [ on $(&lt;) return
      $(PCH_FILE) ] [ on $(&lt;) return $(PCH_HEADER) ] ;</tt><tt><br>
    </tt><tt>}</tt><tt><br>
    </tt><tt><br>
    </tt><tt>actions link.clr.dll bind DEF_FILE
      LIBRARIES_MENTIONED_BY_FILE</tt><tt><br>
    </tt><tt>{</tt><tt><br>
    </tt><tt>    $(.SETUP) $(.LD) /DLL $(LINKFLAGS) /out:"$(&lt;[1]:W)"
      /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS)
      @"@($(&lt;[1]:W).rsp:E=$(.nl)"$(&gt;)"
      $(.nl)$(LIBRARIES_MENTIONED_BY_FILE) $(.nl)$(LIBRARIES)
      $(.nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
      $(.nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
      $(MANIFEST_DEPENDENCIES)</tt><tt><br>
    </tt><tt>    if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%</tt><tt><br>
    </tt><tt>}</tt><tt><br>
    </tt><tt><br>
    </tt><tt>rule link.clr.dll ( targets + : sources * : properties * )</tt><tt><br>
    </tt><tt>{</tt><tt><br>
    </tt><tt>    set-setup-command $(targets) : $(properties) ;</tt><tt><br>
    </tt><tt>    set-manifest-dependencies $(&lt;[1]) : $(properties) ;</tt><tt><br>
    </tt><tt>    DEPENDS $(&lt;) : [ on $(&lt;) return $(DEF_FILE) ] ;</tt><tt><br>
    </tt><tt>    if &lt;embed-manifest&gt;on in $(properties)</tt><tt><br>
    </tt><tt>    {</tt><tt><br>
    </tt><tt>        msvc.manifest.dll $(targets) : $(sources) :
      $(properties) ;</tt><tt><br>
    </tt><tt>    }</tt><tt><br>
    </tt><tt>    copy-assemblies $(&lt;[1]) : $(properties) ;</tt><tt><br>
    </tt><tt>}</tt><br>
    <br>
    <u><br>
    </u><u>Here are the custom features:</u><br>
    <tt><br>
    </tt><tt>feature.feature assembly            :                      
      : free dependency ;</tt><tt><br>
    </tt><tt>feature.feature assembly-dependency :                      
      : free dependency ;</tt><tt><br>
    </tt><tt>feature.feature assembly-dependency-ex :                   
      : free ;</tt><tt><br>
    </tt><tt>feature.feature manifest-dependency :                      
      : free dependency ;</tt><tt><br>
    </tt><tt>feature.feature configuration-file  :                      
      : free dependency ;</tt><tt><br>
    </tt><tt>feature.feature using-clr           : false true           
      : composite ;</tt><tt><br>
    </tt><tt>feature.compose &lt;using-clr&gt;true     :
      &lt;asynch-exceptions&gt;on &lt;runtime-link&gt;shared ;<br>
      <br>
      generators.register [ new msvc-linking-generator   
      msvc.link.clr.dll : OBJ SEARCHED_LIB STATIC_LIB : SHARED_LIB :
      &lt;toolset&gt;msvc &lt;using-clr&gt;true ] ;<br>
      generators.override msvc.link.clr.dll : msvc.link.dll ;<br>
      <br>
      generators.register-c-compiler msvc.compile.c++clr : CPP : OBJ :
      &lt;toolset&gt;msvc &lt;using-clr&gt;true ;</tt><br>
    <br>
    <u><br>
    </u><u>Here are some utility functions used in the above actions:</u><br>
    <tt><br>
    </tt><tt>
      #</tt><tt><br>
    </tt><tt>
      # Add /FU and /AI flags for targets using /clr</tt><tt><br>
    </tt><tt>
      #</tt><tt><br>
    </tt><tt>
      rule set-assemblies ( target : properties * )</tt><tt><br>
    </tt><tt>
      {</tt><tt><br>
    </tt><tt>
          local assemblies-string ;</tt><tt><br>
    </tt><tt>
          local assemblies = [ feature.get-values &lt;assembly&gt; :
      $(properties) ] ;</tt><tt><br>
    </tt><tt>
          if $(assemblies)</tt><tt><br>
    </tt><tt>
          {</tt><tt><br>
    </tt><tt>
              for local assembly in $(assemblies)</tt><tt><br>
    </tt><tt>
              {</tt><tt><br>
    </tt><tt>
                  local assembly-path = [ $(assembly).name ] ;</tt><tt><br>
    </tt><tt>
                  if $(assembly-path:S) != ".pdb"</tt><tt><br>
    </tt><tt>
                  {</tt><tt><br>
    </tt><tt>
                      if ! [ path.is-rooted $(assembly-path) ]</tt><tt><br>
    </tt><tt>
                      {</tt><tt><br>
    </tt><tt>
                          assembly-path = [ path.join [ $(assembly).path
      ] $(assembly-path:D=) ] ;</tt><tt><br>
    </tt><tt>
                      }</tt><tt><br>
    </tt><tt>
                      assembly-path = [ path.native $(assembly-path) ] ;</tt><tt><br>
    </tt><tt>
                      assemblies-string += " /FU\"$(assembly-path)\"" ;</tt><tt><br>
    </tt><tt>
                  }</tt><tt><br>
    </tt><tt>
              }</tt><tt><br>
    </tt><tt>
          }</tt><tt><br>
    </tt><tt>
          ASSEMBLIES on $(target) = $(assemblies-string) ;</tt><tt><br>
    </tt><tt>
    </tt><tt><br>
    </tt><tt>
          # add /AI flags for each assembly-dependency's (unique)
      directory</tt><tt><br>
    </tt><tt>
          local assembly-include-string ;</tt><tt><br>
    </tt><tt>
          local assembly-dependencies = [ feature.get-values
      &lt;assembly-dependency&gt; : $(properties) ] ;</tt><tt><br>
    </tt><tt>
          if $(assembly-dependencies)</tt><tt><br>
    </tt><tt>
          {</tt><tt><br>
    </tt><tt>
              local assembly-include-paths ;</tt><tt><br>
    </tt><tt>
              for local dependency in $(assembly-dependencies)</tt><tt><br>
    </tt><tt>
              {</tt><tt><br>
    </tt><tt>
                  local dependency-path = [ $(dependency).name ] ;</tt><tt><br>
    </tt><tt>
                  if ! [ path.is-rooted $(dependency-path) ]</tt><tt><br>
    </tt><tt>
                  {</tt><tt><br>
    </tt><tt>
                      dependency-path = [ path.join [ $(dependency).path
      ] $(dependency-path:D=) ] ;</tt><tt><br>
    </tt><tt>
                  }</tt><tt><br>
    </tt><tt>
                  dependency-path = [ path.native $(dependency-path) ] ;</tt><tt><br>
    </tt><tt>
                  dependency-path = $(dependency-path:D) ;</tt><tt><br>
    </tt><tt>
                  if ! $(dependency-path) in $(assembly-include-paths)</tt><tt><br>
    </tt><tt>
                  {</tt><tt><br>
    </tt><tt>
                      assembly-include-paths += $(dependency-path) ;</tt><tt><br>
    </tt><tt>
                      assembly-include-string += "
      /AI\"$(dependency-path)\"" ;</tt><tt><br>
    </tt><tt>
                  }</tt><tt><br>
    </tt><tt>
              }</tt><tt><br>
    </tt><tt>
          }</tt><tt><br>
    </tt><tt>
          ASSEMBLY_INCLUDE_PATHS on $(target) =
      $(assembly-include-string) ;</tt><tt><br>
    </tt><tt>
      }</tt><tt><br>
    </tt><tt><br>
    </tt><tt>#</tt><tt><br>
    </tt><tt># Add /MANIFESTDEPENDENCY flags (primarily for side-by-side
      loading of COM DLLs)</tt><tt><br>
    </tt><tt>#</tt><tt><br>
    </tt><tt>local rule set-manifest-dependencies ( target : properties
      * )</tt><tt><br>
    </tt><tt>{</tt><tt><br>
    </tt><tt>    local manifest-dependencies-string ;</tt><tt><br>
    </tt><tt>    local manifest-dependencies = [ feature.get-values
      &lt;manifest-dependency&gt; : $(properties) ] ;</tt><tt><br>
    </tt><tt>    if $(manifest-dependencies)</tt><tt><br>
    </tt><tt>    {</tt><tt><br>
    </tt><tt>        # type='win32' name='&lt;assembly_basename&gt;'
      version='&lt;assembly_version&gt;'</tt><tt><br>
    </tt><tt>        for local dependency in $(manifest-dependencies)</tt><tt><br>
    </tt><tt>        {</tt><tt><br>
    </tt><tt>            local dependency-path = [ path.native [
      $(dependency).name ] ] ;</tt><tt><br>
    </tt><tt>            local dependency-version = [ MATCH
      "FileVersion:     ([0-9\\.]+)" : [ SHELL "ShowVer.exe
      $(dependency-path)" ] ] ;</tt><tt><br>
    </tt><tt>            </tt><tt><br>
    </tt><tt>            # unknown version will cause a runtime-error;
      is there a better solution?</tt><tt><br>
    </tt><tt>            dependency-version ?= "unknown" ;</tt><tt><br>
    </tt><tt>            </tt><tt><br>
    </tt><tt>            # the name of the manifest can not match the
      basename of the DLL because of a Windows XP loader bug</tt><tt><br>
    </tt><tt>            manifest-dependencies-string += "
      /MANIFESTDEPENDENCY:\"type='win32' name='$(dependency-path:B).SxS'
      version='$(dependency-version)'\"" ;</tt><tt><br>
    </tt><tt>        }</tt><tt><br>
    </tt><tt>    }</tt><tt><br>
    </tt><tt>    MANIFEST_DEPENDENCIES on $(target) =
      $(manifest-dependencies-string) ;</tt><tt><br>
    </tt><tt>}</tt><tt><br>
    </tt><tt><br>
    </tt><tt>#</tt><tt><br>
    </tt><tt># Copy .NET assemblies and their native DLL dependencies to
      the target's directory;</tt><tt><br>
    </tt><tt># Also .NET applications may need a side-by-side
      configuration file that must be named like $(target).exe.config -
      copy that if necessary</tt><tt><br>
    </tt><tt>#</tt><tt><br>
    </tt><tt>rule copy-assemblies ( target : properties * )</tt><tt><br>
    </tt><tt>{</tt><tt><br>
    </tt><tt>    local assemblies = [ feature.get-values
      &lt;assembly&gt; : $(properties) ] ;</tt><tt><br>
    </tt><tt>    assemblies += [ feature.get-values
      &lt;assembly-dependency&gt; : $(properties) ] ;</tt><tt><br>
    </tt><tt>    if $(assemblies)</tt><tt><br>
    </tt><tt>    {</tt><tt><br>
    </tt><tt>        local target-path = [ on $(target) return $(LOCATE)
      ] ;</tt><tt><br>
    </tt><tt>        for local assembly in $(assemblies)</tt><tt><br>
    </tt><tt>        {</tt><tt><br>
    </tt><tt>            local assembly-path = [ $(assembly).name ] ;</tt><tt><br>
    </tt><tt>            if ! [ path.is-rooted $(assembly-path) ]</tt><tt><br>
    </tt><tt>            {</tt><tt><br>
    </tt><tt>                assembly-path = [ path.join [
      $(assembly).path ] $(assembly-path:D=) ] ;</tt><tt><br>
    </tt><tt>            }</tt><tt><br>
    </tt><tt>            assembly-path = [ path.native $(assembly-path)
      ] ;</tt><tt><br>
    </tt><tt>            local assembly-at-target-filepath = [
      path.native [ path.join $(target-path) $(assembly-path:D=) ] ] ;</tt><tt><br>
    </tt><tt><br>
    </tt><tt>            if $(assembly-at-target-filepath:L) !=
      $(assembly-path:L) &amp;&amp;</tt><tt><br>
    </tt><tt>               ! ( $(assembly-at-target-filepath:L) in
      $(.unique-targets) )</tt><tt><br>
    </tt><tt>            {</tt><tt><br>
    </tt><tt>                .unique-targets +=
      $(assembly-at-target-filepath:L) ;</tt><tt><br>
    </tt><tt>                if ! [ CHECK_IF_FILE
      $(assembly-at-target-filepath:L) ]</tt><tt><br>
    </tt><tt>                {</tt><tt><br>
    </tt><tt>                    common.hard-link
      $(assembly-at-target-filepath) : $(assembly-path) ;</tt><tt><br>
    </tt><tt>                    DEPENDS $(assembly-at-target-filepath)
      : $(target-path) [ $(assembly).actualize ] ;</tt><tt><br>
    </tt><tt>                    DEPENDS $(target) :
      $(assembly-at-target-filepath) ;</tt><tt><br>
    </tt><tt>                    #JAM_SEMAPHORE on $(target-filepath) =
      "dotNetSemaphore" ;</tt><tt><br>
    </tt><tt>                    #JAM_SEMAPHORE on $(target) =
      "dotNetSemaphore" ;</tt><tt><br>
    </tt><tt>                }</tt><tt><br>
    </tt><tt>            }</tt><tt><br>
    </tt><tt>        }</tt><tt><br>
    </tt><tt>    }</tt><tt><br>
    </tt><tt><br>
    </tt><tt>    # .NET applications may need a side-by-side
      configuration file that must be named like $(target).exe.config</tt><tt><br>
    </tt><tt>    local configuration-file = [ feature.get-values
      &lt;configuration-file&gt; : $(properties) ] ;</tt><tt><br>
    </tt><tt>    if $(configuration-file)</tt><tt><br>
    </tt><tt>    {</tt><tt><br>
    </tt><tt>        local target-path = [ on $(target) return $(LOCATE)
      ] ;</tt><tt><br>
    </tt><tt>        local configuration-file-path = [
      $(configuration-file).name ] ;</tt><tt><br>
    </tt><tt>        if ! [ path.is-rooted $(configuration-file-path) ]</tt><tt><br>
    </tt><tt>        {</tt><tt><br>
    </tt><tt>            configuration-file-path = [ path.join [
      $(configuration-file).path ] $(configuration-file-path:D=) ] ;</tt><tt><br>
    </tt><tt>        }</tt><tt><br>
    </tt><tt>        configuration-file-path = [ path.native
      $(configuration-file-path) ] ;</tt><tt><br>
    </tt><tt>        local target-filepath = [ path.native [ path.join
      $(target-path) $(configuration-file-path:D=) ] ] ;</tt><tt><br>
    </tt><tt>        if $(target-filepath) != $(configuration-file-path)
      &amp;&amp;</tt><tt><br>
    </tt><tt>           ! ( $(configuration-file-path) in
      $(.unique-targets) )</tt><tt><br>
    </tt><tt>        {</tt><tt><br>
    </tt><tt>            .unique-targets += $(configuration-file-path) ;</tt><tt><br>
    </tt><tt>            common.hard-link $(target-filepath) :
      $(configuration-file-path) ;</tt><tt><br>
    </tt><tt>            DEPENDS $(target-filepath) : $(target-path) ;</tt><tt><br>
    </tt><tt>            DEPENDS $(target) : $(target-filepath) ;</tt><tt><br>
    </tt><tt>            #JAM_SEMAPHORE on $(target-filepath) =
      "dotNetSemaphore" ;</tt><tt><br>
    </tt><tt>            #JAM_SEMAPHORE on $(target) = "dotNetSemaphore"
      ;</tt><tt><br>
    </tt><tt>        }</tt><tt><br>
    </tt><tt>    }</tt><tt><br>
    </tt><tt>}</tt><br>
  </body>
</html>

--------------21CA42BC0987BD6EF846758C--

--===============5245480630400970436==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Unsubscribe & other changes: https://lists.boost.org/mailman/listinfo.cgi/boost-build

--===============5245480630400970436==--