web-dev-qa-db-ja.com

Cプリプロセッサを使用して、ファイルが存在するかどうかを確認できますか?

さまざまなC++コンパイラを備えたさまざまなオペレーティングシステムで実行される多数のプロジェクトでコードを共有する非常に大きなコードベース(数千のモジュール)があります。言うまでもなく、ビルドプロセスの維持は非常に面倒です。

コードベースには、プリプロセッサが特定の#includesファイルが現在のフォルダーに存在しなかった場合。誰でもそれを達成する方法を知っていますか?

現在、#ifdef の周辺 #includeは、共有ファイル内にあり、2番目のプロジェクト固有のファイルは、#includeはプロジェクトに存在します。これは機能しますが、見苦しいです。多くの場合、プロジェクトにファイルを追加または削除するときに、定義を適切に更新することを忘れます。このファイルを最新の状態に保つためのビルド前ツールの作成を検討しましたが、プリプロセッサでこれを行うプラットフォームに依存しない方法がある場合は、代わりにその方法を使用します。何か案は?

60
Lisa

通常、これは、ファイルをインクルードしようとするとプリプロセッサを実行しようとするスクリプトを使用して行われます。プリプロセッサがエラーを返すかどうかに応じて、スクリプトは適切な#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 です。

30
Logan

少し更新

一部のコンパイラは、__has_include ( header-name )をサポートする場合があります。

拡張機能が C++ 17標準P0061R1 )に追加されました。

コンパイラーのサポート

  • クラン
  • 5.XからのGCC
  • VS2015 Update 2のVisual Studio(?)

例(clangウェブサイトから):

// Note the two possible file name string formats.
#if __has_include("myinclude.h") && __has_include(<stdint.h>)
# include "myinclude.h"
#endif

ソース

56
Setepenre

欠落しているヘッダー用の特別なフォルダーを作成し、そのフォルダーを最後に検索するようにします
(つまり、コンパイラ固有-「INCLUDES」環境変数の最後の項目、そのようなもの)

次に、header1.hが欠落している場合は、そのフォルダーにスタブを作成します

header1.h:

#define header1_is_missing

今、あなたはいつでも書くことができます

#include <header1.h>
#ifdef header1_is_missing

   // there is no header1.h 

#endif
45
eugensk00

プリプロセッサ自体はファイルの存在を識別できませんが、ビルド環境を使用してそれを確認できます。私はほとんどmakeに精通しているので、makefileで次のようなことができます。

ifdef $(test -f filename && echo "present")
  DEFINE=-DFILENAME_PRESENT
endif

もちろん、VisualStudioのような他のビルド環境でこれに類似したものを見つける必要がありますが、それらは存在するはずです。

8
bmdhacks

現在のディレクトリに存在するファイルの名前を表す#definesのリストを含むインクルードファイルを生成するビルド前のステップを実行できます。

#define EXISTS_FILE1_C
#define EXISTS_FILE1_H
#define EXISTS_FILE2_C

次に、ソースコード内からそのファイルをインクルードすると、ソースはEXISTS_*は、ファイルが存在するかどうかを確認するために定義します。

4
Greg Hewgill

私の知る限り、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
4
DGentry

別の可能性:オプションでインクルードしたいすべてのヘッダーの長さゼロのバージョンをディレクトリに追加します。このディレクトリに-I引数を 最終 そのようなオプション。

GCC cppは、インクルードディレクトリを順番に検索します。以前のディレクトリでヘッダーファイルが見つかった場合、それを使用します。そうでなければ、最終的には長さゼロのファイルを見つけて、満足します。

他のcpp実装も、指定された順序でインクルードディレクトリを検索するものと思われます。

4
DGentry

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
2
Ahmad Mushtaq

ここおよびインターネットでのいくつかの主張に反して、Visual Studio 2015は__has_include機能-少なくとも私の経験によると。アップデート3でテスト済み。

噂は、VS 2017が「バージョン15」とも呼ばれているという事実から生じた可能性があります。 VS 2015は、代わりに「バージョン14」と呼ばれます。この機能のサポートは、「Visual Studio 2017バージョン15.3」で正式に導入されたようです。

1
Christoph Lipka