Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  rc.py   Sprache: Python

 
#!/usr/bin/env python
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""usage: rc.py [options] input.res
A resource compiler for .rc files.

options:
-h, --help     Print this message.
-I<dir>        Add include path, used for both headers and resources.
-imsvc<dir>    Add system include path, used for preprocessing only.
/winsysroot<d> Set winsysroot, used for preprocessing only.
-D<sym>        Define a macro for the preprocessor.
/fo<out>       Set path of output .res file.
/nologo        Ignored (rc.py doesn't print a logo by default).
/showIncludes  Print referenced header and resource files."""

from __future__ import print_function
from collections import namedtuple
import codecs
import os
import re
import subprocess
import sys
import tempfile


THIS_DIR = os.path.abspath(os.path.dirname(__file__))
SRC_DIR = \
    os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(THIS_DIR))))


def ParseFlags():
  """Parses flags off sys.argv and returns the parsed flags."""
  # Can't use optparse / argparse because of /fo flag :-/
  includes = []
  imsvcs = []
  winsysroot = []
  defines = []
  output = None
  input = None
  show_includes = False
  # Parse.
  for flag in sys.argv[1:]:
    if flag == '-h' or flag == '--help':
      print(__doc__)
      sys.exit(0)
    if flag.startswith('-I'):
      includes.append(flag)
    elif flag.startswith('-imsvc'):
      imsvcs.append(flag)
    elif flag.startswith('/winsysroot'):
      winsysroot = [flag]
    elif flag.startswith('-D'):
      defines.append(flag)
    elif flag.startswith('/fo'):
      if output:
        print('rc.py: error: multiple /fo flags''/fo' + output, flag,
              file=sys.stderr)
        sys.exit(1)
      output = flag[3:]
    elif flag == '/nologo':
      pass
    elif flag == '/showIncludes':
      show_includes = True
    elif (flag.startswith('-'or
          (flag.startswith('/'and not os.path.exists(flag))):
      print('rc.py: error: unknown flag', flag, file=sys.stderr)
      print(__doc__, file=sys.stderr)
      sys.exit(1)
    else:
      if input:
        print('rc.py: error: multiple inputs:', input, flag, file=sys.stderr)
        sys.exit(1)
      input = flag
  # Validate and set default values.
  if not input:
    print('rc.py: error: no input file', file=sys.stderr)
    sys.exit(1)
  if not output:
    output = os.path.splitext(input)[0] + '.res'
  Flags = namedtuple('Flags', [
      'includes''defines''output''imsvcs''winsysroot''input',
      'show_includes'
  ])
  return Flags(includes=includes,
               defines=defines,
               output=output,
               imsvcs=imsvcs,
               winsysroot=winsysroot,
               input=input,
               show_includes=show_includes)


def ReadInput(input):
  """"Reads input and returns it. For UTF-16LEBOM input, converts to UTF-8."""
  # Microsoft's rc.exe only supports unicode in the form of UTF-16LE with a BOM.
  # Our rc binary sniffs for UTF-16LE.  If that's not found, if /utf-8 is
  # passed, the input is treated as UTF-8.  If /utf-8 is not passed and the
  # input is not UTF-16LE, then our rc errors out on characters outside of
  # 7-bit ASCII.  Since the driver always converts UTF-16LE to UTF-8 here (for
  # the preprocessor, which doesn't support UTF-16LE), our rc will either see
  # UTF-8 with the /utf-8 flag (for UTF-16LE input), or ASCII input.
  # This is compatible with Microsoft rc.exe.  If we wanted, we could expose
  # a /utf-8 flag for the driver for UTF-8 .rc inputs too.
  # TODO(thakis): Microsoft's rc.exe supports BOM-less UTF-16LE. We currently
  # don't, but for chrome it currently doesn't matter.
  is_utf8 = False
  try:
    with open(input, 'rb'as rc_file:
      rc_file_data = rc_file.read()
      if rc_file_data.startswith(codecs.BOM_UTF16_LE):
        rc_file_data = rc_file_data[2:].decode('utf-16le').encode('utf-8')
        is_utf8 = True
  except IOError:
    print('rc.py: failed to open', input, file=sys.stderr)
    sys.exit(1)
  except UnicodeDecodeError:
    print('rc.py: failed to decode UTF-16 despite BOM', input, file=sys.stderr)
    sys.exit(1)
  return rc_file_data, is_utf8


def Preprocess(rc_file_data, flags):
  """Runs the input file through the preprocessor."""
  clang = os.path.join(SRC_DIR, 'third_party''llvm-build',
                       'Release+Asserts''bin''clang-cl')
  # Let preprocessor write to a temp file so that it doesn't interfere
  # with /showIncludes output on stdout.
  if sys.platform == 'win32':
    clang += '.exe'
  temp_handle, temp_file = tempfile.mkstemp(suffix='.i')
  # Closing temp_handle immediately defeats the purpose of mkstemp(), but I
  # can't figure out how to let write to the temp file on Windows otherwise.
  os.close(temp_handle)
  clang_cmd = [clang, '/P''/DRC_INVOKED''/TC''-''/Fi' + temp_file]
  if flags.imsvcs:
    clang_cmd += ['/X']
  if os.path.dirname(flags.input):
    # This must precede flags.includes.
    clang_cmd.append('-I' + os.path.dirname(flags.input))
  if flags.show_includes:
    clang_cmd.append('/showIncludes')
  clang_cmd += flags.imsvcs + flags.winsysroot + flags.includes + flags.defines
  p = subprocess.Popen(clang_cmd, stdin=subprocess.PIPE)
  p.communicate(input=rc_file_data)
  if p.returncode != 0:
    sys.exit(p.returncode)
  preprocessed_output = open(temp_file, 'rb').read()
  os.remove(temp_file)

  # rc.exe has a wacko preprocessor:
  https://msdn.microsoft.com/en-us/library/windows/desktop/aa381033(v=vs.85).aspx
  # """RC treats files with the .c and .h extensions in a special manner. It
  # assumes that a file with one of these extensions does not contain
  # resources. If a file has the .c or .h file name extension, RC ignores all
  # lines in the file except the preprocessor directives."""
  # Thankfully, the Microsoft headers are mostly good about putting everything
  # in the system headers behind `if !defined(RC_INVOKED)`, so regular
  # preprocessing with RC_INVOKED defined works.
  return preprocessed_output


def RunRc(preprocessed_output, is_utf8, flags):
  if sys.platform.startswith('linux'):
    rc = os.path.join(THIS_DIR, 'linux64''rc')
  elif sys.platform == 'darwin':
    rc = os.path.join(THIS_DIR, 'mac''rc')
  elif sys.platform == 'win32':
    rc = os.path.join(THIS_DIR, 'win''rc.exe')
  else:
    print('rc.py: error: unsupported platform', sys.platform, file=sys.stderr)
    sys.exit(1)
  rc_cmd = [rc]
  # Make sure rc-relative resources can be found:
  if os.path.dirname(flags.input):
    rc_cmd.append('/cd' + os.path.dirname(flags.input))
  rc_cmd.append('/fo' + flags.output)
  if is_utf8:
    rc_cmd.append('/utf-8')
  # TODO(thakis): cl currently always prints full paths for /showIncludes,
  # but clang-cl /P doesn't.  Which one is right?
  if flags.show_includes:
    rc_cmd.append('/showIncludes')
  # Microsoft rc.exe searches for referenced files relative to -I flags in
  # addition to the pwd, so -I flags need to be passed both to both
  # the preprocessor and rc.
  rc_cmd += flags.includes
  p = subprocess.Popen(rc_cmd, stdin=subprocess.PIPE)
  p.communicate(input=preprocessed_output)

  if flags.show_includes and p.returncode == 0:
    TOOL_DIR = os.path.dirname(os.path.relpath(THIS_DIR)).replace("\\""/")
    # Since tool("rc") can't have deps, add deps on this script and on rc.py
    # and its deps here, so that rc edges become dirty if rc.py changes.
    print('Note: including file: {}/tool_wrapper.py'.format(TOOL_DIR))
    print('Note: including file: {}/rc/rc.py'.format(TOOL_DIR))
    print(
        'Note: including file: {}/rc/linux64/rc.sha1'.format(TOOL_DIR))
    print('Note: including file: {}/rc/mac/rc.sha1'.format(TOOL_DIR))
    print(
        'Note: including file: {}/rc/win/rc.exe.sha1'.format(TOOL_DIR))

  return p.returncode


def CompareToMsRcOutput(preprocessed_output, is_utf8, flags):
  msrc_in = flags.output + '.preprocessed.rc'

  # Strip preprocessor line markers.
  preprocessed_output = re.sub(br'^#.*$', b'', preprocessed_output, flags=re.M)
  if is_utf8:
    preprocessed_output = preprocessed_output.decode('utf-8').encode('utf-16le')
  with open(msrc_in, 'wb'as f:
    f.write(preprocessed_output)

  msrc_out = flags.output + '_ms_rc'
  msrc_cmd = ['rc''/nologo''/x''/fo' + msrc_out]

  # Make sure rc-relative resources can be found. rc.exe looks for external
  # resource files next to the file, but the preprocessed file isn't where the
  # input was.
  # Note that rc searches external resource files in the order of
  # 1. next to the input file
  # 2. relative to cwd
  # 3. next to -I directories
  # Changing the cwd means we'd have to rewrite all -I flags, so just add
  # the input file dir as -I flag. That technically gets the order of 1 and 2
  # wrong, but in Chromium's build the cwd is the gn out dir, and generated
  # files there are in obj/ and gen/, so this difference doesn't matter in
  # practice.
  if os.path.dirname(flags.input):
    msrc_cmd += [ '-I' + os.path.dirname(flags.input) ]

  # Microsoft rc.exe searches for referenced files relative to -I flags in
  # addition to the pwd, so -I flags need to be passed both to both
  # the preprocessor and rc.
  msrc_cmd += flags.includes

  # Input must come last.
  msrc_cmd += [ msrc_in ]

  rc_exe_exit_code = subprocess.call(msrc_cmd)
  # Assert Microsoft rc.exe and rc.py produced identical .res files.
  if rc_exe_exit_code == 0:
    import filecmp
    assert filecmp.cmp(msrc_out, flags.output)
  return rc_exe_exit_code


def main():
  # This driver has to do these things:
  # 1. Parse flags.
  # 2. Convert the input from UTF-16LE to UTF-8 if needed.
  # 3. Pass the input through a preprocessor (and clean up the preprocessor's
  #    output in minor ways).
  # 4. Call rc for the heavy lifting.
  flags = ParseFlags()
  rc_file_data, is_utf8 = ReadInput(flags.input)
  preprocessed_output = Preprocess(rc_file_data, flags)
  rc_exe_exit_code = RunRc(preprocessed_output, is_utf8, flags)

  # 5. On Windows, we also call Microsoft's rc.exe and check that we produced
  #   the same output.
  # Since Microsoft's rc has a preprocessor that only accepts 32 characters
  # for macro names, feed the clang-preprocessed source into it instead
  # of using ms rc's preprocessor.
  if sys.platform == 'win32' and rc_exe_exit_code == 0:
    rc_exe_exit_code = CompareToMsRcOutput(preprocessed_output, is_utf8, flags)

  return rc_exe_exit_code


if __name__ == '__main__':
  sys.exit(main())

Messung V0.5
C=94 H=93 G=93

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge