Программирование ARM RT-Thread SCons Sat, October 12 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

RT-Thread SCons Печать
Добавил(а) microsin   

SCons это открытая (open source) система сборки кода, написанная на Python, выполняющая ту же задачу, что и GNU Make. Однако она применяет отличающийся от обычного Makefile принцип для обработки исходного кода, используя в качестве задания содержимое файлов скриптов SConstruct и SConscript. Эти файлы также написаны на Python, и могут содержать код синтаксиса Python, так что в SConstruct могут вызываться стандартные библиотеки Python, и файлы SConscript хорошо подходят для сложной обработки, не ограничиваясь набором правил Makefile.

Подробное руководство пользователя по SCons можно найти на официальном сайте [2]. Здесь описывается базовое использование SCons, как его использовать в проекте RT-Thread.

[Система сборки]

Система сборки это программный инструмент, который компилирует исходный код в исполняемый бинарный в соответствии с определенными правилами или инструкциями. Это самая основная и наиболее важная, но не единственная функция систем сборки. Обычно правила сборки для систем сборки имеют определенный синтаксис и организованы в файлы. Эти файлы используются для управления поведением системы сборки, и с помощью них помимо сборки ПО можно также выполнять и другие действия.

На сегодняшний день самой популярной системой сборки является GNU Make. Множество хорошо известных open source проектов, такие как ядро Linux, собираются с использованием Make. Make определяет организацию и зависимости файлов проекта путем чтения Makefile, и выполняет указанные в нем команды.

По историческим причинам синтаксис Makefile запутанный, и вводит в ступор новичков. Кроме того Make неудобно использовать на платформе Windows, для этого нужно устанавливать командную строку Cygwin или MSYS. Для преодоления недостатков Make, разработаны альтернативные системы сборки, к которым относятся CMake и SCons.

[Система сборки RT-Thread]

Изначально RT-Thread собиралась под управлением Make/Makefile. Начиная с версии 0.3.x команда разработчиков RT-Thread перешла на систему сборки SCons. Целью этого перехода было избавить всех от сложной конфигурации Makefile, упрощение конфигураций различных IDE, перенос фокуса разработки на функционал RT-Thread.

Кое-кто может сомневаться в отличии описанной системы сборки и какой-либо IDE. Система IDE предоставляет пользователю графический интерфейс над конфигурированием и выполнением процесса сборки. Большинство IDE генерируют файлы скрипта наподобие Makefile, CMakeLists.txt или SConscript, основываясь на исходном коде, который пользователь добавил в проект, и при компиляции система IDE просто запускает систему сборки на основе Make, CMake или SCons.

Для работы SCons необходима среда выполнения скриптов Python. Для упрощения установки командой разработчиков RT-Thread поставляется утилита конфигурации Env [3], где предоставлены вместе SCons и Python, так что на платформе Windows не требуется отдельно устанавливать эти две программы.

На операционных системах Linux и BSD система Python по умолчанию уже установлена, так что в наличии имеется Python как минимум версии 2.x. В настоящее время это все, что нужно для установки SCons. Например, на Ubuntu установить SCons можно следующей командой:

sudo apt-get install scons

[Основные функции SCons]

Система сборки RT-Thread поддерживает несколько компиляторов, включая ARM GCC, MDK, IAR, VisualStudio и Visual DSP. В основном используются платформы ARM Cortex M0, M3, M4, которые поддерживаются средами разработки ARM GCC, MDK, IAR. Некоторые BSP могут поддерживать только один компилятор. Ознакомиться с поддерживаемыми в настоящий момент компиляторами можно путем чтения опции CROSS_TOOL файла rtconfig.py, находящегося в директории BSP.

Если чип относится к платформе ARM, то можно использовать утилиту Env и ввести в её командной строке команду scons, чтобы непосредственно скомпилировать BSP. В настоящий момент по умолчанию используется компилятор ARM GCC, потому что Env поставляется с компилятором ARM GCC. Компилирование BSP командой scons показана на сриншоте ниже.

SCons command scons

Если нужно использовать другой компилятор, который BSP уже поддерживает для компиляции проекта, или если чип BSP не относится к платформе ARM, то Вы не сможете непосредственно скомпилировать проект командой scons. Необходимо самостоятельно установить соответствующий компилятор, и указать путь к нему. Перед компиляцией проекта можно использовать следующие две команды в интерфейсе Env, чтобы указать компилятор MDK и путь к нему.

