about summary refs log tree commit diff
path: root/nixpkgs/pkgs/development/interpreters/cling/default.nix
blob: f59c1910a6ff6c2e1d6b3044dea8d8261d085c85 (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
{ cmake
, fetchFromGitHub
, fetchgit
, git
, lib
, libffi
, llvmPackages_9
, makeWrapper
, ncurses
, python3
, runCommand
, zlib

# *NOT* from LLVM 9!
# The compiler used to compile Cling may affect the runtime include and lib
# directories it expects to be run with. Cling builds against (a fork of) Clang,
# so we prefer to use Clang as the compiler as well for consistency.
# It would be cleanest to use LLVM 9's clang, but it errors. So, we use a later
# version of Clang to compile, but we check out the Cling fork of Clang 9 to
# build Cling against.
, clangStdenv

# For runtime C++ standard library
, gcc-unwrapped

# Build with debug symbols
, debug ? false

# Build with libc++ (LLVM) rather than stdlibc++ (GCC).
# This is experimental and not all features work.
, useLLVMLibcxx ? false
}:

let
  stdenv = clangStdenv;

  # The LLVM 9 headers have a couple bugs we need to patch
  fixedLlvmDev = runCommand "llvm-dev-${llvmPackages_9.llvm.version}" { buildInputs = [git]; } ''
    mkdir $out
    cp -r ${llvmPackages_9.llvm.dev}/include $out
    cd $out
    chmod -R u+w include
    git apply ${./fix-llvm-include.patch}
  '';

  unwrapped = stdenv.mkDerivation rec {
    pname = "cling-unwrapped";
    version = "0.9";

    src = fetchgit {
      url = "http://root.cern/git/clang.git";
      rev = "cling-v0.9";
      sha256 = "sha256-ft1NUIclSiZ9lN3Z3DJCWA0U9q/K1M0TKkZr+PjsFYk=";
    };

    clingSrc = fetchFromGitHub {
      owner = "root-project";
      repo = "cling";
      rev = "v0.9";
      sha256 = "0wx3fi19wfjcph5kclf8108i436y79ddwakrcf0lgxnnxhdjyd29";
    };

    prePatch = ''
      echo "add_llvm_external_project(cling)" >> tools/CMakeLists.txt

      cp -r $clingSrc ./tools/cling
      chmod -R a+w ./tools/cling
    '';

    patches = [
      ./no-clang-cpp.patch

      # https://github.com/root-project/root/commit/286d96b12aad8688b9d8e4b3b5df843dcfb716a8
      ./fix-llvm-dylib-usage.patch

      ./force-install-cling-targets.patch
    ];

    nativeBuildInputs = [ python3 git cmake ];
    buildInputs = [ libffi ncurses zlib ];

    strictDeps = true;

    cmakeFlags = [
      "-DLLVM_BINARY_DIR=${llvmPackages_9.llvm.out}"
      "-DLLVM_CONFIG=${llvmPackages_9.llvm.dev}/bin/llvm-config"
      "-DLLVM_LIBRARY_DIR=${llvmPackages_9.llvm.lib}/lib"
      "-DLLVM_MAIN_INCLUDE_DIR=${fixedLlvmDev}/include"
      "-DLLVM_TABLEGEN_EXE=${llvmPackages_9.llvm.out}/bin/llvm-tblgen"
      "-DLLVM_TOOLS_BINARY_DIR=${llvmPackages_9.llvm.out}/bin"
      "-DLLVM_BUILD_TOOLS=Off"
      "-DLLVM_TOOL_CLING_BUILD=ON"

      "-DLLVM_TARGETS_TO_BUILD=host;NVPTX"
      "-DLLVM_ENABLE_RTTI=ON"

      # Setting -DCLING_INCLUDE_TESTS=ON causes the cling/tools targets to be built;
      # see cling/tools/CMakeLists.txt
      "-DCLING_INCLUDE_TESTS=ON"
      "-DCLANG-TOOLS=OFF"
    ] ++ lib.optionals debug [
      "-DCMAKE_BUILD_TYPE=Debug"
    ] ++ lib.optionals useLLVMLibcxx [
      "-DLLVM_ENABLE_LIBCXX=ON"
      "-DLLVM_ENABLE_LIBCXXABI=ON"
    ];

    CPPFLAGS = if useLLVMLibcxx then [ "-stdlib=libc++" ] else [];

    postInstall = lib.optionalString (!stdenv.isDarwin) ''
      mkdir -p $out/share/Jupyter
      cp -r /build/clang/tools/cling/tools/Jupyter/kernel $out/share/Jupyter
    '';

    dontStrip = debug;

    meta = with lib; {
      description = "The Interactive C++ Interpreter";
      homepage = "https://root.cern/cling/";
      license = with licenses; [ lgpl21 ncsa ];
      maintainers = with maintainers; [ thomasjm ];
      platforms = platforms.unix;
    };
  };

  # Runtime flags for the C++ standard library
  cxxFlags = if useLLVMLibcxx then [
    "-I" "${lib.getDev llvmPackages_9.libcxx}/include/c++/v1"
    "-L" "${llvmPackages_9.libcxx}/lib"
    "-l" "${llvmPackages_9.libcxx}/lib/libc++.so"
  ] else [
    "-I" "${gcc-unwrapped}/include/c++/${gcc-unwrapped.version}"
    "-I" "${gcc-unwrapped}/include/c++/${gcc-unwrapped.version}/x86_64-unknown-linux-gnu"
  ];

  # The flags passed to the wrapped cling should
  # a) prevent it from searching for system include files and libs, and
  # b) provide it with the include files and libs it needs (C and C++ standard library plus
  # its own stuff)

  # These are also exposed as cling.flags because it's handy to be able to pass them to tools
  # that wrap Cling, particularly Jupyter kernels such as xeus-cling and the built-in
  # jupyter-cling-kernel, which use Cling as a library.
  # Thus, if you're packaging a Jupyter kernel, you either need to pass these flags as extra
  # args to xcpp (for xeus-cling) or put them in the environment variable CLING_OPTS
  # (for jupyter-cling-kernel).
  flags = [
    "-nostdinc"
    "-nostdinc++"

    "-isystem" "${lib.getLib unwrapped}/lib/clang/9.0.1/include"
  ]
  ++ cxxFlags
  ++ [
    # System libc
    "-isystem" "${lib.getDev stdenv.cc.libc}/include"

    # cling includes
    "-isystem" "${lib.getDev unwrapped}/include"
  ];

in

runCommand "cling-${unwrapped.version}" {
  nativeBuildInputs = [ makeWrapper ];
  inherit unwrapped flags;
  inherit (unwrapped) meta;
} ''
  makeWrapper $unwrapped/bin/cling $out/bin/cling \
    --add-flags "$flags"
''