2023-11-19 13:33:48 +00:00
{ lib
, stdenv
# infrastructure
, populateHawkSourceInfo
, replaceDotWithUnderscore
, buildDotnetModule
, fetchpatch
, fetchzip
, hardLinkJoin
, launchScriptsFor
, makeDesktopItem
, releaseTagSourceInfos
, runCommand
, symlinkJoin
, writeShellScriptBin
# makedeps
, git
# rundeps
2024-03-07 03:11:13 +00:00
, libgdiplus
2023-12-02 18:40:22 +00:00
, libGL
2023-11-19 13:33:48 +00:00
, lua
, mono
2023-11-21 04:15:37 +00:00
, monoBasic
2023-11-19 13:33:48 +00:00
, openal
, SDL2
, udev
, zstd
# other parameters
, buildConfig
, doCheck
, emuhawkBuildFlavour
, extraDefines
, extraDotnetBuildFlags
} : let
/* * t o o v e r r i d e j u s t o n e , y o u ' l l p r o b a b l y w a n t t o m a n u a l l y i m p o r t p a c k a g e s - m a n a g e d . n i x , a n d c o m b i n e t h a t w i t h t h e o u t p u t o f t h i s */
buildExtraManagedDepsFor = hawkSourceInfo : let
pm = import ./packages-managed.nix {
inherit lib
buildDotnetModule runCommand
hawkSourceInfo ;
} ;
in symlinkJoin {
name = " b i z h a w k - m a n a g e d - d e p s " ;
paths = builtins . map ( s : pm . ${ s } ) ( lib . sort lib . lessThan hawkSourceInfo . neededExtraManagedDeps ) ;
} ;
/* *
* NOTE : This impl . is unfinished , only useful for checking that overriding is possible .
* For actually overriding ` extraUnmanagedDeps ` , roll your own ` symlinkJoin ` impl . or something .
*
* TODO replace this with something more like ` buildExtraManagedDepsFor ` ; for existing Nix exprs see https://gitlab.com/YoshiRulz/yoshis-hawk-thoughts/-/issues/10
* /
buildUnmanagedDepsFor = hawkSourceInfo : stdenv . mkDerivation {
2023-11-21 04:15:37 +00:00
inherit ( hawkSourceInfo ) src version ;
2023-11-19 13:33:48 +00:00
pname = " b i z h a w k - n a t i v e - d e p s " ;
dontBuild = true ;
installPhase = ''
runHook preInstall
mkdir - p $ out ; cp - vt $ out Assets/dll /* . s o
chmod - x $ out /*
runHook postInstall
'' ;
dontFixup = true ;
} ;
2024-03-07 05:21:29 +00:00
genDepsHostTargetFor = { hawkSourceInfo , mono' ? mono }: [
( lib . getOutput " o u t " libgdiplus )
lua
mono'
openal
( lib . getOutput " o u t " zstd )
] ++ lib . optionals hawkSourceInfo . needsSDL [ SDL2 ( lib . getOutput " o u t " udev ) ]
2023-12-02 18:40:22 +00:00
++ lib . optional hawkSourceInfo . needsLibGLVND ( lib . getOutput " o u t " libGL ) ;
2023-11-19 13:33:48 +00:00
/* *
* see splitReleaseArtifact re : outputs
* and no you can't build only DiscoHawk and its deps ; deal with it
* /
buildAssembliesFor = hawkSourceInfo' : let
hawkSourceInfo = populateHawkSourceInfo hawkSourceInfo' ;
extraManagedDeps = hawkSourceInfo . extraManagedDeps or buildExtraManagedDepsFor hawkSourceInfo ;
in buildDotnetModule ( lib . fix ( finalAttrs : { # proper `finalAttrs` not supported >:(
inherit doCheck mono ;
2023-11-21 04:15:37 +00:00
inherit ( hawkSourceInfo ) __contentAddressed dotnet-sdk nugetDeps src version ;
2023-11-19 13:33:48 +00:00
pname = " B i z H a w k " ;
isLocalBuild = lib . hasSuffix " - l o c a l " finalAttrs . version ;
postUnpack = lib . optionalString finalAttrs . isLocalBuild '' ( c d B i z H a w k - * - l o c a l ; D i s t / C l e a n u p B u i l d O u t p u t D i r s . s h ) '' ;
outputs = [ " o u t " " a s s e t s " " e x t r a U n m a n a g e d D e p s " " w a t e r b o x C o r e s " ] ;
propagatedBuildOutputs = [ ] ; # without this, other outputs depend on `out`
strictDeps = true ;
2024-06-01 00:07:03 +00:00
nativeBuildInputs = lib . optional finalAttrs . doCheck finalAttrs . mono
++ lib . optional finalAttrs . isLocalBuild git ;
2023-11-19 13:33:48 +00:00
buildInputs = genDepsHostTargetFor {
inherit hawkSourceInfo ;
mono' = finalAttrs . mono ;
} ;
patches = lib . optional ( ! hawkSourceInfo . hasMiscTypeCheckerPatch_6afb3be98 ) ( fetchpatch {
url = " h t t p s : / / g i t h u b . c o m / T A S E m u l a t o r s / B i z H a w k / c o m m i t / 6 a f b 3 b e 9 8 c d 3 d 8 b f 1 1 1 c 8 e 6 1 f d c 2 9 f c 3 1 3 6 a a b 1 e . p a t c h " ;
2024-06-02 00:41:05 +00:00
hash = " s h a 5 1 2 - W p L G b n g 7 T k E H U 6 w W B f k 0 o g D k K 7 U b 9 Z h 5 P K k I Q Z k X D r E R k E t Q K r d T O O Y G h s w F E f J 0 W 4 J e 5 h l 5 i Z 6 O n a 1 4 0 B x h h A = = " ;
2023-11-19 13:33:48 +00:00
} ) ;
postPatch = ''
sed - e ' s/SimpleSubshell ( " u n a m e " , " - r " , [ ^ ) ] \ + ) / " ${ builtins . toString stdenv . hostPlatform . uname . release } " / ' \
- e ' s/SimpleSubshell ( " u n a m e " , " - s " , [ ^ ) ] \ + ) / " ${ builtins . toString stdenv . hostPlatform . uname . system } " / ' \
- i src/BizHawk.Common/OSTailoredCode.cs
sed ' /Assets \ / \ * \ * /d ' - i $ { if hawkSourceInfo . copyingAssetsInEmuHawkProj # stop MSBuild from copying Assets, we'll do that in installPhase
then " s r c / B i z H a w k . C l i e n t . E m u H a w k / B i z H a w k . C l i e n t . E m u H a w k . c s p r o j "
else " s r c / B i z H a w k . C o m m o n / B i z H a w k . C o m m o n . c s p r o j " }
rm - fr References ; cp - LrT ' $ { extraManagedDeps } ' References
'' ;
buildType = buildConfig ; #TODO move debug symbols to `!debug`?
extraDotnetBuildFlags = let
s = lib . optionalString ( extraDefines != " " ) " - p : M a c h i n e E x t r a C o m p i l a t i o n F l a g = ${ extraDefines } " ;
2024-06-02 23:30:50 +00:00
in " - m a x c p u c o u n t : $ N I X _ B U I L D _ C O R E S - p : B u i l d I n P a r a l l e l = t r u e - - n o - r e s t o r e - v n o r m a l - p : C o n t i n u o u s I n t e g r a t i o n B u i l d = t r u e "
+ " - p : D e b u g T y p e = p o r t a b l e ${ s } ${ extraDotnetBuildFlags } " ;
2023-11-19 13:33:48 +00:00
buildPhase = ''
runHook preBuild
$ { if hawkSourceInfo . versionProjNeedsDoubleBuild then
'' c d s r c / B i z H a w k . V e r s i o n
dotnet build $ { finalAttrs . extraDotnetBuildFlags }
cd ../..
'' e l s e " " } D i s t / B u i l d ${ finalAttrs . buildType } . s h ${ finalAttrs . extraDotnetBuildFlags }
runHook postBuild
'' ;
2024-06-01 00:07:03 +00:00
checkNativeInputs = finalAttrs . buildInputs ; # doesn't work???
2023-11-19 13:33:48 +00:00
checkPhase = ''
runHook preCheck
export LD_LIBRARY_PATH = " $ L D _ L I B R A R Y _ P A T H : ${ lib . makeLibraryPath finalAttrs . checkNativeInputs } "
2023-11-25 14:56:06 +00:00
$ { if hawkSourceInfo . testProjectNeedsCIEnvVar then '' e x p o r t G I T L A B _ C I = 1
'' e l s e " " } D i s t / B u i l d T e s t ${ finalAttrs . buildType } . s h ${ finalAttrs . extraDotnetBuildFlags }
2023-11-19 13:33:48 +00:00
# can't build w/ extra Analyzers, it fails to restore :(
2024-06-01 00:12:09 +00:00
Dist/Build $ { finalAttrs . buildType } . sh - p:MachineRunAnalyzersDuringBuild=true $ { finalAttrs . extraDotnetBuildFlags }
2023-11-19 13:33:48 +00:00
runHook postCheck
'' ;
installPhase = ''
runHook preInstall
$ { if hawkSourceInfo . packageScriptRemovesWinFilesFromLinux then " " else
'' (
cd Assets/dll ;
rm - f " l u a 5 4 . d l l " \
" m u p e n 6 4 p l u s - a u d i o - b k m . d l l " " m u p e n 6 4 p l u s - i n p u t - b k m . d l l " " m u p e n 6 4 p l u s - r s p - c x d 4 - s s e 2 . d l l " " m u p e n 6 4 p l u s - r s p - h l e . d l l " " m u p e n 6 4 p l u s - v i d e o - a n g r y l i o n - r d p . d l l " " m u p e n 6 4 p l u s - v i d e o - g l i d e 6 4 . d l l " " m u p e n 6 4 p l u s - v i d e o - g l i d e 6 4 m k 2 . d l l " " m u p e n 6 4 p l u s - v i d e o - G L i d e N 6 4 . d l l " " m u p e n 6 4 p l u s - v i d e o - r i c e . d l l " " m u p e n 6 4 p l u s . d l l " " o c t o s h o c k . d l l " \
" b i z l y n x . d l l " " b i z s w a n . d l l " " b l i p _ b u f . d l l " " l i b b i z h a s h . d l l " " l i b d a r m . d l l " " l i b e m u 8 3 . d l l " " l i b f w u n p a c k . d l l " " l i b g a m b a t t e . d l l " " l i b L i b r e t r o B r i d g e . d l l " " l i b q u i c k n e s . d l l " " l i b r c h e e v o s . d l l " " l i b s a m e b o y . d l l " " m g b a . d l l " " M S X H a w k . d l l " " w a t e r b o x h o s t . d l l "
)
'' } r m A s s e t s / E m u H a w k M o n o . s h # r e p l a c e d w / l a u n c h - s c r i p t s . n i x
cp - avT Assets $ assets
$ { if hawkSourceInfo . hasAssetsInOutput then '' s e d ' / p a c k a g e d _ o u t p u t \ / d l l / d ' - i D i s t / P a c k a g e . s h
rm output/dll /* . x m l # t h a t ' s w h a t t h a t P a c k a g e . s h l i n e d i d , t h o u g h I ' v e f o r g o t t e n w h y a n d d o n ' t c a r e t o r e d i s c o v e r i t
mv - t $ assets/dll output/dll /*
'' e l s e " " } c h m o d - x $a s s e t s / d l l / * . s o # n o i d e a w h y t h e s e a r e a l l e x e c u t a b l e
mkdir - p $ extraUnmanagedDeps/lib ; mv - t $ extraUnmanagedDeps/lib $ assets/dll /* . s o *
mkdir - p $ waterboxCores/dll ; mv - t $ waterboxCores/dll $ assets/dll /* . w b x *
$ { if hawkSourceInfo . packageScriptNeeds7Zip then '' s e d ' / 7 z a a - t 7 z - m x 9 / d ' - i D i s t / P a c k a g e . s h # n o t w o r t h f i g u r i n g t h i s o u t
'' e l s e " " } D i s t / P a c k a g e . s h l i n u x - x 6 4
$ { if hawkSourceInfo . hasAssetsInOutput then '' m k d i r p a c k a g e d _ o u t p u t / d l l
'' e l s e " " } m k d i r - p $o u t ; c p - a v t $o u t p a c k a g e d _ o u t p u t / * . e x e * p a c k a g e d _ o u t p u t / d l l
mv - t $ out/dll $ assets/dll /*
mv - t $ out $ assets/defctrl.json $ assets/gamedb $ assets/Shaders
printf ' $ { emuhawkBuildFlavour } ' > $ out/dll/custombuild.txt
runHook postInstall
'' ;
dontPatchELF = true ;
passthru = {
inherit extraManagedDeps # could use this to backport changes to ExternalProjects? IDK
hawkSourceInfo ; # simple way to override `nugetDeps` for patching: `buildAssembliesFor (bizhawkAssemblies-latest.hawkSourceInfo // { nugetDeps = /*...*/; })`
inherit ( finalAttrs ) mono ;
# extraUnmanagedDeps = buildUnmanagedDepsFor hawkSourceInfo; # this will override the output of the same name, example: `buildEmuHawkInstallableFor { bizhawkAssemblies = bizhawkAssemblies-latest // { extraUnmanagedDeps = /*...*/; }; }`
# can similarly override `assets` output, only used by launch script to populate `BIZHAWK_DATA_HOME` if the dir doesn't exist at runtime,
# and `waterboxCores` output, which holds just the Waterbox cores, as the name suggests
} ;
meta . sourceProvenance = [ lib . sourceTypes . binaryNativeCode ] ; # `extraUnmanagedDeps` and `waterboxCores` outputs; will work on from-source later
} ) ) ;
buildInstallable =
{ bizhawkAssemblies
, pname
, launchScript
, desktopName
, desktopIcon
} : let
exeName = " ${ pname } - ${ bizhawkAssemblies . hawkSourceInfo . version } " ;
in symlinkJoin {
inherit ( bizhawkAssemblies . hawkSourceInfo ) __contentAddressed ;
name = exeName ;
paths = [
( let
# in versions < 2.9.2, Waterbox cores load from `Assembly.GetEntryAssembly().Location + "/../dll"`, but `Location` resolves symlinks so only `!bin` is visible -_-
farm = ( if bizhawkAssemblies . hawkSourceInfo . exePathRespectsEnvVar then symlinkJoin else hardLinkJoin ) {
inherit ( bizhawkAssemblies . hawkSourceInfo ) __contentAddressed ;
name = " b i z h a w k - a s m s - a n d - w b o x " ;
paths = [ bizhawkAssemblies bizhawkAssemblies . waterboxCores ] ;
} ;
in writeShellScriptBin exeName '' B I Z H A W K _ H O M E = ' ${ farm } ' e x e c ' ${ launchScript } ' " $@ " '' )
( makeDesktopItem {
inherit desktopName ; # actually Name
exec = exeName ;
icon = desktopIcon ;
name = exeName ; # actually filename
} )
] ;
passthru = {
inherit ( bizhawkAssemblies ) fetch-deps hawkSourceInfo ;
assemblies = bizhawkAssemblies ;
} ;
meta = let
p = lib . systems . inspect . patterns ;
in {
platforms = [
( p . isLinux // p . isAarch64 )
( p . isLinux // p . isx86_32 )
( p . isLinux // p . isx86_64 )
# `isMacOS` seems to be unused in Nixpkgs, though most mentions of `isDarwin` aren't from `lib.systems.inspect.patterns` so maybe it's only right for the legacy method
# won't bother w/ PPC or x86 Macs, they're too weak
( p . isDarwin // p . isAarch64 )
( p . isDarwin // p . isx86_64 )
# not sure where Nix' Windows support is at right now, whether isWindows is the relevant pattern, or whether Nix on Windows will be suitable for us once it is usable
# (p.isWindows // p.isAarch64)
# (p.isWindows // p.isx86_32)
# (p.isWindows // p.isx86_64)
] ;
badPlatforms = [ p . isDarwin p . isAarch64 p . isx86_32 ] ;
2024-06-05 05:15:38 +00:00
mainProgram = exeName ;
2023-11-19 13:33:48 +00:00
} ;
} ;
buildInstallable' =
{ hawkSourceInfo
, bizhawkAssemblies
2023-12-02 18:40:22 +00:00
, forNixOS
2023-11-19 13:33:48 +00:00
, pname
, launchScriptAttrName
, desktopName
, desktopIcon
} : let
bizhawkAssembliesFinal = if bizhawkAssemblies != null
then lib . traceIf ( hawkSourceInfo != null ) " ` h a w k S o u r c e I n f o ` p a s s e d t o ` b u i l d { E m u H a w k , D i s c o H a w k } I n s t a l l a b l e F o r ` w i l l b e i g n o r e d i n f a v o u r o f ` b i z h a w k A s s e m b l i e s . h a w k S o u r c e I n f o ` "
bizhawkAssemblies
else assert lib . assertMsg ( hawkSourceInfo != null ) " m u s t p a s s e i t h e r ` h a w k S o u r c e I n f o ` o r ` b i z h a w k A s s e m b l i e s ` t o ` b u i l d { E m u H a w k , D i s c o H a w k } I n s t a l l a b l e F o r ` " ;
2023-12-02 18:40:22 +00:00
buildAssembliesFor ( lib . optionalAttrs forNixOS { needsLibGLVND = true ; } // hawkSourceInfo ) ;
2023-11-19 13:33:48 +00:00
in buildInstallable {
inherit desktopName pname ;
bizhawkAssemblies = bizhawkAssembliesFinal ;
desktopIcon = if desktopIcon != null then desktopIcon else pname ;
launchScript = ( launchScriptsFor bizhawkAssembliesFinal false ) . ${ launchScriptAttrName } ;
} ;
in {
inherit buildAssembliesFor buildExtraManagedDepsFor buildUnmanagedDepsFor ;
/* *
* assemblies and ( managed ) dependencies , and some other immutable things like the gamedb , are in the ` out ` output ;
* unmanaged/native dependencies are in the ` extraUnmanagedDeps ` output ( under ` /lib ` ) ;
* Waterbox cores are in the ` waterboxCores ` output ( under ` /dll ` ) ;
* the rest of the " a s s e t s " ( bundled scripts , palettes , etc . ) are in the ` assets ` output
* /
splitReleaseArtifact =
{ hawkSourceInfo
, hashPrePatching
2023-11-21 04:15:37 +00:00
, crossPlatformArtifact ? false
2023-11-19 13:33:48 +00:00
, zippedTarball ? false
2023-11-21 04:15:37 +00:00
, url ? " h t t p s : / / g i t h u b . c o m / T A S E m u l a t o r s / B i z H a w k / r e l e a s e s / d o w n l o a d / ${ hawkSourceInfo . version } / B i z H a w k - ${ hawkSourceInfo . version } ${ if crossPlatformArtifact then " . z i p " else if zippedTarball then " - l i n u x - x 6 4 . t a r . z i p " else " - l i n u x - x 6 4 . t a r . g z " } "
2023-11-19 13:33:48 +00:00
, stripRoot ? true
} : assert buildConfig == " R e l e a s e " ; let
artifact = fetchzip { inherit stripRoot url ; hash = hashPrePatching ; } ;
hawkSourceInfo' = populateHawkSourceInfo hawkSourceInfo ;
in runCommand " B i z H a w k - ${ hawkSourceInfo . version } - b i n " {
buildInputs = genDepsHostTargetFor { hawkSourceInfo = hawkSourceInfo' ; } ; # is using `buildInputs` like this correct? it's necessary because the launch script reads from it
outputs = [ " o u t " " a s s e t s " " e x t r a U n m a n a g e d D e p s " " w a t e r b o x C o r e s " ] ;
passthru = {
inherit mono ;
hawkSourceInfo = hawkSourceInfo' ;
} ;
meta . sourceProvenance = [ lib . sourceTypes . binaryNativeCode lib . sourceTypes . binaryBytecode ] ;
} ''
$ { if zippedTarball then '' m k d i r - p $a s s e t s ; t a r - x f ' ${ artifact } ' / * . t a r - C $a s s e t s '' else '' c p - a T ' ${ artifact } ' $a s s e t s '' }
cd $ assets
find . - type d - exec chmod + w { } \ ;
rm - f EmuHawkMono . sh
$ { if hawkSourceInfo' . releaseArtifactHasRogueOTKAsmConfig then '' m v - f t d l l O p e n T K . d l l . c o n f i g
'' e l s e " " } r m d i r F i r m w a r e
2023-11-21 04:15:37 +00:00
mkdir - p ExternalTools ; touch ExternalTools/.keep
2023-11-19 13:33:48 +00:00
2023-11-21 04:15:37 +00:00
mkdir - p $ out ; mv - t $ out defctrl . json DiscoHawk . exe * dll EmuHawk . exe * gamedb [ Ss ] haders
$ { if hawkSourceInfo' . releaseArtifactNeedsVBDotnetReference then '' c p - t $o u t / d l l ' ${ lib . getOutput " o u t " monoBasic } / u s r / l i b / m o n o / 4 . 5 / M i c r o s o f t . V i s u a l B a s i c . d l l '
'' e l s e " " } ${ if hawkSourceInfo' . releaseArtifactNeedsLowercaseAsms then '' ( c d $o u t / d l l ; f o r s i n C l i e n t . C o m m o n E m u l a t i o n . C o r e s ; d o c p B i z H a w k . $s . d l l B i z h a w k . $s . d l l ; d o n e )
'' e l s e " " } ${ if hawkSourceInfo' . releaseArtifactNeedsOTKAsmConfig then '' c p - t $o u t / d l l ' ${ releaseTagSourceInfos . info-2_6 . src } / A s s e t s / d l l / O p e n T K . d l l . c o n f i g '
'' e l s e " " } p r i n t f ' ${ emuhawkBuildFlavour } ' > $o u t / d l l / c u s t o m b u i l d . t x t
2023-11-19 13:33:48 +00:00
mkdir - p $ extraUnmanagedDeps/lib ; mv - t $ extraUnmanagedDeps/lib $ out/dll /* . s o *
mkdir - p $ waterboxCores/dll ; mv - t $ waterboxCores/dll $ out/dll /* . w b x *
'' ;
buildDiscoHawkInstallableFor =
{ bizhawkAssemblies ? null
, hawkSourceInfo ? null
2023-12-02 18:40:22 +00:00
, forNixOS ? true # currently only adds Mesa to buildInputs, and DiscoHawk doesn't need that, but it's propagated through here so the asms derivation can be shared between it and EmuHawk
2023-11-19 13:33:48 +00:00
, desktopName ? " D i s c o H a w k ( M o n o R u n t i m e ) "
, desktopIcon ? null
} : buildInstallable' {
2023-12-02 18:40:22 +00:00
inherit bizhawkAssemblies desktopIcon desktopName forNixOS hawkSourceInfo ;
2023-11-19 13:33:48 +00:00
pname = " d i s c o h a w k - m o n o r t " ;
launchScriptAttrName = " d i s c o h a w k " ;
} ;
buildEmuHawkInstallableFor =
{ bizhawkAssemblies ? null
, hawkSourceInfo ? null
, forNixOS ? true
, desktopName ? " E m u H a w k ( M o n o R u n t i m e ) "
, desktopIcon ? null
} : buildInstallable' {
2023-12-02 18:40:22 +00:00
inherit bizhawkAssemblies desktopIcon desktopName forNixOS hawkSourceInfo ;
2023-11-19 13:33:48 +00:00
pname = " e m u h a w k - m o n o r t " ;
launchScriptAttrName = if forNixOS then " e m u h a w k " else " e m u h a w k N o n N i x O S " ;
} ;
2023-11-20 02:22:33 +00:00
}