こんにちは。田原です。

第13回 fileコマンドが拡張されているぞ!」のまとめで「残りは次回」って書いていたことをすっかり忘れてました。ごめんなさい。今回は前々回のfileコマンドの続きを解説します。fileコマンドはファイルのリード/ライト、ファイルのコピー等のファイル操作、パス変換が1つのコマンドに押し込められていますので、ちょっと注意です。

1.リードライト

1-1. READとSTRING

READSTRINGはどちらもファイルの内容を変数へ読み込みます。
前者は改行は改行のまま読み込みます。後者は改行で区切ってリストとして読み込みます。

イキナリサンプルです。

file(READ "file.txt" DATA)
message(STATUS "DATA=${DATA}")
message(STATUS "------------")

file(STRINGS "file.txt" DATA)
message(STATUS "DATA=${DATA}")
message(STATUS "------------")
test1
test2
実行結果
[text] >cmake -P sample.cmake
— DATA=test1
test2

— ————
— DATA=test1;test2
— ————
[/text]

1-2. WRITEAPPEND

そのまんまです。ファイルへ上書きとファイルへ追記です。(サンプルの都合でファイル・コピーも使ってますが、解説を後述しています。)

サンプルです。

file(WRITE  "file1.txt" "write1\nwrite2\n")
file(COPY   "file1.txt" DESTINATION "backup")
file(APPEND "file1.txt" "write3\nwrite4\n")
実行結果
[text] >cmake -P sample.cmake
[/text] [text title=”file1.txt”] write1
write2
write3
write4
[/text] [text title=”backup/file1.txt”] write1
write2
[/text]

1-3. ファイルのハッシュ値計算(リード系に分類されています)

指定されたファイルのMD5やSHA1等のハッシュ値を計算します。
計算できるハッシュ値は、STRINGコマンドのハッシュと同じです。

サンプルです。

file(MD5 "file.txt" RESULT)
message(STATUS "RESULT=${RESULT}")
message(STATUS "------------")

file(SHA1 "file.txt" RESULT)
message(STATUS "RESULT=${RESULT}")
message(STATUS "------------")

他のハッシュ計算も使い方は同じです。

実行結果
[text] >cmake -P sample.cmake
— RESULT=0a83be276a24bd1874bad932afda62f7
— ————
— RESULT=bea2192666d0f13a60f4a909337aa8bbec92826f
— ————
[/text]

1-4. TIMESTAMPTOUCH

stringコマンドのTIMESTAMPは現在時刻を返却しましたが、fileコマンドのTIMESTAMPは普通に指定したファイルの更新日時を返却します。

makeを使っている時、たまにtouchコマンドを使うことがあります。このコマンドは指定したファイルの更新日時を現在時刻にします。要するに「ちょっと触ってみる」コマンドです。どんなときに使うかというと、特定のファイルを指定してコンパイルさせたいような時に一々エディタを立ち上げないで済むので便利です。(まぁ最近はエディタやIDEで上書き保存でやることの方が多いように感じます。)
そのコマンドと同様のものがTOUCHとTOUCH_NOCREATEです。

TOUCHは、指定ファイルが無い時、空のファイルが作られます。
TOUCH_NOCREATEは、読んで字のごとしです。指定ファイルが無い時にそのファイルは生成されず、単に無視されます。

サンプルです。

file(TOUCH     "file2.txt")
file(TIMESTAMP "file2.txt" RESULT)
message(STATUS "RESULT=${RESULT}")
message(STATUS "------------")

file(TOUCH_NOCREATE "file3.txt")
file(TIMESTAMP      "file3.txt" RESULT)
message(STATUS "RESULT=${RESULT}")
message(STATUS "------------")
実行結果
[text] >cmake -P sample.cmake
— RESULT=2019-12-01T20:19:11
— ————
— RESULT=
— ————
[/text] file2.txt、file3.txtは存在していなかったのですが、file2.txtはTOUCHで生成されます。サイズは0です。
file3.txtは生成されないため、TIMESTAMPを取得できていません。エラーは発生しません。

他にGET_RUNTIME_DEPENDENCIESが3.16で追加されているようです。またGENERATEというコマンドもありました。でも、ごめんなさい。ざっと見てみたのですが、よく意味が分かっていません。解説は見送ります。

