パソコンでプログラミングしよう ウィンドウズC++プログラミング環境の構築
1.6.3.6(15)
ソースコード(Code::Blocksパーサーのcc1plus.exe実行)

プロジェクトを開くだけでCode::Blocksが子プロセスとしてcc1plus.exeを実行する理由をソースコードから解析する。

ダウンロードリンク

ソースコード(抜粋)

説明を単純化するため[Settings|Editor|Code completion|C/C++ parser]で[...|Options|Use one parser per project]が選択されている(プロジェクト毎にコード補完のためのパーサーを作成する)とする。

コード補完データベースの作成

ワークスペース変更イベント、プロジェクト選択イベント、いくつかのタイマーイベントなどのハンドラがNativeParser::CreateParser(plugins\codecompletion\nativeparser.cpp:554)をコールする。関数はNativeParser::GetParserByProject(plugins\codecompletion\nativeparser.cpp:256)でプロジェクトパーサーの存在をチェックし、無ければ新たに作成する。

ParserBase* NativeParser::CreateParser(cbProject* project)
{
if ( GetParserByProject(project) )
{
return nullptr;
}
...
ParserBase* parser = new Parser(this, project);
if ( !DoFullParsing(project, parser) )
{
delete parser;
return nullptr;
}
...
return parser;
}

パーサーを作成したらNativeParser::DoFullParsing(plugins\codecompletion\nativeparser.cpp:1054)でコード補完に用いるデータベースを直ちに作成する。

bool NativeParser::DoFullParsing(cbProject* project, ParserBase* parser)
{
...
if (!AddCompilerDirs(project, parser)) ...
if (!AddCompilerPredefinedMacros(project, parser)) ...
if (!AddProjectDefinedMacros(project, parser)) ...
// add per-project dirs
...
// parse priority files
...
return true;
}

NativeParser::AddCompilerPredefinedMacrosはコンパイラ定義済みマクロデータベースを作成し、NativeParser::AddCompilerDirsはインクルードディレクトリデータベースを作成する。各々においてcc1plus.exeが実行される。

定義済みマクロデータベース作成時のcc1plus.exe実行

NativeParser::AddCompilerPredefinedMacros(plugins\codecompletion\nativeparser.cpp:1969)はプロジェクトオプションコンパイラについてGCC用実装のNativeParser::AddCompilerPredefinedMacrosGCC(plugins\codecompletion\nativeparser.cpp:2006)をコールし、コンパイラ定義済みマクロのデータベースを作成する。コンパイラコマンドcpp_compiler+argsが構築されwxExecute(wxWidgetsライブラリ関数)で実行する。

bool NativeParser::AddCompilerPredefinedMacrosGCC(const wxString& compilerId, cbProject* project, wxString& defs, ParserBase* parser)
{
Compiler* compiler = CompilerFactory::GetCompiler(compilerId);
...
#ifdef __WXMSW__
const wxString cpp_compiler = masterPath + _T("\\bin\\") + compiler->GetPrograms().CPP;
#else
const wxString cpp_compiler = masterPath + _T("/bin/") + compiler->GetPrograms().CPP;
#endif
...
static std::map<wxString, wxString> gccDefsMap;
if (gccDefsMap[cpp_compiler].IsEmpty())
{
...
// Check if user set language standard version to use
wxString standard = GetCompilerStandardGCC(compiler, project);
#ifdef __WXMSW__
const wxString args(wxString::Format(_T(" -E -dM -x c++ %s nul"), standard.wx_str()) );
#else
const wxString args(wxString::Format(_T(" -E -dM -x c++ %s /dev/null"), standard.wx_str()) );
#endif
...
if ( wxExecute(cpp_compiler + args, output, wxEXEC_SYNC | wxEXEC_NODISABLE) == -1 )
{
...
}
...
wxString& gccDefs = gccDefsMap[cpp_compiler];
for (size_t i = 0; i < output.Count(); ++i)
gccDefs += output[i] + _T("\n");
}
defs = gccDefsMap[cpp_compiler];
return true;
}

インクルードディレクトリデータベース作成時のcc1plus.exe実行

NativeParser::AddCompilerDirs(plugins\codecompletion\nativeparser.cpp:1884)は全てのインクルードディレクトリについてのデータベースを作成する。コンパイラインクルードディレクトリは全ターゲットオプションコンパイラとプロジェクトオプションコンパイラをあらかじめ配列Compilersに代入し、Compilersの各要素をNativeParser::AddCompilerIncludeDirsToParser(plugins\codecompletion\nativeparser.cpp:2298)へ渡すことで取得する。

bool NativeParser::AddCompilerDirs(cbProject* project, ParserBase* parser)
{
...
// alloc array for project compiler AND "no. of targets" times target compilers
int nCompilers = 1 + project->GetBuildTargetsCount();
Compiler** Compilers = new Compiler* [nCompilers];
memset(Compilers, 0, sizeof(Compiler*) * nCompilers);
nCompilers = 0; // reset , use as insert index in the next for loop
// get targets include dirs
for (int i = 0; i < project->GetBuildTargetsCount(); ++i)
{
ProjectBuildTarget* target = project->GetBuildTarget(i);
if (...)
{
...
// get the compiler
wxString CompilerIndex = target->GetCompilerID();
Compiler* tgtCompiler = CompilerFactory::GetCompiler(CompilerIndex);
if (tgtCompiler)
{
Compilers[nCompilers] = tgtCompiler;
++nCompilers;
}
} // if (target)
} // end loop over the targets
// add the project compiler to the array of compilers
if (compiler)
{ // note it might be possible that this compiler is already in the list
Compilers[nCompilers++] = compiler;
}
// add compiler include dirs
for (int idxCompiler = 0; idxCompiler < nCompilers; ++idxCompiler)
AddCompilerIncludeDirsToParser(Compilers[idxCompiler], parser);
...
return true;
}

NativeParser::AddCompilerIncludeDirsToParserは与えられたコンパイラについて次のインクリードディレクトリをパーサーデータベースに加える。

  • [Setting|Compiler|Global compiler settings]の[...|Selected compiler]でコンパイラを選択し[...|Search directories|Compiler]で設定されたディレクトリ
  • コンパイラ組み込みインクルードディレクトリ(cc1plus.exeインクルードディレクトリ)

cc1plus.exeインクルードディレクトリはNativeParser::AddGCCCompilerDirs(plugins\codecompletion\nativeparser.cpp:2408)を介しNativeParser::GetGCCCompilerDirs(plugins\codecompletion\nativeparser.cpp:2319)で取得する。Commandにコンパイラコマンドを構築しwxExecuteで実行する。

const wxArrayString& NativeParser::GetGCCCompilerDirs(const wxString &cpp_compiler)
{
static std::map<wxString, wxArrayString> dirs;
...
// Different command on Windows
wxString Command = platform::windows ? (cpp_compiler + _T(" -v -E -x c++ nul"))
: (cpp_compiler + _T(" -v -E -x c++ /dev/null"));
...
// action time (everything shows up on the error stream)
wxArrayString Output, Errors;
if ( wxExecute(Command, Output, Errors, wxEXEC_SYNC | wxEXEC_NODISABLE) == -1 )
{
...
}
...
// start from "#include <...>", and the path followed
// let's hope this does not change too quickly, otherwise we need
// to adjust our search code (for several versions ...)
...
return dirs[cpp_compiler];
}