1# Copyright (c) 2005 Alexey Pakhunov. 2# Copyright (c) 2011 Juraj Ivancic 3# 4# Use, modification and distribution is subject to the Boost Software 5# License Version 1.0. (See accompanying file LICENSE_1_0.txt or 6# http://www.boost.org/LICENSE_1_0.txt) 7 8# Microsoft Interface Definition Language (MIDL) related routines 9from b2.build import scanner, type 10from b2.build.toolset import flags 11from b2.build.feature import feature 12from b2.manager import get_manager 13from b2.tools import builtin, common 14from b2.util import regex, utility 15 16def init(): 17 pass 18 19type.register('IDL', ['idl']) 20 21# A type library (.tlb) is generated by MIDL compiler and can be included 22# to resources of an application (.rc). In order to be found by a resource 23# compiler its target type should be derived from 'H' - otherwise 24# the property '<implicit-dependency>' will be ignored. 25type.register('MSTYPELIB', ['tlb'], 'H') 26 27# Register scanner for MIDL files 28class MidlScanner(scanner.Scanner): 29 def __init__ (self, includes=[]): 30 scanner.Scanner.__init__(self) 31 self.includes = includes 32 33 # List of quoted strings 34 re_strings = "[ \t]*\"([^\"]*)\"([ \t]*,[ \t]*\"([^\"]*)\")*[ \t]*" ; 35 36 # 'import' and 'importlib' directives 37 self.re_import = "import" + re_strings + "[ \t]*;" ; 38 self.re_importlib = "importlib[ \t]*[(]" + re_strings + "[)][ \t]*;" ; 39 40 # C preprocessor 'include' directive 41 self.re_include_angle = "#[ \t]*include[ \t]*<(.*)>" ; 42 self.re_include_quoted = "#[ \t]*include[ \t]*\"(.*)\"" ; 43 44 def pattern(): 45 # Match '#include', 'import' and 'importlib' directives 46 return "((#[ \t]*include|import(lib)?).+(<(.*)>|\"(.*)\").+)" 47 48 def process(self, target, matches, binding): 49 included_angle = regex.transform(matches, self.re_include_angle) 50 included_quoted = regex.transform(matches, self.re_include_quoted) 51 imported = regex.transform(matches, self.re_import, [1, 3]) 52 imported_tlbs = regex.transform(matches, self.re_importlib, [1, 3]) 53 54 # CONSIDER: the new scoping rule seem to defeat "on target" variables. 55 g = bjam.call('get-target-variable', target, 'HDRGRIST')[0] 56 b = os.path.normpath(os.path.dirname(binding)) 57 58 # Attach binding of including file to included targets. 59 # When target is directly created from virtual target 60 # this extra information is unnecessary. But in other 61 # cases, it allows to distinguish between two headers of the 62 # same name included from different places. 63 g2 = g + "#" + b 64 65 g = "<" + g + ">" 66 g2 = "<" + g2 + ">" 67 68 included_angle = [ g + x for x in included_angle ] 69 included_quoted = [ g + x for x in included_quoted ] 70 imported = [ g + x for x in imported ] 71 imported_tlbs = [ g + x for x in imported_tlbs ] 72 73 all = included_angle + included_quoted + imported 74 75 bjam.call('INCLUDES', [target], all) 76 bjam.call('DEPENDS', [target], imported_tlbs) 77 bjam.call('NOCARE', all + imported_tlbs) 78 engine.set_target_variable(included_angle , 'SEARCH', [utility.get_value(inc) for inc in self.includes]) 79 engine.set_target_variable(included_quoted, 'SEARCH', [utility.get_value(inc) for inc in self.includes]) 80 engine.set_target_variable(imported , 'SEARCH', [utility.get_value(inc) for inc in self.includes]) 81 engine.set_target_variable(imported_tlbs , 'SEARCH', [utility.get_value(inc) for inc in self.includes]) 82 83 get_manager().scanners().propagate(type.get_scanner('CPP', PropertySet(self.includes)), included_angle + included_quoted) 84 get_manager().scanners().propagate(self, imported) 85 86scanner.register(MidlScanner, 'include') 87type.set_scanner('IDL', MidlScanner) 88 89 90# Command line options 91feature('midl-stubless-proxy', ['yes', 'no'], ['propagated'] ) 92feature('midl-robust', ['yes', 'no'], ['propagated'] ) 93 94flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-stubless-proxy>yes'], ['/Oicf' ]) 95flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-stubless-proxy>no' ], ['/Oic' ]) 96flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-robust>yes' ], ['/robust' ]) 97flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-robust>no' ], ['/no_robust']) 98 99# Architecture-specific options 100architecture_x86 = ['<architecture>' , '<architecture>x86'] 101address_model_32 = ['<address-model>', '<address-model>32'] 102address_model_64 = ['<address-model>', '<address-model>64'] 103 104flags('midl.compile.idl', 'MIDLFLAGS', [ar + '/' + m for ar in architecture_x86 for m in address_model_32 ], ['/win32']) 105flags('midl.compile.idl', 'MIDLFLAGS', [ar + '/<address-model>64' for ar in architecture_x86], ['/x64']) 106flags('midl.compile.idl', 'MIDLFLAGS', ['<architecture>ia64/' + m for m in address_model_64], ['/ia64']) 107 108flags('midl.compile.idl', 'DEFINES', [], ['<define>']) 109flags('midl.compile.idl', 'UNDEFS', [], ['<undef>']) 110flags('midl.compile.idl', 'INCLUDES', [], ['<include>']) 111 112 113builtin.register_c_compiler('midl.compile.idl', ['IDL'], ['MSTYPELIB', 'H', 'C(%_i)', 'C(%_proxy)', 'C(%_dlldata)'], []) 114 115 116# MIDL does not always generate '%_proxy.c' and '%_dlldata.c'. This behavior 117# depends on contents of the source IDL file. Calling TOUCH_FILE below ensures 118# that both files will be created so bjam will not try to recreate them 119# constantly. 120get_manager().engine().register_action( 121 'midl.compile.idl', 122 '''midl /nologo @"@($(<[1]:W).rsp:E= 123"$(>:W)" 124-D$(DEFINES) 125"-I$(INCLUDES)" 126-U$(UNDEFS) 127$(MIDLFLAGS) 128/tlb "$(<[1]:W)" 129/h "$(<[2]:W)" 130/iid "$(<[3]:W)" 131/proxy "$(<[4]:W)" 132/dlldata "$(<[5]:W)")" 133{touch} "$(<[4]:W)" 134{touch} "$(<[5]:W)"'''.format(touch=common.file_creation_command())) 135