Skip to content

Commit

Permalink
Support for Static Foreign Libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
alt-romes committed Jan 20, 2024
1 parent 419bf51 commit 3185dd9
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 39 deletions.
44 changes: 22 additions & 22 deletions Cabal/src/Distribution/Simple/Configure.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2622,18 +2622,18 @@ checkForeignLibSupported comp platform flib = go (compilerFlavor comp)
]

goGhcPlatform :: Platform -> Maybe String
goGhcPlatform (Platform _ OSX) = goGhcOsx (foreignLibType flib)
goGhcPlatform (Platform _ Linux) = goGhcLinux (foreignLibType flib)
goGhcPlatform (Platform I386 Windows) = goGhcWindows (foreignLibType flib)
goGhcPlatform (Platform X86_64 Windows) = goGhcWindows (foreignLibType flib)
goGhcPlatform (Platform _ OSX) = goGhcOsx
goGhcPlatform (Platform _ Linux) = goGhcLinux
goGhcPlatform (Platform I386 Windows) = goGhcWindows
goGhcPlatform (Platform X86_64 Windows) = goGhcWindows
goGhcPlatform _ =
unsupported
[ "Building foreign libraries is currently only supported on Mac OS, "
, "Linux and Windows"
]

goGhcOsx :: ForeignLibType -> Maybe String
goGhcOsx ForeignLibNativeShared
goGhcOsx :: Maybe String
goGhcOsx
| not (null (foreignLibModDefFile flib)) =
unsupported
[ "Module definition file not supported on OSX"
Expand All @@ -2642,15 +2642,15 @@ checkForeignLibSupported comp platform flib = go (compilerFlavor comp)
unsupported
[ "Foreign library versioning not currently supported on OSX"
]
| ForeignLibTypeUnknown <- foreignLibType flib =
unsupported
[ "We don't support building unknown-type foreign libraries on OSX"
]
| otherwise =
Nothing
goGhcOsx _ =
unsupported
[ "We can currently only build shared foreign libraries on OSX"
]

goGhcLinux :: ForeignLibType -> Maybe String
goGhcLinux ForeignLibNativeShared
goGhcLinux :: Maybe String
goGhcLinux
| not (null (foreignLibModDefFile flib)) =
unsupported
[ "Module definition file not supported on Linux"
Expand All @@ -2660,15 +2660,15 @@ checkForeignLibSupported comp platform flib = go (compilerFlavor comp)
unsupported
[ "You must not specify both lib-version-info and lib-version-linux"
]
| ForeignLibTypeUnknown <- foreignLibType flib =
unsupported
[ "We don't support building unknown-type foreign libraries on Linux"
]
| otherwise =
Nothing
goGhcLinux _ =
unsupported
[ "We can currently only build shared foreign libraries on Linux"
]

goGhcWindows :: ForeignLibType -> Maybe String
goGhcWindows ForeignLibNativeShared
goGhcWindows :: Maybe String
goGhcWindows
| not standalone =
unsupported
[ "We can currently only build standalone libraries on Windows. Use\n"
Expand All @@ -2681,12 +2681,12 @@ checkForeignLibSupported comp platform flib = go (compilerFlavor comp)
[ "Foreign library versioning not currently supported on Windows.\n"
, "You can specify module definition files in the mod-def-file field."
]
| ForeignLibTypeUnknown <- foreignLibType flib =
unsupported
[ "We don't support building unknown-type foreign libraries on Windows"
]
| otherwise =
Nothing
goGhcWindows _ =
unsupported
[ "We can currently only build shared foreign libraries on Windows"
]

standalone :: Bool
standalone = ForeignLibStandalone `elem` foreignLibOptions flib
Expand Down
2 changes: 1 addition & 1 deletion Cabal/src/Distribution/Simple/GHC/Build.hs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ build numJobs pkg_descr = do
let
wantVanilla = if isLib then withVanillaLib lbi else False
-- ROMES:TODO: Arguably, wantStatic should be "withFullyStaticExe lbi" for
-- executables, but it was not before the refactor.
-- executables, but it was not before the refactor, also, flibs should consider if is fully static flib.
wantStatic = if isLib then withStaticLib lbi else not (wantDynamic || wantProf)
wantDynamic = case component of
CLib{} -> withSharedLib lbi
Expand Down
39 changes: 23 additions & 16 deletions Cabal/src/Distribution/Simple/GHC/Build/Link.hs
Original file line number Diff line number Diff line change
Expand Up @@ -451,23 +451,21 @@ linkFLib flib bi lbi linkerOpts (wantedWays, buildOpts) targetDir runGhcProg = d
else statRtsVanillaLib (rtsStaticInfo rtsInfo)
]

linkOpts :: BuildWay -> GhcOptions
linkOpts way = case foreignLibType flib of
linkOpts = case foreignLibType flib of
ForeignLibNativeShared ->
(buildOpts way)
`mappend` linkerOpts
`mappend` rtsLinkOpts
(buildOpts DynWay)
{ ghcOptShared = toFlag True
, ghcOptFPic = toFlag True
}
ForeignLibNativeStatic ->
(buildOpts StaticWay)
`mappend` mempty
{ ghcOptLinkNoHsMain = toFlag True
, ghcOptShared = toFlag True
, ghcOptFPic = toFlag True
, ghcOptLinkModDefFiles = toNubListR $ foreignLibModDefFile flib
{ ghcOptStaticLib = toFlag True
-- ROMES:TODO: Currently ignoring linkerOpts already sets this, but
-- only for fully static exes... should converge to considering flibs
-- when defining fully static exe probably?
, ghcOptLinkOptions = ["-static"]
}
ForeignLibNativeStatic ->
-- this should be caught by buildFLib
-- (and if we do implement this, we probably don't even want to call
-- ghc here, but rather Ar.createArLibArchive or something)
cabalBug "static libraries not yet implemented"
ForeignLibTypeUnknown ->
cabalBug "unknown foreign lib type"
-- We build under a (potentially) different filename to set a
Expand All @@ -476,8 +474,17 @@ linkFLib flib bi lbi linkerOpts (wantedWays, buildOpts) targetDir runGhcProg = d
let buildName = flibBuildName lbi flib
-- There should not be more than one wanted way when building an flib
assert (Set.size wantedWays == 1) $
forM_ wantedWays $ \way -> do
runGhcProg (linkOpts way){ghcOptOutputFile = toFlag (targetDir </> buildName)}
-- ROMES:TODO: Using the "wantedWay" is a bit senseless here, we likely
-- just want to use the Way of each ForeignLib type.
forM_ wantedWays $ \_way -> do
runGhcProg $
(linkOpts
`mappend` linkerOpts
`mappend` rtsLinkOpts
`mappend` mempty
{ ghcOptLinkNoHsMain = toFlag True
, ghcOptLinkModDefFiles = toNubListR $ foreignLibModDefFile flib
}){ ghcOptOutputFile = toFlag (targetDir </> buildName) }
renameFile (targetDir </> buildName) (targetDir </> flibTargetName lbi flib)

-- | Calculate the RPATHs for the component we are building.
Expand Down
5 changes: 5 additions & 0 deletions cabal-testsuite/PackageTests/ForeignLibStatic/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Revision history for tmp-gvHDXD5qma

## 0.1.0.0 -- YYYY-mm-dd

* First version. Released on an unsuspecting world.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <stdlib.h>
#include "HsFFI.h"

HsBool myForeignLibInit(void){
int argc = 2;
char *argv[] = { "+RTS", "-A32m", NULL };
char **pargv = argv;

// Initialize Haskell runtime
hs_init(&argc, &pargv);

// do any other initialization here and
// return false if there was a problem
return HS_BOOL_TRUE;
}

void myForeignLibExit(void){
hs_exit();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module MyForeignLib where

import MyLib

sayHi :: IO ()
sayHi = someFunc

Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
cabal-version: 3.0
-- The cabal-version field refers to the version of the .cabal specification,
-- and can be different from the cabal-install (the tool) version and the
-- Cabal (the library) version you are using. As such, the Cabal (the library)
-- version used must be equal or greater than the version stated in this field.
-- Starting from the specification version 2.2, the cabal-version field must be
-- the first thing in the cabal file.

-- Initial package description 'tmp-gvHDXD5qma' generated by
-- 'cabal init'. For further documentation, see:
-- http://haskell.org/cabal/users-guide/
--
-- The name of the package.
name: foreignlibstatic

-- The package version.
-- See the Haskell package versioning policy (PVP) for standards
-- guiding when and how versions should be incremented.
-- https://pvp.haskell.org
-- PVP summary: +-+------- breaking API changes
-- | | +----- non-breaking API additions
-- | | | +--- code changes with no API change
version: 0.1.0.0

-- A short (one-line) description of the package.
-- synopsis:

-- A longer description of the package.
-- description:

-- The license under which the package is released.
license: NONE

-- The package author(s).
-- author:

-- An email address to which users can send suggestions, bug reports, and patches.
-- maintainer:

-- A copyright notice.
-- copyright:
build-type: Simple

-- Extra doc files to be distributed with the package, such as a CHANGELOG or a README.
extra-doc-files: CHANGELOG.md

-- Extra source files to be distributed with the package, such as examples, or a tutorial module.
-- extra-source-files:

common warnings
ghc-options: -Wall

library
-- Import common warning flags.
import: warnings

-- Modules exported by the library.
exposed-modules: MyLib

-- Modules included in this library but not exported.
-- other-modules:

-- LANGUAGE extensions used by modules in this package.
-- other-extensions:

-- Other library packages from which modules are imported.
build-depends: base ^>=4.19.0.0

-- Directories containing source files.
hs-source-dirs: src

-- Base language which the package is written in.
default-language: Haskell2010

foreign-library myflib
type: native-static

other-modules: MyForeignLib
build-depends: base, foreignlibstatic
hs-source-dirs: flib
c-sources: csrc/MyForeignLibWrapper.c
default-language: Haskell2010
4 changes: 4 additions & 0 deletions cabal-testsuite/PackageTests/ForeignLibStatic/src/MyLib.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module MyLib (someFunc) where

someFunc :: IO ()
someFunc = putStrLn "someFunc"

0 comments on commit 3185dd9

Please sign in to comment.