77

私は非常に大きなコードベース (読み取り: 数千のモジュール) を持っており、さまざまな C++ コンパイラを使用してさまざまなオペレーティング システムで実行される多数のプロジェクト間でコードが共有されています。言うまでもなく、ビルド プロセスを維持するのは非常に面倒です。

#includesファイルが現在のフォルダーに存在しないかどうかをプリプロセッサに確実に無視させる方法があれば、コードを大幅にクリーンアップできるコードベースの場所がいくつかあります。誰もそれを達成する方法を知っていますか?

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

4

9 に答える 9

107

リトルアップデート

一部のコンパイラは、__has_include ( header-name ).

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

コンパイラのサポート

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

例 (clang の Web サイトから):

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

ソース

于 2015-10-21T13:03:23.107 に答える
51

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

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

header1.h:

#define header1_is_missing

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

#include <header1.h>
#ifdef header1_is_missing

   // there is no header1.h 

#endif
于 2008-09-27T04:34:08.533 に答える
32

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

于 2008-09-27T03:47:02.220 に答える
11

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

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

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

于 2008-09-27T03:48:16.147 に答える
5

別の可能性:オプションで含めたいすべてのヘッダーの長さゼロのバージョンをディレクトリのどこかに配置します。最後のそのようなオプションとして、このディレクトリに-I引数を渡します。

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

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

于 2008-09-27T04:31:23.050 に答える
4

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

#define EXISTS_FILE1_C
#define EXISTS_FILE1_H
#define EXISTS_FILE2_C

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

于 2008-09-27T03:27:29.397 に答える
4

私の知る限り、cpp にはファイルの存在に関するディレクティブはありません。

プラットフォーム間で同じ make を使用している場合は、Makefile の助けを借りてこれを達成できるかもしれません。Makefile 内のファイルの存在を検出できます。

foo.o: foo.c
    if [ -f header1.h ]; then CFLAGS+=-DHEADER1_INC

@Greg Hewgill が言及しているように、#includes を条件付きにすることができます。

#ifdef HEADER1_INC
#include <header1.h>
#endif
于 2008-09-27T03:54:43.887 に答える
2

__has_includeここやインターネットでのいくつかの主張に反して、少なくとも私の経験によれば、Visual Studio 2015 はこの機能をサポートしていません。Update 3 でテスト済み。

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

于 2018-09-11T11:59:59.490 に答える
1

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終了

check.mk ファイルを bld.inf ファイルに含めます。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
于 2009-07-02T11:38:12.487 に答える