2.ファイル操作

前節で書いたCOPYのように、ファイルのコピーや削除、フォルダの作成等のファイル操作を行うコマンドもfileコマンドです。第13回 fileコマンドが拡張されているぞ!で解説したGLOB/GLOB_RECURSEもファイル操作系です。

自明なコマンドばかりなので表で簡単に示します。

名前 動作内容
GLOB / GLOB_RECURSE ファイル・リストの抽出です。詳しくは第13回を参照下さい
RENAME ファイル名変更です(一般的なlinuxコマンドのようなmv(move)はありません)
REMOVE ファイル削除です
REMOVE_RECURSE 再帰的にファイルを削除します。フォルダを削除する時に使います
MAKE_DIRECTORY フォルダを作ります
COPY / INSTALL 複数のファイルを指定したフォルダへコピーします。
注意事項があります!!フォルダ・ツリーは維持されません
全てのファイルが指定フォルダ直下へコピーされます(昔かなりハマりました)
INSTALLはCOPYとほぼ同じです
SIZE ファイルのバイト数を指定変数へ取り出します
READ_SYMLINK シンボリックリンクが参照する実ファイルのパスを指定変数へ取り出します
CREATE_LINK 指定ファイルのシンボリックリンクを作成します

振る舞いが分かりにくいものについてのサンプルです。

file(REMOVE_RECURSE "destination")
file(COPY "file.txt" "backup/file1.txt" DESTINATION "destination")
file(GLOB_RECURSE FILE_LIST RELATIVE "${CMAKE_SOURCE_DIR}" "destination/*")
message(STATUS "FILE_LIST=${FILE_LIST}")
message(STATUS "------------")
実行結果
[text] >cmake -P sample.cmake
— FILE_LIST=destination/file.txt;destination/file1.txt
— ————
[/text]

3.パス変換

文字列を「パス」とみなして変換します。ファイルの実体とは無関係です。実体がなくてもパス変換されます。

名前 動作内容
RELATIVE_PATH 絶対パスを相対パスへ変換します。
TO_CMAKE_PATH CMake形式のパスへ変換します。要するに区切り記号が ‘/’ です
TO_NATIVE_PATH 使っているOS形式のパスへ変換します

比較的 良く使うコマンドのサンプルです。

file(RELATIVE_PATH RESULT "C:/dummy/" "C:/dummy/abc.txt")
message(STATUS "RESULT=${RESULT}")
message(STATUS "------------")

file(RELATIVE_PATH RESULT "/dummy/" "/dummy/def.txt")
message(STATUS "RESULT=${RESULT}")
message(STATUS "------------")

file(TO_NATIVE_PATH "C:/dummy/abc.txt" RESULT)
message(STATUS "RESULT=${RESULT}")
message(STATUS "------------")

file(TO_NATIVE_PATH "/dummy/def.txt" RESULT)
message(STATUS "RESULT=${RESULT}")
message(STATUS "------------")

file(TO_CMAKE_PATH "C:\\dummy\\abc.txt" RESULT)
message(STATUS "RESULT=${RESULT}")
message(STATUS "------------")

file(TO_CMAKE_PATH "\\dummy\\abc.txt" RESULT)
message(STATUS "RESULT=${RESULT}")
message(STATUS "------------")
実行結果
[text] >cmake -P sample.cmake
— RESULT=abc.txt
— ————
— RESULT=def.txt
— ————
— RESULT=C:\dummy\abc.txt
— ————
— RESULT=\dummy\def.txt
— ————
— RESULT=C:/dummy/abc.txt
— ————
— RESULT=/dummy/abc.txt
— ————
[/text]

4.まとめ

fileコマンド、如何でしたか? 毛色が似ているけど多くのケースで異なる系統のコマンドが1つのコマンドに押し込められていますね。覚えやすいような覚えにくいような微妙な線です。
そして、実はfileコマンドの一部と被るような機能が CMake -E コマンドでも提供されています。次回はそれらについて対比してみたいと思います。

年内は恐らく今回の投稿が最後と思います。ちょっと早いですが、みなさんも良いお年をお過ごし下さい。

あ~~、年賀状を用意しなければ...