[devel] re-writing GNU C; part1.3.2: how to apply (WIP)

Ivan Zakharyaschev imz на altlinux.org
Ср Янв 27 21:04:38 MSK 2016


On Wed, 27 Jan 2016, Ivan Zakharyaschev wrote:

> Шлю записки о том, как начать применять cuglify/Process в работе с
> какой-то "инородной" платформой FOO/Linux (без GCC). Скажем, в работе

> Один вариант -- более основательный и ценный для будущего, второй
> вариант, который я могу представить (и уже опробовал на практике) --
> проще и позволяет побыстрее увидеть результат компиляции.
> (Третий вариант, который я пытаюсь сейчас осуществить и который
> достижим побыстрее, чем первый основательный, опишу подробнее в
> следующей части сообщения.)

Итак, "второй вариант" я осуществил на практике. (С поправкой на то,
что Process не понимал расширения .i входного файла.)

Теперь хочется, чтобы всё происходило более гладко и незаметно для
собирающего под FOO/Linux, при этом давая ему уже реализованные
преимущества. И нам не до того, чтобы копаться со сборкой .hs via-С
("первый вариант").

Двигаемся к этой цели. (Это "третий вариант", который где-то между
полным "первым" и ручным "вторым" и удобнее с точки зрения
автоматизации; берём пример с ccache или скорее distcc):

Обращения к x86-машине за результатами вычислений, нужных при сборке
--------------------------------------------------------------------

Давайте вставим Process во что-то вроде distcc. Вот как это
будет работать:

1. на компилируемом файле исполняется препроцессор
2. результат пропускается через Process на удалённой x86-машине
3. результат принимается обратно на FOO/Linux и скармливается foo-cc

Пояснение такой схемы в общем:

раз на FOO/Linux какие-то инструменты-преобразователи (наш
Process) невозможно запустить, то мы во время сборки на FOO/Linux
попросим x86-машину сделать это вычисление за нас.

(Заметим, что сборочная система для Sisyphus ориентирована на нативную
сборку. И здесь мы действуем с этой стороны, т.е. пропихиваем сборку
со стороны FOO/Linux, а не так:

> Тут была мысль для удобства доделать Process на предмет вызова
> cpp/foo-cc по ssh сразу, вместо локального cpp/gcc, чтобы облегчить
> ход действий

)

Шаги 1.-3. этой схемы работы надо уточнить/усложнить в связи со
следующими соображениями.

Формулировка задачи Process как фильтра, работающего с семантикой
-----------------------------------------------------------------

Process является такого рода фильтром, целью которого является
поддержка задуманной программистом (и мейнтейнером пакета) семантики
его C-кода с использованием в качестве backend-а не GCC, а foo-cc.

Задуманная семантика может выражаться не только в C-коде (со своими
особыми конструкциями вроде nested functions, которые мы переписываем
из-за ограничений backend-а), но и в опциях gcc. Опции, работа которых
в foo-cc нас не устраивает, мы будем исполнять по возможности сами, а
опции для backend-а переписывать (хотя в простом случае просто
передаём их без изменений). Это знание о семантике некоторых опций GCC
и особенностях их реализации в foo-cc закладывается в Process.

Process управляет командами
---------------------------

Соответственно, в этой схеме работы на шаге:

1. опции препроцессора контролируются Process
2. --
3. опции foo-cc контролируются Process

Сейчас Process (как и примеры в language-c) устроен так, что он
умеет 1. (сам вызывает локальный cpp со всеми релевантными опциями), а 3.
не было у них в language-c задумано (ну потому что не было у них цели
вызывать cc для завершения анализа исходников).

К тому же такой контроль осложняется тем, что Process будет
запускаться удалённо, и от него мы должны получить команды для
запуска:

1. cpp
2. --
3. foo-cc

Т.е. помимо stdin для .c/.i, stdout для переработанного .i и stderr
для warnings, нужны каналы для дачи команд cpp и cc.

открытый вопрос: устройство вызова Process из distcc-подобного клиента
======================================================================

Посмотреть устройство distcc (или ccache) на предмет того, как можно
было бы его использовать для врезания cugligy/Process (запускаемого на
другой машине) в foo-cc/gcc.

