Программирование ARM SCons: мультиплатформенная конфигурация Fri, March 29 2024  

Поделиться

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

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

SCons: мультиплатформенная конфигурация Печать
Добавил(а) microsin   

В SCons встроена поддержка конфигурации сборки в стиле GNU Autoconf, однако разработанная для прозрачной поддержки многими платформами. Система конфигурации может помочь определить, доступны ли системе сборки внешние требования к сборке, такие как системные библиотеки или заголовочные файлы, доступные системе сборки. В этой секции описывается, как использовать эту возможность SCons (для дополнительной информации также см. документацию man для SCons).

Контексты Configure. Базовый фреймворк для мультиплатформенной конфигурации сборки SCons заключается в создании контекста конфигурации внутри construction-окружения путем вызова функции Configure, выполнения желаемых проверок библиотек, функций, заголовочных файлов и т. д., и затем вызова метода Finish контекста конфигурации для завершения конфигурации:

env = Environment()
conf = Configure(env)
# Здесь выполняются проверки библиотек, заголовков и прочего!
env = conf.Finish()

Вызов Finish необходим; если во время активного контекста создается новый контекст, даже в другом construction-окружении, то scons выдаст ошибку и завершит работу.

SCons предоставляет несколько предварительно определенных базовых проверок, как и механизм для добавления ваших собственных проверок.

Есть несколько ошибочных стратегий проверки конфигурации. Некоторые проверки могут быть для элементов, без которых продолжение невозможно. Простой метод обработки таких ситуаций - простое завершение работы SCons - многие из примеров в этой главе реализованы таким способом. Однако если есть несколько жестких требований, то пользователю может быть удобнее установить флаг в случае любого сбоя поддержки жестких требований и накопления записей по ним, так что после завершения контекста конфигурирования все они могут быть перечислены до сбоя построения - иначе может быть неприятно постоянно повторять сборки для настройки каждого исправления ошибки обработки определенного требования. Другие проверки могут быть для функций, без которых вы можете обойтись, и здестт обычная стратегия - установить construction-переменную, которую остальная часть процесса сборки может проверить на присутствие или отсутствие, или установить определенные флаги компилятора, списки библиотек и т. д., в зависимости от обстоятельств, так что можно продолжить сборку в соответствии с доступными возможностями.

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

Следующие секции описывают базовые проверки, поддерживаемые SCons, как и добалвение ваших собственных проверок.

Проверка наличия файлов заголовка. Тестирование существующих заголовочных файлов требует знания, для какого языка эти файлы предназначены. Эта информация предоставляется параметром с ключевым словом language для метода CheckHeader. Поскольку scons развивалась в мире кода C/C++, контекст конфигурирования также имеет метод CheckCHeader, который специально проверяет наличие заголовочного файла языка C:

env = Environment()
conf = Configure(env)
if not conf.CheckCHeader('math.h'):
    print('Math.h must be installed!')
    Exit(1)
if conf.CheckCHeader('foo.h'):
    conf.env.Append(CPPDEFINES='HAS_FOO_H')
env = conf.Finish()

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

Если нужно проверить наличие заголовка C++, используйте метод CheckCXXHeader:

env = Environment()
conf = Configure(env)
if not conf.CheckCXXHeader('vector.h'):
    print('vector.h must be installed!')
    Exit(1)
env = conf.Finish()

Проверка доступности функции. Проверить наличия определенной функции можно с помощью метода CheckFunc:

env = Environment()
conf = Configure(env)
if not conf.CheckFunc('strcpy'):
    print('Did not find strcpy(), using local version')
    conf.env.Append(CPPDEFINES=('strcpy','my_local_strcpy'))
env = conf.Finish()

Проверка доступности библиотеки. Чтобы проверить наличие библиотеки, используйте метод CheckLib. Вы указываете только базовую часть имени библиотеки, т. е. не надо указывать префикс lib или суффикс/расширение .a или .lib:

env = Environment()
conf = Configure(env)
if not conf.CheckLib('m'):
    print('Did not find libm.a or m.lib, exiting!')
    Exit(1)
env = conf.Finish()

Из-за того, что возможность использования библиотеки часто зависит от наличия доступа к её файлу заголовка, где описывается интерфейс библиотеки, вы можете проверить сразу наличие библиотеки и заголовка в одном вызове метода CheckLibWithHeader:

env = Environment()
conf = Configure(env)
if not conf.CheckLibWithHeader('m', 'math.h', language='c'):
    print('Did not find libm.a or m.lib, exiting!')
    Exit(1)
env = conf.Finish()

Это удобнее, чем делать отдельные вызовы функций CheckHeader и CheckLib с проверкой их результатов.

Проверка доступности typedef. Можно проверить наличие определения типа методом CheckType:

