ALT Linux Team development discussions
 help / color / mirror / Atom feed
* [devel] re-writing GNU C extensions (part0)
@ 2016-01-11  8:48 Ivan Zakharyaschev
  2016-01-11 18:21 ` [devel] re-writing GNU C extensions (part1) Ivan Zakharyaschev
  0 siblings, 1 reply; 8+ messages in thread
From: Ivan Zakharyaschev @ 2016-01-11  8:48 UTC (permalink / raw)
  To: devel

[-- Attachment #1: Type: text/plain, Size: 27329 bytes --]

Пишу преобразователь C-кода, который бы переписывал некоторые GNU
extensions. Это делается для того, чтобы такие программы можно было
компилировать компилятором, который не поддерживает GNU extensions.
Например, clang-ом. (Реализуется на библиотеке
<http://hackage.haskell.org/package/language-c>.)

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

(Это сообщение сохранено как
[ann0.md](http://hub.darcs.net/imz/cuglify/browse/ann0.md).)

Вопросы:
========

Может быть, кто-нибудь может быстро дать совет, который пригодится в
этой работе:

как встроить её в пересборку Sisyphus? (На данном этапе это ценно
только для тестирования возможностей language-c на реальном коде из
Sisyphus -- не ломается ли на чём-то, т.е. не очень интересно для
широкого круга разработчиков. До проведения такой проверки у меня пока
руки не дошли. Думаю, это реализовать будет несложно и проверить
пересборку по крайней мере избранных пакетов.)

Это поспособствует потенциальной переносимости Sisyphus на платформы
без gcc.

Ещё интересуют любые замеченные ошибки в работе, если вдруг кто-то
будет пробовать.

Описание
========

Разные варианты программы-заготовки живут в файле examples/Process.hs
в разных ветках изменённой language-c:

1. <http://hub.darcs.net/imz/language-c_process_analyze-silently>,
2. <http://hub.darcs.net/imz/language-c_process_analyze-printAST>,
3. <http://hub.darcs.net/imz/language-c_process_analyze-generate>.

[Вот](http://hub.darcs.net/imz/cuglify/browse/run-tests.sh) скриптик
для тестирования Process.hs, который демонстрирует идею:

если запустить программу с теми же опциями, что cpp/gcc, то её
поведение должно быть в некотором смысле эквивалентно cpp/gcc.
(Сравниваются коды возврата и демонстрируется diff между
выводом `gcc -E` и нашего `examples/Process`.)

Что умеют эти варианты examples/Process:
----------------------------------------

1. молча парсит и анализирует входной C-файл и завершается с успехом
или неуспехом, т.е. грубо говоря (не)успех ожидается в тех же случаях,
что у `gcc -c`

2. парсит и анализирует входной C-файл, а потом в случае успеха
анализа печатает C-код по своему внутреннему AST, т.е. должен быть
заменой `cpp`/`gcc -E`

3. парсит и анализирует входной C-файл, а потом (в случае успеха,
конечно) генерирует нечто похожее на C-код по своему внутреннему
семантическому представлению

(Может быть, где-то реальное поведение не соответствует заявленному
выше. Тогда это ошибка, которая требует исправления. Я пока ещё
внимательно не проверял все случаи.)

Как массово проверять разные варианты examples/Process и зачем:
---------------------------------------------------------------

1 интересно встраивать в процесс пересборки так: (если пакет успешно
пересобирается в Sisyphus, то) перед всяким вызовом gcc молча вызывать
Process и отваливаться в случае неуспеха. (Подменять cpp и gcc для
других языков не надо, потому что cpp может натравливаться на разный
код, а Process рассчитан на код, который C семантически.)

2 интересно встроить вместо этапа препроцессинга. (Чтобы проверить
печаталку Process на годность.)

3 в таком виде никуда встраивать не планируется, потому что генератор
просто вываливает код для всех встреченных глобальных семантических
объектов неважно в каком порядке. Это интересно для изучения работы
генератора человеком. Использовать генератор всё равно планируется,
чтобы сгенерировать только кусочки переписанного кода, а не всю
программу.

Примеры работы на ex-nested_undef.c
-----------------------------------

(на других примерах -- см. в конце письма):

### 1.

     PROCESSING ex-nested_undef.c...
     * with gcc -c:
     0
     * with ../language-c_process_analyze-silently/examples/Process:
     ex-nested_undef.c:7: (column 3) [WARNING]  >>> AST invariant violated
       unknown function: h

     0
     * diff against gcc -E:
     ex-nested_undef.c:7: (column 3) [WARNING]  >>> AST invariant violated
       unknown function: h

     --- /dev/fd/63	2016-01-09 05:35:09.788220253 +0300
     +++ /dev/fd/62	2016-01-09 05:35:09.789220179 +0300
     @@ -1,12 +0,0 @@
     -# 1 "ex-nested_undef.c"
     -# 1 "<command-line>"
     -# 1 "ex-nested_undef.c"
     -void f(int a) {
     -  int b = 5;
     -  int g(int x) {
     -    return b + x + a;
     -  }
     -  g(0);
     -  h(1);
     -  g(2);
     -}
     TEST OK on ex-nested_undef.c

### 2.

     PROCESSING ex-nested_undef.c...
     * with gcc -c:
     0
     * with ../language-c_process_analyze-printAST/examples/Process:
     ex-nested_undef.c:7: (column 3) [WARNING]  >>> AST invariant violated
       unknown function: h

     void f(int a)
     {
         int b = 5;
         int g(int x)
         {
             return b + x + a;
         }
         g(0);
         h(1);
         g(2);
     }
     0
     * diff against gcc -E:
     ex-nested_undef.c:7: (column 3) [WARNING]  >>> AST invariant violated
       unknown function: h

     --- /dev/fd/63	2016-01-09 05:23:34.198134568 +0300
     +++ /dev/fd/62	2016-01-09 05:23:34.199134493 +0300
     @@ -1,9 +1,8 @@
     -# 1 "ex-nested_undef.c"
     -# 1 "<command-line>"
     -# 1 "ex-nested_undef.c"
     -void f(int a) {
     +void f(int a)
     +{
        int b = 5;
     -  int g(int x) {
     +    int g(int x)
     +    {
          return b + x + a;
        }
        g(0);
     TEST OK on ex-nested_undef.c

### 3.

     PROCESSING ex-nested_undef.c...
     * with gcc -c:
     0
     * with ../language-c_process_analyze-generate/examples/Process:
     ex-nested_undef.c:7: (column 3) [WARNING]  >>> AST invariant violated
       unknown function: h

     void f(int a)
     {
         int b = 5;
         int g(int x)
         {
             return b + x + a;
         }
         g(0);
         h(1);
         g(2);
     }
     void * __builtin_extract_return_addr(void *);
     static const char __FUNCTION__[];
     int __builtin___snprintf_chk(char *,
                                  int,
                                  int,
                                  int,
                                  char * const, ...);
     int __builtin___vsprintf_chk(char *,
                                  int,
                                  int,
                                  char * const,
                                  va_list);
     void * __builtin___memcpy_chk(void *, void * const, int, int);
     char * __builtin___stpcpy_chk(char * const, char * const, int);
     char * __builtin___strcat_chk(char * const, char * const, int);
     char * __builtin___strcpy_chk(char * const, char * const, int);
     int __builtin___sprintf_chk(char *, int, int, char * const, ...);
     void * __builtin_return_address(unsigned int);
     int __builtin_va_arg_pack();
     void * __builtin___memmove_chk(void *, void * const, int, int);
     int __builtin___vsnprintf_chk(char *,
                                   int,
                                   int,
                                   int,
                                   char * const,
                                   va_list);
     char * __builtin___strncat_chk(char * const,
                                    char * const,
                                    int,
                                    int);
     char * __builtin___strncpy_chk(char * const,
                                    char * const,
                                    int,
                                    int);
     void * __builtin___mempcpy_chk(void *, void * const, int, int);
     void * __builtin___memset_chk(void *, int, int, int);
     int __builtin_constant_p(__ty_any);
     void __builtin_va_start(va_list, void *);
     void * __builtin_frame_address(unsigned int);
     void __builtin_va_end(va_list);
     void * __builtin_alloca(int);
     int __builtin_object_size(void *, int);
     void __builtin_va_copy(va_list, va_list);
     char * __builtin_strncat(char * const, char * const, int);
     double __builtin_copysign(double, double);
     void * __builtin_memcpy(void *, void * const, int);
     double __builtin_fabs(double);
     float __builtin_fabsf(float);
     long double __builtin_fabsl(long double);
     int __builtin_strspn(char * const, char * const);
     char * __builtin_strncpy(char * const, char * const, int);
     int __builtin_strcmp(char * const, char * const);
     int __builtin_strcspn(char * const, char * const);
     char * __builtin_strpbrk(char * const, char * const);
     void __builtin_prefetch(void * const);
     char * __builtin_strchr(char * const, int);
     static const char __PRETTY_FUNCTION__[];
     double __builtin_huge_val();
     int __builtin_clz(unsigned int);
     float __builtin_huge_valf();
     long double __builtin_huge_vall();
     long __builtin_expect(long, long);
     double __builtin_inf();
     float __builtin_inff();
     long double __builtin_infl();
     static const char __func__[];
     void __builtin_bzero(void *, int);
     int __builtin_va_arg_pack_len();
     0
     * diff against gcc -E:
     ex-nested_undef.c:7: (column 3) [WARNING]  >>> AST invariant violated
       unknown function: h

     --- /dev/fd/63	2016-01-09 05:33:00.477902543 +0300
     +++ /dev/fd/62	2016-01-09 05:33:00.477902543 +0300
     @@ -1,12 +1,79 @@
     -# 1 "ex-nested_undef.c"
     -# 1 "<command-line>"
     -# 1 "ex-nested_undef.c"
     -void f(int a) {
     +void f(int a)
     +{
        int b = 5;
     -  int g(int x) {
     +    int g(int x)
     +    {
          return b + x + a;
        }
        g(0);
        h(1);
        g(2);
      }
     +void * __builtin_extract_return_addr(void *);
     +static const char __FUNCTION__[];
     +int __builtin___snprintf_chk(char *,
     +                             int,
     +                             int,
     +                             int,
     +                             char * const, ...);
     +int __builtin___vsprintf_chk(char *,
     +                             int,
     +                             int,
     +                             char * const,
     +                             va_list);
     +void * __builtin___memcpy_chk(void *, void * const, int, int);
     +char * __builtin___stpcpy_chk(char * const, char * const, int);
     +char * __builtin___strcat_chk(char * const, char * const, int);
     +char * __builtin___strcpy_chk(char * const, char * const, int);
     +int __builtin___sprintf_chk(char *, int, int, char * const, ...);
     +void * __builtin_return_address(unsigned int);
     +int __builtin_va_arg_pack();
     +void * __builtin___memmove_chk(void *, void * const, int, int);
     +int __builtin___vsnprintf_chk(char *,
     +                              int,
     +                              int,
     +                              int,
     +                              char * const,
     +                              va_list);
     +char * __builtin___strncat_chk(char * const,
     +                               char * const,
     +                               int,
     +                               int);
     +char * __builtin___strncpy_chk(char * const,
     +                               char * const,
     +                               int,
     +                               int);
     +void * __builtin___mempcpy_chk(void *, void * const, int, int);
     +void * __builtin___memset_chk(void *, int, int, int);
     +int __builtin_constant_p(__ty_any);
     +void __builtin_va_start(va_list, void *);
     +void * __builtin_frame_address(unsigned int);
     +void __builtin_va_end(va_list);
     +void * __builtin_alloca(int);
     +int __builtin_object_size(void *, int);
     +void __builtin_va_copy(va_list, va_list);
     +char * __builtin_strncat(char * const, char * const, int);
     +double __builtin_copysign(double, double);
     +void * __builtin_memcpy(void *, void * const, int);
     +double __builtin_fabs(double);
     +float __builtin_fabsf(float);
     +long double __builtin_fabsl(long double);
     +int __builtin_strspn(char * const, char * const);
     +char * __builtin_strncpy(char * const, char * const, int);
     +int __builtin_strcmp(char * const, char * const);
     +int __builtin_strcspn(char * const, char * const);
     +char * __builtin_strpbrk(char * const, char * const);
     +void __builtin_prefetch(void * const);
     +char * __builtin_strchr(char * const, int);
     +static const char __PRETTY_FUNCTION__[];
     +double __builtin_huge_val();
     +int __builtin_clz(unsigned int);
     +float __builtin_huge_valf();
     +long double __builtin_huge_vall();
     +long __builtin_expect(long, long);
     +double __builtin_inf();
     +float __builtin_inff();
     +long double __builtin_infl();
     +static const char __func__[];
     +void __builtin_bzero(void *, int);
     +int __builtin_va_arg_pack_len();
     TEST OK on ex-nested_undef.c

Appendix. Как воспроизвести:
============================

(Последний раздел. Дальше можно не читать. Кстати, готовые варианты
исполняемого файла examples/Process кто-то может взять, чтобы не
воспроизводить, в vb2:/home/imz/public/cuglify-WIP/ .)


Инструменты и зависимости:
--------------------------

Побольше всего, чтобы поменьше пересобирать cabal-ом:

     # apt-get install ghc7.6.1-cabal-install ghc7.6.1 ghc7.6.1-darcs 
ghc7.6.1-language-c ghc7.6.1-happy ghc7.6.1-alex ghc7.6.1-haskell-src 
ghc7.6.1-mtl

Устанавливаем новую версию cabal-install с поддержкой sandboxes:
(TODO: упаковать в Sisyphus. См. также <http://altlinux.org/Haskell>)

     $ cabal update
     $ cabal install cabal-install
     $ ln -s ~/.cabal/bin/cabal ~/bin -v
     «/home/imz/bin/cabal» -> «/home/imz/.cabal/bin/cabal»
     $

После этого нужно, чтобы shell не вызывал старый cabal (можно
по-простому заново зайти).

Скачиваем несколько вариантов кода
----------------------------------

(Чтобы в итоге собрать разные варианты, делаем, например, так:)

     $ mkdir cuglify-WIP
     $ cd cuglify-WIP
     $ darcs clone 
http://hub.darcs.net/imz/language-c_process_analyze-silently
     $ darcs clone 
http://hub.darcs.net/imz/language-c_process_analyze-printAST
     $ darcs clone 
http://hub.darcs.net/imz/language-c_process_analyze-generate

Собираем библиотеку
-------------------

Несовместимых изменений в разных вариантах библиотеки нет, поэтому
можно скомпилировать и установить в sandbox одну на всех (самую полную):

     [imz@vb2 cuglify-WIP]$ cd language-c_process_analyze-generate/
     [imz@vb2 language-c_process_analyze-generate]$ darcs pull 
http://hub.darcs.net/imz/language-c_WIP -p tmp
     [imz@vb2 language-c_process_analyze-generate]$ cabal sandbox 
--sandbox=/storage/imz/CABAL-SANDBOX-cuglify init
     [imz@vb2 language-c_process_analyze-generate]$ cabal install
     [imz@vb2 language-c_process_analyze-generate]$ cd ..

### Замечание (о проверке компилятором полноты реализации):

При компиляции Export.hs из библиотеки предупреждения
компилятора рассказывают нам, экспорт каких конструкций ещё не
реализован. (Я пока не думал толком, можно ли это требование закодировать 
более
явно на Haskell, а не полагаться на определённый стиль написания
функций и предупреждения компилятора.) Вот например:

     [28 of 39] Compiling Language.C.Analysis.Export ( 
src/Language/C/Analysis/Export.hs, 
dist/dist-sandbox-36d68e1d/build/Language/C/Analysis/Export.o )

     src/Language/C/Analysis/Export.hs:236:39: Warning:
         Defined but not used: `g_tags'

     src/Language/C/Analysis/Export.hs:236:46: Warning:
         Defined but not used: `g_typedefs'

     src/Language/C/Analysis/Export.hs:241:1: Warning:
         Pattern match(es) are non-exhaustive
         In an equation for `exportIdentDecl':
             Patterns not matched: EnumeratorDef _

