У меня очень специфическая ситуация с зависимостями, которую я хотел бы упаковать в один пакет Stack / Cabal: мне нужно собрать и запустить мою программу, чтобы получить входные данные для генератора кода, который производит выходные данные, которые необходимо связать в ... моей программе.
ОК, так что более конкретно, вот шаги вручную:
stack build
, чтобы установить все зависимости и построить все без Verilator -использование исполняемых файлов. stack exec phase1
для запуска первой фазы, которая генерирует, среди прочего, файл Verilog и файл Cla sh .manifest
. - У меня есть пользовательский источник генератор, который использует файл
.manifest
из шага 2 и генерирует код C ++ и Makefile
, который можно использовать для управления Verilator. - Запустите
Makefile
, созданный на шаге 3: - Он запускает Verilator на источниках Verilog, начиная с шага 2, который производит больше исходного кода на C ++ и новый
Makefile
- Затем он запускает только что созданный второй
Makefile
, который создает двоичную библиотеку
- * 10 28 * строит второй исполняемый файл. Этот исполняемый файл содержит
.hsc
файлов, которые обрабатывают заголовки, созданные на шаге 2, и он ссылается на библиотеки C ++, созданные на шаге 4 / 2.
Я хотел бы автоматизировать это, чтобы я мог просто запустить stack build
и все это произошло бы за кадром. С чего мне начать?!
Чтобы проиллюстрировать весь процесс, вот отдельная модель:
package.yaml
name: clashilator-model
version: 0
category: acme
dependencies:
- base
- directory
source-dirs:
- src
flags:
phase2:
manual: True
default: False
executables:
phase1:
main: phase1.hs
phase2:
main: phase2.hs
when:
- condition: flag(phase2)
then:
source-dirs:
- src
- _build/generated
extra-libraries: stdc++
extra-lib-dirs: _build/compiled
ghc-options:
-O3 -fPIC -pgml g++
-optl-Wl,--allow-multiple-definition
-optl-Wl,--whole-archive -optl-Wl,-Bstatic
-optl-Wl,-L_build/compiled -optl-Wl,-lImpl
-optl-Wl,-Bdynamic -optl-Wl,--no-whole-archive
build-tools: hsc2hs
include-dirs: _build/generated
else:
buildable: false
src/phase1.hs
import System.Directory
main :: IO ()
main = do
createDirectoryIfMissing True "_build/generated"
writeFile "_build/generated/Interface.hsc" hsc
writeFile "_build/generated/Impl.h" h
writeFile "_build/generated/Impl.c" c
writeFile "_build/Makefile" makeFile
makeFile = unlines
[ "compiled/libImpl.a: compiled/Impl.o"
, "\trm -f $@"
, "\tmkdir -p compiled"
, "\tar rcsT $@ $^"
, ""
, "compiled/Impl.o: generated/Impl.c generated/Impl.h"
, "\tmkdir -p compiled"
, "\t$(COMPILE.c) $(OUTPUT_OPTION) $<"
]
hsc = unlines
[ "module Interface where"
, "import Foreign.Storable"
, "import Foreign.Ptr"
, ""
, "data FOO = FOO Int deriving Show"
, ""
, "#include \"Impl.h\""
, ""
, "foreign import ccall unsafe \"bar\" bar :: Ptr FOO -> IO ()"
, "instance Storable FOO where"
, " alignment _ = #alignment FOO"
, " sizeOf _ = #size FOO"
, " peek ptr = FOO <$> (#peek FOO, fd1) ptr"
, " poke ptr (FOO x) = (#poke FOO, fd1) ptr x"
]
h = unlines
[ "#pragma once"
, ""
, "typedef struct{ int fd1; } FOO;"
]
c = unlines
[ "#include \"Impl.h\""
, "#include <stdio.h>"
, ""
, "void bar(FOO* arg)"
, "{ printf(\"bar: %d\\n\", arg->fd1); }"
]
src/phase2.hs
import Interface
import Foreign.Marshal.Utils
main :: IO ()
main = with (FOO 42) bar
Скрипт для запуска всего процесса вручную
stack build
stack run phase1
make -C _build
stack build --flag clashilator-model:phase2
stack exec phase2