about summary refs log tree commit diff
path: root/pkgs/development/libraries/libiconv/default.nix
diff options
context:
space:
mode:
authorRandy Eckenrode <randy@largeandhighquality.com>2023-06-14 16:09:25 -0400
committerRandy Eckenrode <randy@largeandhighquality.com>2023-06-21 19:05:54 -0400
commit057dd0effeb0a748738b1b93f8cb072a0ddc439f (patch)
treef0b451e2ece66eee96debbaeb0a9232b4116100a /pkgs/development/libraries/libiconv/default.nix
parent23bd312777fd2265e0e1c38effe2c32c160b5d3b (diff)
libiconvReal: implement ABI compatibility on Darwin
This commit prepares libiconvReal to replace darwin.libiconv, allowing
it to be used with binary derivations that patch out references to the
system libiconv with one from nixpkgs.

Apple’s libiconv is based on GNU libiconv 1.11 (the last version before
it switched to LGPLv3+). Any newer releases by Apple appear to be build
system tweaks. The core sources are barely updated. This means that
Darwin users won’t get any fixes from upstream updates, and maintaining
darwin.libiconv requires dealing with a separate and different build
system (because Apple now builds it with Xcode). Fortunately, it is
possible to build upstream libiconv in a way that is compatible with
Apple’s distribution of it.

There are two things that need to happen to produce an ABI-compatible
build of libiconv:

* Existing symbols need to be exported with the `iconv_` prefix instead
  of the `libiconv_` prefix. New symbols can have the `libiconv` prefix,
  and one symbol in Apple’s distribution does, but older ones must have
  the older prefix; and
* Reexport `libcharset.dylib` from `libiconv.dylib`. This is explained
  by Apple as the result of a bug in their transition to an Xcode-based
  build system.

Both these these are doable and have been done by this commit. I have
tested it with building GHC, which downloads a binary distribution as
part of its bootstrap and replaces references to the system libiconv
with darwin.libiconv. Using this patch, libiconvReal is able to work
without any changes to the GHC derivation.

Note that this patch does not actually deprecate or remove
darwin.libiconv yet. That will be done in a future patch after Darwin
support is added for aliases and deprecating packages in the `darwin`
attrset.
Diffstat (limited to 'pkgs/development/libraries/libiconv/default.nix')
-rw-r--r--pkgs/development/libraries/libiconv/default.nix28
1 files changed, 28 insertions, 0 deletions
diff --git a/pkgs/development/libraries/libiconv/default.nix b/pkgs/development/libraries/libiconv/default.nix
index a6481970ef27e..91b0df75f87ba 100644
--- a/pkgs/development/libraries/libiconv/default.nix
+++ b/pkgs/development/libraries/libiconv/default.nix
@@ -1,6 +1,7 @@
 { fetchurl, stdenv, lib
 , enableStatic ? stdenv.hostPlatform.isStatic
 , enableShared ? !stdenv.hostPlatform.isStatic
+, enableDarwinABICompat ? false
 }:
 
 # assert !stdenv.hostPlatform.isLinux || stdenv.hostPlatform != stdenv.buildPlatform; # TODO: improve on cross
@@ -28,8 +29,35 @@ stdenv.mkDerivation rec {
       ''
     + lib.optionalString (!enableShared) ''
       sed -i -e '/preload/d' Makefile.in
+    ''
+    # The system libiconv is based on libiconv 1.11 with some ABI differences. The following changes
+    # build a compatible libiconv on Darwin, allowing it to be sustituted in place of the system one
+    # using `install_name_tool`. This removes the need to for a separate, Darwin-specific libiconv
+    # derivation and allows Darwin to benefit from upstream updates and fixes.
+    + lib.optionalString enableDarwinABICompat ''
+      for iconv_h_in in iconv.h.in iconv.h.build.in; do
+        substituteInPlace "include/$iconv_h_in" \
+          --replace "#define iconv libiconv" "" \
+          --replace "#define iconv_close libiconv_close" "" \
+          --replace "#define iconv_open libiconv_open" "" \
+          --replace "#define iconv_open_into libiconv_open_into" "" \
+          --replace "#define iconvctl libiconvctl" "" \
+          --replace "#define iconvlist libiconvlist" ""
+      done
     '';
 
+  # This is hacky, but `libiconv.dylib` needs to reexport `libcharset.dylib` to match the behavior
+  # of the system libiconv on Darwin. Trying to do this by modifying the `Makefile` results in an
+  # error linking `iconv` because `libcharset.dylib` is not at its final path yet. Avoid the error
+  # by building without the reexport then clean and rebuild `libiconv.dylib` with the reexport.
+  #
+  # For an explanation why `libcharset.dylib` is reexported, see:
+  # https://github.com/apple-oss-distributions/libiconv/blob/a167071feb7a83a01b27ec8d238590c14eb6faff/xcodeconfig/libiconv.xcconfig
+  postBuild = lib.optionalString enableDarwinABICompat ''
+    make clean -C lib
+    NIX_CFLAGS_COMPILE+=" -Wl,-reexport-lcharset -L. " make -C lib -j$NIX_BUILD_CORES SHELL=$SHELL
+  '';
+
   configureFlags = [
     (lib.enableFeature enableStatic "static")
     (lib.enableFeature enableShared "shared")