text: # Copyright (c) 2005 Alexey Pakhunov.
  # Copyright (c) 2011 Juraj Ivancic
  #
  # Use, modification and distribution is subject to the Boost Software
  # License Version 1.0. (See accompanying file LICENSE_1_0.txt or
  # http://www.boost.org/LICENSE_1_0.txt)
  
  # Microsoft Interface Definition Language (MIDL) related routines
  from b2.build import scanner, type
  from b2.build.toolset import flags
  from b2.build.feature import feature
  from b2.manager import get_manager
  from b2.tools import builtin, common
  from b2.util import regex, utility
  
  def init():
      pass
  
  type.register('IDL', ['idl'])
  
  # A type library (.tlb) is generated by MIDL compiler and can be included
  # to resources of an application (.rc). In order to be found by a resource 
  # compiler its target type should be derived from 'H' - otherwise
  # the property '<implicit-dependency>' will be ignored.
  type.register('MSTYPELIB', ['tlb'], 'H')
  
  # Register scanner for MIDL files
  class MidlScanner(scanner.Scanner):
      def __init__ (self, includes=[]):
          scanner.Scanner.__init__(self)
          self.includes = includes
  
          # List of quoted strings 
          re_strings = "[ \t]*\"([^\"]*)\"([ \t]*,[ \t]*\"([^\"]*)\")*[ \t]*" ;
  
          # 'import' and 'importlib' directives 
          self.re_import    = "import" + re_strings + "[ \t]*;" ;
          self.re_importlib = "importlib[ \t]*[(]" + re_strings + "[)][ \t]*;" ;
  
          # C preprocessor 'include' directive
          self.re_include_angle  = "#[ \t]*include[ \t]*<(.*)>" ;
          self.re_include_quoted = "#[ \t]*include[ \t]*\"(.*)\"" ;
  
      def pattern():
          # Match '#include', 'import' and 'importlib' directives
          return "((#[ \t]*include|import(lib)?).+(<(.*)>|\"(.*)\").+)"
  
      def process(self, target, matches, binding):
          included_angle  = regex.transform(matches, self.re_include_angle)
          included_quoted = regex.transform(matches, self.re_include_quoted)
          imported        = regex.transform(matches, self.re_import, [1, 3])
          imported_tlbs   = regex.transform(matches, self.re_importlib, [1, 3])
  
          # CONSIDER: the new scoping rule seem to defeat "on target" variables.
          g = bjam.call('get-target-variable', target, 'HDRGRIST')[0]
          b = os.path.normpath(os.path.dirname(binding))
  
          # Attach binding of including file to included targets.
          # When target is directly created from virtual target
          # this extra information is unnecessary. But in other
          # cases, it allows to distinguish between two headers of the 
          # same name included from different places.      
          g2 = g + "#" + b
  
          g = "<" + g + ">"
          g2 = "<" + g2 + ">"
  
          included_angle  = [ g + x for x in included_angle  ]
          included_quoted = [ g + x for x in included_quoted ]
          imported        = [ g + x for x in imported        ]
          imported_tlbs   = [ g + x for x in imported_tlbs   ]
  
          all = included_angle + included_quoted + imported
  
          bjam.call('INCLUDES', [target], all)
          bjam.call('DEPENDS', [target], imported_tlbs)
          bjam.call('NOCARE', all + imported_tlbs)
          engine.set_target_variable(included_angle , 'SEARCH', [utility.get_value(inc) for inc in self.includes])
          engine.set_target_variable(included_quoted, 'SEARCH', [utility.get_value(inc) for inc in self.includes])
          engine.set_target_variable(imported       , 'SEARCH', [utility.get_value(inc) for inc in self.includes])
          engine.set_target_variable(imported_tlbs  , 'SEARCH', [utility.get_value(inc) for inc in self.includes])
          
          get_manager().scanners().propagate(type.get_scanner('CPP', PropertySet(self.includes)), included_angle + included_quoted)
          get_manager().scanners().propagate(self, imported)
  
  scanner.register(MidlScanner, 'include')
  type.set_scanner('IDL', MidlScanner)
  
  
  # Command line options
  feature('midl-stubless-proxy', ['yes', 'no'], ['propagated'] )
  feature('midl-robust', ['yes', 'no'], ['propagated'] )
  
  flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-stubless-proxy>yes'], ['/Oicf'     ])
  flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-stubless-proxy>no' ], ['/Oic'      ])
  flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-robust>yes'        ], ['/robust'   ])
  flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-robust>no'         ], ['/no_robust'])
  
  # Architecture-specific options
  architecture_x86 = ['<architecture>' , '<architecture>x86']
  address_model_32 = ['<address-model>', '<address-model>32']
  address_model_64 = ['<address-model>', '<address-model>64']
  
  flags('midl.compile.idl', 'MIDLFLAGS', [ar + '/' + m for ar in architecture_x86 for m in address_model_32 ], ['/win32'])
  flags('midl.compile.idl', 'MIDLFLAGS', [ar + '/<address-model>64' for ar in architecture_x86], ['/x64'])
  flags('midl.compile.idl', 'MIDLFLAGS', ['<architecture>ia64/' + m for m in address_model_64], ['/ia64'])
  
  flags('midl.compile.idl', 'DEFINES', [], ['<define>'])
  flags('midl.compile.idl', 'UNDEFS', [], ['<undef>'])
  flags('midl.compile.idl', 'INCLUDES', [], ['<include>'])
  
  
  builtin.register_c_compiler('midl.compile.idl', ['IDL'], ['MSTYPELIB', 'H', 'C(%_i)', 'C(%_proxy)', 'C(%_dlldata)'], [])
  
  
  # MIDL does not always generate '%_proxy.c' and '%_dlldata.c'. This behavior 
  # depends on contents of the source IDL file. Calling TOUCH_FILE below ensures
  # that both files will be created so bjam will not try to recreate them 
  # constantly.
  get_manager().engine().register_action(
      'midl.compile.idl',
      '''midl /nologo @"@($(<[1]:W).rsp:E=
  "$(>:W)"
  -D$(DEFINES)
  "-I$(INCLUDES)"
  -U$(UNDEFS)
  $(MIDLFLAGS)
  /tlb "$(<[1]:W)"
  /h "$(<[2]:W)"
  /iid "$(<[3]:W)"
  /proxy "$(<[4]:W)"
  /dlldata "$(<[5]:W)")"
  {touch} "$(<[4]:W)"  
  {touch} "$(<[5]:W)"'''.format(touch=common.file_creation_command()))
  