C / C ++. Verwendung eingebetteter Anwendungsressourcen bei der Arbeit in GCC unter Linux

Ich wollte außerdem irgendwie eingebettete Linux-Ressourcen automatisch verwenden. Im Allgemeinen ist die Aufgabe folgende:


  1. In C ++ gibt es ein Eclipse-Projektprogramm.
  2. Betriebssystem: Linux Ubuntu. Compiler: G ++
  3. Das Projekt verwendet Daten aus externen Dateien: Lokalisierungszeichenfolgen, SQL-Abfragen, Bilder, Sounds usw.
  4. Alle Ressourcen müssen in die ausführbare Datei eingebettet sein, da das Programm als portabel verteilt werden soll.
  5. Außerdem möchte ich, dass der Prozess wegen Faulheit so automatisiert wie möglich ist.

Zunächst bot eine Suche in den Foren verschiedene Möglichkeiten, um das Problem zu lösen. Unter den universellsten schien mir die Idee, den Parameter " --format=binary " des Linkers " ld " zu verwenden. Forenbeiträge versprachen ein Team der Form:

 g++ -Wl,--format=binary -Wl,my.res -Wl,--format=default 

verknüpft die Datei "my.res" mit der Anwendung und erstellt zwei Zeichen - _binary_my_res_start und _binary_my_res_end , die jeweils den Anfang und das Ende derselben Daten angeben, die sich in der verknüpften Datei _binary_my_res_end . Der Zugriff auf Daten aus C ++ kann daher folgendermaßen erfolgen:
 extern const uint8_t my_res_start[] asm("_binary_my_res_start"); extern const uint8_t my_res_end[] asm("_binary_my_res_end"); 

Aber da war es. Wir schreiben alles so, wie es sollte, und der Compiler ist nicht glücklich. Das Symbol «_binary_my_res_start» kann nicht gefunden werden. Nun, nichts, nm , um uns zu helfen. Wir schreiben den folgenden Befehl:

 nm MyProgramm |grep -w -o -P -e '_binary_[\w\d_]+' 

Und wir bekommen:

 _binary__home_unknown_workspace_MyProgramm_res_my_res_sql_end _binary__home_unknown_workspace_MyProgramm_res_my_res_sql_start 

Es stellt sich heraus, dass der Name des Symbols den gesamten Pfad dazu enthält, was in Zukunft dazu führen kann, dass die Header-Datei mit Links zu Ressourcen ständig neu geschrieben werden muss. Das Problem wird behoben, wenn dem PostBuild-Ereignis in den Eclipse-Projekteinstellungen das folgende Skript hinzugefügt wird:

 #!/bin/bash OUTPUT=$1/resources.h printf '#ifndef __RESOURCES_H__\n' > "$OUTPUT" printf '#define __RESOURCES_H__\n\n' >> "$OUTPUT" printf '#include <inttypes.h>\n\n' >> "$OUTPUT" SYMBOLS=$(nm NewsParser |grep -w -o -P -e '_binary_[\w\d_]+') >> "$OUTPUT" VAR_SIZES_LIST='' for SYMBOL in $SYMBOLS do VAR_NAME=$(echo $SYMBOL | grep -o -P -e 'res_[\w\d_]+'|cut -c 5-) if [[ -z $(echo $SYMBOL|grep _size) ]] then printf '\textern const uint8_t '$VAR_NAME'[]\tasm("'$SYMBOL'");\n\n' >> "$OUTPUT" else START_VAR=$(echo $VAR_NAME|rev|cut -c 5-|rev)'start' END_VAR=$(echo $VAR_NAME|rev|cut -c 5-|rev)'end' VAR_SIZES_LIST=$VAR_SIZES_LIST$(printf '\\tconst uint64_t '$VAR_NAME'\\t=\\t'$END_VAR' - '$START_VAR';\\n\\n') fi done printf "$VAR_SIZES_LIST" >> "$OUTPUT" printf '#endif\n' >> "$OUTPUT" printf 'File '$OUTPUT' is generated.\n' 

So fügen Sie das Skript "update_resource.sh" im Stammverzeichnis des Projekts zum PostBuild-Ereignis in den Eclipse-Projekteinstellungen hinzu.


Gut. Jetzt ist die Header-Datei jedes Mal wie neu, und Sie können über die Namen von Variablen auf die Daten zugreifen, die sich nur ändern, wenn Sie die Ressourcendatei selbst umbenennen. Darüber hinaus berechnet dieses Skript die Größe für jede Ressource. Es war nicht nur ein großes Problem, den Zeiger vom Zeiger bis zum Ende zum Anfang zu bringen, sondern es ist auch bequemer.

Aber das ist vorerst noch nicht alles. Schließlich wird das Hinzufügen jeder neuen Ressource zu einem Projekt zu einem geformten AD. Und dieses Problem kann auch mit Hilfe eines Skripts nur in der Verknüpfungsphase gelöst werden:

 FLAGS=$1 OUTPUT_FLAG=$2 OUTPUT_PREFIX=$3 OUTPUT=$4 INPUTS=$5 RESOURCE_PATH=$6 RESOURCES='' for res_file in $(ls $RESOURCE_PATH/*) do RESOURCES=$RESOURCES' '-Wl,$res_file echo ' '$res_file'   ' done g++ $FLAGS $OUTPUT_FLAG $OUTPUT_PREFIX$OUTPUT $INPUTS -Wl,--format=binary $RESOURCES -Wl,--format=default 

So ersetzen Sie den Aufruf des Standardlinkers durch ein benutzerdefiniertes Skript in den Eclipse-Projekteinstellungen.


  • Die Stelle in Rot ist im Bild markiert, wo sich anstelle des Standardbefehls zum Aufrufen des Linkers der Pfad zum Skript „link.sh“ im Stammverzeichnis des Projekts befindet.
  • Grün im Bild ist ein Ort, an dem ein weiterer Linker zu den üblichen Linkerparametern hinzugefügt wird, der dem Skript den Speicherort des Verzeichnisses mit Ressourcen mitteilt.
  • Darüber hinaus ist es wichtig, nicht zu vergessen, die verbleibenden Parameter in doppelte Anführungszeichen zu setzen, damit sie nicht versehentlich mit Leerzeichen in der falschen Reihenfolge unterbrochen werden, in der das Skript auf sie wartet.


Großartig. Jetzt fallen alle Dateien, die sich im Unterverzeichnis "res" befinden, bei jeder Assembly selbst in die Ressourcen.

Source: https://habr.com/ru/post/de468399/


All Articles