Компилируем все варианты нашего examples/Process
------------------------------------------------

### 1.

     [imz@vb2 cuglify-WIP]$ cd language-c_process_analyze-silently/
     [imz@vb2 language-c_process_analyze-silently]$ darcs pull 
http://hub.darcs.net/imz/language-c_WIP -p tmp
     [imz@vb2 language-c_process_analyze-silently]$ cabal sandbox 
--sandbox=/storage/imz/CABAL-SANDBOX-cuglify init
     [imz@vb2 language-c_process_analyze-silently]$ cabal exec -- make -C 
examples -j Process
     [imz@vb2 language-c_process_analyze-silently]$ cd ..

### 2.

     [imz@vb2 cuglify-WIP]$ cd language-c_process_analyze-printAST/
     [imz@vb2 language-c_process_analyze-printAST]$ darcs pull 
http://hub.darcs.net/imz/language-c_WIP -p tmp
     [imz@vb2 language-c_process_analyze-printAST]$ cabal sandbox 
--sandbox=/storage/imz/CABAL-SANDBOX-cuglify init
     [imz@vb2 language-c_process_analyze-printAST]$ cabal exec -- make -C 
examples -j Process
     make: Вход в каталог 
`/home/imz/public/cuglify-WIP/language-c_process_analyze-printAST/examples'
     ghc -Wall -package language-c-0.4.8 --make -O Process.hs
     [1 of 1] Compiling Main             ( Process.hs, Process.o )

     Process.hs:3:1: Warning:
         The import of `Data.List' is redundant
           except perhaps to import instances from `Data.List'
         To import instances alone, use: import Data.List()

     Process.hs:14:1: Warning:
         The import of `System.Console.GetOpt' is redundant
           except perhaps to import instances from `System.Console.GetOpt'
         To import instances alone, use: import System.Console.GetOpt()

     Process.hs:16:1: Warning:
         The import of `System.Exit' is redundant
           except perhaps to import instances from `System.Exit'
         To import instances alone, use: import System.Exit()
     Linking Process ...
     make: Выход из каталога 
`/home/imz/public/cuglify-WIP/language-c_process_analyze-printAST/examples'
     [imz@vb2 language-c_process_analyze-printAST]$ cd ..

