新しいコンパイラを追加する

このセクションでは基本的なCCTを生成するためのフィルタの記述の仕方を示します。CCTの詳細については Auto CCTsを参照してください。

コンパイラが GNU ベースのコンパイラまたは、すでに実装してあるコンパイラがGNU ベースのコンパイラに似ている場合、既存のフィルタからフィルタファイルをコピーすることからスタートします。場所については後述されています。

使用しているプロセス名に対しどのフィルタファイルを使用するかを選択する設定ファイルについての詳細についてはAUTO CCT スクリプトを使って作業する を参照してください。

CCTを生成するためには以下の基本的な要件があります。

Built-in Defines

各コンパイラは自動的にい付くかのシンボルを定義します。例えば、よく知られているものとしては __WIN32 および __GNUC__ があります。ほとんどのコンパイラにはシンボルのリストを取得する方法があります。

Auto CCT はGNU オプションをデフォルトで使用しすべての defines (および インクルードパス)をリストするようコンパイラに要請します。

gcc -Wp,-v -Wp,-dM -E <filename> 

このコマンドを実行することで、どの define をコンパイラが自動的に追加したかを表示する#define で始まる長いリストを生成します。リストこのはパースされ生成されるCCTに追加されます。

その他のコンパイラは異なるオプションを必要とし、異なる出力形式のリストを生成します。CCTを生成するためには、コンパイラマニュアルまたは、その他の手段でこの情報を取得する必要があります。

もしリストを生成する簡単なオプションがない場合、ハードコードされたリストなど他の手段でリストを取得するために read_defines 関数を使用することができます。詳細についてはfilter_init 関数 と filterの設定を参照してください。

Include Paths

CCTを生成するには stdio.h または、 iostream などコンパイラのヘッダを含むフォルダのリストも必要とします。GNUの場合、definesのリスト表示する同じコマンドが includesのリストも含むため、Auto CCT システムは1つの結果を使って作業し、その出力から includes defines をパースするようデフォルト設定されています。

ユーザのコンパイラが異なるオプション設定を必要とする場合、read_includes 関数で対応が可能です。詳細については、filter_init 関数 と filterの設定を参照してください。

Version

CCTはコンパイラのバージョン番号を情報としてもっています。 バージョンは version_options のパラメータおよび、version_re を使用した出力のパースの結果を使用しコンパイラを実行することで取得できます。詳細については、filter_init 関数 と filterの設定を参照してください。

バージョンが取得できれば、もっとも基本的なCCTを生成することができます。例えば、このフィルタは Microchip xc8 コンパイラに上記の基本的な機能を実装します。

GNUとは異なる形式の defines を生成するため、Microchip xc8 format を読込むために read_ defines が記述されていることに留意してください。インクルードファイルもGNUとはことなる形式を使用します。

決まった場所に記述するボイラープレートコードがあります。それはCCT dataクラス (後に説明があります)および、 _generates_cip_include の値を True に設定する必要のある Configurator クラスです。includes をCIP生成の段階に依存するのではなくフィルタ内で検索するため、Configurator クラスが必要とされます。

Configurator クラスには2つのプロパティがあり、表示の目的でCIPファイルに情報を提供するだけのために定義する必要があります。

import shlex

from emb import debug

from qa_cctdata import CCTData from qa_gnu_kwinject_api 
import * from qa_non_msvs_configurator import 
QANonMSVSConfigurator

import qa_util


class XC8CCTData(CCTData):
    def __init__(self):
        super(XC8CCTData, self).__init__()

    @property
    def size_type_map(self):
        return {}
class QAxc8Configurator(QANonMSVSConfigurator):
    def __init__(self, *args, **kwargs): 
        super(QAxc8Configurator, self).__init__(*args, 
        **kwargs)
        self._generates_cip_includes = True
        
    @property
    def target(self):
        return qa_util.get_option(r'--chip=([a-zA-Z0-9_]+)', self.conf.path)

    @property
    def hierarchy(self):
        return 'Microchip'

def _read_defines(buf, *discard_args):
    debug("xc8 read_defines")
    defines = []
    for line in buf.splitlines():
        m = re.match(r'.*(\[.*\])', line)
        if m:
            params = m.group(1)[1:-1]

        for opt in shlex.split(params):
            if opt[:2] == '-D':
                if '=' in opt:
                    defines.append(opt)
                else:
                    defines.append(opt + '=')
        return defines
    return defines
    
def _read_includes(buf, compiler_path, *discard_args):
    debug("xc8 read_includes " + str(compiler_path) + " " + buf)     
include_lines = []
    include_flags = ['-I']
    for line in buf.splitlines():
        if any(x in line for x in include_flags):
            for param in shlex.split(line):
                debug("checking " + param)
                for include_flag in include_flags:
                    if param.startswith(
                        include_flag
                    ) and param not in QAEnvStorage.get_command_args(compiler_ path):
                        
                        include_lines.append(param[len(include_flag) :])
    unique_include_lines = []
    for include in include_lines:
        if include not in unique_include_lines:
            unique_include_lines.append(include)
    return unique_include_lines
    
    
