さまざまなC++コンパイラを備えたさまざまなオペレーティングシステムで実行される多数のプロジェクトでコードを共有する非常に大きなコードベース(数千のモジュール)があります。言うまでもなく、ビルドプロセスの維持は非常に面倒です。
コードベースには、プリプロセッサが特定の#includes
ファイルが現在のフォルダーに存在しなかった場合。誰でもそれを達成する方法を知っていますか?
現在、#ifdef
の周辺 #include
は、共有ファイル内にあり、2番目のプロジェクト固有のファイルは、#include
はプロジェクトに存在します。これは機能しますが、見苦しいです。多くの場合、プロジェクトにファイルを追加または削除するときに、定義を適切に更新することを忘れます。このファイルを最新の状態に保つためのビルド前ツールの作成を検討しましたが、プリプロセッサでこれを行うプラットフォームに依存しない方法がある場合は、代わりにその方法を使用します。何か案は?
通常、これは、ファイルをインクルードしようとするとプリプロセッサを実行しようとするスクリプトを使用して行われます。プリプロセッサがエラーを返すかどうかに応じて、スクリプトは適切な#define(または#undef)で生成された.hファイルを更新します。 bashでは、スクリプトは漠然とこのように見えるかもしれません:
cat > .test.h <<'EOM'
#include <asdf.h>
EOM
if gcc -E .test.h
then
echo '#define HAVE_ASDF_H 1' >> config.h
else
echo '#ifdef HAVE_ASDF_H' >> config.h
echo '# undef HAVE_ASDF_H' >> config.h
echo '#endif' >> config.h
fi
このような移植性チェック(および他の何千もの)を移植可能に操作するためのかなり徹底的なフレームワークは、 autoconf です。
一部のコンパイラは、__has_include ( header-name )
をサポートする場合があります。
拡張機能が C++ 17標準 ( P0061R1 )に追加されました。
// Note the two possible file name string formats.
#if __has_include("myinclude.h") && __has_include(<stdint.h>)
# include "myinclude.h"
#endif
欠落しているヘッダー用の特別なフォルダーを作成し、そのフォルダーを最後に検索するようにします
(つまり、コンパイラ固有-「INCLUDES」環境変数の最後の項目、そのようなもの)
次に、header1.hが欠落している場合は、そのフォルダーにスタブを作成します
header1.h:
#define header1_is_missing
今、あなたはいつでも書くことができます
#include <header1.h>
#ifdef header1_is_missing
// there is no header1.h
#endif
プリプロセッサ自体はファイルの存在を識別できませんが、ビルド環境を使用してそれを確認できます。私はほとんどmakeに精通しているので、makefileで次のようなことができます。
ifdef $(test -f filename && echo "present")
DEFINE=-DFILENAME_PRESENT
endif
もちろん、VisualStudioのような他のビルド環境でこれに類似したものを見つける必要がありますが、それらは存在するはずです。
現在のディレクトリに存在するファイルの名前を表す#definesのリストを含むインクルードファイルを生成するビルド前のステップを実行できます。
#define EXISTS_FILE1_C
#define EXISTS_FILE1_H
#define EXISTS_FILE2_C
次に、ソースコード内からそのファイルをインクルードすると、ソースはEXISTS_*
は、ファイルが存在するかどうかを確認するために定義します。
私の知る限り、cppにはファイルの存在に関するディレクティブがありません。
プラットフォーム間で同じmakeを使用している場合は、Makefileの助けを借りてこれを実現できる場合があります。 Makefile内のファイルの存在を検出できます。
foo.o: foo.c
if [ -f header1.h ]; then CFLAGS+=-DHEADER1_INC
@Greg Hewgillが言及しているように、#includeを条件付きにすることができます:
#ifdef HEADER1_INC
#include <header1.h>
#endif
別の可能性:オプションでインクルードしたいすべてのヘッダーの長さゼロのバージョンをディレクトリに追加します。このディレクトリに-I引数を 最終 そのようなオプション。
GCC cppは、インクルードディレクトリを順番に検索します。以前のディレクトリでヘッダーファイルが見つかった場合、それを使用します。そうでなければ、最終的には長さゼロのファイルを見つけて、満足します。
他のcpp実装も、指定された順序でインクルードディレクトリを検索するものと思われます。
Symbian OSでも同様のことをしなければなりませんでした。これが私がやった方法です。ファイル "file_strange.h"が存在するかどうかを確認し、いくつかのヘッダーを含めるか、いくつかのライブラリにリンクするそのファイルの存在について。
最初にそのファイルの存在を確認するための小さなバッチファイルを作成します。
autoconfは優れていますが、多くの小規模なプロジェクトにとっては過剰です。
---------- check.bat
@echo off
IF EXIST [\epoc32\include\domain\middleware\file_strange] GOTO NEW_API
GOTO OLD_API
GOTO :EOF
:NEW_API
echo.#define NEW_API_SUPPORTED>../inc/file_strange_supported.h
GOTO :EOF
:OLD_API
echo.#define OLD_API_SUPPORTED>../inc/file_strange_supported.h
GOTO :EOF
---------- check.batが終了します
それからgnumakeファイルを作成しました
----------checkmedialist.mk
do_nothing :
@rem do_nothing
MAKMAKE :
check.bat
BLD : do_nothing
CLEAN : do_nothing
LIB : do_nothing
CLEANLIB : do_nothing
RESOURCE : do_nothing
FREEZE : do_nothing
SAVESPACE : do_nothing
RELEASABLES : do_nothing
FINAL : do_nothing
----------check.mkが終了します
bld.infファイルにcheck.mkファイルを含めます。MMPファイルの前になければなりません
PRJ_MMPFILES
gnumakefile checkmedialist.mk
コンパイル時にファイルfile_strange_supported.h
には適切なフラグが設定されます。このフラグは、cppファイルで使用することも、mmpファイルで使用することもできます(例:mmp
#include "../inc/file_strange_supported.h"
#ifdef NEW_API_SUPPORTED
LIBRARY newapi.lib
#else
LIBRARY oldapi.lib
#endif
および.cppで
#include "../inc/file_strange_supported.h"
#ifdef NEW_API_SUPPORTED
CStrangeApi* api = Api::NewLC();
#else
// ..
#endif
ここおよびインターネットでのいくつかの主張に反して、Visual Studio 2015は__has_include
機能-少なくとも私の経験によると。アップデート3でテスト済み。
噂は、VS 2017が「バージョン15」とも呼ばれているという事実から生じた可能性があります。 VS 2015は、代わりに「バージョン14」と呼ばれます。この機能のサポートは、「Visual Studio 2017バージョン15.3」で正式に導入されたようです。