about summary refs log tree commit diff
path: root/nixpkgs/pkgs/development/compilers/llvm/17/libcxx/default.nix
blob: 8f4b0cec8d400908cb6325f035b45e48eb3e212c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
{ lib, stdenv, llvm_meta
, monorepoSrc, runCommand, fetchpatch
, cmake, ninja, python3, fixDarwinDylibNames, version
, cxxabi ? if stdenv.hostPlatform.isFreeBSD then libcxxrt else libcxxabi
, libcxxabi, libcxxrt, libunwind
, enableShared ? !stdenv.hostPlatform.isStatic

# If headersOnly is true, the resulting package would only include the headers.
# Use this to break the circular dependency between libcxx and libcxxabi.
#
# Some context:
# https://reviews.llvm.org/rG1687f2bbe2e2aaa092f942d4a97d41fad43eedfb
, headersOnly ? false
}:

let
  basename = "libcxx";
in

assert stdenv.isDarwin -> cxxabi.libName == "c++abi";

stdenv.mkDerivation rec {
  pname = basename + lib.optionalString headersOnly "-headers";
  inherit version;

  src = runCommand "${pname}-src-${version}" {} ''
    mkdir -p "$out"
    cp -r ${monorepoSrc}/cmake "$out"
    cp -r ${monorepoSrc}/${basename} "$out"
    mkdir -p "$out/libcxxabi"
    cp -r ${monorepoSrc}/libcxxabi/include "$out/libcxxabi"
    mkdir -p "$out/llvm"
    cp -r ${monorepoSrc}/llvm/cmake "$out/llvm"
    cp -r ${monorepoSrc}/llvm/utils "$out/llvm"
    cp -r ${monorepoSrc}/third-party "$out"
    cp -r ${monorepoSrc}/runtimes "$out"
  '';

  sourceRoot = "${src.name}/runtimes";

  outputs = [ "out" ] ++ lib.optional (!headersOnly) "dev";

  prePatch = ''
    cd ../${basename}
    chmod -R u+w .
  '';

  patches = [
    # fix for https://github.com/NixOS/nixpkgs/issues/269548
    # https://github.com/llvm/llvm-project/pull/77218
    (fetchpatch {
      name = "darwin-system-libcxxabi-link-flags.patch";
      url = "https://github.com/llvm/llvm-project/commit/c5b89b29ee6e3c444a355fd1cf733ce7ab2e316a.patch";
      hash = "sha256-LNoPg1KCoP8RWxU/AzHR52f4Dww24I9BGQJedMhFxyQ=";
      relative = "libcxx";
    })
  ] ++ lib.optionals (stdenv.isDarwin && lib.versionOlder stdenv.hostPlatform.darwinMinVersion "10.13") [
    # https://github.com/llvm/llvm-project/issues/64226
    (fetchpatch {
      name = "0042-mbstate_t-not-defined.patch";
      url = "https://github.com/macports/macports-ports/raw/acd8acb171f1658596ed1cf25da48d5b932e2d19/lang/llvm-17/files/0042-mbstate_t-not-defined.patch";
      relative = "libcxx";
      hash = "sha256-fVbX99W1gQrSaMFeBkzsJmNWNy0xVSw+oFvDe4AYXL0=";
    })
  ];

  postPatch = ''
    cd ../runtimes
  '';

  preConfigure = lib.optionalString stdenv.hostPlatform.isMusl ''
    patchShebangs utils/cat_files.py
  '';

  nativeBuildInputs = [ cmake ninja python3 ]
    ++ lib.optional stdenv.isDarwin fixDarwinDylibNames;

  buildInputs =
    lib.optionals (!headersOnly) [ cxxabi ]
    ++ lib.optionals (stdenv.hostPlatform.useLLVM or false && !stdenv.hostPlatform.isWasm) [ libunwind ];

  cmakeFlags = let
    # See: https://libcxx.llvm.org/BuildingLibcxx.html#cmdoption-arg-libcxx-cxx-abi-string
    libcxx_cxx_abi_opt = {
      "c++abi" = "system-libcxxabi";
      "cxxrt" = "libcxxrt";
    }.${cxxabi.libName} or (throw "unknown cxxabi: ${cxxabi.libName} (${cxxabi.pname})");
  in [
    "-DLLVM_ENABLE_RUNTIMES=libcxx"
    "-DLIBCXX_CXX_ABI=${if headersOnly then "none" else libcxx_cxx_abi_opt}"
  ] ++ lib.optional (!headersOnly && cxxabi.libName == "c++abi") "-DLIBCXX_CXX_ABI_INCLUDE_PATHS=${cxxabi.dev}/include/c++/v1"
    ++ lib.optional (stdenv.hostPlatform.isMusl || stdenv.hostPlatform.isWasi) "-DLIBCXX_HAS_MUSL_LIBC=1"
    ++ lib.optionals (stdenv.hostPlatform.useLLVM or false) [
      "-DLIBCXX_USE_COMPILER_RT=ON"
      # There's precedent for this in llvm-project/libcxx/cmake/caches.
      # In a monorepo build you might do the following in the libcxxabi build:
      #   -DLLVM_ENABLE_PROJECTS=libcxxabi;libunwinder
      #   -DLIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY=On
      # libcxx appears to require unwind and doesn't pull it in via other means.
      "-DLIBCXX_ADDITIONAL_LIBRARIES=unwind"
    ] ++ lib.optionals stdenv.hostPlatform.isWasm [
      "-DLIBCXX_ENABLE_THREADS=OFF"
      "-DLIBCXX_ENABLE_FILESYSTEM=OFF"
      "-DLIBCXX_ENABLE_EXCEPTIONS=OFF"
      "-DUNIX=ON" # Required otherwise libc++ fails to detect the correct linker
    ] ++ lib.optional (!enableShared) "-DLIBCXX_ENABLE_SHARED=OFF"
    # If we're only building the headers we don't actually *need* a functioning
    # C/C++ compiler:
    ++ lib.optionals (headersOnly) [
      "-DCMAKE_C_COMPILER_WORKS=ON"
      "-DCMAKE_CXX_COMPILER_WORKS=ON"
    ];

  ninjaFlags = lib.optional headersOnly "generate-cxx-headers";
  installTargets = lib.optional headersOnly "install-cxx-headers";

  passthru = {
    isLLVM = true;
    inherit cxxabi;
  };

  meta = llvm_meta // {
    homepage = "https://libcxx.llvm.org/";
    description = "C++ standard library";
    longDescription = ''
      libc++ is an implementation of the C++ standard library, targeting C++11,
      C++14 and above.
    '';
    # "All of the code in libc++ is dual licensed under the MIT license and the
    # UIUC License (a BSD-like license)":
    license = with lib.licenses; [ mit ncsa ];
  };
}