@ -436,9 +436,30 @@ class Vs2010Backend(backends.Backend):
# they are part of the CustomBuildStep Outputs.
return
@classmethod
def quote_define_cmdline ( cls , arg ) :
return re . sub ( r ' ^([-/])D(.*?)= " (.*) " $ ' , r ' \ 1D \ 2= \ " \ 3 \ " ' , arg )
@staticmethod
def escape_preprocessor_define ( define ) :
# See: https://msdn.microsoft.com/en-us/library/bb383819.aspx
table = str . maketrans ( { ' % ' : ' % 25 ' , ' $ ' : ' % 24 ' , ' @ ' : ' % 40 ' ,
" ' " : ' % 27 ' , ' ; ' : ' % 3B ' , ' ? ' : ' %3F ' , ' * ' : ' % 2A ' ,
# We need to escape backslash because it'll be un-escaped by
# Windows during process creation when it parses the arguments
# Basically, this converts `\` to `\\`.
' \\ ' : ' \\ \\ ' } )
return define . translate ( table )
@staticmethod
def escape_additional_option ( option ) :
# See: https://msdn.microsoft.com/en-us/library/bb383819.aspx
table = str . maketrans ( { ' % ' : ' % 25 ' , ' $ ' : ' % 24 ' , ' @ ' : ' % 40 ' ,
" ' " : ' % 27 ' , ' ; ' : ' % 3B ' , ' ? ' : ' %3F ' , ' * ' : ' % 2A ' , ' ' : ' % 20 ' , } )
option = option . translate ( table )
# Since we're surrounding the option with ", if it ends in \ that will
# escape the " when the process arguments are parsed and the starting
# " will not terminate. So we escape it if that's the case. I'm not
# kidding, this is how escaping works for process args on Windows.
if option . endswith ( ' \\ ' ) :
option + = ' \\ '
return ' " {} " ' . format ( option )
@staticmethod
def split_link_args ( args ) :
@ -633,7 +654,7 @@ class Vs2010Backend(backends.Backend):
# so filter them out if needed
d_compile_args = compiler . unix_compile_flags_to_native ( d . get_compile_args ( ) )
for arg in d_compile_args :
if arg . startswith ( ' -I ' ) :
if arg . startswith ( ' -I ' ) or arg . startswith ( ' /I ' ) :
inc_dir = arg [ 2 : ]
# De-dup
if inc_dir not in inc_dirs :
@ -641,8 +662,24 @@ class Vs2010Backend(backends.Backend):
else :
general_args . append ( arg )
defines = [ ]
# Split preprocessor defines and include directories out of the list of
# all extra arguments. The rest go into %(AdditionalOptions).
for l , args in extra_args . items ( ) :
extra_args [ l ] = [ Vs2010Backend . quote_define_cmdline ( x ) for x in args ]
extra_args [ l ] = [ ]
for arg in args :
if arg . startswith ( ' -D ' ) or arg . startswith ( ' /D ' ) :
define = self . escape_preprocessor_define ( arg [ 2 : ] )
# De-dup
if define not in defines :
defines . append ( define )
elif arg . startswith ( ' -I ' ) or arg . startswith ( ' /I ' ) :
inc_dir = arg [ 2 : ]
# De-dup
if inc_dir not in inc_dirs :
inc_dirs . append ( inc_dir )
else :
extra_args [ l ] . append ( self . escape_additional_option ( arg ) )
languages + = gen_langs
has_language_specific_args = any ( l != extra_args [ ' c ' ] for l in extra_args . values ( ) )
@ -669,7 +706,7 @@ class Vs2010Backend(backends.Backend):
inc_dirs . append ( ' % (AdditionalIncludeDirectories) ' )
ET . SubElement ( clconf , ' AdditionalIncludeDirectories ' ) . text = ' ; ' . join ( inc_dirs )
preproc = ET . SubElement ( clconf , ' PreprocessorDefinitions ' )
ET . SubElement ( clconf , ' PreprocessorDefinitions ' ) . text = ' ; ' . join ( defines )
rebuild = ET . SubElement ( clconf , ' MinimalRebuild ' )
rebuild . text = ' true '
funclink = ET . SubElement ( clconf , ' FunctionLevelLinking ' )