### 3.

     [imz@vb2 cuglify-WIP]$ cd language-c_process_analyze-generate/
     [imz@vb2 language-c_process_analyze-generate]$ darcs pull 
http://hub.darcs.net/imz/language-c_WIP -p tmp
     [imz@vb2 language-c_process_analyze-generate]$ cabal sandbox 
--sandbox=/storage/imz/CABAL-SANDBOX-cuglify init
     [imz@vb2 language-c_process_analyze-generate]$ cabal exec -- make -C 
examples -j Process
     make: Вход в каталог 
`/home/imz/public/cuglify-WIP/language-c_process_analyze-generate/examples'
     ghc -Wall -package language-c-0.4.8 --make -O Process.hs
     [1 of 1] Compiling Main             ( Process.hs, Process.o )

     Process.hs:3:1: Warning:
         The import of `Data.List' is redundant
           except perhaps to import instances from `Data.List'
         To import instances alone, use: import Data.List()

     Process.hs:15:1: Warning:
         The import of `System.Console.GetOpt' is redundant
           except perhaps to import instances from `System.Console.GetOpt'
         To import instances alone, use: import System.Console.GetOpt()

     Process.hs:17:1: Warning:
         The import of `System.Exit' is redundant
           except perhaps to import instances from `System.Exit'
         To import instances alone, use: import System.Exit()
     Linking Process ...
     make: Выход из каталога 
`/home/imz/public/cuglify-WIP/language-c_process_analyze-generate/examples'
     [imz@vb2 language-c_process_analyze-generate]$ cd ..