Связанная с этой темой проблема, которая имеется в моей модельной
реализации взаимодействия distcc-подобного клиента и Process (см.
ниже) -- это то, что последняя полученная команда (собственно `foo-cc -c`)
выполняется в параллельном процессе, хотя как основная по смыслу и
последняя должна бы и быть тем, что работает до конца и отдаёт код
возврата.

Если немного подумать, наверное, можно переустроить скрипт; просто я
пока не додумал.

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

Другими словами, одно дело fork-и-exec, а другое -- exec. Первое
должно делаться со вспомогательными командами на шагах 1.-2. (их
результатов мы дожидаемся и перерабатываем), а команда из шага 3. должна
делаться просто exec. А в моём скрипте такая разница не предусмотрена
оказалась. (Кажется, я сейчас понял, что не сложно переписать это
правильно, особенно как в моём упрощённом случае, когда порядок и
количество команд заранее предопределено.)

***

(Эти два сообщения сохранены как
<http://hub.darcs.net/imz/cuglify/browse/heterogeneous-platform-initial-next-step.md>.)

Модель реализации такой связки с каналом для команд
===================================================

(Скрипты сохранены в <http://hub.darcs.net/imz/cuglify/>.)

`server_dummy.sh` (на месте Process на x86-машине; вызывается, когда
нужны результаты его работы):

     #!/bin/bash

     set -ex

     readonly PORT="$1"
     shift

     try_send_cmd() {
         # in a format suitable for xargs:
         for w in "$@"; do echo "$w"; done | nc 0 "$PORT"
     }

     # Connection may (temporarily) fail in any case!
     #
     # (In case of local ideal connections, there still is a similar
     # problem: the listening side may not be listening yet for a short
     # period of time after it handled the previous connection.)
     send_cmd() {
         while ! try_send_cmd "$@"; do :; done
     }

     send_cmd a.i

     send_cmd echo a
     sed 's:a:b:'
     exec <&- >&-
     send_cmd cat a.i

Простые helpers (для реакции на стороне клиента на команды от сервера;
ради того, чтобы быстро слушать порт дальше после принятия команды --
&):

`bg_exec`:

     #!/bin/sh

     exec "$@" &

`bg_cat_fromOUT_to`:

     #!/bin/bash

     exec cat <&101- > "$1" &

`bg_exec_toIN`:

     #!/bin/bash

     exec "$@" >&100- &

`client.sh` (в роли distcc там, где собираем):

     #!/bin/bash

     set -ex

     # Preparation:
     # The pipe with Process (run on server-side):
     rm -fv Process_{in,out}.pipe
     mkfifo Process_{in,out}.pipe

     # Overall, we were asked (by Makefile etc.):
     #     gcc -c a.c -o a.o
     # and we pass the args to Process,
     # because it decides what to do.

     # The listeners for commands (are run in parallel):
     {
     exec 100>Process_in.pipe
     exec 101<Process_out.pipe

     # 0. Get the filename (say, a.i) to save the output of Process to:
     nc -l 9876 | xargs ./bg_cat_fromOUT_to 100>&-
     exec 101<&-

     # 1. Instead of running the above single command,
     # we get the result of (via stdout instead of a.orig.i):
     #     gcc -E a.c [-o a.orig.i]
     # as asked by:
     nc -l 9876 | xargs ./bg_exec_toIN
     exec 100>&-

     # 2. ...And send it to Process
     # (or gcc in the case of distcc):
     #     ...(through Process_in.pipe)
     # which sends the result back
     # (either a.o in the case of `distcc`
     # or a.i in the case of Process):
     #     ...(through Process_out.pipe or a.i directly)

     # 3. And we are asked to run on it (saved as a.i):
     #     gcc -c a.i -o a.o
     nc -l 9876 | xargs ./bg_exec
     } &

     # Running Process (or real gcc in case of distcc):
     exec ./server_dummy.sh 9876 arg1 arg2 <Process_in.pipe >Process_out.pipe


-- 
Best regards,
Ivan



Подробная информация о списке рассылки Devel