web-dev-qa-db-ja.com

自動生成されたCヘッダーへの手動変更を検出する

CSVファイルとpythonスクリプトから生成されたCヘッダーがあります。Cヘッダーには主に#define定数のリストが含まれています。

コンパイル中にこのヘッダーへの手動の変更を検出できるようにしたい(開発のこの初期段階で頻繁に発生する傾向がある)。コンパイラーに警告を表示して、CSVファイルを更新してヘッダーを再生成するように開発者に指示します。

これを行うとしたら、pythonスクリプトでファイル自体に関するある種のメタデータ(おそらくハッシュ)を生成し、コンパイラーが何らかの形でこのハッシュをチェックして比較することになります。ファイルには何がありますか?しかし、それを実行するための最良の方法はわかりません。GCCには、この種の目的に使用できる機能がありますか?

23
9a3eedi

GCCには、この種のものに使用できる機能がありますか?

私はそのような機能を認識しているわけではありません。

ただし、ヘッダーファイルを生成して別のファイル(header_name.md5など)に挿入した後で、MD5チェックサムを生成するようなこともできます。
次に、ビルドシステムで比較することにより、これらをチェックするための事前ビルドステップをセットアップできます。


ファイル自体にハッシュを保持したいというコメントについて:

これは確かに実行可能ですが、次のように少し複雑になります。

  1. 特別なコメントタグなどに保持されている番号なしで、事前構築ステップでハッシュを再構築する必要があります(たとえば、フィルターで除外し、いくつかの標準ツールを使用してMD5ハッシュを構築します)。
  2. MD5ハッシュをファイルから単純に構築し、それを別の場所に保存するのはかなり簡単です。元のファイル自体にそれを置くことは追加のステップです。

「乱雑」に余分なファイルがあるソースツリーについては、それほど心配する必要はありません。これらがビルドプロセス全体で意味と重要性を持っている場合は、ビルド前のステップを誰にとっても簡潔かつ簡潔にしたいと思います。


さらに、あなたが解決しようとしている実際の問題に対する答えが得られないにもかかわらず、@ docbrownの answer に同意します。
これらの生成されたファイルは手動で変更しないでください。

7

この問題に間違った角度から取り組んでいると思います。

ジェネレーターがCヘッダーファイルの先頭に明確で目に見えるコメントを配置できるようにしてください

// This file is autogenerated, don't change it manually,
// any manual changes will get lost after next regeneration.

次に、ビルドプロセスの一部であるCSVファイルからCファイルを生成します(makeファイルで記述します)。

誰かが最初にコメントを無視した場合-運が悪ければ、彼らは確かに数時間の作業を失った後、これをもう一度行うことはありません。

以下のコメンターからのいくつかの追加の推奨事項(すべての寄稿者に感謝):

  • どのツールがどのソースからこのファイルを生成したかを、生成されたコメントに追加します

  • 生成されたファイルを読み取り専用にします(IDEは読み取り専用フラグを無視します)をチームが使用しないようにします)

ヘッダーファイルに時々手動でメンテナンスする必要があるパーツが含まれている場合は、生成されたファイルからインクルードされる2番目のファイルにそれらを移動し、自動生成されるファイルと手動で編集されるファイルを明確に分離します。 。この分離によって、これが「開発の初期段階」であるかどうかにかかわらず、「このヘッダーに手動で変更」を適用する理由はnoになるはずです。

95
Doc Brown

生成されたCヘッダーファイルをまったくコミットしません。実際、現在のファイルを削除し(@ user1936に感謝)、スクリプトを変更してヘッダーファイル.g.h(@davidbakに感謝)を呼び出し、.gitignoreに追加して、誤ってコミットされないようにします。 (@cmasterに感謝します)。