set RTT_CC=keil
set RTT_EXEC_PATH=C:/Keilv5

[Основные команды SCons]

В этой секции описаны часто используемые для компиляции RT-Thread команды SCons. SCons может не только выполнять основную компиляцию, но также может генерировать проекты MDK/IAR/VS.

scons

Перейдите в среде командной строки Env в каталог BSP проекта, и выполните команду scons, чтобы непосредственно скомпилировать проект. Если некоторые файлы были модифицированы после предыдущего запуска команды scons, и команда scons запущена снова, то SCons выполнит инкрементальную компиляцию, компилируя только измененные исходные файлы, после чего выполнит их линковку.

scons -s

За scons может идти параметр -s, и команда scons -s отличается от простой команды scons тем, что не будут печататься определенные внутренние команды.

scons -c

Выполнит очистку цели компиляции (аналог команды make clean). Эта команда очистит временные файлы и файлы target, которые были сгенерированы после выполнения последней команды scons.

scons --target=XXX

Если Вы используете проект, разрабатываемый в MDK/IAR, то когда Вы откроете или закроете некоторые компоненты, необходимо использовать следующие команды для регенерации соответствующего настроенного проекта, когда выполняете компиляцию и загрузку в mdk/iar.

scons --target=iar
scons --target=mdk4
scons --target=mdk5

В командной строки Env войдите в директорию BSP компилируемого проекта. После использования команды scons --target=mdk5 в каталоге BSP сгенерируется новый файл проекта MDK с именем project.uvprojx. Двойным кликом на этом файле откройте этот проект, чтобы компилировать и отлаживать его в среде MDK. Команда scons --target=iar будет генерировать новый проект IAR с именем project.eww. Пользователи, которые не используют SCons, могут использовать этот метод. Если project.uvproj не открылся, то удалите project.uvopt и пересоберите проект.

В директории bsp/simulator можно использовать следующую команду, чтобы генерировать проект для vs2012 или vs2005.

scons --target=vs2012
scons --target=vs2005

Если Вы предоставляете файлы шаблона для других проектов IDE в каталоге BSP, то можно также использовать эту команду для генерации соответствующих новых проектов, таких как ua, vs, cb, cdk.

За этой командой также может идти параметр -s (например scons –target=mdk5 -s), чтобы не печатались внутренние команды.

Примечание: для генерации файла проекта MDK или IAR предпосылкой является файл шаблона проекта в директории BSP, и тогда scons добавит в генерируемый проект соответствующий исходный код, пути поиска заголовков, параметры компилятора, параметры линкера и т. д., в соответствии с файлом шаблона. Касательно того, какой чип используется для проекта, то это напрямую указывается в этом файле технического шаблона. В большинстве случаев этот файл шаблона пустой файл проекта, который помогает SCons в генерации project.uvprojx или project.eww.

scons -jN

Многопоточная цель компиляции, можно использовать эту команду для ускорения компиляции для компьютерах, где есть несколько ядер. Обычно одно ядро CPU может поддерживать 2 потока. Используйте команду scons -j4 на двухядерном PC.

Примечание: если Вы хотите разобраться в ошибках или предупреждениях компиляции, то лучше не использовать параметр -j, потому что в консоль будут сыпаться сообщения от параллельно выполняющихся потоков компиляции.

Сборка фреймворка проекта. Есть интересная команда, которая позволяет подготовить проект к копированию в другое место.

scons --dist

Использование этой команды сгенерирует директорию dist в каталоге BSP. Это структура каталогов разрабатываемого проекта, включая исходный код RT-Thread и связанные с BSP проекты. Не относящиеся к BSP папки и libcpu будут удалены, и Вы можете свободно скопировать свою работу в любую директорию.

scons --verbose

Эта команда приведет к очень подробному выводу сообщений компиляции. Вряд ли когда-нибудь эта команда Вам понадобится.

[Расширенное использование SCons]

SCons использует файлы SConscript и SConstruct для организации структуры исходного кода. Обычно в проекте есть только один файл SConstruct, но может быть несколько файлов SConscript. Обычно файл SConscript размещается в каждом подкаталоге, где находится исходный код.

Чтобы улучшить поддержку RT-Thread нескольких компиляторов и упростить настройку параметров компиляции, RT-Thread создает отдельный файл rtconfig.py для каждого BSP. Таким образом, с каждом каталоге RT-Thread BSP существуют 3 файла: rtconfig.py, SConstruct и SConscript, которые управляют процессом компиляции BSP. Существует только один файл SConstruct в BSP, но файлов SConscript несколько. Можно сказать, что файл SConscript является основой организации исходного кода.

