- PVSM.RU - https://www.pvsm.ru -
Захотелось как-то мне использовать в Linux внедряемые ресурсы, причём, автоматически. В общем, задача такая:
Для начала, поиск по форумам дал несколько возможных способов решения задачи. Среди найденных наиболее универсальным мне показалась идея использовать параметр «--format=binary
» линковщика «ld
». Посты на форумах обещали, что команда вида
g++ -Wl,--format=binary -Wl,my.res -Wl,--format=default
прилинкует к приложению файл «my.res» и создаст два символа — _binary_my_res_start
и _binary_my_res_end
, указывающих, соответственно, на начало и конец тех самых данных, которые были в прилинкованном файле. Следовательно, обращение к данным из C++ можно было бы осуществить как-то так:
extern const uint8_t my_res_start[] asm("_binary_my_res_start");
extern const uint8_t my_res_end[] asm("_binary_my_res_end");
Но не тут-то было. Пишем всё, как надо, а компилятор недоволен. Символа «_binary_my_res_start»
, видите ли, он найти не может. Ну ничего, nm
нам в помощь. Пишем следующую команду:
nm MyProgramm |grep -w -o -P -e '_binary_[wd_]+'
И получаем:
_binary__home_unknown_workspace_MyProgramm_res_my_res_sql_end
_binary__home_unknown_workspace_MyProgramm_res_my_res_sql_start
Выходит, что имя символа включает в себя весь путь до него, что, в перспективе, может привести к необходимости постоянного переписывания заголовочного файла, содержащего ссылки на ресурсы. Проблема решается, если в событие PostBuild в настройках проекта Eclipse добавить вызов следующего скрипта:
#!/bin/bash
OUTPUT=$1/resources.h
printf '#ifndef __RESOURCES_H__n' > "$OUTPUT"
printf '#define __RESOURCES_H__nn' >> "$OUTPUT"
printf '#include <inttypes.h>nn' >> "$OUTPUT"
SYMBOLS=$(nm NewsParser |grep -w -o -P -e '_binary_[wd_]+') >> "$OUTPUT"
VAR_SIZES_LIST=''
for SYMBOL in $SYMBOLS
do
VAR_NAME=$(echo $SYMBOL | grep -o -P -e 'res_[wd_]+'|cut -c 5-)
if [[ -z $(echo $SYMBOL|grep _size) ]]
then
printf 'textern const uint8_t '$VAR_NAME'[]tasm("'$SYMBOL'");nn' >> "$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 '#endifn' >> "$OUTPUT"
printf 'File '$OUTPUT' is generated.n'
Хорошо. Теперь заголовочный файл будет каждый раз как новенький, а обращаться к данным можно по именам переменных, которые не будут меняться, если только не переименовать сам ресурсный файл. Кроме того, данный скрипт вычисляет размер для каждого ресурса. Не то что бы отнять от указателя на конец указатель на начало было большой проблемой, но, всё же, так удобнее.
Но это, пока что, не всё. Ведь добавление каждого нового ресурса в проект будет превращаться в форменный АД. И эту проблему также можно решить при помощи скрипта, только уже на этапе линковки:
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
Отлично. Теперь все файлы, которые лежат в подкаталоге «res», будут сами попадать в ресурсы при каждой сборке.
Автор: Михайлуц Юрий
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-3/330845
Ссылки в тексте:
[1] Источник: https://habr.com/ru/post/468399/?utm_source=habrahabr&utm_medium=rss&utm_campaign=468399
Нажмите здесь для печати.