1
1
mirror of https://github.com/NixOS/mobile-nixos.git synced 2024-12-18 05:21:47 +03:00
mobile-nixos/overlay/mruby-builder/mruby/default.nix
2020-02-28 23:14:09 -05:00

224 lines
5.8 KiB
Nix

# As we're re-using the default values, define them outside the callPackage
# declaration.
let
defaultGemBoxes = ["default"];
defaultGems = [
# Without this, a cross-compilation will be missing its mrbc.
# This is useful when mruby is intended to be run on the target.
#:core => 'mruby-bin-mrbc'
{ core = "mruby-bin-mrbc"; }
];
in
{ stdenv
, buildPackages
, ruby
, bison
, fetchFromGitHub
, file
, mruby
, writeText
# When unset the default gembox will be used.
# For a native build, use the default gembox
# For a cross build, use no gembox
, gemBoxes ? []
# When unset [] no additional mrbgem is added.
# Add paths to mrbgems to add gems.
, gems ? []
# Add additional configuration to the target config.
, additionalBuildConfig ? ""
# Adds `enable_debug`.
, debug ? false
# Prepends defaults to `gems` and `gemBoxes`.
, useDefaults ? true
}:
let
inherit (stdenv.lib)
concatMapStringsSep
concatStringsSep
isDerivation
mapAttrsToList
optionals
optionalString
;
inherit (builtins)
toJSON
typeOf
;
# Naïve and minimal implementation to turn an input into ruby.
# This is the minimum required for our needs.
toRuby = input:
if isDerivation input then
toJSON (toString input)
else if typeOf input == "set" then
# Assumes attrsets are built only from symbole => value equivalents.
concatStringsSep ", " (mapAttrsToList (
name: value: ":${name} => ${toRuby value}"
) input)
else if typeOf input == "string" then
# Strings are simply their "toJSON" equivalents since it's a generally
# proper "C-like" escape.
toJSON input # heh, this is a cheezy shortcut
else if typeOf input == "bool" then
toJSON input
else
throw "toRuby doesn't know how to handle type ${typeOf input}"
;
isCross = stdenv.hostPlatform != stdenv.buildPlatform;
targetName = if isCross then "${stdenv.cc.targetPrefix}config" else "host";
# For cross-compilations, guards against customized mrubies.
# This is only since mrbc is required.
buildMruby = buildPackages.mruby.override {
gemBoxes = defaultGemBoxes;
gems = defaultGems;
additionalBuildConfig = "";
useDefaults = false;
};
concatGemAttr = attr: gems: builtins.concatLists (map (gem:
if typeOf gem == "set" && (builtins.hasAttr attr gem)
then gem."${attr}" ++ (concatGemAttr attr gem."${attr}")
else []
) gems);
gemsForGems = concatGemAttr "requiredGems" gems;
gems' = optionals useDefaults defaultGems ++ gems ++ gemsForGems;
gemBoxes' = optionals useDefaults defaultGemBoxes ++ gemBoxes;
gemBuildInputs = concatGemAttr "gemBuildInputs" gems;
gemNativeBuildInputs = concatGemAttr "gemNativeBuildInputs" gems;
compilerFlags = [
"-std=c99"
"-Os"
]
++ concatGemAttr "compilerFlags" gems
;
linkerFlags = [
"-lm"
"-lmruby"
]
++ concatGemAttr "linkerFlags" gems
;
shared-config = ''
# Gemboxes
${concatMapStringsSep "\n" (box: "conf.gembox '${box}'") gemBoxes'}
# Gems
${concatMapStringsSep "\n" (gem: "conf.gem(${toRuby gem})") gems'}
# Additional build config
${additionalBuildConfig}
'';
# This configuration file is aimed solely at producing cross-compiled mrubies.
mruby-config = writeText "mruby-config" ''
MRuby::${optionalString isCross "Cross"}Build.new("${targetName}") do |conf|
toolchain :gcc
${optionalString debug ''
enable_debug
# C compiler settings
conf.cc.defines = %w(MRB_ENABLE_DEBUG_HOOK)
# Generate mruby debugger command (require mruby-eval)
conf.gem :core => "mruby-bin-debugger"
''}
${optionalString isCross
# Makes a cross-compiled mruby aware of our existing "host" build of
# mruby. Otherwise it will build a "host" mruby for the target.
''
def mrbcfile()
"${buildMruby}/bin/mrbc"
end
''}
${shared-config}
end
${optionalString (!isCross) ''
MRuby::Build.new('test') do |conf|
toolchain :gcc
enable_debug
conf.enable_bintest
conf.enable_test
${shared-config}
end
''}
'';
in
stdenv.mkDerivation rec {
pname = "mruby";
version = "2.1.0";
src = fetchFromGitHub {
owner = "mruby";
repo = "mruby";
rev = version;
sha256 = "1y072c7dh9jf8xwy7kia6cb4dkpspq4zf24ssn7zm5f46p4waxni";
};
patches = [
./0001-HACK-Ensures-a-host-less-build-can-be-made.patch
./0001-Nixpkgs-dump-linker-flags-for-re-use.patch
];
nativeBuildInputs = [ ruby bison ] ++ gemNativeBuildInputs;
buildInputs = gemBuildInputs;
# Necessary so it uses `gcc` instead of `ld` for linking.
# https://github.com/mruby/mruby/blob/35be8b252495d92ca811d76996f03c470ee33380/tasks/toolchains/gcc.rake#L25
preBuild = if stdenv.isLinux then "unset LD" else null;
SKIP_HOST = if isCross then "true" else null;
buildPhase = ''
runHook preBuild
cp -vf ${mruby-config} build_config.rb
ruby ./minirake -v -j$NIX_BUILD_CORES
ruby ./minirake -v dump_linker_flags
runHook postBuild
'';
checkPhase = ''
runHook preCheck
ruby ./minirake test -j$NIX_BUILD_CORES
runHook postCheck
'';
doCheck = true;
# TODO: Allow cross-compiling the binaries too.
installPhase = ''
mkdir -p $out/share/mruby/
cp build_config.rb $out/share/mruby
cp -R build/${targetName}/bin $out
cp -R build/${targetName}/lib $out
cp -R include $out
mkdir -p $out/nix-support
cp mruby_linker_flags.sh $out/nix-support/
'';
meta = with stdenv.lib; {
description = "An embeddable implementation of the Ruby language";
homepage = https://mruby.org;
maintainers = [ maintainers.nicknovitski ];
license = licenses.mit;
platforms = platforms.unix;
};
passthru = {
inherit linkerFlags compilerFlags;
};
enableParallelBuilding = true;
}