RT-Thread SConscript также присутствуют в большинстве папок с исходным кодом. Файлы исходного кода "ищет" файл SConscript, и добавляет соответствующие файлы к макросу, определенному для компилятора в rtconfig.h. Ниже в качестве примера, как SCons делает сборку проекта, приведено описание компиляции stm32f10x-HAL/BSP.

Встроенные функции SCons. Если Вы хотите добавить свои собственные исходные файлы кода к системе сборки SCons, то можете создать файл SConscript, или просто изменить существующий. Файл SConscript может управлять добавлением исходных файлов, и может указывать группу исходных файлов (подобно концепции Groups в таких IDE, как MDK/IAR).

SCons предоставляет несколько встроенных функций, помогающих быстро добавить исходный код, и этими простыми операторами Python мы можем добавлять в проект код, или удалять код из проекта. Ниже приведен короткий обзор некоторых общих функций.

GetCurrentDir()

Берет путь текущей директории.

Glob('*.c')

Берет все C-файлы в текущей директории. Измените значение параметра в этой функции, чтобы расширение имени файла соответствовало всем файлам в текущей директории.

GetDepend(macro)

Эта функция определена в файле скрипта building.py, находящегося в директории tools. Она читает информацию конфигурации из файла rtconfig.h для макроса с именем macro. Эта функция вернет true, если в файле rtconfig.h этот макрос включен, иначе вернет false.

Split(str)

Разделит строку str на список строк.

DefineGroup(name, src, depend, **parameters)

Это функция RT-Thread, основанная на расширении SCons. DefineGroup используется для определения компонента. Компонентом может быть директория (в файле или подкаталоге), и группа или папка в некоторых последующих файлах проекта IDE.

Параметры DefineGroup():

Параметр Описание
name Имя группы.
src Файлы, содержащиеся в группе, обычно это исходные файлы C/C++. Для удобства Вы можете использовать функцию Glob, чтобы перечислить соответствующие файлы в директории, где находится файл SConscript, с помощью шаблона wildcard.
depend Опции, от которых группа зависит при компиляции (например, компонент FinSH зависит от определения макроса RT_USING_FINSH). Опция компиляции обычно соответствует макросу RT_USING_xxx, определенному в rtconfig.h. Когда соответствующий макрос определен в конфигурационном файле rtconfig.h, то эта группа будет добавлена для компиляции к рабочему окружению сборки. Если макрос зависимости не определен в rtconfig.h, то эта группа не будет добавлена к компиляции. Подобным образом, когда scons используется для генерации файла проекта IDE, если макрос зависимости не определен, то соответствующая группа не появится в файле проекта.
parameters Конфигурирует другие параметры, их значения можно найти в таблице ниже. В реальном использовании Вам не нужно конфигурировать все параметры.

Что может быть указано в parameters: 

Параметр Описание
CCFLAGS Параметры компиляции исходного файла.
CPPPATH Путь поиска заголовков.
CPPDEFINES Параметры линковки.
LIBRARY Если включить этот параметр, то генерируемый компонентом объектный файл будет упакован в файл библиотеки.

SConscript(dirs, variant_dir, duplicate)

Читает новый файл SConscript. Описание параметров:

Параметр Описание
dirs Путь файлов SConscript.
variant_dir Указывает путь для сохранения генерируемого целевого файла.
duiplicate Указывает, делать ли копию или линковку исходного файла в variant_dir.

[Примеры SConscript]

Ниже показаны несколько примеров SConscript, поясняющих, как использовать утилиту scons.

Ниже показано содержимое файла SConscript в каталоге stm32f10x-HAL/BSP. Этот файл управляет всеми другими файлами SConscript в подкаталогах BSP, как показано ниже.

import os
 
cwd = str(Dir('#'))
objs = []list = os.listdir(cwd)
for d in list:
    path = os.path.join(cwd, d)
       if os.path.isfile(os.path.join(path, 'SConscript')):
        objs = objs + SConscript(os.path.join(d, 'SConscript'))
Return('objs')

import os: импортирует модуль os системы программирования Python, после чего можно вызывать все функции этого модуля для обработки файлов и директорий.