代わりに、csvとpythonスクリプトをコミットし、コンパイル時にCヘッダーファイルを生成するカスタムステップを追加します。これを行う方法の詳細は、特定のツールチェーン(使用するmake/cmake /など.

必要でない場合はスクリプトを実行しないでください。そうしないと、増分ビルドが中断され、すべてが毎回再構築されます。これは通常、makeなどの依存関係として表されます。

@ docbrown's answer で提案されているように、どのようにしてどのソースファイルから生成されたかについてのコメントを、生成されたファイルに追加してください。これにより、特にファイルを変更してすぐに再生成する人にとって、問題の追跡が容易になります。

41
Jonathan

まず免責事項:これは良い考えではないと思います。

しかし、とにかくこれを行う方法の1つを次に示します。

void check_file_time() {
    if (strcmp(__TIMESTAMP__, "Sun Feb 16 19:38:35 2020") != 0)
    {
        asm("do_not_modify_this_file\n");
    }
}

これは、GCC固有のいくつかのトリックに依存しています。

  • 非標準のプリプロセッサマクロ__TIMESTAMP__は、ファイルの変更時刻に展開されます。
  • GCCはstrcmp()について十分に理解しており、-O0であっても、コンパイル時に最適化します。
  • GCCはインラインアセンブラーを許可しますが、到達できなかった場合は無効な命令の生成をスキップします。

生成されるエラーメッセージの例:

$ touch -d 'Sun Feb 16 19:38:35 2020' test.c
$ gcc -Wall test.c
$ touch test.c  # Uh-oh, someone modified it!
$ gcc -Wall test.c
test.c: Assembler messages:
test.c:16: Error: no such instruction: `do_not_modify_this_file'

エラーではなく警告のみが必要な場合は、次のバリアントを使用できます。

void check_file_time() {
        int *do_not_modify_this_file;
        if (strcmp(__TIMESTAMP__, GENERATED_TIMESTAMP) != 0)
        {
                *do_not_modify_this_file = 0;
        }
}

test.c:17:28: warning: ‘do_not_modify_this_file’ is used uninitialized in this function
17
jpa

自動生成された大量のコードを含む多数のコードベースで作業しました。これらのファイルを変更する人々によって引き起こされる問題の量は非常に少なく、通常はすぐに見つけてすぐに解決できます。

ビルドセットアップと使用しているツールについて十分な詳細情報を提供していません。 gccには、ジョブ用のツールがないか、@ jpaで述べたように、それを使用している可能性があります。しかし、これは単なるコンパイルの問題というよりはビルドの問題のようです。Makefile、gradle、またはファイルが生成されてから変更されていないことを確認する場所にステップがあります。

しかし、これは何よりも建築やデザインの問題だと感じています。これが私があなたに行うことを提案するものです:

  • 生成されたファイルの上部に、ユーザーが触れてはならない免責事項を追加します。
  • おそらくファイルにfoo.gen.hしたがって、これらが通常のソースコードではないことは明らかです。
  • これらのファイルを/genディレクトリ、次の/srcリポジトリに1つ(または同等のもの)。とにかく、通常のコードと生成されたコードを明確に分離する必要があります。
  • csvファイルをリポジトリに保存します。 csv -> hビルドステップの一部としての生成。人々が.hファイルは、ビルドの一部としてとにかく再生成されます。
6
Horia Coman

ファイルは編集可能であるか、または生成されています。あなたが本当にそれを両方にしたいのなら、あなたがどの方法を選んだとしても、悪い時間を過ごすことになります。

生成されたファイルの編集を防ぐのは簡単です。コンパイル手順としてファイルを再生成します。 Make、CMakeなどがこれに最適なツールです。もちろん、ファイルはバージョン管理から除外する必要があります(ただし、ソースは必ずバージョン管理する必要があります)。

ここで、プロジェクトに携わる人々がCSVソースの代わりに生成されたヘッダーを編集することを選択する理由があるはずです。理由を見つけて修正してください。多分それは、ヘッダー生成スクリプトを再実行する必要がないという便宜のためだけなのかもしれません。その場合、ビルドプロセスの一部としてそれを実行するのが良い解決策です。

1
Kafein

GNU diffutils またはgit diffを使用します( [〜#〜] git [〜#〜] ...を使用)。いくつかの優れた ビルドオートメーション ツール( ninja または少なくともmakeなど)も使用します。おそらく ccache を使用します。 Makefilerulescmp(1) を使用している可能性があります。組み込みの GNU make ルールを理解するには、make -pも実行します。

コンパイルコマンドを実行するために、変更時間ではなくコンテンツを使用してツールを構築することを検討する場合があります。 scons または omake を調べます。 gccオプション -M のように調べたい場合があります ccacheプリコンパイル済みヘッダー を使用します。

RefPerSys ではomakeを試しましたが、後で GNU make + ccache に切り替え、実際にヘッダーファイルを生成しています。 omakeをあきらめたのは、誰もそのドキュメントを学ぶ時間がないためであり、最近のLinuxディストリビューションではomakeのパッケージが不十分なためです。

継続的インテグレーション を使用していますか?そうでない場合、なぜそうではないのですか?

別の方法として、S.Oの質問 makeファイルからbashスクリプトを実行する を読んでください。

重要なのは、ヘッダーファイルはビルドプロセス(Jenkinsなど、またはmake)によって生成され( "ジャストインタイム")、手動による変更が上書きされることです。


[更新]コメントで言ったように、それが1人のプロジェクトの場合、ファイルの命名規則はどうですか、ファイル名のどこかにCONSTを追加するだけですか?