diff options
-rw-r--r-- | Makefile-giscanner.am | 1 | ||||
-rw-r--r-- | giscanner/ccompiler.py | 64 | ||||
-rw-r--r-- | giscanner/msvccompiler.py | 101 | ||||
-rw-r--r-- | giscanner/sourcescanner.py | 46 |
4 files changed, 171 insertions, 41 deletions
diff --git a/Makefile-giscanner.am b/Makefile-giscanner.am index c2273cd6..5bc84253 100644 --- a/Makefile-giscanner.am +++ b/Makefile-giscanner.am @@ -43,6 +43,7 @@ pkgpyexec_PYTHON = \ giscanner/libtoolimporter.py \ giscanner/maintransformer.py \ giscanner/message.py \ + giscanner/msvccompiler.py \ giscanner/shlibs.py \ giscanner/scannermain.py \ giscanner/sectionparser.py \ diff --git a/giscanner/ccompiler.py b/giscanner/ccompiler.py index 884fc2cc..f9105fe7 100644 --- a/giscanner/ccompiler.py +++ b/giscanner/ccompiler.py @@ -61,7 +61,15 @@ class CCompiler(object): compiler_name = distutils.ccompiler.get_default_compiler() # Now, create the distutils ccompiler instance based on the info we have. - self.compiler = distutils.ccompiler.new_compiler(compiler=compiler_name) + if compiler_name == 'msvc': + # For MSVC, we need to create a instance of a subclass of distutil's + # MSVC9Compiler class, as it does not provide a preprocess() + # implementation + from . import msvccompiler + self.compiler = msvccompiler.get_msvc_compiler() + + else: + self.compiler = distutils.ccompiler.new_compiler(compiler=compiler_name) customize_compiler(self.compiler) # customize_compiler from distutils only does customization @@ -147,6 +155,31 @@ class CCompiler(object): else: args.append('-l' + library) + def preprocess(self, source, output, cpp_options): + extra_postargs = ['-C'] + (include_paths, macros, postargs) = self._set_cpp_options(cpp_options) + + # We always want to include the current path + include_dirs = ['.'] + + include_dirs.extend(include_paths) + extra_postargs.extend(postargs) + + # Define these macros when using Visual C++ to silence many warnings, + # and prevent stepping on many Visual Studio-specific items, so that + # we don't have to handle them specifically in scannerlexer.l + if self.check_is_msvc(): + macros.append(('_USE_DECLSPECS_FOR_SAL', None)) + macros.append(('_CRT_SECURE_NO_WARNINGS', None)) + macros.append(('_CRT_NONSTDC_NO_WARNINGS', None)) + macros.append(('SAL_NO_ATTRIBUTE_DECLARATIONS', None)) + + self.compiler.preprocess(source=source, + output_file=output, + macros=macros, + include_dirs=include_dirs, + extra_postargs=extra_postargs) + def resolve_windows_libs(self, libraries, options): args = [] libsearch = [] @@ -238,3 +271,32 @@ class CCompiler(object): return True else: return False + + # Private APIs + def _set_cpp_options(self, options): + includes = [] + macros = [] + other_options = [] + + for o in options: + option = utils.cflag_real_include_path(o) + if option.startswith('-I'): + includes.append(option[len('-I'):]) + elif option.startswith('-D'): + macro = option[len('-D'):] + macro_index = macro.find('=') + if macro_index == -1: + macro_name = macro + macro_value = None + else: + macro_name = macro[:macro_index] + macro_value = macro[macro_index + 1:] + macros.append((macro_name, macro_value)) + elif option.startswith('-U'): + macros.append((option[len('-U'):],)) + else: + # We expect the preprocessor to remove macros. If debugging is turned + # up high enough that won't happen, so don't add those flags. Bug #720504 + if option not in ['-g3', '-ggdb3', '-gstabs3', '-gcoff3', '-gxcoff3', '-gvms3']: + other_options.append(option) + return (includes, macros, other_options) diff --git a/giscanner/msvccompiler.py b/giscanner/msvccompiler.py new file mode 100644 index 00000000..63248093 --- /dev/null +++ b/giscanner/msvccompiler.py @@ -0,0 +1,101 @@ +# -*- Mode: Python -*- +# GObject-Introspection - a framework for introspecting GObject libraries +# Copyright (C) 2014 Chun-wei Fan +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +import os +import distutils + +from distutils.errors import (DistutilsExecError, CompileError, LibError, + LinkError, UnknownFileError) +from distutils.ccompiler import CCompiler, gen_preprocess_options +from distutils.dep_util import newer + +# Distutil's MSVCCompiler does not provide a preprocess() +# Implementation, so do our own here. + + +def get_msvc_compiler(): + return MSVCCompiler() + + +class MSVCCompiler(distutils.msvccompiler.MSVCCompiler): + + def __init__(self, verbose=0, dry_run=0, force=0): + CCompiler.__init__(self, verbose, dry_run, force) + self.__paths = [] + self.__arch = None # deprecated name + if os.name == 'nt': + if isinstance(self, distutils.msvc9compiler.MSVCCompiler): + self.__version = distutils.msvc9compiler.VERSION + self.initialized = False + self.preprocess_options = None + + def preprocess(self, + source, + output_file=None, + macros=None, + include_dirs=None, + extra_preargs=None, + extra_postargs=None): + if self.initialized is False: + self.initialize() + + (_, macros, include_dirs) = \ + self._fix_compile_args(None, macros, include_dirs) + pp_opts = gen_preprocess_options(macros, include_dirs) + preprocess_options = ['-E'] + source_basename = None + + if output_file is not None: + preprocess_options.append('-P') + source_basename = self._get_file_basename(source) + cpp_args = self.cc.split() + if extra_preargs is not None: + cpp_args[:0] = extra_preargs + if extra_postargs is not None: + preprocess_options.extend(extra_postargs) + cpp_args.extend(preprocess_options) + cpp_args.extend(pp_opts) + cpp_args.append(source) + + # We need to preprocess: either we're being forced to, or the + # source file is newer than the target (or the target doesn't + # exist). + if self.force or output_file is None or newer(source, output_file): + try: + self.spawn(cpp_args) + except DistutilsExecError, msg: + print msg + raise CompileError + + # The /P option for the MSVC preprocessor will output the results + # of the preprocessor to a file, as <source_without_extension>.i, + # so in order to output the specified filename, we need to rename + # that file + if output_file is not None: + if output_file != source_basename + '.i': + os.rename(source_basename + '.i', output_file) + + def _get_file_basename(self, filename): + if filename is None: + return None + if filename.rfind('.') == -1: + return filename[filename.rfind('\\') + 1:] + else: + return filename[filename.rfind('\\') + 1:filename.rfind('.')] diff --git a/giscanner/sourcescanner.py b/giscanner/sourcescanner.py index 9310cff2..e66ed7de 100644 --- a/giscanner/sourcescanner.py +++ b/giscanner/sourcescanner.py @@ -25,6 +25,7 @@ import tempfile from .libtoolimporter import LibtoolImporter from .message import Position +from .ccompiler import CCompiler with LibtoolImporter(None, None): if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ: @@ -282,6 +283,8 @@ class SourceScanner(object): defines = ['__GI_SCANNER__'] undefs = [] + cc = CCompiler() + tmp_fd_cpp, tmp_name_cpp = tempfile.mkstemp(prefix='g-ir-cpp-', suffix='.c') fp_cpp = os.fdopen(tmp_fd_cpp, 'w') self._write_preprocess_src(fp_cpp, defines, undefs, filenames) @@ -293,46 +296,9 @@ class SourceScanner(object): # so we want the name to match the output file name of the MSVC preprocessor tmpfile_output = tmpfile_basename + '.i' - cpp_args = os.environ.get('CC', 'cc').split() # support CC="ccache gcc" - - cpp_args += ['-E', '-C', '-I.'] - - # MSVC: The '-P' option makes the preprocessor output to a file, but we - # can't specify directly the name of the output file, so we use the - # MSVC-style preprocessor output file name for all builds for simplicity - # Define the following macros to silence many, many warnings - # in using the MSVC preprocessor during the parsing stage... - if 'cl.exe' in cpp_args or 'cl' in cpp_args: - cpp_args += ('-P', - '-D_USE_DECLSPECS_FOR_SAL', - '-D_CRT_SECURE_NO_WARNINGS', - '-D_CRT_NONSTDC_NO_WARNINGS', - '-DSAL_NO_ATTRIBUTE_DECLARATIONS') - - cpp_args += self._cpp_options - cpp_args += [tmp_name_cpp] - - # We expect the preprocessor to remove macros. If debugging is turned - # up high enough that won't happen, so strip these out. Bug #720504 - for flag in ['-g3', '-ggdb3', '-gstabs3', '-gcoff3', '-gxcoff3', '-gvms3']: - try: - cpp_args.remove(flag) - except ValueError: - pass - - proc = subprocess.Popen(cpp_args, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - - if 'cl.exe' not in cpp_args and'cl' not in cpp_args: - cpp_args += ['-o', tmpfile_output] - - proc = subprocess.Popen(cpp_args) - - assert proc, 'Proc was none' - proc.wait() - if proc.returncode != 0: - raise SystemExit('Error while processing the source.') + cc.preprocess(tmp_name_cpp, + tmpfile_output, + self._cpp_options) os.unlink(tmp_name_cpp) fp = open(tmpfile_output, 'r') |