cwd = str(Dir('#')): берет директорию верхнего уровня проекта, и присваивает её строковой переменной cwd. Эта директория, где находится файл SConstruct проекта, тот же самый эффект даст cwd = GetCurrentDir().

objs = []: определяется переменная objs, содержащая пустой список.

list = os.listdir(cwd): получит все директории текущей директории, и сохранит их в переменную list.

Далее идет цикл for на языке Python, который просматривает все подкаталоги BSP, и запускает находящиеся в них файлы SConscript. Конкретная операция состоит в том, чтобы получить подкаталог текущего каталога, использовать os.path.join(cwd, d) получения полного пути, и затем определить, существует ли в этом подкаталоге файл SConscript. Если он существует, то выполняется objs = objs + SConscript(os.path.join(d, 'SConscript')). Это выражение использует встроенную функцию SConscript() (она предоставлена системой SCons), которая может прочитать новый файл SConscript, и добавить исходный файл, указанный файле SConscript, к списку компиляции objs.

С этим файлом SConscript исходный код, требуемый для проекта BSP, добавляется в список компиляции.

Как обстоят дела с другими SConscript-файлами stm32f10x-HAL/BSP? Давайте взглянем на файл SConscript в директории drivers, он управляет компиляцией всех исходных кодов этой директории. В директории drivers находится низкоуровневый код, используемый RT-Thread.

Import('rtconfig')
from building import *
 
cwd = GetCurrentDir()
 
# Добавление основных драйверов.
src = Split("""
board.c
stm32f1xx_it.c
""")
 
if GetDepend(['RT_USING_PIN']):
    src += ['drv_gpio.c']
if GetDepend(['RT_USING_SERIAL']):
    src += ['drv_usart.c']
if GetDepend(['RT_USING_SPI']):
    src += ['drv_spi.c']
if GetDepend(['RT_USING_USB_DEVICE']):
    src += ['drv_usb.c']
if GetDepend(['RT_USING_SDCARD']):
    src += ['drv_sdcard.c']
 
if rtconfig.CROSS_TOOL == 'gcc':
    src += ['gcc_startup.s']
 
CPPPATH = [cwd]
 
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
 
Return('group')

Import('rtconfig'): импортирует объект rtconfig, и rtconfig.CROSS_TOOL, используемый позже, как он определен в этом модуле rtconfig.

from building import *: все содержимое собираемого модуля импортируется в текущий модуль, и этом модуле находится DefineGroup, что используется далее.

cwd = GetCurrentDir(): получение текущего пути и сохранение его в строковую переменную cwd.

Следующая строка использует функцию Split(), чтобы преобразовать строку с именами файлов в список src. Эффект от этого такой же, как от оператора:

src = ['board.c', 'stm32f1xx_it.c']

Далее оператор if и функция GetDepend() используются для проверки, открыт ли соответствующий макрос в конфигурационном файле rtconfig.h. Если этот макрос определен, то src += [src_name] используется для добавления исходного кода к переменной списка src.

CPPPATH = [cwd]: сохраняет текущий путь в переменную списка CPPPATH.

Последняя строка использует DefineGroup для создания группы с именем Drivers, которая соответствует группам исходного кода в MDK или IAR. Файлы исходного кода для этой группы указываются переменной src, и параметр dependency пустой, что показывает, что эта группа не зависит от каких-либо макросов rtconfig.h.

CPPPATH = CPPPATH означает добавление текущего пути к системному пути поиска заголовков. CPPPATH слева от оператора присваивания это параметр для DefineGroup, который представляет путь поиска заголовков. CPPPATH справа определен предыдущей строкой. Таким способом мы можем обращаться к файлам заголовка директории drivers из другого исходного кода.

Давайте рассмотрим файл SConscript, находящийся в директории applications, он управляет исходным кодом в этой директории. В результате компилируется исходный код приложения пользователя.

from building import *
 
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd, str(Dir('#'))]
 
group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH)
 
Return('group')

src = Glob('*.c'): получает все исходные файлы C в текущей директории.

CPPPATH = [cwd, str(Dir('#'))]: сохранит текущий путь и путь файла SConstruct в переменную списка CPPPATH.

Предпоследняя строка использует DefineGroup для создания группы с именем Applications. Файлы исходного кода для этой группы указываются параметром src. Если параметр dependency пуст, как в этом примере, то группа не зависит ни от одного из макросов в rtconfig.h, и сохраняемый CPPPATH путь добавляется с системному пути поиска заголовков. На такие каталоги приложения и каталоги директории stm32f10x-HAL/BSP можно ссылаться где-нибудь в исходном коде, когда добавляются директивы #include.

