Статическое связывание библиотеки C с библиотекой Haskell

У меня есть проект на Haskell, который направлен на создание некоторых привязок C ++. Я написал оболочки C и собрал их в автономную статически связанную библиотеку.

Я хотел бы написать привязки Haskell для статической связи с оболочками C, чтобы мне не приходилось раздельно распространять оболочки C, но я не могу заставить ее работать, и был бы признателен за некоторую помощь.

Я указываю библиотеку C как дополнительную библиотеку, но мой cabal build Шаг не добавляет его в команду компиляции.

Я создал небольшой проект, чтобы проиллюстрировать это (http://github.com/deech/CPlusPlusBindings).

Содержит небольшой класс C ++ (https://github.com/deech/CPlusPlusBindings/tree/master/cpp-src), обертка C (https://github.com/deech/CPlusPlusBindings/tree/master/c-src), рабочая программа тестирования С (https://github.com/deech/CPlusPlusBindings/tree/master/c-test) и файл на Haskell (https://github.com/deech/CPlusPlusBindings/blob/master/src/BindingTest.chs).

Библиотека C добавлена ​​в Setup.hs, а не в файле Cabal, потому что у меня есть настоящий проект, который собирает библиотеку C с помощью «make» через Cabal непосредственно перед этапом сборки. Я проверил, что на этапе сборки extraLibs часть BuildInfo содержит имя библиотеки и extraLibDirs содержит правильный каталог.

Выход моего cabal build является:

creating dist/setup
./dist/setup/setup build --verbose=2
creating dist/build
creating dist/build/autogen
Building CPlusPlusBinding-0.1.0.0...
Preprocessing library CPlusPlusBinding-0.1.0.0...
Building library...
creating dist/build
/usr/local/bin/ghc --make -fbuilding-cabal-package -O -odir dist/build -hidir dist/build -stubdir dist/build -i -idist/build -isrc -idist/build/autogen -Idist/build/autogen -Idist/build -I/home/deech/Old/Haskell/CPlusPlusBinding/c-src -I/home/deech/Old/Haskell/CPlusPlusBinding/cpp-includes -optP-include -optPdist/build/autogen/cabal_macros.h -package-name CPlusPlusBinding-0.1.0.0 -hide-all-packages -package-db dist/package.conf.inplace -package-id base-4.6.0.1-8aa5d403c45ea59dcd2c39f123e27d57 -XHaskell98 -XForeignFunctionInterface BindingTest
Linking...
/usr/bin/ar -r dist/build/libHSCPlusPlusBinding-0.1.0.0.a dist/build/BindingTest.o
/usr/bin/ar: creating dist/build/libHSCPlusPlusBinding-0.1.0.0.a
/usr/bin/ld -x --hash-size=31 --reduce-memory-overheads -r -o dist/build/HSCPlusPlusBinding-0.1.0.0.o dist/build/BindingTest.o
In-place registering CPlusPlusBinding-0.1.0.0...
/usr/local/bin/ghc-pkg update - --global --user --package-db=dist/package.conf.inplace

К сожалению, ни компиляция, ни этап компоновки не используют библиотеку C. Других предупреждений или ошибок нет.

14

Решение

Для решения этой проблемы мне пришлось:

  1. повторно связать библиотеку Haskell с объектными файлами привязок C и
  2. использовать ghc-options тег в моем интрига файл, чтобы убедиться, что они связаны в правильном порядке.

Все изменения в тестовом проекте (http://github.com/deech/CPlusPlusBindings).

Ниже подробно описан процесс создания нового архива, включающего объекты C и Haskell, и он не прост. Сложность возникает из-за того, что нет способа (начиная с Cabal 1.16.0.2) подключиться к компоновщику в процессе сборки.

Установка флагов в файле Cabal тривиальна, поэтому здесь она не описана.

Пересмотр библиотеки Haskell

  1. Установите тип сборки custom добавляя:

    build-type: custom
    

    в файл клики.

  2. Вставьте настроенную логику сборки, заменив main метод в Setup.hs с:

    main = defaultMainWithHooks simpleUserHooks {
    buildHook = myBuildHook,
    ...
    }
    

    Это говорит процессу сборки, что вместо использования процесса сборки по умолчанию, определенного в simpleUserHooks следует использовать myBuildHook функция, которая определена ниже. Аналогичным образом процесс очистки отменяется пользовательской функцией. myCleanHook,

  3. Определите сборочный хук. Этот хук сборки будет работать make в командной строке для создания частей C ++ и 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}
    
  4. Теперь мы запускаем хук сборки по умолчанию с обновленными записями:

    buildHook simpleUserHooks new_pkg_descr lib_lbi user_hooks bld_flags
    
  5. Как только это сделано, создание архива было создано, но мы должны заново создать его, чтобы включить объекты 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 ()
    
  6. По умолчанию 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
    
  7. Теперь мы сохраняем путь к этой копии в 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]}
    
  8. Теперь мы наконец запустили дефолт buildHook снова с обновленными записями (которые теперь знают о новом архиве) только для исполняемых компонентов:

    buildHook simpleUserHooks exe_pkg_descr exe_lbi user_hooks bld_flags
    
11

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]