From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on sa.local.altlinux.org X-Spam-Level: X-Spam-Status: No, score=-1.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DNS_FROM_AHBL_RHSBL,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_PASS,T_FREEMAIL_FORGED_FROMDOMAIN, T_HEADER_FROM_DIFFERENT_DOMAINS autolearn=no autolearn_force=no version=3.4.0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:date:from:to:subject:message-id:user-agent:mime-version :content-type; bh=3QKQ1/I1ZET/tlYLox8CuTTo9LLaQ0qn3fi6OZ1bM0U=; b=B9s00BhIvwa2/rL74/GAt7k49pnGaKKcETbaobstgtZ5j+MIgtfYNx3Q0d3vil6Jik MVKOTGEaW6kwM5R7S6Td76yNxj6AGheTl+zLpeTgTv25pbM3hNQToUw7SUhgmzdI29nH UUT/rGqor5/ZahSJa4bviiukRzuUJUwF1ro10HFqessvCfhLzbDHnwf5AeaMxXnL7njs Jke5lwurLke37cNe8ymwgoJjLUKpSarp8LBitcUZ7flrucBwPfH7lZiqwpeg1FvVJXCc IiPlHsyN+ywU03+2T2xcS13JiwUjA9vSaTFzUTE8FZOzON7xbvyg0qt7dCnzN0vSROrU wsQg== X-Received: by 10.112.55.39 with SMTP id o7mr28093813lbp.49.1452502134085; Mon, 11 Jan 2016 00:48:54 -0800 (PST) Sender: Ivan Zakharyaschev Date: Mon, 11 Jan 2016 11:48:36 +0300 (MSK) From: Ivan Zakharyaschev X-X-Sender: imz@ovicaa.localdomain To: devel@lists.altlinux.org Message-ID: User-Agent: Alpine 2.20 (LFD 67 2015-01-07) MIME-Version: 1.0 Content-Type: multipart/mixed; BOUNDARY="8323328-272465603-1452502122=:4319" Subject: [devel] re-writing GNU C extensions (part0) X-BeenThere: devel@lists.altlinux.org X-Mailman-Version: 2.1.12 Precedence: list Reply-To: ALT Linux Team development discussions List-Id: ALT Linux Team development discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jan 2016 08:49:00 -0000 Archived-At: List-Archive: List-Post: This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. --8323328-272465603-1452502122=:4319 Content-Type: text/plain; format=flowed; charset=UTF-8 Content-Transfer-Encoding: 8BIT Пишу преобразователь C-кода, который бы переписывал некоторые GNU extensions. Это делается для того, чтобы такие программы можно было компилировать компилятором, который не поддерживает GNU extensions. Например, clang-ом. (Реализуется на библиотеке .) Сейчас хочу предварительно, пока преобразователь ещё не полностью готов, показать заготовку, т.е. интерфейс этой программы. В следующих сообщениях будут описываться работающие преобразования. (Это сообщение сохранено как [ann0.md](http://hub.darcs.net/imz/cuglify/browse/ann0.md).) Вопросы: ======== Может быть, кто-нибудь может быстро дать совет, который пригодится в этой работе: как встроить её в пересборку Sisyphus? (На данном этапе это ценно только для тестирования возможностей language-c на реальном коде из Sisyphus -- не ломается ли на чём-то, т.е. не очень интересно для широкого круга разработчиков. До проведения такой проверки у меня пока руки не дошли. Думаю, это реализовать будет несложно и проверить пересборку по крайней мере избранных пакетов.) Это поспособствует потенциальной переносимости Sisyphus на платформы без gcc. Ещё интересуют любые замеченные ошибки в работе, если вдруг кто-то будет пробовать. Описание ======== Разные варианты программы-заготовки живут в файле examples/Process.hs в разных ветках изменённой language-c: 1. , 2. , 3. . [Вот](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 "" -# 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 "" -# 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 "" -# 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. См. также ) $ 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 "" -# 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 "" -# 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 "" -# 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 --8323328-272465603-1452502122=:4319--