Если суммировать, то эта программа добавит все C-модули в текущей директории в группу Applications, так что если Вы добавите или удалите файлы в этой директории, то они будут соответственно добавлены в проект или удалены из проекта. Это подходит для добавления исходных файлов в пакеты.

Ниже показано содержимое файла component/finsh/SConscript системы RT-Thread, который управляет исходным кодом в каталоге finsh.

Import('rtconfig')
from building import *
 
cwd     = GetCurrentDir()
src     = Split('''
shell.c
symbol.ccmd.c
''')
 
fsh_src = Split('''
finsh_compiler.c
finsh_error.c
finsh_heap.c
finsh_init.c
finsh_node.c
finsh_ops.c
finsh_parser.c
finsh_var.c
finsh_vm.c
finsh_token.c
''')
 
msh_src = Split('''
msh.cmsh_cmd.cmsh_file.c
''')
 
CPPPATH = [cwd]
if rtconfig.CROSS_TOOL == 'keil':
    LINKFLAGS = '--keep *.o(FSymTab)'
 
    if not GetDepend('FINSH_USING_MSH_ONLY'):
        LINKFLAGS = LINKFLAGS + '--keep *.o(VSymTab)'
else:
    LINKFLAGS = ''
 
if GetDepend('FINSH_USING_MSH'):
    src = src + msh_src
if not GetDepend('FINSH_USING_MSH_ONLY'):
    src = src + fsh_src
 
group = DefineGroup('finsh', src, depend = ['RT_USING_FINSH'],
                     CPPPATH = CPPPATH, LINKFLAGS = LINKFLAGS)
 
Return('group')

Давайте взглянем здесь на первый условный оператор Python. Если инструмент компиляции keil, то переменной LINKFLAGS присваивается '--keep *.o(FSymTab)', иначе она будет пустая.

DefinGroup также создает группу для файлов src в директории finsh с именем finsh. Параметр зависимости depend = ['RT_USING_FINSH'] показывает, что эта группа зависит от макроса RT_USING_FINSH в файле конфигурации rtconfig.h. Когда макрос RT_USING_FINSH открыт в файле rtconfig.h, исходный код в группе finsh будет скомпилирован, иначе SCons не будет его компилировать.

Затем директория finsh добавляется к системным путям поиска заголовков, чтобы мы из другого исходного кода могли ссылаться на её заголовки директивой #include.

LINKFLAGS = LINKFLAGS имеет тот же смысл, что и CPPPATH = CPPPATH. Здесь LINKFLAGS слева представляет параметр линковки, и LINKFLAGS справа это значение, определенное предыдущим оператором if/else. Таким способом для проекта указываются параметры линковки.

[Управление проектами с помощью SCons]

В предыдущих секциях мы подробно рассмотрели файлы SConscript, относящиеся к исходному коду RT-Thread. Также Вам следует знать некоторые общие методы написания файлов SConscript, в этой секции показывается, как с помощью SCons управлять своими проектами.

Добавление кода приложения. Как упоминалось выше, папка applications в каталоге BSP используется для сохранения кода приложения пользователя. Сейчас здесь находится только один файл main.c. Если код приложения пользователя невелик, то рекомендуется добавлять модули исходного кода в папку applications. В этом примере в папку applications добавляются 2 файла hello.c и hello.h.

Файл hello.h:

#ifndef _HELLO_H_
#define _HELLO_H_
 
int hello_world(void);
 
#endif /* _HELLO_H_ */

Файл hello.c:

#include < stdio.h>
#include < finsh.h>
#include < rtthread.h>
 
int hello_world(void)
{
   rt_kprintf("Hello, world!\n");
   return 0;
}
 
MSH_CMD_EXPORT(hello_world, Hello world!);

Файл SConscript в директории applications добавит все исходные файлы в текущей директории в текущую директорию проекта. Вам нужно использовать команду --target=xxx, чтобы добавить 2 новых файла в свой проект. Обратите внимание, что проект регенерируется каждый раз при добавлении нового файла.

Добавление модуля. Как упоминалось выше, в случае, когда исходных файлов не очень много, рекомендуется просто добавлять их в папку applications. Если же у пользователя много исходного кода, и он хочет создать отдельный модуль проекта, или если нужно использовать другие модули, полученные из стороннего источника, то что более подходит для такого случая?

