summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile-giscanner.am1
-rw-r--r--giscanner/ccompiler.py64
-rw-r--r--giscanner/msvccompiler.py101
-rw-r--r--giscanner/sourcescanner.py46
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')