Ответ 1
Чтобы решить эту проблему, мне пришлось:
- повторно связать библиотеку Haskell с объектными файлами C bindings и
- используйте тег
ghc-options
в файле Cabal, чтобы убедиться, что они связаны в правильном порядке.
Все изменения находятся в тестовом проекте (http://github.com/deech/CPlusPlusBindings).
Ниже описывается процесс создания нового архива, который включает как объекты C, так и Haskell, и это не просто. Сложность возникает, потому что нет способа (как и для Cabal 1.16.0.2) подключиться к компоновщике процесса сборки.
Установка флагов в файле Cabal является тривиальной, поэтому она не описывается здесь.
Перезагрузка Библиотека Haskell
-
Задайте тип сборки
custom
, добавив:build-type: custom
в файл камеры.
-
Вставьте настраиваемую логику сборки, заменив метод
main
вSetup.hs
на:main = defaultMainWithHooks simpleUserHooks { buildHook = myBuildHook, ... }
Это говорит о том, что вместо процесса сборки по умолчанию, определенного в
simpleUserHooks
, он должен использовать функциюmyBuildHook
, которая определена ниже. Аналогичным образом процесс очистки отменяется с помощью настраиваемой функцииmyCleanHook
. -
Определите крюк сборки. Этот крюк сборки будет запускать
make
в командной строке для сборки частей С++ и C, а затем использовать объектные файлы C при создании связывания привязок Haskell.Начнем с
myBuildHook
:myBuildHook pkg_descr local_bld_info user_hooks bld_flags = do
сначала выполнив
make
без аргументов:rawSystemExit normal "make" []
Затем добавьте местоположения файлов заголовков и библиотек и самой библиотеки в запись PackageDescription и обновите LocalBuildInfo с новым описанием пакета:
let new_pkg_descr = (addLib . addLibDirs . addIncludeDirs $ pkg_descr) new_local_bld_info = local_bld_info {localPkgDescr = new_pkg_descr}
Перед тем, как
buildHook
выпустилconfigureHook
, сохранил порядок компиляции в ключеcompBuildOrder
(порядок сборки компонентов) записиLocalBuildInfo
. Нам нужно изолировать здание библиотеки, чтобы мы отделили здание библиотеки и исполняемые части здания процесса сборки.Порядок сборки - это просто список, и мы знаем, что компонент сборки является библиотекой, если он просто простой конструктор типа
CLibName
, поэтому мы выделяем эти элементы из списка и обновляем записьLocalBuildInfo
только ими:let (libs, nonlibs) = partition (\c -> case c of CLibName -> True _ -> False) (compBuildOrder new_local_bld_info) lib_lbi = new_local_bld_info {compBuildOrder = libs}
-
Теперь мы запускаем сборку по умолчанию с обновленными записями:
buildHook simpleUserHooks new_pkg_descr lib_lbi user_hooks bld_flags
-
После создания архива была создана, но мы должны заново создать его для включения объектов C, сгенерированных командой
make
на шаге 1. Таким образом, мы получаем некоторые настройки и список C путь к объектным файлам:let verbosity = fromFlag (buildVerbosity bld_flags) info verbosity "Relinking archive ..." let pref = buildDir local_bld_info verbosity = fromFlag (buildVerbosity bld_flags) cobjs <- getLibDirContents >>= return . map (\f -> combine clibdir f) . filter (\f -> takeExtension f == ".o")
И затем передайте его на
withComponentsLBI
, который действует на каждый компонент сборки. В этом случае, поскольку мы имеем дело только с частью библиотеки, есть только один компонент.Cabal
предоставляетgetHaskellObjects
для получения списка объектных файлов Haskell иcreateArLibArchive
для создания архива, чтобы мы могли повторно запустить компоновщик:withComponentsLBI pkg_descr local_bld_info $ \comp clbi -> case comp of (CLib lib) -> do hobjs <- getHaskellObjects lib local_bld_info pref objExtension True let staticObjectFiles = hobjs ++ cobjs (arProg, _) <- requireProgram verbosity arProgram (withPrograms local_bld_info) let pkgid = packageId pkg_descr vanillaLibFilePath = pref </> mkLibName pkgid Ar.createArLibArchive verbosity arProg vanillaLibFilePath staticObjectFiles _ -> return ()
-
По умолчанию
buildHook
, который был запущен на шаге 4, был создан файл базы данных временного пакета с именем "package.conf.inplace", который содержит описание библиотеки, которая была построена, чтобы исполняемый файл мог ссылаться на него без библиотеку, которая должна быть установлена в файл системного пакета по умолчанию. К сожалению, каждыйbuildHook
запускает пробелы, поэтому нам нужно удержать временную копию:let distPref = fromFlag (buildDistPref bld_flags) dbFile = distPref </> "package.conf.inplace" (tempFilePath, tempFileHandle) <- openTempFile distPref "package.conf" hClose tempFileHandle copyFile dbFile tempFilePath
-
Теперь мы сохраняем путь к этой копии в структуру
LocalBuildInfo
вместе с исполняемыми частями процесса сборки, которые были отфильтрованы на шаге 3.let exe_lbi = new_local_bld_info { withPackageDB = withPackageDB new_local_bld_info ++ [SpecificPackageDB tempFilePath], compBuildOrder = nonlibs }
и сохраните путь еще раз в
extraTmpFiles
частиPackageDescription
, чтобы его можно было удалить с помощью очистителя по умолчанию.exe_pkg_descr = new_pkg_descr {extraTmpFiles = extraTmpFiles new_pkg_descr ++ [tempFilePath]}
-
Теперь мы снова запускаем по умолчанию
buildHook
с обновленными записями (которые теперь знают о новом архиве) только для исполняемых компонентов:buildHook simpleUserHooks exe_pkg_descr exe_lbi user_hooks bld_flags