Возьмем для примера те же самые файлы hello.c и hello.h, и разместим их в отдельном подкаталоге, чтобы создать из них группу в проекте MDK, и их можно было бы выбрать через menuconfig. Для этого добавим папку hello в каталог BSP, и перенесем туда файлы hello.c и hello.h.

SCons hello files

Обратите внимание на дополнительный файл SConscript в этом каталоге. Если вы хотите добавить какой-то свой исходный код к окружению сборки SCons, то можно просто создать или изменить существующий файл SConscript. Содержание нашего нового файла SConscript, созданного для модуля hello:

from building import *
 
cwd          = GetCurrentDir()
include_path = [cwd]
src          = []
 
if GetDepend(['RT_USING_HELLO']):
    src += ['hello.c']
 
group = DefineGroup('hello', src, depend = [''], CPPPATH = include_path)
 
Return('group')

С помощью такого простого кода создается новая группа hello, в эту группу добавляются файл исходного кода, управляемый макросом RT_USING_HELLO, и к системному пути поиска заголовков добавляется директория группы.

Kconfig и menuconfig. Давайте рассмотрим, где определяется пользовательский макрос RT_USING_HELLO. Для этого есть файл Kconfig, он используется для конфигурирования ядра и интерфейса конфигурации команды menuconfig. Команда menuconfig используется в системе Env, когда конфигурируются опции, определенные в файле Kconfig. Команда menuconfig генерирует интерфейс конфигурации для пользователя, чтобы конфигурировать ядро путем чтения различных файлов Kconfig проекта. И в завершении все связанные с конфигурацией определения макросов сохраняются в файл rtconfig.h, находящийся в каталоге BSP. Каждый BSP имеет такой файл rtconfig.h, это конфигурационная информация для него.

Ниже показан файл Kconfig для этого BSP, находящегося в подкаталоге BSP папки stm32f10x-HAL, и мы можем добавить опции конфигурации в этот файл. Символом # обозначаются комментарии.

menu "hello module"                          # создает меню "hello module"
 
   config RT_USING_HELLO                     # опции конфигурации RT_USING_HELLO
      bool "Enable hello module"             # RT_USING_HELLO это переменная bool, и её описание
                                             # отображается как "Enable hello module"
      default y                              # RT_USING_HELLO может получать значения y и n,
                                             # по умолчанию y
      help                                   # Если использовать help, то это отобразит сообщение
      this hello module only used for test   # "this hello module only used for test"
 
   config RT_HELLO_NAME                      # опции конфигурации RT_HELLO_NAME
      string "hello name"                    # RT_HELLO_NAME строковая переменная, и меню
                                             # отображается как "hello name"
      default "hello"                        # имя по умолчанию "hello"
 
   config RT_HELLO_VALUE                     # опции конфигурации RT_HELLO_VALUE
      int "hello value"                      # RT_HELLO_VALUE переменная int, и это покажет меню
                                             # как "hello value"
      default 8                              # значение по умолчанию 8
 
endmenu                                      # конец меню hello

После входа в каталог stm32f10x-HAL/BSP из командной строки Env, можно использовать команду menuconfig, чтобы увидеть меню конфигурации нового модуля hello на главной странице. После входа в меню отобразится следующий экран.

SCons menuconfig hello menu

Здесь мы можем поменять значение для hello.

SCons menuconfig hello value

После сохранения конфигурации и выхода из конфигурационного интерфейса команды menuconfig откройте файл rtconfig.h, находящийся в директории stm32f10x-HAL/BSP. Здесь Вы увидите, что появилась конфигурационная информация для модуля hello.

SCons hello rtconfig

Важное замечание: используйте команду scons --target=XXX для генерации нового проекта всякий раз, когда меняете конфигурацию с помощью menuconfig.

Из-за того, что в rtconfig.h был определен макрос RT_USING_HELLO, к обновленному проекту добавляется файл hello.c, который будет компилироваться при последующей сборке.

Показанный выше пример можно использовать для добавления собственных модулей к опциям конфигурации файла Kconfig или создания собственных файлов Kconfig. Также см. руководство [4], где также описывается, как изменять и добавлять опции конфигурации.