env = Environment()
conf = Configure(env)
if not conf.CheckType('off_t'):
    print('Did not find off_t typedef, assuming int')
    conf.env.Append(CPPDEFINES=('off_t','int'))
env = conf.Finish()

Вы также можете добавить строку, которая будет помещена в начало тестового файла, используемого для проверки typedef. Это позволяет указать файлы, которые должны быть включены в поиск typedef:

env = Environment()
conf = Configure(env)
if not conf.CheckType('off_t', '#include < sys/types.h>\n'):
    print('Did not find off_t typedef, assuming int')
    conf.env.Append(CPPDEFINES=('off_t','int'))
env = conf.Finish()

Проверка размера типа данных. Проверить размер типа данных можно методом CheckTypeSize:

env = Environment()
conf = Configure(env)
int_size = conf.CheckTypeSize('unsigned int')
print('sizeof unsigned int is', int_size)
env = conf.Finish()

Результат запуска:

% scons -Q
sizeof unsigned int is 4
scons: `.' is up to date.

Проверка наличия программы. Проверить наличие программы можно методом CheckProg:

env = Environment()
conf = Configure(env)
if not conf.CheckProg('foobar'):
  print('Unable to find the program foobar on the system')
  Exit(1)
env = conf.Finish()

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

mylib_test_source_file = """
#include < mylib.h>
int main(int argc, char **argv)
{
    MyLibrary mylib(argc, argv);
    return 0;
}"""
 
def CheckMyLibrary(context):
    context.Message('Checking for MyLibrary...')
    result = context.TryLink(mylib_test_source_file, '.c')
    context.Result(result)
    return result

Методы Message и Result должны обычно начинаться и заканчиваться пользовательской проверкой, чтобы пользователь знал, что происходит: вызов Message печатает указанное сообщение (без завершающего перехода на новую строку) и вызов Result напечатает yes, если проверка успешна, и no, если это не так. Метод TryLink фактически проверяет, был ли успешно линкован указанный текст программы.

Обратите внимание, что пользовательская проверка может менять свою проверку на основе переданных в неё аргументов, или на основе использования или модификации контекста конфигурирующего окружения в атрибуте context.env.

Эта функция пользовательской проверки затем подсоединяется к configure-контексту передачей словаря в вызов Configure, который привязывает имя проверки к нижележащей функции:

env = Environment()
conf = Configure(env, custom_tests={'CheckMyLibrary': CheckMyLibrary})

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

Мы можем объединить эти части вместе вызовом проверки CheckMyLibrary следующим образом:

mylib_test_source_file = """
#include < mylib.h>
int main(int argc, char **argv)
{
    MyLibrary mylib(argc, argv);
    return 0;
}"""
 
def CheckMyLibrary(context):
    context.Message('Checking for MyLibrary... ')
    result = context.TryLink(mylib_test_source_file, '.c')
    context.Result(result)
    return result
 
env = Environment()
conf = Configure(env, custom_tests={'CheckMyLibrary': CheckMyLibrary})
if not conf.CheckMyLibrary():
    print('MyLibrary is not installed!')
    Exit(1)
env = conf.Finish()
 
# Затем мы добавим реальные вызовы наподобие Program(), чтобы выполнить
# сборку чего-нибудь с использованием construction-окружения "env".

Если библиотека MyLibrary в системе не установлена, то вывод будет следующим:

% scons
scons: Reading SConscript file ...
Checking for MyLibrary... no
MyLibrary is not installed!

Если MyLibrary установлена, то вывод получится такой:

% scons
scons: Reading SConscript file ...
Checking for MyLibrary... yes
scons: done reading SConscript
scons: Building targets ...
    .
    .
    .

Очистка без конфигурирования. Использование мультиплатформенной конфигурации, как было описано в предыдущих секциях, запустит команды конфигурации, даже когда был запуск scons -c для очистки целей сборки (clean targets):

% scons -Q -c
Checking for MyLibrary... yes
Removed foo.o
Removed foo

Хотя запуск проверок платформы, когда удаляются временные файлы сборки, никому не вредят, это скорее всего делать нежелательно. Вы можете избежать этого, используя метод GetOption для проверки, указывалась ли опция очистки -c (clean) в командной строке SCons:

env = Environment()
if not env.GetOption('clean'):
    conf = Configure(env, custom_tests={'CheckMyLibrary': CheckMyLibrary})
    if not conf.CheckMyLibrary():
        print('MyLibrary is not installed!')
        Exit(1)
    env = conf.Finish()

Результат запуска:

% scons -Q -c
Removed foo.o
Removed foo

[Ссылки]

1. SCons: руководство пользователя, быстрый старт.
2. SCons: кэширование файлов построения.

 

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


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

Top of Page