Skip to content

Add support for js-sources #8636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cabal/src/Distribution/Simple/Build.hs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ buildComponent verbosity numJobs pkg_descr lbi suffixes
$ flip addExtraCmmSources extras
$ flip addExtraCxxSources extras
$ flip addExtraCSources extras
$ flip addExtraJsSources extras
$ libbi
}

Expand Down Expand Up @@ -454,6 +455,13 @@ addExtraAsmSources :: BuildInfo -> [FilePath] -> BuildInfo
addExtraAsmSources bi extras = bi { asmSources = new }
where new = ordNub (extras ++ asmSources bi)

-- | Add extra JS sources generated by preprocessing to build
-- information.
addExtraJsSources :: BuildInfo -> [FilePath] -> BuildInfo
addExtraJsSources bi extras = bi { jsSources = new }
where new = ordNub (extras ++ jsSources bi)


-- | Add extra HS modules generated by preprocessing to build
-- information.
addExtraOtherModules :: BuildInfo -> [ModuleName.ModuleName] -> BuildInfo
Expand Down
25 changes: 25 additions & 0 deletions Cabal/src/Distribution/Simple/GHC.hs
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,11 @@ buildOrReplLib mReplFlags verbosity numJobs pkg_descr lbi lib clbi = do
, toNubListR (cxxSources libBi)
, toNubListR (cmmSources libBi)
, toNubListR (asmSources libBi)
, toNubListR (jsSources libBi)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is adding JS to cLikeSources. Is "C-like" a misnomer or was the original intention to exclude JS? Change of plans? I don't see any "non-C-like sources" list in the codebase that we could add JS source to, instead, so this must be the right place.

Perhaps the C-like vs non-C-like distinction is a left over from some special cases for GHCJS? Is JS C-like enough when considered by GHC JS backend, but not C-like when fed to GHCJS?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes for the JS backend we've reworked the way JS sources are treated. They are now C-like because we've added support for a "compilation" from .js to .o files (basically a file renaming with a header added). It makes them less special for tools like Hadrian and cabal.

(in the GHCJS code path (Distribution.Simple.GHCJS) these files were directly passed as link options)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this deserves a NOTE JS Sources are C-Like or similar.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Profpatsch: GHC note or cabal note? Or one of those and hyperlink from the other place?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a comment explaining that JS sources are C-like in the JS backend.

-- JS files are C-like with GHC's JS backend: they are
-- "compiled" into `.o` files (renamed with a header).
-- This is a difference from GHCJS, for which we only
-- pass the JS files at link time.
]
cLikeObjs = map (`replaceExtension` objExtension) cLikeSources
baseOpts = componentGhcOptions verbosity lbi libBi clbi libTargetDir
Expand Down Expand Up @@ -724,6 +729,25 @@ buildOrReplLib mReplFlags verbosity numJobs pkg_descr lbi lib clbi = do
unless forRepl $ whenProfLib (runGhcProgIfNeeded profCcOpts)
| filename <- cSources libBi]

-- build any JS sources
unless (not has_code || null (jsSources libBi)) $ do
info verbosity "Building JS Sources..."
sequence_
[ do let vanillaJsOpts = Internal.componentJsGhcOptions verbosity implInfo
lbi libBi clbi relLibTargetDir filename
profJsOpts = vanillaJsOpts `mappend` mempty {
ghcOptProfilingMode = toFlag True,
ghcOptObjSuffix = toFlag "p_o"
}
odir = fromFlag (ghcOptObjDir vanillaJsOpts)
createDirectoryIfMissingVerbose verbosity True odir
let runGhcProgIfNeeded jsOpts = do
needsRecomp <- checkNeedsRecompilation filename jsOpts
when needsRecomp $ runGhcProg jsOpts
runGhcProgIfNeeded vanillaJsOpts
unless forRepl $ whenProfLib (runGhcProgIfNeeded profJsOpts)
| filename <- jsSources libBi]

-- build any ASM sources
unless (not has_code || null (asmSources libBi)) $ do
info verbosity "Building Assembler Sources..."
Expand Down Expand Up @@ -2063,6 +2087,7 @@ installLib verbosity lbi targetDir dynlibTargetDir _builtDir pkg lib clbi = do
&& null (cxxSources (libBuildInfo lib))
&& null (cmmSources (libBuildInfo lib))
&& null (asmSources (libBuildInfo lib))
&& null (jsSources (libBuildInfo lib))
has_code = not (componentIsIndefinite clbi)
whenHasCode = when has_code
whenVanilla = when (hasLib && withVanillaLib lbi)
Expand Down
27 changes: 27 additions & 0 deletions Cabal/src/Distribution/Simple/GHC/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module Distribution.Simple.GHC.Internal (
componentCmmGhcOptions,
componentCxxGhcOptions,
componentAsmGhcOptions,
componentJsGhcOptions,
componentGhcOptions,
mkGHCiLibName,
mkGHCiProfLibName,
Expand Down Expand Up @@ -382,6 +383,32 @@ componentAsmGhcOptions verbosity _implInfo lbi bi clbi odir filename =
ghcOptObjDir = toFlag odir
}

