GCC: spec-файлы |
![]() |
Добавил(а) microsin |
GCC это драйвер процесса сборки программы. Он выполняет свою работу путем организации последовательности запуска других программ, чтобы успешно прошла компиляция, ассемблирование и компоновка (линковка). GCC интерпретирует параметры своей командной строки и использует их, чтобы определить, какие программы он должен вызвать, и какие параметры командной строки следует использовать для каждой вызываемой программы. Это поведение управляется spec-строками. В большинстве случаев для каждой программы существует одна spec-строка, которую может применить GCC, однако у некоторых программ существует несколько spec-строк для управления их поведением. Встроенные в GCC spec-строки можно перезадать опцией -specs=имя_файла (или --specs=имя_файла), где указывается spec-файл. Spec-файлы это простые текстовые файлы, которые содержат в себе spec-строки (далее вместо "spec-строка" может быть указано просто "spec"). Эти строки составляют последовательность директив, отделенных друг от друга пустыми строками. Тип директивы определяется по первому символу строки, не являющемуся пробелом. Этот символ может быть одним из следующих: %command Выдает команду процессору spec-файла. Здесь могут появляться следующие команды: %include < file> %include_noerr < file> %rename old_name new_name *[spec_name]: Это указывает компилятору создать, переназначить или удалить именованную spec-строку. Все строки после этой директивы до следующей директивы или пустой строки считаются текстом для spec-строки. Если результат выполнения этой команды пустая строка, то эта spec-строка удаляется (или, если spec-строка не существует, то ничего не произойдет). Иначе, если spec в настоящее время не существует, будет создана новая spec. Если spec существует, то её содержимое будет переназначено текстом этой директивы, за исключением случая, когда первый символ текста является '+', тогда текст директивы пристыковывается к существующей spec. [suffix]: Создает новую пару '[suffix] spec'. Все строки после этой директивы и до следующей директивы или пустой строки считаются составляющими spec-строку для показанного suffix. Когда компилятор сталкивается с входным файлом с именем suffix, он обрабатывает spec-строку, чтобы решить, как компилировать этот файл. Следующий пример говорит, что файл, заканчивающийся на '.ZZ', должен быть передан программе 'z-compile', для которой передается опция командной строки -input и с результатом выполнения подстановки '%i' (см. далее): .ZZ: z-compile -input %i В качестве альтернативы предоставлению spec-строки, следующий за директивой suffix текст может быть одним из следующих: @language .ZZ: @c++ #name name compiler not installed on this system. У GCC имеется большой список встроенных в него суффиксов. Эта директива добавляет запись в конец списка суффиксов, но поскольку этот список просматривается от конца к началу, то эта техника позволяет переназначить уже существующие суффиксы. У GCC имеется следующий встроенный в него список spec-строк. Spec-файлы могут переназначать эти строки или создавать свои собственные. Обратите внимание, отдельные цели компиляции (target) могут иметь также свои собственные spec-строки для этого списка. asm Опции для передачи ассемблеру. asm_final Опции для передачи пост-процессору ассемблера. cpp Опции для передачи препроцессору C. cc1 Опции для передачи компилятору C. cc1plus Опции для передачи компилятору C++. endfile Объектные файлы для подключения в конец линковки. link Опции для передачи компоновщику (линкеру). lib Библиотеки для подключения в командную строку для линкера. libgcc Решает, какую библиотеку поддержки GCC передать линкеру. linker Устанавливает имя линкера. predefines Определения define для передачи препроцессору C. signed_char Определения define для передачи в CPP, чтобы указать, что char startfile Объектные файлы для подключения в начале линковки. Вот небольшой пример spec-файла: %rename lib old_lib Этот пример переименовывает spec с именем 'lib' в 'old_lib', и затем перезадает предыдущее определение 'lib' на новое. Это новое определение добавляет некоторые дополнительные опции командной строки перед подключением текста старого определения. Spec-строки это список опций командной строки для передачи в соответствующую им программу. Дополнительно spec-строки могут содержать последовательности с префиксом '%' замены текстовой переменной или вставки текста в командную строку. Использование подобных конструкций позволяет генерировать довольно сложные командные строки. Ниже приведена таблица всех определенных '%'-последовательностей для spec-строк. Обратите внимание, что пробелы не создаются автоматически вокруг результатов развертывания этих последовательностей. Таким образом, вы можете соединить их друг с другом, или скомбинировать их с постоянным текстом в один аргумент. %% Заменит один '%' имя программы или аргумент. %" Заменит пустой аргумент. %i Заменит имя входного обрабатываемого файла. %b Заменит базовое имя для выходных результатов, связанных с обрабатываемым входным файлом. Часто это подстрока до (и не включая) последней точки и не включая директорию, но если не активна %w, это расширяется до базового имени дополнительных выходных результатов, на которые могут влиять явное имя выходных результатов, и различные другие опции, которые управляют, как задается имя для дополнительных выходных результатов. %B То же самое, что и '%b', но включает суффикс файла (текст после последней точки). Без %w это расширяется в базовое имя для дампа выходных результатов. %d Помечает аргумент, содержащий или следующий за '%d' как имя временного файла, чтобы этот файл был удален после успешного завершения GCC. В отличие от '%g' это не вносит текст в аргумент. %gsuffix Заменит имя файла у которого есть суффикс suffix, который выбирается один раз на компиляцию, и помечает аргумент так же, как '%d'. Чтобы уменьшить возможности для атак типа отказ в обслуживании, имя файла теперь выбирается таким образом, что его трудно предсказать, даже когда известно ранее выбранные имена файлов. Например, '%g.s … %g.o … %g.s' может превратиться в 'ccUVUUAU.s ccXYAXZ12.o ccUVUUAU.s'. Значение suffix, совпадающее с regexp '[.A-Za-z]*' или специальной строке '%O', которая обрабатывается точно так же, как если бы '%O' был предварительно обработан. Ранее '%g' просто заменялся на имя файла, выбранное один раз на компиляцию, не обращая внимания на какой-либо присоединенный суффикс (который таким образом считался обычным текстом), что повышало вероятность успеха таких атак. %usuffix Подобно '%g', но генерирует новый временный файл при каждом появлении вместо одного файла на компиляцию. %Usuffix Заменяет последнее имя файла, сгенерированное с '%usuffix', генерируя новое, если нет такого последнего имени файла. При отсутствии какого-либо '%usuffix' это работает просто как '%gsuffix', за исключением того, что не используется одно и то же пространство суффиксов, так что '%g.s … %U.s … %g.s … %U.s' приведет к генерации двух различных имен файлов, один для каждого '%g.s', и другой для каждого '%U.s'. Ранее '%U' просто заменялось на имя файла, выбранное предыдущим '%u', не обращая внимания на какой-либо присоединенный суффикс. %jsuffix Заменит имя HOST_BIT_BUCKET, если оно есть, и если оно записываемое, и если не используется -save-temps; иначе заменит имя временного файла, наподобие как это делает '%u'. Этот временный файл предназначен не для обмена данными между процессами, а скорее как механизм удаления ненужного мусора (junk disposal mechanism). %|suffix Работает наподобие '%g', кроме активности -pipe. В этом случае '%|' заменяется на одиночное тире, а '%m' ни на что не заменяется. Это два самых общих способа инструктировать программу, что она должна считывать из стандартного ввода, или записывать в стандартный вывод. Если вам нужно что-то более сложное, то можете использовать конструкцию '%{pipe:X}', см. пример gcc/fortran/lang-specs.h. %.SUFFIX Заменит .SUFFIX для суффиксов, которые совпали с аргументами ключа при последующем выводе с '%*'. SUFFIX завершается следующим пробелом или %. %w Пометит аргумент, содержащий или следующий за '%w' как назначенный выходной файл для этой компиляции. Это поместит аргумент в последовательность аргументов, которую подставляет '%o'. %V Показывает, это эта компиляция не создает выходного файла. %o Подставляет имена всех выходных файлов, автоматически обрамляя их пробелами. Также необходимо указать пробелы вокруг '%o', иначе результат будет неопределенным. '%o' предназначен для использования в spec-строках с целью запуска линкера. Входные файлы, имена которых не имеют распознанного суффикса, вообще не компилируются, но подключаются вместе с выходными файлами, т. е. линкуются. %O Подстановка суффикса для объектных файлов. Обратите внимание, что это обрабатывается специально, когда следует сразу за '%g', '%u' или '%U', из-за необходимости формирования полных имен файлов. Обработка такова, что '%O' обрабатывается точно так же, как если бы замена произошла, за исключением того, что '%g', '%u' и '%U' в настоящее время не поддерживают дополнительные символы суффикса, следующие за '%O', как например '.o'. %I Подстановка любого -iprefix (сделанного из GCC_EXEC_PREFIX), -isysroot (сделанного из TARGET_SYSTEM_ROOT), -isystem (сделанного из COMPILER_PATH и опций -B) и -imultilib по мере необходимости. %s Текущий аргумент это имя библиотеки или startup-файла некоторого вида. Поиск для этого файла в стандартном списке директорий и замена найденного полного имени. Текущая рабочая директория включена в список сканируемых директорий. %T Текущий аргумент это имя файла настроек компоновщика (linker script). Поиск этого файла осуществляется в текущем списке директорий на предмет сканирования библиотек. Если файл найден, то в командную строку вставляется опция --script, за которой идет полный путь до найденного файла. Если файл не найден, то генерируется сообщение об ошибке. Замечание: в текущей рабочей директории поиск не осуществляется. %estr Напечатает строку str как сообщение об ошибке. Строка str терминируется новой строкой. Используйте это при обнаружении несогласованных параметров. %nstr Напечатает строку str как примечание. Строка str терминируется новой строкой. %(name) В этом месте заменит содержимое spec-строки name. %x{option} Накопление опции для '%X'. %X Вывод накопленных опций линкера, указанных spec-строкой '%x'. %Y Вывод накопленных опций ассемблера, указанных через -Wa. %Z Вывод накопленных опций препроцессора, указанных -Wp. %M Вывод multilib_os_dir. %R Вывод конкатенации target_system_root и target_sysroot_suffix. %a Обработка asm spec. Это используется для вычисления ключей для передачи в ассемблер. %A Обработка asm_final spec. Это spec-строка для передачи ключей в постпроцессор ассемблера, если нужна такая программа. %l Обработка link spec. Это spec-строка для вычисления командной строки, передаваемой компоновщику (линкеру). Обычно это приводит к использованию последовательностей '%L %G %S %D and %E'. %D Вывод дампа опции -L для каждой директории, которая по мнению GCC может содержать startup файлы. Если цель компиляции (target) поддерживает multilib-ы, то текущая multilib-директория добавляется к каждому из этих путей. %L Обработка lib spec. Это spec-строка для принятия решения, какие библиотеки подключаются в командную строку линкера. %G Обработка libgcc spec. Это spec-строка для принятия решения, какая библиотека поддержки GCC подключается в командную строку линкера. %S Обработка startfile spec. Это spec-строка для принятия решения, какие объектные файлы первыми будут переданы линкеру. Обычно это может быть файл с именем crt0.o. %E Обработка endfile spec. Это spec-строка, которая указывает последние объектные файлы, передаваемые линкеру. %C Обработка cpp spec. Это используется для составления аргументов, передаваемых препроцессору C. %1 Обработка cc1 spec. Это используется для составления опций, передаваемых актуальному компилятору C (cc1). %2 Обработка cc1plus spec. Это используется для составления опций, передаваемых актуальному компилятору C++ (cc1plus). %* Замена переменной части совпавшей опции, см. далее. Обратите внимание, что каждая запятая в замещенной строке заменяется на одиночный пробел. %< S Удаляет всех вхождения -S из командной строки. Замечание: эта команда зависит от позиции. Команды '%' в spec-строке перед этой видят -S, команды '%' в spec-строке после этой не видят -S. %< S* Подобно '%< S', но соответствует всем ключам, начинающимся на -S. %>S Подобно '%< S', но сохраняет -S в командной строке GCC. %:function(args) Вызовет функцию по имени function с передачей ей аргументов args. Здесь args сначала обрабатываются как вложенная spec-строка, затем разделяется на вектор аргументов обычным образом. Функция возвращает строку, которая обрабатывается как если бы она литерально появлялась как часть текущей spec. Предоставляются следующие встроенные spec-функции: getenv %:getenv(TOPDIR /include) ... расширится в /path/to/top/include. if-exists *startfile: crt0%O%s %:if-exists(crti%O%s) crtbegin%O%s if-exists-else *startfile: crt0%O%s %:if-exists(crti%O%s) \ %:if-exists-else(crtbeginT%O%s crtbegin%O%s) if-exists-then-else -l%:if-exists-then-else(%:getenv(VSB_DIR rtnet.h) rtnet net) sanitize %{%:sanitize(address):-funwind-tables} replace-outfile %{fgnu-runtime:%:replace-outfile(-lobjc -lobjc-gnu)} remove-outfile %:remove-outfile(-lm) version-compare < comparison-op> < arg1> [< arg2>] < switch> < result> Функция вернет результат, если сравнение было вычислено как true, иначе вернет NULL. Поддерживаемые значения для оператора сравнения comparison-op следующие: >= !> < !< >< < > Если switch вообще не присутствует, то условием будет false, за исключением случая, когда перед comparison-op стоит логическая инверсия !. В следующем примере добавится -lmx, если было передано -mmacosx-version-min=10.3.9. %:version-compare(>= 10.3 mmacosx-version-min= -lmx) include %{static-libasan|static:%:include(libsanitizer.spec)%(link_libasan)} pass-through-libs %:pass-through-libs(%G %L %G) print-asm-header Assembler options ================= Это используется, чтобы отделить опции компилятора от опций ассемблера в выводе --target-help. gt %{%:gt(%{ftree-parallelize-loops=*:%*} 1):%:include(libgomp.spec)%(link_gomp)} debug-level-gt %{%:debug-level-gt(0):%{gdwarf*:--gdwarf2}} %{S} Заменяет ключ -S, если этот ключ предоставлен для GCC. Если этот ключ не указан, то ничего не подставляется. Обратите внимание, что начальное тире при указании этой опции опускается, и автоматически вставляется, если выполняется замена. Таким образом, spec-строка '%{foo}' будет соответствовать опции командной строки -foo, и выведет опцию командной строки -foo. %W{S} Наподобие %{S}, но помечает последний указанный аргумент как удаляемый в случае ошибки файл. %@{S} Наподобие %{S}, но выводит результат в FILE, и заменяет @FILE, если был предоставлен аргумент @file. %{S*} Заменяет все ключи, указанные для GCC, которые начинаются на -S, но которые также принимают аргумент. Это используется для ключей наподобие -o, -D, -I и т. п. GCC считает -o foo как один ключ, имя которого начинается на 'o'. %{o*} заменит этот текст, включая пробел. Таким образом, генерируются 2 аргумента. %{S*&T*} Наподобие %{S*}, но сохраняет порядок следования опций S и T (порядок S и T в spec не имеет значения). Здесь может быть любое количество разделенных амперсандом (&) переменных; опционально для каждого может быть wildcard. Полезно для CPP как '%{D*&U*&A*}'. %{S:X} Заменяет X, если для GCC указан ключ -S. %{!S:X} Заменяет X, если для GCC не был указан ключ -S. %{S*:X} Заменяет X, если для GCC указаны один или большее количество ключей, у которых имена начинаются на -S. Обычно X заменяется только один раз не обращая внимания, сколько появилось таких ключей. Однако если %* появился где-то в X, то X заменяется по одному для каждого совпавшего ключа с %*, замененным на часть этого ключа, который совпал с *. Если %* появился как последняя часть spec-последовательности, то добавляется пробел после конца последней замены. Однако если в последовательности больше текста, то пробел не генерируется. Это позволяет замене %* использоваться как часть строки большего размера. Например spec-строка наподобие следующей: %{mcu=*:--script=%*/memory.ld} ... когда совпадет с опций наподобие -mcu=newchip, создаст: --script=newchip/memory.ld %{.S:X} Заменит X, если обрабатывается файл с суффиксом S. %{!.S:X} Заменит X, если не обрабатывается файл с суффиксом S. %{,S:X} Заменит X, если обрабатывается файл для языка S. %{!,S:X} Заменит X, если не обрабатывается файл для языка S. %{S|P:X} Заменит X если либо -S, либо -P были предоставлены для GCC. Это может также комбинироваться с '!', '.', ',' и * последовательностями, хотя они имеют более строгую привязку, чем '|'. Если %* появляется в X, то все альтернативы должны быть помечены звездочкой, и заменяется только первая совпавшая альтернатива. Например, spec-строка наподобие: %{.c:-foo} %{!.c:-bar} %{.c|d:-baz} %{!.c|d:-boggle} ... выведет следующие опции командной строки из следующих входных опций командной строки: fred.c -foo -baz %{%:function(args):X} Вызовет функцию по имени function с аргументами args. Если функция вернет не-NULL, то X заменится, если вернет NULL, то замены не будет. %{S:X; T:Y; :D} Если для GCC предоставлена S, то заменит X; иначе если для GCC предоставлена T, то заменит Y; иначе заменит D. Здесь может быть любое количество элементов в последовательности условий. Это может комбинироваться с ., ,, !, | и * по мере необходимости. Совпавший с ключом S текст в '%{S}', '%{S:X}' или подобной конструкции может использовать обратный слеш для игнорирования специального значения следующего за ним символа, что позволяет литеральное соответствие символа, который иначе бы попал в специальную обработку. Например, '%{std=iso9899\:1999:X}' заменит X, если была предоставлена опция -std=iso9899:1999. Текст условия X в '%{S:X}' или подобной конструкции может содержать вложенные '%' конструкты или пробелы, или даже новые строки. Они обрабатываются обычным образом, как было описано выше. Завершающий пробел в X игнорируется. Пробел также может появляться в любом месте этих конструктов слева от двоеточия, кроме . или * и соответствующего слова. Ключи -O, -f, -m и -W в этих конструктах обрабатываются специальным образом. Если позже в командной строке было найдено другое значение -O или отрицающая форма ключа -f, -m или -W, то более ранний ключ игнорируется, кроме {S*}, где S это просто одна буква, которая передает все соответствующие опции. Символ '|' в начале текста предиката используется, чтобы показать, что команда должна быть перенаправлена (pipe) в следующую команду, но только если указана -pipe. Это встроено в GCC: какие ключи получают аргументы, а какие нет. Вы можете подумать, что было бы полезно обобщить это, чтобы позволить spec каждого компилятора указывать, какие ключи принимают аргументы. Однако это не может быть осуществлено целостно. GCC даже не может решить, какие входные файлы были указаны, если не знает, какие ключи принимают аргументы, и он должен знать, какие входные файлы компилировать, чтобы сказать, какие компиляторы запускать. GCC также неявно знает, что аргументы, начинающиеся на -l, должны рассматриваться как выходные файлы компилятора и переданы линкеру в их правильном положении среди других выходных файлов. [Ссылки] 1. Specifying Subprocesses and the Switches to Pass to Them site:gcc.gnu.org. |