Тестируем разные варианты
-------------------------

     [imz@vb2 cuglify-WIP]$ darcs clone http://hub.darcs.net/imz/cuglify 
--set-scripts-executable
     [imz@vb2 cuglify-WIP]$ cd cuglify/

### Смотрим прохождение тестов (коротко):

     [imz@vb2 cuglify]$ ./run-tests.sh 
../language-c_process_analyze-silently/examples/Process 2> /dev/null
     TEST OK on ex-nested.c
     TEST OK on ex-nested_typemismatch.c
     TEST OK on ex-nested_undef.c
     TEST OK on ex-nested-with-id-collisions.c
     [imz@vb2 cuglify]$ ./run-tests.sh 
../language-c_process_analyze-printAST/examples/Process 2> /dev/null
     TEST OK on ex-nested.c
     TEST OK on ex-nested_typemismatch.c
     TEST OK on ex-nested_undef.c
     TEST OK on ex-nested-with-id-collisions.c
     [imz@vb2 cuglify]$ ./run-tests.sh 
../language-c_process_analyze-generate/examples/Process 2> /dev/null
     TEST OK on ex-nested.c
     TEST OK on ex-nested_typemismatch.c
     TEST OK on ex-nested_undef.c
     TEST OK on ex-nested-with-id-collisions.c

### Пример того, что происходит (за кулисами):

     [imz@vb2 cuglify]$ ./run-tests.sh 