Добавление библиотеки. Если нужно добавить дополнительную библиотеку к своему проекту, то следует уделить внимание к системе именования библиотек в различных тулчейнах. Например, тулчейн GCC распознает имена библиотек, такие как libabc.a, можно указать abc вместо libabc, когда указываете эту библиотеку. Соответственно это нужно учесть в файле SConscript, когда линкуются дополнительные библиотеки. Дополнительно при добавлении библиотек хорошей идеей будет указать пути поиска соответствующей библиотеки. Вот пример:

Import('rtconfig')
from building import *
 
cwd = GetCurrentDir()
src = Split('''
''')
 
LIBPATH = [cwd + '/libs']
LIBS = ['abc']
 
group = DefineGroup('ABC', src, depend = [''], LIBS = LIBS, LIBPATH=LIBPATH)

Здесь LIBPATH задает путь до библиотеки, и LIBS указывает имя библиотеки. Если тулчейн GCC, то имя библиотеки должно быть libabc.a; если тулчейн armcc, то имя библиотеки должно быть abc.lib.LIBPATH = [cwd + '/libs'], показывающее, что путь поиска библиотеки это подкаталог 'libs' в текущей директории.

Опции компилятора. Скрипт rtconfig.py это стандартный файл конфигурации RT-Thread для компилятора, который управляет большинством опций конфигурации. Этот файл скрипта написан на Python, и используется для следующего:

• Указывает компилятор (выбирает один из нескольких поддерживаемых компиляторов).
• Указывает параметры для компилятора, такие как опции компиляции, опции линкера, и т. д.

Когда мы компилируем проект с использованием команды scons, проект компилируется в соответствии с опциями конфигурации компилятора, указанными в rtconfig.py. Следующий код это часть кода rtconfig.py в директории stm32f10x-HAL/BSP.

import os
 
# опции тулчейна
ARCH='arm'
CPU='cortex-m3'
CROSS_TOOL='gcc'
 
if os.getenv('RTT_CC'):
   CROSS_TOOL = os.getenv('RTT_CC')
 
# cross_tool предоставляет кросс-компилятор
# EXEC_PATH это путь запуска компилятора, например CodeSourcery, Keil MDK, IAR
 
if  CROSS_TOOL == 'gcc':
   PLATFORM    = 'gcc'
   EXEC_PATH   = '/usr/local/gcc-arm-none-eabi-5_4-2016q3/bin/'
elif CROSS_TOOL == 'keil':
   PLATFORM    = 'armcc'
   EXEC_PATH   = 'C:/Keilv5'
elif CROSS_TOOL == 'iar':
   PLATFORM    = 'iar'
   EXEC_PATH   = 'C:/Program Files/IAR Systems/Embedded Workbench 6.0 Evaluation'
 
if os.getenv('RTT_EXEC_PATH'):
   EXEC_PATH = os.getenv('RTT_EXEC_PATH')
 
BUILD = 'debug'
 
if LATFORM == 'gcc':
   # тулчейны
   PREFIX = 'arm-none-eabi-'
   CC = PREFIX + 'gcc'
   AS = PREFIX + 'gcc'
   AR = PREFIX + 'ar'
   LINK = PREFIX + 'gcc'
   TARGET_EXT = 'elf'
   SIZE = PREFIX + 'size'
   OBJDUMP = PREFIX + 'objdump'
   OBJCPY = PREFIX + 'objcopy'
 
   DEVICE = '-mcpu=cortex-m3 -mthumb -ffunction-sections -fdata-sections'
   CFLAGS = DEVICE
   AFLAGS = '-c' + DEVICE + '-x assembler-with-cpp'
   LFLAGS = DEVICE + '-Wl,--gc-sections,-Map=rtthread-stm32.map,-cref,-u,Reset_Handler -T stm32_rom.ld'

Здесь CFLAGS указывает опции компилятора для C-файлов, AFLAGS опции компиляции для файлов ассемблера, и LFLAGS это опции для линкера. Переменная BUILD управляет уровнем оптимизации кода. По умолчанию BUILD получает значение 'debug', что соответствует компиляции в режиме отладки, с уровнем оптимизации 0 (отсутствие оптимизации). Если Вы как-нибудь измените эту переменную, то при компиляции будет применен уровень оптимизации 2. Ниже показаны соответствующие возможные варианты для этой переменной (все они соответствуют конфигурации без отладки, no 'debug').

BUILD = ''
BUILD = 'release'
BUILD = 'hello, world'

Рекомендуется для использования режим debug (без оптимизации) на стадии разработки, и когда продукт станет стабильным, рассмотреть вариант применения оптимизации.

