12.2. Создание Haskell интерфейсов для кода C: hsc2hs
Команда hsc2hs может использоваться для автоматизации некоторых частей процесса написания Haskell привязок к коду C. Она читает почти-Haskell исходный код со встроенными специальными конструкциями и выводит реальный Haskell файл с обработанными конструкциями, основанными на информации, взятой из заголовков C. Дополнительные конструкции обрабатывают доступ к данным C из Haskell.
Она также может вывести файл C, который содержит дополнительные функции C для линковки в программу, вместе с заголовком C, который включается в код C, в который будет компилироваться Haskell модуль (при компиляции через C) и в файл C. Эти два файла создаются при использовании конструкции #def (см. ниже).
На самом деле hsc2hs не выводит Haskell файл напрямую. Она создаёт программу на C, которая включает заголовки, автоматически компилируется и выполняется. Эта программа выводит Haskell код.
В дальнейшем, «Haskell файл» — это основной вывод (обычно файл .hs), «скомпилированный Haskell файл» — это Haskell файл после того, как ghc скомпилировал его в C (т.е. файл .hc), «программа на C» — это программа, которая выводит Haskell файл, «файл C» — это необязательно сгенерированный файл C, а «заголовок C» — это его заголовочный файл.
12.2.1. Синтаксис командной строки
hsc2hs принимает файлы ввода в качестве аргументов и флаги, которые изменяют его поведение:
-
-o FILE, --output=FILE
-
Имя Haskell файла.
-
-t FILE, --template=FILE
-
Шаблонный файл (см. ниже).
-
-c PROG, --cc=PROG
-
Компилятор C для использования (по умолчанию: gcc)
-
-l PROG, --ld=PROG
-
Используемый линкер (по умолчанию: gcc).
-
-C FLAG, --cflag=FLAG
-
Дополнительный флаг для передачи компилятору C.
-
-I DIR
-
Передаётся компилятору C.
-
-L FLAG, --lflag=FLAG
-
Дополнительный флаг для передачи линковщику.
-
-i FILE, --include=FILE
-
Как будто соответствующая директива #include была размещена в исходном коде.
-
-D NAME[=VALUE], --define=NAME[=VALUE]
-
Как будто соответствующая директива #define была размещена в исходном коде.
-
--no-compile
-
Остановка после записи промежуточной программы на C в диск. Имя файла для промежуточной программы на C — имя входного файла с .hsc заменённым на _hsc_make.c.
-
-k, --keep-files
-
Продолжить в обычном режиме, но не удалять промежуточные файлы.
-
-x, --cross-compile
-
Активировать режим кросс-компиляции (см. Кросс-компиляция).
-
--cross-safe
-
Ограничить директивы .hsc теми, которые поддерживаются режимом --cross-compile (см. Кросс-компиляция). Это должно быть полезно, если ваши файлы .hsc должны быть безопасно кросс-скомпилированы, и вы хотите предотвратить проникновение в них неподдерживаемых в кросс-компиляции конструкций.
-
-?, --help
-
Вывести сводку доступных флагов и успешно завершить работу.
-
-V, --version
-
Вывести информацию о версии и успешно завершить работу.
Входной файл должен оканчиваться на .hsc (он должен содержать только обычный Haskell исходный код; грамотный Haskell не поддерживается в настоящее время). Выходные файлы по умолчанию получают имена с .hsc суффиксом, заменённым:
.hs
| Haskell файл |
_hsc.h
| Заголовок C |
_hsc.c
| Файл C |
Программа на C компилируется с помощью компилятора Haskell. Это предоставляет путь включения HsFFI.h , который автоматически включается в программу на C.
12.2.3. Пользовательские конструкции
#const, #type, #peek, #poke и #ptr не жёстко запрограммированы в hsc2hs, но определены в шаблоне C, который включён в программу на C: template-hsc.h. Также могут быть использованы пользовательские конструкции и шаблоны. Любая #-конструкция с неизвестным ключом должна обрабатываться шаблоном C.
Шаблон C должен определить макрос или функцию с именем, начинающимся с префикса hsc_, который обрабатывает конструкцию путём вывода расширения в stdout. См. template-hsc.h для примеров.
Эти макросы также могут быть определены непосредственно в исходном коде. Они полезны для создания макроса типа #let, расширение которого использует другие #let макросы. Простое #let добавляет префикс hsc_ к имени макроса и заключает определение в вызов printf.