如何在CMake中将整数写入文件为字节?

huangapple go评论58阅读模式
英文:

How can I write an int to a file as bytes in CMake?

问题

在CMake中是否有一种原生方法将整数写入文件作为字节?

例如:

file(SIZE generated_file.txt file_size)  # file_size == 465435

file(WRITE output.txt "\x00\x07\x1a\x1b"

我希望${file_size}以固定数量的字节(例如4个)写入,如\x00\x07\x1a\x1b而不是465435

英文:

Is there a native way in CMake to write an int to a file as bytes?

E.g.

file(SIZE generated_file.txt file_size)  # file_size == 465435

file(WRITE output.txt "${file_size}"

Where I would like ${file_size} written as a fixed number of bytes (E.g. 4) \x00\x07\x1a\x1b vs 465435

答案1

得分: 2

CMake不具备整数类型,它只有字符串。如果您想将非ASCII数字文字编码为CMake字符串,可以参考CMake字符串中的转义序列文档:https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#escape-sequences。似乎没有其他方法来编写二进制/十六进制文字,除非实际将这些字符放入字符串中(并在必要时进行转义-例如\")。

另一种方法是调用一个程序,将ASCII十进制字符串转换为整数值并将其写入文件,或者将整数输出到标准输出流,然后使用您用于调用该程序的CMake命令的机制将标准输出作为CMake字符串获取,然后调用file(WRITE ...)。要在配置时执行此操作,请参阅execute_process。要在构建时执行此操作,请参阅add_custom_commandadd_custom_target

英文:

CMake doesn't have integer types. It just has strings. If you want to encode a non-ASCII number literal as a CMake string, the docs for escape sequences in CMake strings is here: https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#escape-sequences. There seems to be no way to write binary/hex literals other than to actually put those characters in the string (and escape them if necessary- Ex. \").

Another approach would be to invoke a program that converts the ASCII decimal string to the integer value and writes it to the file, or outputs the integer to the standard output stream and then use the mechanism of whatever CMake command you use to invoke that program to get the standard output as a CMake string and then call file(WRITE ...). To do that at configure-time, see execute_process. To do it at build-time, see add_custom_command or add_custom_target.

答案2

得分: 2

CMake具有一个名为 string(ASCII) 的命令,用于创建具有给定代码的字节。但要从单个数字创建多个字节,需要手动执行将该数字分割为代码的操作。

CMake对算术和字符串中的字符处理支持不够强大,因此似乎简单的任务 - 将数字分割为十六进制代码 - 需要一些代码:

# 包含一个单个空字节的变量。
#
# CMake不允许在代码中创建空字节。
# 例如,使用“
# 包含一个单个空字节的变量。
#
# CMake不允许在代码中创建空字节。
# 例如,使用“\0”会导致错误“Invalid character escape '\0'.”。
# 因此,我们预先创建一个仅包含单个空字节的文件
# 并在CMake中读取该文件。
#
# 可以使用以下命令创建名为'null.txt'的文件:
#
#   printf "\0" > null.txt
#
file(READ "null.txt" null_char)
# write_number_to_file(<number> <bytes_count> <filename>)
#
# 将给定的数字以字节序列的形式写入文件。
#
# 参数:
# - number - 要写入的数字。
#          可以是十进制、十六进制(前缀为0x),
#          甚至是可由math(EXPR)理解的表达式。
#
# - bytes_count - 应该写入的字节数。
#           如果字节数多于表示数字所需的字节数,
#           则第一个字节将为零。
#
# - filename - 要写入数字的文件路径。
#
function(write_number_to_file number bytes_count filename)
# 将数字转换为十六进制
math(EXPR number_hex "${number}" OUTPUT_FORMAT HEXADECIMAL)
# .. 并去掉 '0x' 前缀
string(SUBSTRING "${number_hex}" 2 -1 number_hex)
# 计算数字中十六进制数字的数量。
string(LENGTH "${number_hex}" hex_digits_count)
# 请求的字节数最大的十六进制数字数。
math(EXPR hex_digits_max_count "${bytes_count} * 2")
# 执行十六进制数字填充,直到达到最大数字
# 要填充的字节数。
math(EXPR pad_len "${hex_digits_max_count} - ${hex_digits_count}")
# 包含将前缀数字的零的字符串。
string(REPEAT "0" ${pad_len} pad_str)
# 填充数字。
string(CONCAT number_hex ${pad_str} ${number_hex})
# 将写入文件的字节
set(bytes)
# 遍历十六进制数字的对,每对将生成一个字节
# 1..<bytes_count>
foreach(i1 RANGE 1 ${bytes_count})
# 第一位数字的索引。
math(EXPR first_digit_index "${i1} * 2 - 2")
# 创建字节的十六进制代码。
string(SUBSTRING "${number_hex}" ${first_digit_index} 2 byte_hex)
if (byte_hex STREQUAL "00")
# 特殊情况:代码为0,但CMake无法创建空字节。
string(CONCAT bytes "${bytes}" "${null_char}")
else()
# 常规情况:非零代码。
# 将代码转换为十进制,因为string(ASCII)不理解十六进制。
math(EXPR byte_code "0x${byte_hex}")
# 使用给定的ASCII代码创建字节。
string(ASCII ${byte_code} byte)
string(CONCAT bytes "${bytes}" "${byte}")
endif()
endforeach()
# 现在一切准备就绪,可以写入文件。
file(WRITE "${filename}" "${bytes}")
endfunction()
”会导致错误“Invalid character escape '
# 包含一个单个空字节的变量。
#
# CMake不允许在代码中创建空字节。
# 例如,使用“\0”会导致错误“Invalid character escape '\0'.”。
# 因此,我们预先创建一个仅包含单个空字节的文件
# 并在CMake中读取该文件。
#
# 可以使用以下命令创建名为'null.txt'的文件:
#
#   printf "\0" > null.txt
#
file(READ "null.txt" null_char)
# write_number_to_file(<number> <bytes_count> <filename>)
#
# 将给定的数字以字节序列的形式写入文件。
#
# 参数:
# - number - 要写入的数字。
#          可以是十进制、十六进制(前缀为0x),
#          甚至是可由math(EXPR)理解的表达式。
#
# - bytes_count - 应该写入的字节数。
#           如果字节数多于表示数字所需的字节数,
#           则第一个字节将为零。
#
# - filename - 要写入数字的文件路径。
#
function(write_number_to_file number bytes_count filename)
# 将数字转换为十六进制
math(EXPR number_hex "${number}" OUTPUT_FORMAT HEXADECIMAL)
# .. 并去掉 '0x' 前缀
string(SUBSTRING "${number_hex}" 2 -1 number_hex)
# 计算数字中十六进制数字的数量。
string(LENGTH "${number_hex}" hex_digits_count)
# 请求的字节数最大的十六进制数字数。
math(EXPR hex_digits_max_count "${bytes_count} * 2")
# 执行十六进制数字填充,直到达到最大数字
# 要填充的字节数。
math(EXPR pad_len "${hex_digits_max_count} - ${hex_digits_count}")
# 包含将前缀数字的零的字符串。
string(REPEAT "0" ${pad_len} pad_str)
# 填充数字。
string(CONCAT number_hex ${pad_str} ${number_hex})
# 将写入文件的字节
set(bytes)
# 遍历十六进制数字的对,每对将生成一个字节
# 1..<bytes_count>
foreach(i1 RANGE 1 ${bytes_count})
# 第一位数字的索引。
math(EXPR first_digit_index "${i1} * 2 - 2")
# 创建字节的十六进制代码。
string(SUBSTRING "${number_hex}" ${first_digit_index} 2 byte_hex)
if (byte_hex STREQUAL "00")
# 特殊情况:代码为0,但CMake无法创建空字节。
string(CONCAT bytes "${bytes}" "${null_char}")
else()
# 常规情况:非零代码。
# 将代码转换为十进制,因为string(ASCII)不理解十六进制。
math(EXPR byte_code "0x${byte_hex}")
# 使用给定的ASCII代码创建字节。
string(ASCII ${byte_code} byte)
string(CONCAT bytes "${bytes}" "${byte}")
endif()
endforeach()
# 现在一切准备就绪,可以写入文件。
file(WRITE "${filename}" "${bytes}")
endfunction()
'.”。 # 因此,我们预先创建一个仅包含单个空字节的文件 # 并在CMake中读取该文件。 # # 可以使用以下命令创建名为'null.txt'的文件: # # printf "
# 包含一个单个空字节的变量。
#
# CMake不允许在代码中创建空字节。
# 例如,使用“\0”会导致错误“Invalid character escape '\0'.”。
# 因此,我们预先创建一个仅包含单个空字节的文件
# 并在CMake中读取该文件。
#
# 可以使用以下命令创建名为'null.txt'的文件:
#
#   printf "\0" > null.txt
#
file(READ "null.txt" null_char)
# write_number_to_file(<number> <bytes_count> <filename>)
#
# 将给定的数字以字节序列的形式写入文件。
#
# 参数:
# - number - 要写入的数字。
#          可以是十进制、十六进制(前缀为0x),
#          甚至是可由math(EXPR)理解的表达式。
#
# - bytes_count - 应该写入的字节数。
#           如果字节数多于表示数字所需的字节数,
#           则第一个字节将为零。
#
# - filename - 要写入数字的文件路径。
#
function(write_number_to_file number bytes_count filename)
# 将数字转换为十六进制
math(EXPR number_hex "${number}" OUTPUT_FORMAT HEXADECIMAL)
# .. 并去掉 '0x' 前缀
string(SUBSTRING "${number_hex}" 2 -1 number_hex)
# 计算数字中十六进制数字的数量。
string(LENGTH "${number_hex}" hex_digits_count)
# 请求的字节数最大的十六进制数字数。
math(EXPR hex_digits_max_count "${bytes_count} * 2")
# 执行十六进制数字填充,直到达到最大数字
# 要填充的字节数。
math(EXPR pad_len "${hex_digits_max_count} - ${hex_digits_count}")
# 包含将前缀数字的零的字符串。
string(REPEAT "0" ${pad_len} pad_str)
# 填充数字。
string(CONCAT number_hex ${pad_str} ${number_hex})
# 将写入文件的字节
set(bytes)
# 遍历十六进制数字的对,每对将生成一个字节
# 1..<bytes_count>
foreach(i1 RANGE 1 ${bytes_count})
# 第一位数字的索引。
math(EXPR first_digit_index "${i1} * 2 - 2")
# 创建字节的十六进制代码。
string(SUBSTRING "${number_hex}" ${first_digit_index} 2 byte_hex)
if (byte_hex STREQUAL "00")
# 特殊情况:代码为0,但CMake无法创建空字节。
string(CONCAT bytes "${bytes}" "${null_char}")
else()
# 常规情况:非零代码。
# 将代码转换为十进制,因为string(ASCII)不理解十六进制。
math(EXPR byte_code "0x${byte_hex}")
# 使用给定的ASCII代码创建字节。
string(ASCII ${byte_code} byte)
string(CONCAT bytes "${bytes}" "${byte}")
endif()
endforeach()
# 现在一切准备就绪,可以写入文件。
file(WRITE "${filename}" "${bytes}")
endfunction()
" > null.txt # file(READ "null.txt" null_char) # write_number_to_file(<number> <bytes_count> <filename>) # # 将给定的数字以字节序列的形式写入文件。 # # 参数: # - number - 要写入的数字。 # 可以是十进制、十六进制(前缀为0x), # 甚至是可由math(EXPR)理解的表达式。 # # - bytes_count - 应该写入的字节数。 # 如果字节数多于表示数字所需的字节数, # 则第一个字节将为零。 # # - filename - 要写入数字的文件路径。 # function(write_number_to_file number bytes_count filename) # 将数字转换为十六进制 math(EXPR number_hex "${number}" OUTPUT_FORMAT HEXADECIMAL) # .. 并去掉 '0x' 前缀 string(SUBSTRING "${number_hex}" 2 -1 number_hex) # 计算数字中十六进制数字的数量。 string(LENGTH "${number_hex}" hex_digits_count) # 请求的字节数最大的十六进制数字数。 math(EXPR hex_digits_max_count "${bytes_count} * 2") # 执行十六进制数字填充,直到达到最大数字 # 要填充的字节数。 math(EXPR pad_len "${hex_digits_max_count} - ${hex_digits_count}") # 包含将前缀数字的零的字符串。 string(REPEAT "0" ${pad_len} pad_str) # 填充数字。 string(CONCAT number_hex ${pad_str} ${number_hex}) # 将写入文件的字节 set(bytes) # 遍历十六进制数字的对,每对将生成一个字节 # 1..<bytes_count> foreach(i1 RANGE 1 ${bytes_count}) # 第一位数字的索引。 math(EXPR first_digit_index "${i1} * 2 - 2") # 创建字节的十六进制代码。 string(SUBSTRING "${number_hex}" ${first_digit_index} 2 byte_hex) if (byte_hex STREQUAL "00") # 特殊情况:代码为0,但CMake无法创建空字节。 string(CONCAT bytes "${bytes}" "${null_char}") else() # 常规情况:非零代码。 # 将代码转换为十进制,因为string(ASCII)不理解十六进制。 math(EXPR byte_code "0x${byte_hex}") # 使用给定的ASCII代码创建字节。 string(ASCII ${byte_code} byte) string(CONCAT bytes "${bytes}" "${byte}") endif() endforeach() # 现在一切准备就绪,可以写入文件。 file(WRITE "${filename}" "${bytes}") endfunction()

定义的函数 write_number_to_file 可以如下使用:

file(SIZE generated_file.txt file_size)  # file_size == 465435

# 将数字以4个字节的形式写入指定文件
write_number_to_file("${file_size}" 4 output.txt)

更方便的做法是创建一个函数,该函数返回数字的字节表示形式。这样,字节不仅可以使用 file(WRITE) 写入文件,还可以使用 file(APPEND) 或其他方法写入。不幸的是,CMake无法正确处理变量中的空字节,并且来自函数 write_number_to_file 的潜在调用

   set(outer_var "${bytes}" PARENT_SCOPE)

会将 outer_var ... 设置为空字符串(因为 bytes 变量中的第一个字节是空的)。

英文:

CMake has a command string(ASCII) which can be used for create a byte with the given code. But for create several bytes from a single number, splitting this number into codes should be performed manually.

CMake has not so great support for arithmetic and handling characters in a string, so that seemingly a simple task - splitting a number into hex codes - requires some code:

# Variable which contain a single null-byte.
#
# CMake doesn&#39;t allow to create null-byte in the code.
# E.g. using &quot;
# Variable which contain a single null-byte.
#
# CMake doesn&#39;t allow to create null-byte in the code.
# E.g. using &quot;\0&quot; emits error &quot;Invalid character escape &#39;\0&#39;.&quot;
# For that reason we pre-create a file which contains only a single null-byte
# and read that file in CMake.
#
# A file &#39;null.txt&#39; could be created using this command:
#
#   printf &quot;\0&quot; &gt; null.txt
#
file(READ &quot;null.txt&quot; null_char)
# write_number_to_file(&lt;number&gt; &lt;bytes_count&gt; &lt;filename&gt;)
#
# Writes given number into the file as a sequence of bytes.
#
# Arguments:
# - number - number to write.
#          Could be a decimal, a hexadecimal (prefixed with 0x)
#          or even an expression which is understandable by math(EXPR).
#
# - bytes_count - number of bytes which should be written.
#           If bytes count is more then bytes required to represent a number,
#           the first bytes will be zero.
#
# - filename - path to the file where to write the number.
#
function(write_number_to_file number bytes_count filename)
# Convert number to hex
math(EXPR number_hex &quot;${number}&quot; OUTPUT_FORMAT HEXADECIMAL)
# .. and strip &#39;0x&#39; prefix
string(SUBSTRING &quot;${number_hex}&quot; 2 -1 number_hex)
# Compute number of the hex digits in the number.
string(LENGTH &quot;${number_hex}&quot; hex_digits_count)
# Maximum number of hex digits, which can be representable by the requested bytes count.
math(EXPR hex_digits_max_count &quot;${bytes_count} * 2&quot;)
# Perform the padding of hex number up to maximum digits
# Number of bytes to pad.
math(EXPR pad_len &quot;${hex_digits_max_count} - ${hex_digits_count}&quot;)
# A string with zeros which will prepend the number.
string(REPEAT &quot;0&quot; ${pad_len} pad_str)
# Pad the number.
string(CONCAT number_hex ${pad_str} ${number_hex})
# Bytes which will be written into the file
set(bytes)
# Iterate over pairs of hex digits, every of which will produce a single byte
# 1..&lt;bytes_count&gt;
foreach(i1 RANGE 1 ${bytes_count})
# Index of the first digit in the pair.
math(EXPR first_digit_index &quot;${i1} * 2 - 2&quot;)
# Hexadecimal code of the created byte.
string(SUBSTRING &quot;${number_hex}&quot; ${first_digit_index} 2 byte_hex)
if (byte_hex STREQUAL &quot;00&quot;)
# Special case: the code is 0, but CMake cannot create null-byte.
string(CONCAT bytes &quot;${bytes}&quot; &quot;${null_char}&quot;)
else()
# Regular case: non-0 code.
# Covert the code into decimal, as string(ASCII) doesn&#39;t understand hex.
math(EXPR byte_code &quot;0x${byte_hex}&quot;)
# Create a byte with the given ASCII code.
string(ASCII ${byte_code} byte)
string(CONCAT bytes &quot;${bytes}&quot; &quot;${byte}&quot;)
endif()
endforeach()
# Now everything is ready to write the file.
file(WRITE &quot;${filename}&quot; &quot;${bytes}&quot;)
endfunction()
&quot; emits error &quot;Invalid character escape &#39;
# Variable which contain a single null-byte.
#
# CMake doesn&#39;t allow to create null-byte in the code.
# E.g. using &quot;\0&quot; emits error &quot;Invalid character escape &#39;\0&#39;.&quot;
# For that reason we pre-create a file which contains only a single null-byte
# and read that file in CMake.
#
# A file &#39;null.txt&#39; could be created using this command:
#
#   printf &quot;\0&quot; &gt; null.txt
#
file(READ &quot;null.txt&quot; null_char)
# write_number_to_file(&lt;number&gt; &lt;bytes_count&gt; &lt;filename&gt;)
#
# Writes given number into the file as a sequence of bytes.
#
# Arguments:
# - number - number to write.
#          Could be a decimal, a hexadecimal (prefixed with 0x)
#          or even an expression which is understandable by math(EXPR).
#
# - bytes_count - number of bytes which should be written.
#           If bytes count is more then bytes required to represent a number,
#           the first bytes will be zero.
#
# - filename - path to the file where to write the number.
#
function(write_number_to_file number bytes_count filename)
# Convert number to hex
math(EXPR number_hex &quot;${number}&quot; OUTPUT_FORMAT HEXADECIMAL)
# .. and strip &#39;0x&#39; prefix
string(SUBSTRING &quot;${number_hex}&quot; 2 -1 number_hex)
# Compute number of the hex digits in the number.
string(LENGTH &quot;${number_hex}&quot; hex_digits_count)
# Maximum number of hex digits, which can be representable by the requested bytes count.
math(EXPR hex_digits_max_count &quot;${bytes_count} * 2&quot;)
# Perform the padding of hex number up to maximum digits
# Number of bytes to pad.
math(EXPR pad_len &quot;${hex_digits_max_count} - ${hex_digits_count}&quot;)
# A string with zeros which will prepend the number.
string(REPEAT &quot;0&quot; ${pad_len} pad_str)
# Pad the number.
string(CONCAT number_hex ${pad_str} ${number_hex})
# Bytes which will be written into the file
set(bytes)
# Iterate over pairs of hex digits, every of which will produce a single byte
# 1..&lt;bytes_count&gt;
foreach(i1 RANGE 1 ${bytes_count})
# Index of the first digit in the pair.
math(EXPR first_digit_index &quot;${i1} * 2 - 2&quot;)
# Hexadecimal code of the created byte.
string(SUBSTRING &quot;${number_hex}&quot; ${first_digit_index} 2 byte_hex)
if (byte_hex STREQUAL &quot;00&quot;)
# Special case: the code is 0, but CMake cannot create null-byte.
string(CONCAT bytes &quot;${bytes}&quot; &quot;${null_char}&quot;)
else()
# Regular case: non-0 code.
# Covert the code into decimal, as string(ASCII) doesn&#39;t understand hex.
math(EXPR byte_code &quot;0x${byte_hex}&quot;)
# Create a byte with the given ASCII code.
string(ASCII ${byte_code} byte)
string(CONCAT bytes &quot;${bytes}&quot; &quot;${byte}&quot;)
endif()
endforeach()
# Now everything is ready to write the file.
file(WRITE &quot;${filename}&quot; &quot;${bytes}&quot;)
endfunction()
&#39;.&quot; # For that reason we pre-create a file which contains only a single null-byte # and read that file in CMake. # # A file &#39;null.txt&#39; could be created using this command: # # printf &quot;
# Variable which contain a single null-byte.
#
# CMake doesn&#39;t allow to create null-byte in the code.
# E.g. using &quot;\0&quot; emits error &quot;Invalid character escape &#39;\0&#39;.&quot;
# For that reason we pre-create a file which contains only a single null-byte
# and read that file in CMake.
#
# A file &#39;null.txt&#39; could be created using this command:
#
#   printf &quot;\0&quot; &gt; null.txt
#
file(READ &quot;null.txt&quot; null_char)
# write_number_to_file(&lt;number&gt; &lt;bytes_count&gt; &lt;filename&gt;)
#
# Writes given number into the file as a sequence of bytes.
#
# Arguments:
# - number - number to write.
#          Could be a decimal, a hexadecimal (prefixed with 0x)
#          or even an expression which is understandable by math(EXPR).
#
# - bytes_count - number of bytes which should be written.
#           If bytes count is more then bytes required to represent a number,
#           the first bytes will be zero.
#
# - filename - path to the file where to write the number.
#
function(write_number_to_file number bytes_count filename)
# Convert number to hex
math(EXPR number_hex &quot;${number}&quot; OUTPUT_FORMAT HEXADECIMAL)
# .. and strip &#39;0x&#39; prefix
string(SUBSTRING &quot;${number_hex}&quot; 2 -1 number_hex)
# Compute number of the hex digits in the number.
string(LENGTH &quot;${number_hex}&quot; hex_digits_count)
# Maximum number of hex digits, which can be representable by the requested bytes count.
math(EXPR hex_digits_max_count &quot;${bytes_count} * 2&quot;)
# Perform the padding of hex number up to maximum digits
# Number of bytes to pad.
math(EXPR pad_len &quot;${hex_digits_max_count} - ${hex_digits_count}&quot;)
# A string with zeros which will prepend the number.
string(REPEAT &quot;0&quot; ${pad_len} pad_str)
# Pad the number.
string(CONCAT number_hex ${pad_str} ${number_hex})
# Bytes which will be written into the file
set(bytes)
# Iterate over pairs of hex digits, every of which will produce a single byte
# 1..&lt;bytes_count&gt;
foreach(i1 RANGE 1 ${bytes_count})
# Index of the first digit in the pair.
math(EXPR first_digit_index &quot;${i1} * 2 - 2&quot;)
# Hexadecimal code of the created byte.
string(SUBSTRING &quot;${number_hex}&quot; ${first_digit_index} 2 byte_hex)
if (byte_hex STREQUAL &quot;00&quot;)
# Special case: the code is 0, but CMake cannot create null-byte.
string(CONCAT bytes &quot;${bytes}&quot; &quot;${null_char}&quot;)
else()
# Regular case: non-0 code.
# Covert the code into decimal, as string(ASCII) doesn&#39;t understand hex.
math(EXPR byte_code &quot;0x${byte_hex}&quot;)
# Create a byte with the given ASCII code.
string(ASCII ${byte_code} byte)
string(CONCAT bytes &quot;${bytes}&quot; &quot;${byte}&quot;)
endif()
endforeach()
# Now everything is ready to write the file.
file(WRITE &quot;${filename}&quot; &quot;${bytes}&quot;)
endfunction()
&quot; &gt; null.txt # file(READ &quot;null.txt&quot; null_char) # write_number_to_file(&lt;number&gt; &lt;bytes_count&gt; &lt;filename&gt;) # # Writes given number into the file as a sequence of bytes. # # Arguments: # - number - number to write. # Could be a decimal, a hexadecimal (prefixed with 0x) # or even an expression which is understandable by math(EXPR). # # - bytes_count - number of bytes which should be written. # If bytes count is more then bytes required to represent a number, # the first bytes will be zero. # # - filename - path to the file where to write the number. # function(write_number_to_file number bytes_count filename) # Convert number to hex math(EXPR number_hex &quot;${number}&quot; OUTPUT_FORMAT HEXADECIMAL) # .. and strip &#39;0x&#39; prefix string(SUBSTRING &quot;${number_hex}&quot; 2 -1 number_hex) # Compute number of the hex digits in the number. string(LENGTH &quot;${number_hex}&quot; hex_digits_count) # Maximum number of hex digits, which can be representable by the requested bytes count. math(EXPR hex_digits_max_count &quot;${bytes_count} * 2&quot;) # Perform the padding of hex number up to maximum digits # Number of bytes to pad. math(EXPR pad_len &quot;${hex_digits_max_count} - ${hex_digits_count}&quot;) # A string with zeros which will prepend the number. string(REPEAT &quot;0&quot; ${pad_len} pad_str) # Pad the number. string(CONCAT number_hex ${pad_str} ${number_hex}) # Bytes which will be written into the file set(bytes) # Iterate over pairs of hex digits, every of which will produce a single byte # 1..&lt;bytes_count&gt; foreach(i1 RANGE 1 ${bytes_count}) # Index of the first digit in the pair. math(EXPR first_digit_index &quot;${i1} * 2 - 2&quot;) # Hexadecimal code of the created byte. string(SUBSTRING &quot;${number_hex}&quot; ${first_digit_index} 2 byte_hex) if (byte_hex STREQUAL &quot;00&quot;) # Special case: the code is 0, but CMake cannot create null-byte. string(CONCAT bytes &quot;${bytes}&quot; &quot;${null_char}&quot;) else() # Regular case: non-0 code. # Covert the code into decimal, as string(ASCII) doesn&#39;t understand hex. math(EXPR byte_code &quot;0x${byte_hex}&quot;) # Create a byte with the given ASCII code. string(ASCII ${byte_code} byte) string(CONCAT bytes &quot;${bytes}&quot; &quot;${byte}&quot;) endif() endforeach() # Now everything is ready to write the file. file(WRITE &quot;${filename}&quot; &quot;${bytes}&quot;) endfunction()

The defined function write_number_to_file could be used as follows:

file(SIZE generated_file.txt file_size)  # file_size == 465435

# Write a number as 4 bytes into the specified file
write_number_to_file(&quot;${file_size}&quot; 4 output.txt)

It would be more convenient to have a function which returns bytes representation of a number. So that bytes can be written to the file not only with file(WRITE) but with file(APPEND) or other methods. Unfortunately, CMake badly handles null bytes in the variables, and potential call from the function write_number_to_file

   set(outer_var &quot;${bytes}&quot; PARENT_SCOPE)

would set the outer_var ... to the empty string (because the first byte in bytes variable is null).

huangapple
  • 本文由 发表于 2023年6月1日 02:26:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76376363.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定