../language-c_process_analyze-printAST/examples/Process
     PROCESSING ex-nested.c...
     * with gcc -c:
     0
     * with ../language-c_process_analyze-printAST/examples/Process:
     void f(int a)
     {
         int b = 5;
         int g(int x)
         {
             return b + x + a;
         }
         g(0);
         g(1);
         g(2);
     }
     0
     * diff against gcc -E:
     --- /dev/fd/63	2016-01-09 05:23:34.041146328 +0300
     +++ /dev/fd/62	2016-01-09 05:23:34.042146253 +0300
     @@ -1,9 +1,8 @@
     -# 1 "ex-nested.c"
     -# 1 "<command-line>"
     -# 1 "ex-nested.c"
     -void f(int a) {
     +void f(int a)
     +{
        int b = 5;
     -  int g(int x) {
     +    int g(int x)
     +    {
          return b + x + a;
        }
        g(0);
     TEST OK on ex-nested.c
     PROCESSING ex-nested_typemismatch.c...
     * with gcc -c:
     ex-nested_typemismatch.c: In function ‘f’:
     ex-nested_typemismatch.c:7:4: error: called object ‘b’ is not a 
function
     1
     * with ../language-c_process_analyze-printAST/examples/Process:
     Process: user error (ex-nested_typemismatch.c:7: (column 3) [ERROR] 
>>> AST invariant violated
       attempt to call non-function of type int
     )
     1
     TEST OK on ex-nested_typemismatch.c
     PROCESSING ex-nested_undef.c...
     * with gcc -c:
     0
     * with ../language-c_process_analyze-printAST/examples/Process:
     ex-nested_undef.c:7: (column 3) [WARNING]  >>> AST invariant violated
       unknown function: h

     void f(int a)
     {
         int b = 5;
         int g(int x)
         {
             return b + x + a;
         }
         g(0);
         h(1);
         g(2);
     }
     0
     * diff against gcc -E:
     ex-nested_undef.c:7: (column 3) [WARNING]  >>> AST invariant violated
       unknown function: h

     --- /dev/fd/63	2016-01-09 05:23:34.198134568 +0300
     +++ /dev/fd/62	2016-01-09 05:23:34.199134493 +0300
     @@ -1,9 +1,8 @@
     -# 1 "ex-nested_undef.c"
     -# 1 "<command-line>"
     -# 1 "ex-nested_undef.c"
     -void f(int a) {
     +void f(int a)
     +{
        int b = 5;
     -  int g(int x) {
     +    int g(int x)
     +    {
          return b + x + a;
        }
        g(0);
     TEST OK on ex-nested_undef.c
     PROCESSING ex-nested-with-id-collisions.c...
     * with gcc -c:
     ex-nested-with-id-collisions.c: In function ‘g’:
     ex-nested-with-id-collisions.c:10:5: warning: return makes integer 
from pointer without a cast [enabled by default]
     0
     * with ../language-c_process_analyze-printAST/examples/Process:
     void f(int x);
     void g(int x);
     void h(int x);
     int b = 11;
     void f(int a)
     {
         int b = 5;
         int g(int x)
         {
             return f + x + a;
         }
         g(0);
         g(1);
         g(2);
     }
     void f(int y);
     void g(int y);
     void h(int y);
     0
     * diff against gcc -E:
     --- /dev/fd/63	2016-01-09 05:23:34.309126253 +0300
     +++ /dev/fd/62	2016-01-09 05:23:34.310126178 +0300
     @@ -1,23 +1,18 @@
     -# 1 "ex-nested-with-id-collisions.c"
     -# 1 "<command-line>"
     -# 1 "ex-nested-with-id-collisions.c"
      void f(int x);
      void g(int x);
      void h(int x);
     -
      int b = 11;
     -
     -void f(int a) {
     +void f(int a)
     +{
        int b = 5;
     -  int g(int x) {
     +    int g(int x)
     +    {
          return f + x + a;
        }
     -
        g(0);
        g(1);
        g(2);
      }
     -
      void f(int y);
      void g(int y);
      void h(int y);
     TEST OK on ex-nested-with-id-collisions.c
     [imz@vb2 cuglify]$

Best regards.
Ivan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [devel] re-writing GNU C extensions (part1)
  2016-01-11  8:48 [devel] re-writing GNU C extensions (part0) Ivan Zakharyaschev
@ 2016-01-11 18:21 ` Ivan Zakharyaschev
  2016-01-12 20:28   ` imz
                     ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Ivan Zakharyaschev @ 2016-01-11 18:21 UTC (permalink / raw)
  To: devel

[-- Attachment #1: Type: text/plain, Size: 6180 bytes --]

Вот продолжение -- промежуточный этап (пока не очень полезный)
создания переписывателя GNU C extensions.

На этом этапе он должен ставить вложенные функции на верхний уровень
(без какой-либо проверки и переписывания параметров и т.п.; но с точки
зрения внутреннего устройства это приближает к реализации цели).

Представлен в репозитории:

http://hub.darcs.net/imz/language-c_1_process_analyze-printAST

(1 -- по номеру сообщения; в предыдущем сообщении уже было в основном
описано, как производить его запуск и пр. это сообщение сохранено как
[ann1.md](http://hub.darcs.net/imz/cuglify/browse/ann1.md).)

Сборка:
=======

На этот раз изменённую библиотеку стоит поставить в свой отдельный
sandbox, собрать с ней examples/Process (в этом случае такой порядок
действий darcs проверен, а при другом можно наткнуться на
неприятности, к сожаленью):

     [imz@vb2 ~]$ cd public/cuglify-WIP/
     [imz@vb2 cuglify-WIP]$ darcs clone language-c_process_analyze-printAST 
language-c_1_process_analyze-printAST
     [imz@vb2 cuglify-WIP]$ cd language-c_1_process_analyze-printAST
     [imz@vb2 language-c_1_process_analyze-printAST]$ darcs pull -a 
http://hub.darcs.net/imz/language-c_1_process_analyze-printAST
     [imz@vb2 language-c_1_process_analyze-printAST]$ cabal sandbox init
     [imz@vb2 language-c_1_process_analyze-printAST]$ cabal install
     [imz@vb2 language-c_1_process_analyze-printAST]$ cabal exec -- make -C 
examples Process

Тестирование:
=============

     [imz@vb2 language-c_1_process_analyze-printAST]$ cd ../cuglify/
     [imz@vb2 cuglify]$ ./run-tests.sh 
../language-c_1_process_analyze-printAST/examples/Process
     PROCESSING ex-nested.c...
     * with gcc -c:
     0
     * with ../language-c_1_process_analyze-printAST/examples/Process:
     int g(int x)
     {
         return b + x + a;
     }
     void f(int a)
     {
         int b = 5;
         g(0);
         g(1);
         g(2);
     }
     0
     * diff against gcc -E:
     --- /dev/fd/63	2016-01-11 21:09:08.920889328 +0300
     +++ /dev/fd/62	2016-01-11 21:09:08.920889328 +0300
     @@ -1,11 +1,10 @@
     -# 1 "ex-nested.c"
     -# 1 "<command-line>"
     -# 1 "ex-nested.c"
     -void f(int a) {
     -  int b = 5;
     -  int g(int x) {
     +int g(int x)
     +{
          return b + x + a;
     -  }
     +}
     +void f(int a)
     +{
     +    int b = 5;
        g(0);
        g(1);
        g(2);
     TEST OK on ex-nested.c
     PROCESSING ex-nested_typemismatch.c...
     * with gcc -c:
     ex-nested_typemismatch.c: In function ‘f’:
     ex-nested_typemismatch.c:7:4: error: called object ‘b’ is not a 
function
     1
     * with ../language-c_1_process_analyze-printAST/examples/Process:
     Process: user error (ex-nested_typemismatch.c:7: (column 3) [ERROR] 
>>> AST invariant violated
       attempt to call non-function of type int
     )
     1
     TEST OK on ex-nested_typemismatch.c
     PROCESSING ex-nested_undef.c...
     * with gcc -c:
     0
     * with ../language-c_1_process_analyze-printAST/examples/Process:
     ex-nested_undef.c:7: (column 3) [WARNING]  >>> AST invariant violated
       unknown function: h

     int g(int x)
     {
         return b + x + a;
     }
     void f(int a)
     {
         int b = 5;
         g(0);
         h(1);
         g(2);
     }
     0
     * diff against gcc -E:
     ex-nested_undef.c:7: (column 3) [WARNING]  >>> AST invariant violated
       unknown function: h

     --- /dev/fd/63	2016-01-11 21:09:09.069878241 +0300
     +++ /dev/fd/62	2016-01-11 21:09:09.070878166 +0300
     @@ -1,11 +1,10 @@
     -# 1 "ex-nested_undef.c"
     -# 1 "<command-line>"
     -# 1 "ex-nested_undef.c"
     -void f(int a) {
     -  int b = 5;
     -  int g(int x) {
     +int g(int x)
     +{
          return b + x + a;
     -  }
     +}
     +void f(int a)
     +{
     +    int b = 5;
        g(0);
        h(1);
        g(2);
     TEST OK on ex-nested_undef.c
     PROCESSING ex-nested-with-id-collisions.c...
     * with gcc -c:
     ex-nested-with-id-collisions.c: In function ‘g’:
     ex-nested-with-id-collisions.c:10:5: warning: return makes integer 
from pointer without a cast [enabled by default]
     0
     * with ../language-c_1_process_analyze-printAST/examples/Process:
     void f(int x);
     void g(int x);
     void h(int x);
     int b = 11;
     int g(int x)
     {
         return f + x + a;
     }
     void f(int a)
     {
         int b = 5;
         g(0);
         g(1);
         g(2);
     }
     void f(int y);
     void g(int y);
     void h(int y);
     0
     * diff against gcc -E:
     --- /dev/fd/63	2016-01-11 21:09:09.178870130 +0300
     +++ /dev/fd/62	2016-01-11 21:09:09.178870130 +0300
     @@ -1,23 +1,18 @@
     -# 1 "ex-nested-with-id-collisions.c"
     -# 1 "<command-line>"
     -# 1 "ex-nested-with-id-collisions.c"
      void f(int x);
      void g(int x);
      void h(int x);
     -
      int b = 11;
     -
     -void f(int a) {
     -  int b = 5;
     -  int g(int x) {
     +int g(int x)
     +{
          return f + x + a;
     -  }
     -
     +}
     +void f(int a)
     +{
     +    int b = 5;
        g(0);
        g(1);
        g(2);
      }
     -
      void f(int y);
      void g(int y);
      void h(int y);
     TEST OK on ex-nested-with-id-collisions.c
     [imz@vb2 cuglify]$

Вопросы:
========

Остаются вопросы помимо реализации задуманного преобразования, как я
писал, про встройку программы с таким интерфейсом в gcc, clang и т.п.,
обнаружение ошибок.

Best regards,
Ivan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [devel] re-writing GNU C extensions (part1)
  2016-01-11 18:21 ` [devel] re-writing GNU C extensions (part1) Ivan Zakharyaschev
@ 2016-01-12 20:28   ` imz
  2016-01-20 10:28     ` imz
  2016-01-27 17:59   ` [devel] re-writing GNU C; part1.3.1: how to apply Ivan Zakharyaschev
  2016-02-09 18:29   ` [devel] re-writing GNU C; part1.4: .i bug fixed Ivan Zakharyaschev
  2 siblings, 1 reply; 8+ messages in thread
From: imz @ 2016-01-12 20:28 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 1813 bytes --]

Добрый вечер!

On Mon, 11 Jan 2016, Ivan Zakharyaschev wrote:

> Вот продолжение -- промежуточный этап (пока не очень полезный)
> создания переписывателя GNU C extensions.
>
> На этом этапе он должен ставить вложенные функции на верхний уровень
> (без какой-либо проверки и переписывания параметров и т.п.; но с точки
> зрения внутреннего устройства это приближает к реализации цели).

> (1 -- по номеру сообщения; в предыдущем сообщении уже было в основном
> описано, как производить его запуск и пр. это сообщение сохранено как
> [ann1.md](http://hub.darcs.net/imz/cuglify/browse/ann1.md).)

На одном из следующих этапов ожидается (ещё до окончательной
готовности), что преобразователь будет уметь правильно работать с
вложенными функциями, которые только читают переменные из local scope
(но не пишут в них). (На этапе 1, описанном в предыдущем сообщении --
только с теми, которые не пишут и не читают. + нет конфликтов имён)

В поиске простых вложенных функций посмотрим на патч (предложил mike@)
http://git.altlinux.org/gears/r/rpm.git?p=rpm.git;a=commitdiff;h=2cee1a78a713a9e9cb2dfc66a5310d497e72dd33
(committer Gleb Fotengauer-Malinovskiy <glebfm@altlinux.org>
Thu, 21 May 2015 15:08:21 +0000 (18:08 +0300)).

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

Кое-что простое тут находится.

Функции, затронутые в этом патче:

put_digit: на первый взгляд read-only
(читает указатель, пишет уже туда;
могло бы годиться для следующего промежуточного этапа), но на самом
деле меняет и указатель и потом это изменённое значение используется,
так что: r/w

put6bits, put4bits: то же (r/w)

log2i: none (ни читает, ни пишет; т.е. годится для теста сейчас)

cmp: none
hash: none
uniqv: none

-- эти тоже.


Best regards,
Ivan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [devel] re-writing GNU C extensions (part1)
  2016-01-12 20:28   ` imz
@ 2016-01-20 10:28     ` imz
  0 siblings, 0 replies; 8+ messages in thread
From: imz @ 2016-01-20 10:28 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 2234 bytes --]

Добрый день!

On Tue, 12 Jan 2016, imz@altlinux.org wrote:

>>  Вот продолжение -- промежуточный этап (пока не очень полезный)
>>  создания переписывателя GNU C extensions.
>>
>>  На этом этапе он должен ставить вложенные функции на верхний уровень
>>  (без какой-либо проверки и переписывания параметров и т.п.; но с точки

mike@ столкнулся с вложенными функциями в gpm -- 
http://lists.linux.it/pipermail/gpm/2011-April/001122.html .
Это как раз хороший пример на read-only вложенные функции.

Как я писал, по сложности переписывания их можно классифицировать на: 
1. pure (придумалось короткое понятное слово для их обозначения),
2. read-only
3. и read-write.

(Это же соответствует порядку предполагаемой реализации такой возможности 
в cuglify/Process.)

Пока примера реальных исходников, с которыми можно было бы расправиться на 
втором этапе, не было; например, в rpm наблюдалась смесь pure и read-write 
вложенных функций -- как я разбирал:

> На одном из следующих этапов ожидается (ещё до окончательной
> готовности), что преобразователь будет уметь правильно работать с
> вложенными функциями, которые только читают переменные из local scope
> (но не пишут в них). (На этапе 1, описанном в предыдущем сообщении --
> только с теми, которые не пишут и не читают. + нет конфликтов имён)
>
> В поиске простых вложенных функций посмотрим на патч (предложил mike@)
> http://git.altlinux.org/gears/r/rpm.git?p=rpm.git;a=commitdiff;h=2cee1a78a713a9e9cb2dfc66a5310d497e72dd33
> (committer Gleb Fotengauer-Malinovskiy <glebfm@altlinux.org>
> Thu, 21 May 2015 15:08:21 +0000 (18:08 +0300)).
>
> Ищем примеры таких вложенных функций в реальном коде, которые 
> преобразователь, умеющий ещё не всё, смог бы уже правильно преобразовать.
>
> Кое-что простое тут находится.
>
> Функции, затронутые в этом патче:
>
> put_digit: на первый взгляд read-only
> (читает указатель, пишет уже туда;
> могло бы годиться для следующего промежуточного этапа), но на самом
> деле меняет и указатель и потом это изменённое значение используется,
> так что: r/w
>
> put6bits, put4bits: то же (r/w)
>
> log2i: none (ни читает, ни пишет; т.е. годится для теста сейчас)
>
> cmp: none
> hash: none
> uniqv: none
>
> -- эти тоже.
>
>
> Best regards,
> Ivan
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [devel] re-writing GNU C; part1.3.1: how to apply
  2016-01-11 18:21 ` [devel] re-writing GNU C extensions (part1) Ivan Zakharyaschev
  2016-01-12 20:28   ` imz
@ 2016-01-27 17:59   ` Ivan Zakharyaschev
  2016-01-27 18:04     ` [devel] re-writing GNU C; part1.3.2: how to apply (WIP) Ivan Zakharyaschev
  2016-02-09 18:29   ` [devel] re-writing GNU C; part1.4: .i bug fixed Ivan Zakharyaschev
  2 siblings, 1 reply; 8+ messages in thread
From: Ivan Zakharyaschev @ 2016-01-27 17:59 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 5797 bytes --]

Добрый день!

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

(FOO/Linux -- какая-нибудь платформа, где есть свой foo-cc, который в
чём-то похож на GCC, а в чём-то нет; и foo-cc патчить мы не можем.)

Есть несколько вариантов, как сделать первый шаг такого применения.

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

Какую пользу ожидать от применения
==================================

Для делания порта на FOO/Linux пользу от применения cuglify/Process
можно получить уже сейчас, пока доделываю преобразователь C-кода.
Описываемые варианты применения сработают (но с частью вложенных
функций оно не справится -- разбирал примеры в devel: из патча
[на rpm][] и [на gpm][]).

Так незаметно для собирающего под FOO/Linux будет убрана часть проблем
с компиляцией (уже с помощью Process промежуточной готовности) и отлажена
схема применения cuglify/Process в этой работе. (Ещё вот что: возникла
необходимость переписывать опции компилятора, чтобы сохранять
задуманную мейнтейнером пакета семантику набора опций как у GCC --
опять же для гладкости сборки; чтобы такую гладкость побыстрее
достичь, я занимаюсь сейчас упомянутым третьим вариантом применения
Process на FOO/Linux, похожим по идее на distcc/ccache.)

При применении всегда можно брать (у меня или по инструкции)
свежесобранный Process под x86 с последним набором работающих фич.

[на rpm]: https://lists.altlinux.org/pipermail/devel/2016-January/200702.html
   (копия: [ann1_1.md](http://hub.darcs.net/imz/cuglify/browse/ann1_1.md))

[на gpm]: https://lists.altlinux.org/pipermail/devel/2016-January/200718.html
   (копия: [ann1_2.md](http://hub.darcs.net/imz/cuglify/browse/ann1_2.md))

Первый вариант:
===============

1. (придумать, как) соединить мой Process (который должен вести себя как
    cpp) так-как-он-есть-сейчас с gcc/clang/foo-cc (понять, куда воткнуть во
    внутренности вместо внутреннего cpp)
2. под x86 скомпилировать Process с помощью ghc с результатом на C (опции
    вроде via-C и т.п. -- надо мне повнимательнее посмотреть)
3. этот "Process.c" из 2 скомпилировать под FOO/Linux с помощью foo-cc
    (запуская там)
4. тестировать компиляцию исходников избранных пакетов (например,
    избранного коммита исходников rpm или gpm) связкой Process+foo-cc,
    придуманной в 1.


Второй вариант:
===============

* натравить Process на исходники избранного пакета, результат
   сохранить вместо оригинальных .c и собрать это foo-cc. (Не попробуешь
   -- сходу не скажешь, какие особенности вылезут из-за того, что
   результат Process будет не очень похож на оригинальные .c, потому
   что это вывод cpp.)

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

конечно, cpp втащит includes, и пока что Process не обучен прятать
includes обратно; includes в любом случае разумно брать с FOO/Linux --
при этом это могут быть(?) не только стандартные места вроде
/usr/include/ и явно указанные места (которое мы можем довольно легко
подменить), но и внутренние штуки foo-cc. Так что x86-cpp не будет
знать, куда лезть (если специально не разобраться в этом)...

...ну хорошо, на вход Process можно (по крайней мере должно работать)
подавать .i, уже сделанные cpp (местным, на машине с FOO/Linux). Потом
Process их немного пожуёт, а полученные .i подложим вместо
.c-исходников на машину с FOO/Linux. (Это мне нравится больше, чем
обработка на x86-машине исходного .c, потому что тут всё чисто сразу.
Тут была мысль для удобства доделать Process на предмет вызова
cpp/foo-cc по ssh сразу, вместо локального cpp/gcc, чтобы облегчить
ход действий, но в итоге пошёл немного другим путём, "третьим".)

Развитие первого варианта и трудности реализации
================================================

Второй вариант хорош тем, что можно попробовать сразу. А первый
вариант потенциально доделывается до:

5. попросить нечто (то ли rpm, то ли hasher, то ли такой специальный
пакет сделать) подменять перед началом сборки /usr/bin/cc и всё такое
на связку Process+cc, придуманную в 1.
6. Собирать Process полностью на FOO/Linux, без x86 (собрав ghc с помощью
foo-cc и запуская его в режиме via-C) -- в этом нет первоочередной
практической необходимости (и можно будет заняться в последнюю
очередь, когда все фичи будут работать и пр).

В реализации первого варианта было бы эффективно покопаться мне -- с
ghc (via-C; хотя можно, наверное, обойти удалённым запуском Process),
а второй вариант доступен всякому.

автоматическая оценка исходных пакетов
--------------------------------------

Также первый вариант приближает к возможности запустить автоматическую
компиляцию списка избранных пакетов и потом посмотреть ошибки. Если
какой-то пакет не собирался раньше и собрался теперь, он будет интересным
успешным примером. (Можно их и автоматически классифицировать вызовом
Process -- имеется в виду, на то, с чем будет справляться Process на
разных этапах готовности, т.е. на pure, reader-only, r/w вложенные
функции, как в
[ann1_2.md](http://hub.darcs.net/imz/cuglify/browse/ann1_2.md).) Это
избавит от чтения вручную исходников всех проблемных пакетов в поисках
случаев, подходящих для тестирования и демонстрации работы Process в
той или иной степени готовности.

-- 
Best regards,
Ivan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [devel] re-writing GNU C; part1.3.2: how to apply (WIP)
  2016-01-27 17:59   ` [devel] re-writing GNU C; part1.3.1: how to apply Ivan Zakharyaschev
@ 2016-01-27 18:04     ` Ivan Zakharyaschev
  0 siblings, 0 replies; 8+ messages in thread
From: Ivan Zakharyaschev @ 2016-01-27 18:04 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 8073 bytes --]

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


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [devel] re-writing GNU C; part1.4: .i bug fixed
  2016-01-11 18:21 ` [devel] re-writing GNU C extensions (part1) Ivan Zakharyaschev
  2016-01-12 20:28   ` imz
  2016-01-27 17:59   ` [devel] re-writing GNU C; part1.3.1: how to apply Ivan Zakharyaschev
@ 2016-02-09 18:29   ` Ivan Zakharyaschev
  2016-02-10 10:30     ` Ivan Zakharyaschev
  2 siblings, 1 reply; 8+ messages in thread
From: Ivan Zakharyaschev @ 2016-02-09 18:29 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 5281 bytes --]

Пока подготавливал всё для описанной системы (использования 
cuglify/Process на
"инородной" платформе), был поправлен упомянутый minor bug:

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

Текущее состояние в <http://hub.darcs.net/imz/language-c_WIP>.

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

> patch 1d40ac438dfa206c7a23e647b1eeb3eb910bc055
> Author: Ivan Zakharyaschev <imz@altlinux.org>
> Date:   Tue Feb  9 16:05:53 MSK 2016
>   * examples/Process: now cuglify environment variable controls the 
debug mode:
>
>
>   data DebugMode = SilentlyAnalyse
>                  | PrintAST
>                  | Uglify
>                  | Generate
>
>   No need to maintain several variants of the binary.

Обновлённые инструкции по воспроизведению:
==========================================

(Последний раздел. Дальше можно не читать. Кстати, готовые варианты
исполняемого файла examples/Process кто-то может взять, чтобы не
воспроизводить, в vb2:/home/imz/public/cuglify-WIP/language-c_WIP/ .)

Инструменты и зависимости:
--------------------------

(Напоминание для случая, когда они не установлены)

> Побольше всего, чтобы поменьше пересобирать cabal-ом:
>
>     # apt-get install ghc7.6.1-cabal-install ghc7.6.1 ghc7.6.1-darcs 
ghc7.6.1-language-c ghc7.6.1-happy ghc7.6.1-alex ghc7.6.1-haskell-src 
ghc7.6.1-mtl
>
> Устанавливаем новую версию cabal-install с поддержкой sandboxes:
> (TODO: упаковать в Sisyphus. См. также <http://altlinux.org/Haskell>)
>
>     $ cabal update
>     $ cabal install cabal-install
>     $ ln -s ~/.cabal/bin/cabal ~/bin -v
>     «/home/imz/bin/cabal» -> «/home/imz/.cabal/bin/cabal»
>     $
>
> После этого нужно, чтобы shell не вызывал старый cabal (можно
> по-простому заново зайти).

Скачиваем код с хаками
----------------------

     $ mkdir cuglify-WIP
     $ cd cuglify-WIP
     $ darcs clone http://hub.darcs.net/imz/language-c_WIP
     $ git clone https://github.com/imz/directory

Собираем библиотеку
-------------------

Удалим старый sandbox (если остался):

     $ rm -rf /storage/imz/CABAL-SANDBOX-cuglify

Зависимости с хаками:

     $ pushd directory/
     $ cabal sandbox --sandbox=/storage/imz/CABAL-SANDBOX-cuglify init

Понял, что надо предварительно поставить свежий filepath (чтобы избежать 
несовместимых
требований библиотек directory и language-c в дальнейшем):

     $ cabal install filepath

Возвращаемся к сборке библиотеки directory:

     $ autoreconf -i
     $ cabal install
     $ popd

Наконец, наша библиотека:

     $ pushd language-c_WIP/
     $ cabal sandbox --sandbox=/storage/imz/CABAL-SANDBOX-cuglify init
     $ cabal install
     $ popd

Компилируем examples/Process
----------------------------

     $ pushd language-c_WIP/
     $ cabal exec -- make -C examples Process
     $ popd

Тестируем разные варианты
-------------------------

     $ darcs clone http://hub.darcs.net/imz/cuglify 
--set-scripts-executable
     $ pushd cuglify

     [imz@vb2 cuglify]$ cuglify=PrintAST ./run-tests.sh 
../language-c_WIP/examples/Process 2> /dev/null
     TEST OK on *.i
     TEST OK on ex-nested.c
     TEST OK on ex-nested-in-block.c
     TEST OK on ex-nested-pure.c
     TEST OK on ex-nested_typemismatch.c
     TEST OK on ex-nested_undef.c
     TEST OK on ex-nested-with-id-collisions.c
     TEST OK on ex-unnested-with-unbound-after-nested.c
     TEST OK on ex-unnested-with-unbound.c
     [imz@vb2 cuglify]$ ./run-tests.sh ../language-c_WIP/examples/Process 
2> /dev/null
     TEST OK on *.i
     TEST OK on ex-nested.c
     TEST OK on ex-nested-in-block.c
     TEST OK on ex-nested-pure.c
     TEST OK on ex-nested_typemismatch.c
     TEST OK on ex-nested_undef.c
     TEST OK on ex-nested-with-id-collisions.c
     TEST OK on ex-unnested-with-unbound-after-nested.c
     TEST OK on ex-unnested-with-unbound.c
     [imz@vb2 cuglify]$

(Это сообщение сохранено как
[ann1_4.md](http://hub.darcs.net/imz/cuglify/browse/ann1_4.md).)

-- 
Best regards,
Ivan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [devel] re-writing GNU C; part1.4: .i bug fixed
  2016-02-09 18:29   ` [devel] re-writing GNU C; part1.4: .i bug fixed Ivan Zakharyaschev
@ 2016-02-10 10:30     ` Ivan Zakharyaschev
  0 siblings, 0 replies; 8+ messages in thread
From: Ivan Zakharyaschev @ 2016-02-10 10:30 UTC (permalink / raw)
  To: ALT Linux Team development discussions

[-- Attachment #1: Type: text/plain, Size: 1459 bytes --]

On Tue, 9 Feb 2016, Ivan Zakharyaschev wrote:

> Скачиваем код с хаками
> ----------------------
>
>     $ mkdir cuglify-WIP
>     $ cd cuglify-WIP
>     $ darcs clone http://hub.darcs.net/imz/language-c_WIP
>     $ git clone https://github.com/imz/directory

Подумал, что нехорошо, что в сообщениях нет ссылок на конкретную
ревизию исходников.

Внутри следующего репозитория помимо прочего теперь сохранён контекст
репозитория language-c (аналог тега) на момент написания этого
сообщения, чтобы потом было нетрудно убедиться, что мы воспроизводим
действия на тех же исходниках. Поэтому клонируем его сначала и
используем .context-файлы из него (а в git-репозитории я поставил
указанный ниже тег):

     $ darcs clone http://hub.darcs.net/imz/cuglify 
--set-scripts-executable

(или, конечно, если он уже склонирован, `darcs pull` внутри), а потом:

     $ darcs clone --context=cuglify/ann1_4-language-c.context 
http://hub.darcs.net/imz/language-c_WIP
     $ git clone --branch=cuglify/ann1_4 https://github.com/imz/directory


-- 
Best regards,
Ivan


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-02-10 10:30 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-11  8:48 [devel] re-writing GNU C extensions (part0) Ivan Zakharyaschev
2016-01-11 18:21 ` [devel] re-writing GNU C extensions (part1) Ivan Zakharyaschev
2016-01-12 20:28   ` imz
2016-01-20 10:28     ` imz
2016-01-27 17:59   ` [devel] re-writing GNU C; part1.3.1: how to apply Ivan Zakharyaschev
2016-01-27 18:04     ` [devel] re-writing GNU C; part1.3.2: how to apply (WIP) Ivan Zakharyaschev
2016-02-09 18:29   ` [devel] re-writing GNU C; part1.4: .i bug fixed Ivan Zakharyaschev
2016-02-10 10:30     ` Ivan Zakharyaschev

ALT Linux Team development discussions

This inbox may be cloned and mirrored by anyone:

	git clone --mirror http://lore.altlinux.org/devel/0 devel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 devel devel/ http://lore.altlinux.org/devel \
		devel@altlinux.org devel@altlinux.ru devel@lists.altlinux.org devel@lists.altlinux.ru devel@linux.iplabs.ru mandrake-russian@linuxteam.iplabs.ru sisyphus@linuxteam.iplabs.ru
	public-inbox-index devel

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://lore.altlinux.org/org.altlinux.lists.devel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git