Специфичный смысл этих опций можно расшифровать, обратившись к руководству компилятора, такому как armcc, который используется средой разработки MDK (в этом случае следует смотреть help для среды разработки MDK).

Как уже упоминалось выше, если нужно компилировать проект другим компилятором, когда выполняется команда scons, то Вы можете использовать соответствующие команды для указания компилятора и пути до него в командной строке Env. Однако такая модификация будет доступна только для текущего процесса Env. Когда Вы перезапустите командную строку Env, то нужно будет заново ввести настройки команды. Чтобы этого избежать, можно напрямую изменить файл rtconfig.py, чтобы достичь необходимого функционала, чтобы определенная конфигурация компилятора применялась постоянно. В общем случае нам надо будет только поменять опции CROSS_TOOL и EXEC_PATH:

CROSS_TOOL: указывает компилятор. Возможные значения для этой опции keil, gcc, iar. Просмотрите файл rtconfig.py, чтобы увидеть, какие компиляторы поддерживаются текущим BSP. Если на вашем PC установлен MDK, то можно изменить CROSS_TOOL на keil, и использовать MDK для компиляции проекта.
EXEC_PATH: путь, где установлен компилятор.

По поводу пути компилятора нужно учитывать следующее:

(1) Когда устанавливается компилятор (такой как MDK, GNU GCC, IAR, и т. д.), избегайте использования в имени каталога для установки национальных символов и пробелов. Иначе при парсинге пути до компилятора могут быть ошибки. Некоторые программы по умолчанию ставятся в папки наподобие C:\Program Files, и в этом пути присутствует пробел. Рекомендуется использовать другие пути для установки.
(2) При модификации EXEC_PATH следует уделить внимание формату пути. На платформах Windows разделитель пути по умолчанию это обратный слеш \, который используется как escape-символ на языках C и Python. При модификации пути поменяйте \ на /, или добавьте r (специфичный для Python синтаксис для сырых данных).

Предположим, что компилятор установлен в каталог D:\Dir1\Dir2. Ниже показаны корректные варианты записи пути:

# В этом примере в начале строки указан символ r,
# тогда мы можем нормально использовать символ \:
EXEC_PATH = r'D:\Dir1\Dir2'
# Здесь вместо \ используется /, символ r не нужен:
EXEC_PATH = 'D:/Dir1/Dir2'
# Пример экранирования символа \, чтобы символ \ нормально
# передавался как разделитель пути:
EXEC_PATH = 'D:\\Dir1\\Dir2'

Неправильный способ указания пути:

EXEC_PATH = 'D:\Dir1\Dir2'

Если в rtconfig.py есть следующий код, закомментируйте его, когда используете свой собственный компилятор.

if os.getenv('RTT_CC'):
   CROSS_TOOL = os.getenv('RTT_CC')
...
if os.getenv('RTT_EXEC_PATH'):
   EXEC_PATH = os.getenv('RTT_EXEC_PATH')

Эти два оператора if установят CROSS_TOOL и EXEC_PATH в значение по умолчанию Env.

После того, как компилятор сконфигурирован, мы можем использовать SCons для компиляции BSP RT-Thread. Откройте окно командной строки в директории BSP, и выполните команду scons для запуска процесса компиляции.

Вспомогательный скрипт компиляции RT-Thread. В директории tools исходного кода RT-Thread находятся некоторые вспомогательные скрипты, определенные RT-Thread, такие как файлы проекта для автоматической генерации RT-Thread с некоторыми IDE. Самый важный из них это скрипт building.py.

Для сложных компилируемых систем их исходный код скорее всего будет состоять из множества файлов, распределенных по разным каталогам. Вероятно это будет комбинация нескольких папок на первом уровне.

В SCons можно написать скрипты SConscript для компиляции файлов в этих относительно независимых директориях, и также можно использовать в SCons функции Export и Import, чтобы обмениваться данными между файлами SConstruct и SConscript (т. е. данными объектов Python). Для дополнительной информации по использованию SCons см. официальную документацию [5].

[Ссылки]

1. RT-Thread / rtthread-manual-doc site:github.com.
2. SCons User Guide site:scons.org.
3. Download RT-Thread site: rt-thread.io.
4. RT-Thread User Manual of Env site:github.com.
5. SCons Current Documentation site:scons.org.

 

Добавить комментарий


Защитный код
Обновить

Top of Page