From c3c4ef859a31d59e223433eba61fbaf0140208f8 Mon Sep 17 00:00:00 2001 From: sternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org> Date: Thu, 22 Jul 2021 13:52:40 +0200 Subject: [PATCH] gprbuild, xmlada: init at 21.0.0 GPRbuild is a multi language build system developed by AdaCore which is mostly used for build Ada-related projects using GNAT. Since GPRbuild is used to build itself and its dependency library XML/Ada we first build a bootstrap version of it using the provided bash build script bootstrap.sh as the gprbuild-boot derivation. gprbuild-boot is then used to build xmlada and the proper gprbuild derivation. GPRbuild has its own search path mechanism via GPR_PROJECT_PATH which we address via a setupHook. It currently works quite similar to the pkg-config one: It accumulates all inputs into GPR_PROJECT_PATH, GPR_PROJECT_PATH_FOR_BUILD etc. However this is quite limited at the moment as we don't have a gprbuild wrapper yet which understands the _FOR_BUILD suffix. However, we'll need to address this in the future as it is currently basically impossible to test since the distinction only affects cross-compilation, but it is not possible to build a GNAT cross-compiler in nixpkgs at the moment (I'm working on changing that, however). Another issue we had to solve was GPRbuild not finding the right GNAT via its gprconfig tool: GPRbuild has a knowledge base with compiler definitions which run some checks and collect info about binaries which are in PATH. In the end the first compiler in PATH that supports the desired language is selected. We want GPRbuild to discover our wrapped GNAT since the unwrapped one is incapable of producing working binaries since it won't find the crt*.o objects distributed with libc. GPRbuild however needs to find the Ada runtime distributed with GNAT which is not part of the wrapper derivation, so it will skip the wrapper and select the unwrapped GNAT. Symlinking the unwrapped's lib directory into the wrapper fixes this problem, but breaks linking in some cases (e. g. when linking against OMP from gcc, the runtime variant will shadow the problem dynamic lib from buildInputs). Additionally it uses gnatls as an indicator it has found GNAT which is not part of the wrapper. The solution we opted to adopt here is to install a custom compiler description into gprbuild's knowledge base which properly detects the nixpkgs GNAT wrapper: It uses gnatmake to detect GNAT instead of gnatls and discovers the runtime via a symlink we add to `$out/nix-support`. This additional definition is enough to properly detect GNAT, since the plain wrapped gcc detection works out of the box. It may, however, be necessary to add special definitions for other languages in the future where gprbuild also needs to discover the runtime. One future improvement would be to install libgpr into a separate output or split it into a separate derivation (which would require to link gprbuild statically always since otherwise we end up with a cyclical dependency). --- pkgs/build-support/cc-wrapper/default.nix | 5 ++ .../libraries/ada/xmlada/default.nix | 35 ++++++++ .../tools/build-managers/gprbuild/boot.nix | 90 +++++++++++++++++++ .../tools/build-managers/gprbuild/default.nix | 65 ++++++++++++++ .../gprbuild/gpr-project-path-hook.sh | 8 ++ .../build-managers/gprbuild/nixpkgs-gnat.xml | 56 ++++++++++++ pkgs/top-level/all-packages.nix | 6 ++ 7 files changed, 265 insertions(+) create mode 100644 pkgs/development/libraries/ada/xmlada/default.nix create mode 100644 pkgs/development/tools/build-managers/gprbuild/boot.nix create mode 100644 pkgs/development/tools/build-managers/gprbuild/default.nix create mode 100644 pkgs/development/tools/build-managers/gprbuild/gpr-project-path-hook.sh create mode 100644 pkgs/development/tools/build-managers/gprbuild/nixpkgs-gnat.xml diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix index 235d244a7c0..678027f9bf4 100644 --- a/pkgs/build-support/cc-wrapper/default.nix +++ b/pkgs/build-support/cc-wrapper/default.nix @@ -234,6 +234,11 @@ stdenv.mkDerivation { wrap ${targetPrefix}gnatmake ${./gnat-wrapper.sh} $ccPath/${targetPrefix}gnatmake wrap ${targetPrefix}gnatbind ${./gnat-wrapper.sh} $ccPath/${targetPrefix}gnatbind wrap ${targetPrefix}gnatlink ${./gnat-wrapper.sh} $ccPath/${targetPrefix}gnatlink + + # this symlink points to the unwrapped gnat's output "out". It is used by + # our custom gprconfig compiler description to find GNAT's ada runtime. See + # ../../development/tools/build-managers/gprbuild/{boot.nix, nixpkgs-gnat.xml} + ln -sf ${cc} $out/nix-support/gprconfig-gnat-unwrapped '' + optionalString cc.langD or false '' diff --git a/pkgs/development/libraries/ada/xmlada/default.nix b/pkgs/development/libraries/ada/xmlada/default.nix new file mode 100644 index 00000000000..b855166d559 --- /dev/null +++ b/pkgs/development/libraries/ada/xmlada/default.nix @@ -0,0 +1,35 @@ +{ stdenv +, lib +, fetchFromGitHub +, gnat +# use gprbuild-boot since gprbuild proper depends +# on this xmlada derivation. +, gprbuild-boot +}: + +stdenv.mkDerivation rec { + pname = "xmlada"; + version = "21.0.0"; + + src = fetchFromGitHub { + name = "xmlada-${version}-src"; + owner = "AdaCore"; + repo = "xmlada"; + rev = "v${version}"; + sha256 = "00vljkvck951nj853v9sda5qbfm1mp8y2k61ja2595rmp8qcrazw"; + }; + + nativeBuildInputs = [ + gnat + gprbuild-boot + ]; + + meta = with lib; { + description = "XML/Ada: An XML parser for Ada"; + homepage = "https://github.com/AdaCore/xmlada"; + maintainers = [ maintainers.sternenseemann ]; + license = licenses.gpl3Plus; + platforms = platforms.all; + }; +} + diff --git a/pkgs/development/tools/build-managers/gprbuild/boot.nix b/pkgs/development/tools/build-managers/gprbuild/boot.nix new file mode 100644 index 00000000000..352cd0b137b --- /dev/null +++ b/pkgs/development/tools/build-managers/gprbuild/boot.nix @@ -0,0 +1,90 @@ +{ stdenv +, lib +, fetchFromGitHub +, gnat +, which +, xmlada # for src +}: + +let + version = "21.0.0"; + + gprConfigKbSrc = fetchFromGitHub { + name = "gprconfig-kb-${version}-src"; + owner = "AdaCore"; + repo = "gprconfig_kb"; + rev = "v${version}"; + sha256 = "11qmzfdd0ipmhxl4k2hjidqc9i40bywrfkbiivd3lhscxca5pxpg"; + }; +in + +stdenv.mkDerivation { + pname = "gprbuild-boot"; + inherit version; + + src = fetchFromGitHub { + name = "gprbuild-${version}"; + owner = "AdaCore"; + repo = "gprbuild"; + rev = "v${version}"; + sha256 = "1knpwasbrz6sxh3dhkc4izchcz4km04j77r4vxxhi23fbd8v1ynj"; + }; + + nativeBuildInputs = [ + gnat + which + ]; + + postPatch = '' + # The Makefile uses gprbuild to build gprbuild which + # we can't do at this point, delete it to prevent the + # default phases from failing. + rm Makefile + + # make sure bootstrap script runs + patchShebangs --build bootstrap.sh + ''; + + # This setupHook populates GPR_PROJECT_PATH which is used by + # gprbuild to find dependencies. It works quite similar to + # the pkg-config setupHook in the sense that it also splits + # dependencies into GPR_PROJECT_PATH and GPR_PROJECT_PATH_FOR_BUILD, + # but gprbuild itself doesn't support this, so we'll need to + # introducing a wrapper for it in the future remains TODO. + # For the moment this doesn't matter since we have no situation + # were gprbuild is used to build something used at build time. + setupHook = ./gpr-project-path-hook.sh; + + installPhase = '' + runHook preInstall + + ./bootstrap.sh \ + --with-xmlada=${xmlada.src} \ + --with-kb=${gprConfigKbSrc} \ + --prefix=$out + + # Install custom compiler description which can detect nixpkgs' + # GNAT wrapper as a proper Ada compiler. The default compiler + # description expects the runtime library to be installed in + # the same prefix which isn't the case for nixpkgs. As a + # result, it would detect the unwrapped GNAT as a proper + # compiler which is unable to produce working binaries. + # + # Our compiler description is very similar to the upstream + # GNAT description except that we use a symlink in $out/nix-support + # created by the cc-wrapper to find the associated runtime + # libraries and use gnatmake instead of gnatls to find GNAT's + # bin directory. + install -m644 ${./nixpkgs-gnat.xml} $out/share/gprconfig/nixpkgs-gnat.xml + + runHook postInstall + ''; + + meta = with lib; { + description = "Multi-language extensible build tool"; + homepage = "https://github.com/AdaCore/gprbuild"; + license = licenses.gpl3Plus; + maintainers = [ maintainers.sternenseemann ]; + platforms = platforms.all; + }; +} diff --git a/pkgs/development/tools/build-managers/gprbuild/default.nix b/pkgs/development/tools/build-managers/gprbuild/default.nix new file mode 100644 index 00000000000..3155151ae0f --- /dev/null +++ b/pkgs/development/tools/build-managers/gprbuild/default.nix @@ -0,0 +1,65 @@ +{ lib +, stdenv +, fetchFromGitHub +, fetchpatch +, gprbuild-boot +, which +, gnat +, xmlada +}: + +stdenv.mkDerivation { + pname = "gprbuild"; + + # See ./boot.nix for an explanation of the gprbuild setupHook, + # our custom knowledge base entry and the situation wrt a + # (future) gprbuild wrapper. + inherit (gprbuild-boot) + version + src + setupHook + meta + ; + + nativeBuildInputs = [ + gnat + gprbuild-boot + which + ]; + + propagatedBuildInputs = [ + xmlada + ]; + + makeFlags = [ + "ENABLE_SHARED=${if stdenv.hostPlatform.isStatic then "no" else "yes"}" + "PROCESSORS=$(NIX_BUILD_CORES)" + # confusingly, for gprbuild --target is autoconf --host + "TARGET=${stdenv.hostPlatform.config}" + "prefix=${placeholder "out"}" + ] ++ lib.optionals (!stdenv.hostPlatform.isStatic) [ + "LIBRARY_TYPE=relocatable" + ]; + + # Fixes gprbuild being linked statically always + patches = lib.optional (!stdenv.hostPlatform.isStatic) (fetchpatch { + name = "gprbuild-relocatable-build.patch"; + url = "https://aur.archlinux.org/cgit/aur.git/plain/relocatable-build.patch?h=gprbuild&id=1d4e8a5cb982e79135a0aaa3ef87654bed1fe4f0"; + sha256 = "1r3xsp1pk9h666mm8mdravkybmd5gv2f751x2ffb1kxnwq1rwiyn"; + }); + + buildFlags = [ "all" "libgpr.build" ]; + + installFlags = [ "all" "libgpr.install" ]; + + # link gprconfig_kb db from gprbuild-boot into build dir, + # the install process copies its contents to $out + preInstall = '' + ln -sf ${gprbuild-boot}/share/gprconfig share/gprconfig + ''; + + # no need for the install script + postInstall = '' + rm $out/doinstall + ''; +} diff --git a/pkgs/development/tools/build-managers/gprbuild/gpr-project-path-hook.sh b/pkgs/development/tools/build-managers/gprbuild/gpr-project-path-hook.sh new file mode 100644 index 00000000000..f98b2ab9e58 --- /dev/null +++ b/pkgs/development/tools/build-managers/gprbuild/gpr-project-path-hook.sh @@ -0,0 +1,8 @@ +addAdaObjectsPath() { + local role_post + getHostRoleEnvHook + + addToSearchPath "GPR_PROJECT_PATH${role_post}" "$1/share/gpr" +} + +addEnvHooks "$targetOffset" addAdaObjectsPath diff --git a/pkgs/development/tools/build-managers/gprbuild/nixpkgs-gnat.xml b/pkgs/development/tools/build-managers/gprbuild/nixpkgs-gnat.xml new file mode 100644 index 00000000000..ead88dc365c --- /dev/null +++ b/pkgs/development/tools/build-managers/gprbuild/nixpkgs-gnat.xml @@ -0,0 +1,56 @@ + + + + + + GNAT + (.*-.*-.*)?gnatmake + + ${PREFIX}gnatmake -v + + + Ada + + ${PREFIX}gcc -v + + + + + readlink -n ${PATH}/../nix-support/gprconfig-gnat-unwrapped + + + $gnat_unwrapped/lib/gcc(-lib)?/$TARGET/$gcc_version/adalib/ + $gnat_unwrapped/lib/gcc(-lib)?/$TARGET/$gcc_version/ada_object_path + $gnat_unwrapped/lib/gcc(-lib)?/$TARGET/$gcc_version/rts-(.*)/adalib/ + $gnat_unwrapped/$TARGET/lib/gnat/(.*)/adalib/ + + + ${PREFIX}gcc -dumpmachine + + + + diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index aa642484b2d..23e5dd061e5 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -13772,6 +13772,10 @@ in gotty = callPackage ../servers/gotty { }; + gprbuild-boot = callPackage ../development/tools/build-managers/gprbuild/boot.nix { }; + + gprbuild = callPackage ../development/tools/build-managers/gprbuild { }; + gputils = callPackage ../development/tools/misc/gputils { }; gpuvis = callPackage ../development/tools/misc/gpuvis { }; @@ -19098,6 +19102,8 @@ in ]; }; + xmlada = callPackage ../development/libraries/ada/xmlada { }; + xmlrpc_c = callPackage ../development/libraries/xmlrpc-c { }; xmlsec = callPackage ../development/libraries/xmlsec { };