componentJsGhcOptions :: Verbosity -> GhcImplInfo -> LocalBuildInfo
-> BuildInfo -> ComponentLocalBuildInfo
-> FilePath -> FilePath
-> GhcOptions
componentJsGhcOptions verbosity _implInfo lbi bi clbi odir filename =
mempty {
-- Respect -v0, but don't crank up verbosity on GHC if
-- Cabal verbosity is requested. For that, use --ghc-option=-v instead!
ghcOptVerbosity = toFlag (min verbosity normal),
ghcOptMode = toFlag GhcModeCompile,
ghcOptInputFiles = toNubListR [filename],

ghcOptCppIncludePath = toNubListR $ [autogenComponentModulesDir lbi clbi
,autogenPackageModulesDir lbi
,odir]
-- includes relative to the package
++ includeDirs bi
-- potential includes generated by `configure'
-- in the build directory
++ [buildDir lbi </> dir | dir <- includeDirs bi],
ghcOptHideAllPackages= toFlag True,
ghcOptPackageDBs = withPackageDB lbi,
ghcOptPackages = toNubListR $ mkGhcOptPackages clbi,
ghcOptObjDir = toFlag odir
}


componentGhcOptions :: Verbosity -> GhcImplInfo -> LocalBuildInfo
-> BuildInfo -> ComponentLocalBuildInfo -> FilePath
Expand Down
3 changes: 1 addition & 2 deletions Cabal/src/Distribution/Simple/Register.hs
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,7 @@ generalInstalledPackageInfo adjustRelIncDirs pkg abi_hash lib lbi clbi installDi
|| not (null (asmSources bi))
|| not (null (cmmSources bi))
|| not (null (cxxSources bi))
|| (not (null (jsSources bi)) &&
compilerFlavor comp == GHCJS))
|| not (null (jsSources bi)))
&& not (componentIsIndefinite clbi)
libdirsStatic
| hasLibrary = libdir installDirs : extraLibDirsStaticOrFallback
Expand Down
1 change: 1 addition & 0 deletions cabal-testsuite/PackageTests/JS/JsSources/cabal.project
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: .
8 changes: 8 additions & 0 deletions cabal-testsuite/PackageTests/JS/JsSources/cabal.test.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Test.Cabal.Prelude

main = setupAndCabalTest $ do
skipUnlessGhcVersion ">= 9.6"
skipUnlessJavaScript

res <- cabal' "v2-run" ["demo"]
assertOutputContains "Hello JS!" res
6 changes: 6 additions & 0 deletions cabal-testsuite/PackageTests/JS/JsSources/demo/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Main where

import Lib

main :: IO ()
main = foo
3 changes: 3 additions & 0 deletions cabal-testsuite/PackageTests/JS/JsSources/jsbits/lib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function foo() {
console.log("Hello JS!");
}
17 changes: 17 additions & 0 deletions cabal-testsuite/PackageTests/JS/JsSources/jssources.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cabal-version: 3.0
name: jssources
version: 0
build-type: Simple

library
default-language: Haskell2010
js-sources: jsbits/lib.js
hs-source-dirs: src
exposed-modules: Lib
build-depends: base

executable demo
default-language: Haskell2010
main-is: Main.hs
hs-source-dirs: demo
build-depends: base, jssources
3 changes: 3 additions & 0 deletions cabal-testsuite/PackageTests/JS/JsSources/src/Lib.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module Lib where

foreign import javascript foo :: IO ()
15 changes: 13 additions & 2 deletions cabal-testsuite/src/Test/Cabal/Prelude.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import Distribution.Simple.PackageDescription (readGenericPackageDescription)
import Distribution.Simple.Program.Types
import Distribution.Simple.Program.Db
import Distribution.Simple.Program
import Distribution.System (OS(Windows,Linux,OSX), buildOS)
import Distribution.System (OS(Windows,Linux,OSX), Arch(JavaScript), buildOS, buildArch)
import Distribution.Simple.Utils
( withFileContents, withTempDirectory, tryFindPackageDesc )
import Distribution.Simple.Configure
Expand Down Expand Up @@ -889,7 +889,13 @@ skipUnlessGhcVersion :: String -> TestM ()
skipUnlessGhcVersion range = skipUnless ("needs ghc " ++ range) =<< isGhcVersion range

skipIfGhcVersion :: String -> TestM ()
skipIfGhcVersion range = skipUnless ("incompatible with ghc " ++ range) =<< isGhcVersion range
skipIfGhcVersion range = skipIf ("incompatible with ghc " ++ range) =<< isGhcVersion range

skipUnlessJavaScript :: TestM ()
skipUnlessJavaScript = skipUnless "needs the JavaScript backend" =<< isJavaScript

skipIfJavaScript :: TestM ()
skipIfJavaScript = skipIf "incompatible with the JavaScript backend" =<< isJavaScript

isWindows :: TestM Bool
isWindows = return (buildOS == Windows)
Expand All @@ -900,6 +906,11 @@ isOSX = return (buildOS == OSX)
isLinux :: TestM Bool
isLinux = return (buildOS == Linux)

isJavaScript :: TestM Bool
isJavaScript = return (buildArch == JavaScript)
-- should probably be `hostArch` but Cabal doesn't distinguish build platform
-- and host platform

skipIfWindows :: TestM ()
skipIfWindows = skipIf "Windows" =<< isWindows

Expand Down
8 changes: 8 additions & 0 deletions changelog.d/pr-8636
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
synopsis: Support `js-sources` with GHC, not only with GHCJS
prs: #8636
description: {

- Take into account js-sources when building library components with GHC
- Missing support for js-sources in executable components is tracked in #8639

}