filter_init(
    "Microchip XC8",     version_re=r'V(\d+)\.(\d+)',     
version_options=['--help'],     info_args=['-V', '-
V', '--pass1'],     read_defines=_read_defines,     
read_includes=_read_includes,     
configurator_cls=QAxc8Configurator,     
cctdata_selector={'c': XC8CCTData(), 'c++': None}, 
)

上記のように設定されたフィルタを使用したAuto CCT同期メソッドの使用はインクルードフォルダのリストおよび、built-in defines のリストをもつCCTファイルを生成します。

しかし、CIP(Compiler Include Paths)の生成が失敗するため、未知の例外エラーがレポートされます。これはCIPスクリプトが指定されていないためです。


CIP Generation

Auto CCTの前にCIPスクリプトがコンパイラのインクルードフォルダの場所を検索します。スクリプトは解析の直前に実行されます。

Auto CCTでは、ここで示したようにフィルタでこの作業をすることが道理にかなっています。パーサに渡される情報にプロジェクト特有のインクルードの場所を追加するためにはCIPスクリプトが必要とされます。この情報はコンパイラ特有ではないため、同じCIPスクリプトをAuto CCT で生成するCCTに使用することができます。

CCTにCIPスクリプトを追加するためには XC8CCTDataC class に以下を追加します。

@property
def masterscript_include(self):
    return 'DATA/autocct/Script/master_script.py'

CIP生成スクリプトが指定されたので、CCTの生成はエラーなしで完了し、基本コードの解析は正常に動作します。

Compiler オプション

Microchip はGNUベースであり、Auto CCTの生成はGNUオプションをデフォルトで認識するため何もする必要がありません。その他のコンパイラについては、Visitor クラスを定義しなければならず、パラメータタイプを指定するコンパイラオプションのリストが必要とされます。

qa_tasking_filter.py に Visitor クラスの例があります。クラスの最初の部分を以下に示します。

class QATaskingVisitor(QAVisitor):
    _aliases = {
        'include_file': ['H', 'include-macros-file'],
    }
    
    def __init__(self):
        debug("QATaskingVisitor::__init__()"
        super(QATaskingVisitor, self).__init__()
        # GNUと同じparser_options だが -ex dollar - がない
        self._qac_parser_options = {'bits': False, 'u': False}
        self._qacpp_parser_options = {'bits': False, 'ifn': False, 'sig': False,
'sep': True}

    def visit_include_file(self, option):
        # "Forced include" サポート
        self._set_option_always('fi', '"' + self.convert_to_posix_like(option.args [0]) + '"')

最初にエイリアスの設定をすることで -H または、 -include-macros-file が強制インクルードファイルオプションとして機能することを許容します。両方とも visit_include_file 関数が呼出される要因です。

コンストラクタはCCTのオプション依存部分のいくつかのデフォルト値を定義します。シンプルなものとしてC言語のchar型の符号属性を制御する u フラグがあります。 その他の設定についてはPerforce QAC for C コンポーネントマニュアルを参照してください。

Auto CCTがプロセスできるオプションのリストは指定されなければなりません。例えば、以下は Tasking filter のリストです。

class TaskingOptions(QAOptions):
    def _get_options(self):
        return {
            'I': [1],
            'include_path': [1],
            'D': [1],
            'define': [1],
            'include-file': [1],
            'include-macros-file': [1],
            'H': [1],
            'user-defined-literals': [0],
            'nullptr': [0],
            'no-nullptr': [0],
            'no-auto-storage': [0],
            'signed-bitfields': [0],
            'ignore-std': [0],
            'friend-injection': [0],
            'no-dep-name': [0],
            'no-arg-dep-lookup': [0],
        }

角括弧内の数字はオプションが要するパラメータの数です。各オプションは名前の最初に visit_ をつけることにより、Visitor クラスの同じ名前の関数を呼出します。

Stub Files

製品付随のCCTと同様、コンパイラ機能または、ビルトイン関数をエミュレートするインクルードファイルが必要なことが度々あります。additional_include 関数内でフォルダの場所を指定することができます。

@property
def additional_includes(self):
    return 'DATA/autocct/Stub/Tasking_C'
テスト

CCTが完了したことを確実にするためのテストとしてすべてのコンパイラヘッダを含むファイルを解析する方法があります。多くの場合、コンパイラがサポートする非標準拡張による問題を表示します。

その他の設定

CCTのフル機能を活用するためにはさらに多くの設定が必要です。 例えば、size_type_map 関数には様々な標準型のサイズを指定する必要があります。

前述したように、追加の設定の加え方の例として既存のフィルタを使用します。詳細についてはAuto CCTのクラスに関するドキュメントを参照してください。