【问题标题】:What is the portable way in CMake to determine the size of a file?CMake中确定文件大小的可移植方式是什么?
【发布时间】:2011-06-30 12:48:39
【问题描述】:

我需要通过 CMake 脚本确定任意文件中的字节数,但要以可移植的方式。

此文件可能很大,因此使用 file(READ...) 命令读取它并计算字符串长度并不是最佳的。

如果我只需要在 MacOS 和/或 Linux 上运行,我只会使用 wc -c,这正是我想要的。但是脚本需要与 Windows 兼容,假设只有 Windows 工具链。 (我对 Windows 开发不是很了解。)

我希望这是一个常见的操作,但在 CMake 模块源代码中没有找到任何类似的东西(可能是搜索错误的东西),并且 cmake -E 命令的 andy 似乎不支持它。

因此,我正在寻找一种通过单个命令获取此信息的巧妙方法,或者关于我可以在 Windows 中使用哪些命令并环绕 if(WIN32) 条件的建议。

【问题讨论】:

  • 我很好奇为什么你会认为这是一个常见的操作。
  • 在设计用于创建和检查各种类型文件的工具中,文件的大小是一个基本属性。 @sakara 的解决方案还包括一个 TIMESTAMP 子命令,这是另一个基本属性。

标签: windows scripting posix cmake portable-applications


【解决方案1】:

有一个名为FileInformation 的 CMake 模块可以让您以可移植的方式获取文件的大小。它在 CMake 的内置 file 命令中添加了一个新的子命令:

file (SIZE filename variable)

【讨论】:

  • 完美!感谢分享这个模块。真的应该是官方发行版的一部分。
  • 我很想知道 macro(file) 的覆盖和使用 _file() 是否是可以与所有 CMake 命令一起使用的常见模式,或者它是否可能只是因为 @ 的底层实现987654327@提供这种能力?我找不到有关此的文档。这是一个非常强大的机制。
  • 这是 CMake 邮件列表中提到的常见模式。见here
【解决方案2】:

不确定你是否会喜欢这个,但我认为编译和运行一个小型 C 程序并使用它的输出将是最简单的方法。毕竟,您需要做的是非常自定义的,但在 C 中很容易做到。

cmake_minimum_required(VERSION 2.8)
project(test)

try_run(RUN_RESULT COMPILE_RESULT ${CMAKE_CURRENT_BINARY_DIR}/bin
    ${CMAKE_CURRENT_SOURCE_DIR}/filesize.c
    RUN_OUTPUT_VARIABLE FILE_SIZE
    ARGS ${CMAKE_CURRENT_SOURCE_DIR}/bigfile)

if (NOT COMPILE_RESULT)
    message(FATAL_ERROR "Filesize failed to compile")
endif()

if (RUN_RESULT EQUAL 0)
    message(STATUS "Filesize ${FILE_SIZE}")
else()
    message(WARNING "Filesize failed")
endif()

在filesize.c中:

#include <stdio.h>
int main(int argc, const char *argv[])
{
        FILE *fp = fopen(argv[1], "rb");
        if (fp != NULL) {
                fseek(fp, 0, SEEK_END);
                printf("%d", ftell(fp));
                fclose(fp);
                return 0;
        }
        return 1;
}

COMPILE_RESULT 为 TRUE 或 FALSE。如果未找到该文件,try_run 将返回错误(在 RUN_RESULT 中)。否则,cmake 会运行程序,该程序会查找文件末尾并以字节为单位打印大小。结果被捕获在 FILE_SIZE 变量中。

唯一的问题是它不适用于交叉编译,因为在这种情况下 try_run 不会运行任何东西。

【讨论】:

  • 感谢您提供详细的方法,并提醒您 CMake 非常擅长创建动态实用程序。我接受了@sakra 的回答,因为它与现有的file() 命令很好地集成在一起,并且很好地封装在一个模块中。这也是一个很好且有用的答案。
  • 没错,加上 sakra 的解决方案适用于交叉编译的代码,因为它不依赖于编译的代码,而是使用特定于平台的脚本(尽管特定于平台的脚本是一个非常滑的斜坡) !)。
【解决方案3】:

好吧,对于短文件,您可以这样做:

function(get_file_size var filename)
    file(READ "${filename}" content HEX)
    string(LENGTH "${content}" content_length)
    math(EXPR content_length "${content_length} / 2")
    set(${var} ${content_length} PARENT_SCOPE)
endfunction()

get_file_size(len "main.c")
message(STATUS "len(main.c)=${len}")

【讨论】:

  • 您需要一些额外的引用,例如string(LENGTH "${content}" content_length) 如果文件包含分号。是的,CMake 引用很奇怪。
猜你喜欢
  • 2022-12-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 1970-01-01
  • 2015-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多