HomeBlogMagic

Cmake generiere Source Datei von einer Binär Datei

Hin und wieder müssen Binärdateien einer Applikation oder Dll hinzugefügt werden.
Meistens handelt es sich hier um Icons, Bilder oder Configs.

Um diese Dateien in ein Array oder ein String zu speichern, habe ich früher eine Eigene Applikation genutzt. Das war allerdings unhandlich wenn es sich hier um Config-Dateien gehandelt hat welche sich hin und wieder ändern.

Deshalb habe ich Dafür ein CMake Script und ein Makro erstellt, welches mir das während der Configuration automatisch macht. Vorteil an dem ganzen ist, wenn sich die Input Datei ändert, lässt Cmake die Sourcen neu generieren.

Als Ausgabe wird der Dateiname von H und C ohne extension angegeben.

Das Convertierungs-Script (FileToSource.cmake)

file(READ ${FileToSource_SOURCE} CONTENT HEX)
file(SIZE ${FileToSource_SOURCE} CONTENT_SIZE )
set(CONTENT_OFFSET 0)

file(WRITE ${FileToSource_TARGET}.h "// Generated Header\n")
file(APPEND ${FileToSource_TARGET}.h "#include \"CcBase.h\"\n")
file(APPEND ${FileToSource_TARGET}.h "CCEXTERNC const char ${FileToSource_VARIABLE}[${CONTENT_SIZE}];\n")
file(APPEND ${FileToSource_TARGET}.h "CCEXTERNC size_t ${FileToSource_VARIABLE}_Size;\n")

file(WRITE ${FileToSource_TARGET}.c "// Generated Source\n")
file(APPEND ${FileToSource_TARGET}.c "#include \"CcBase.h\"\n")
file(APPEND ${FileToSource_TARGET}.c "size_t ${FileToSource_VARIABLE}_Size = ${CONTENT_SIZE};\n")
file(APPEND ${FileToSource_TARGET}.c "const char ${FileToSource_VARIABLE}[] = {\n")
while(${CONTENT_SIZE} GREATER 0)
  string(SUBSTRING ${CONTENT} ${CONTENT_OFFSET} 2 CONTENT_SUB)
  file(APPEND ${FileToSource_TARGET}.c "0x${CONTENT_SUB}, ")
  math(EXPR CONTENT_SIZE "${CONTENT_SIZE}-1")
  math(EXPR CONTENT_OFFSET "${CONTENT_OFFSET}+2")
  math(EXPR CONTENT_MODULO "${CONTENT_OFFSET}%16")
  if(${CONTENT_MODULO} EQUAL 0)
    file(APPEND ${FileToSource_TARGET}.c "\n")
  endif()
endwhile()
file(APPEND ${FileToSource_TARGET}.c "0x00};")

Das Makro

Das Makro ist in einer Datei definiert, welches parallel zu dem Script liegt

set(CC_MACRO_DIR ${CMAKE_CURRENT_LIST_DIR})
macro(GenerateSourceFromFile FilePath TargetPath VariableName List)
  add_custom_command(
    OUTPUT ${TargetPath}.h
    OUTPUT ${TargetPath}.c
    COMMAND ${CMAKE_COMMAND} 
      -D "FileToSource_SOURCE=${FilePath}" 
      -D "FileToSource_TARGET=${TargetPath}" 
      -D "FileToSource_VARIABLE=${VariableName}" 
      -P ${CC_MACRO_DIR}/FileToSource.cmake
  )
  list(APPEND ${List}
    ${TargetPath}.h
    ${TargetPath}.c
  )
endmacro()

Beispiel:

In diesem Beispiel wird eine Datei TestBild-24bit.bmp convertiert und die generierten Dateinamen in der Variable CURRENT_TEST_PROJECT_RESOURCE_FILES gespeichert.

Immer wenn das Target neu gebaut wird werden bei Bedarf die Dateien neu generiert.

GenerateSourceFromFile(
  ${CMAKE_CURRENT_LIST_DIR}/Resources/TestBild-24bit.bmp
  ${CMAKE_BINARY_DIR}/Generated/TestBild-24bit.bmp
  TestBild_24Bit_Bmp
  CURRENT_TEST_PROJECT_RESOURCE_FILES
)
include_directories(${CMAKE_BINARY_DIR}/Generated)

add_library(Target ..... ${CURRENT_TEST_PROJECT_RESOURCE_FILES})

TestBild-24bit.bmp.c

// Generated Source
#include "CcBase.h"
size_t TestBild_24Bit_Bmp_Size = 374;
const char TestBild_24Bit_Bmp[] = {
0x42, 0x4d, 0x76, 0x01, 0x00, 0x00, 0x00, 0x00,
...}

TestBild-24bit.bmp.h

// Generated Header
#include "CcBase.h"
CCEXTERNC const char TestBild_24Bit_Bmp[374];
CCEXTERNC size_t TestBild_24Bit_Bmp_Size;
Permalink: https://adirmeier.de/Blog/ID_454
Tags: Blog, C/C++, cmakevon am 2024-02-06