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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
{
apple-sdk,
cmake,
fetchFromGitHub,
git,
lib,
libffi,
llvmPackages_20,
makeWrapper,
ncurses,
python3,
zlib,
# The compiler used to *compile* Cling, independent of the LLVM/Clang that
# Cling is built against (the root-project/llvm-project fork checked out below)
# and of llvmPackages_20 (used only for the runtime wrapper flags). The compiler
# can affect the runtime include and lib directories Cling expects, and since
# Cling builds against a fork of Clang we use Clang as the compiler too for
# consistency.
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 ? clangStdenv.hostPlatform.isDarwin,
}:
let
stdenv = clangStdenv;
version = "1.3";
clingSrc = fetchFromGitHub {
owner = "root-project";
repo = "cling";
rev = "v${version}";
sha256 = "sha256-/qCHd9KfPW4dMjktaSdnJG+VDD1lLSI4ZFllTcxWsmc=";
};
unwrapped = stdenv.mkDerivation {
pname = "cling-unwrapped";
inherit version;
src = fetchFromGitHub {
owner = "root-project";
repo = "llvm-project";
rev = "cling-llvm20-20260119-01";
sha256 = "sha256-fv7nrpZ5Dhbf+nW0ED0pkc8NDBXeaBs9MV2TW6o7FGU=";
};
preConfigure = ''
cp -r ${clingSrc} cling-source
# cling 1.3 only builds the clingUserInterface library (which the cling
# driver always links) when CLING_INCLUDE_TESTS is on. Always build it.
chmod -R u+w cling-source
pushd cling-source
patch -p1 < ${./always-build-user-interface.patch}
popd
cd llvm
'';
nativeBuildInputs = [
python3
git
cmake
];
buildInputs = [
libffi
ncurses
zlib
];
strictDeps = true;
cmakeBuildType = if debug then "Debug" else "Release";
cmakeFlags = [
"-DLLVM_EXTERNAL_PROJECTS=cling"
"-DLLVM_EXTERNAL_CLING_SOURCE_DIR=../../cling-source"
"-DLLVM_ENABLE_PROJECTS=clang"
"-DLLVM_TARGETS_TO_BUILD=host;NVPTX"
"-DLLVM_INCLUDE_TESTS=OFF"
"-DLLVM_ENABLE_RTTI=ON"
]
++ lib.optionals useLLVMLibcxx [
"-DLLVM_ENABLE_LIBCXX=ON"
"-DLLVM_ENABLE_LIBCXXABI=ON"
];
env.CPPFLAGS = lib.optionalString useLLVMLibcxx "-stdlib=libc++";
postInstall = ''
mkdir -p $out/share/Jupyter
cp -r ../../cling-source/tools/Jupyter/kernel $out/share/Jupyter
'';
dontStrip = debug;
meta = {
description = "Interactive C++ Interpreter";
mainProgram = "cling";
homepage = "https://root.cern/cling/";
license = with lib.licenses; [
lgpl21
ncsa
];
maintainers = with lib.maintainers; [ thomasjm ];
platforms = lib.platforms.unix;
};
};
# 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++"
"-resource-dir"
"${llvmPackages_20.llvm.lib}/lib"
"-isystem"
"${lib.getLib unwrapped}/lib/clang/20/include"
]
++ lib.optionals useLLVMLibcxx [
"-I"
"${lib.getDev llvmPackages_20.libcxx}/include/c++/v1"
"-L"
"${llvmPackages_20.libcxx}/lib"
"-l"
"${llvmPackages_20.libcxx}/lib/libc++${stdenv.hostPlatform.extensions.sharedLibrary}"
]
++ lib.optionals (!useLLVMLibcxx) [
"-I"
"${gcc-unwrapped}/include/c++/${gcc-unwrapped.version}"
"-I"
"${gcc-unwrapped}/include/c++/${gcc-unwrapped.version}/${stdenv.hostPlatform.config}"
]
++ [
# System libc on Linux
# On Darwin, this is an empty directory, so we need a separate include with
# apple-sdk (see below)
"-isystem"
"${lib.getDev stdenv.cc.libc}/include"
# cling includes
"-isystem"
"${lib.getDev unwrapped}/include"
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
# On Darwin, we need the system includes
"-isystem"
"${apple-sdk}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include"
];
in
stdenv.mkDerivation {
pname = "cling";
version = unwrapped.version;
nativeBuildInputs = [ makeWrapper ];
inherit unwrapped flags;
inherit (unwrapped) meta;
dontUnpack = true;
dontConfigure = true;
buildPhase = ''
runHook preBuild
makeWrapper $unwrapped/bin/cling $out/bin/cling \
--add-flags "$flags"
runHook postBuild
'';
doCheck = true;
checkPhase = ''
runHook preCheck
output=$($out/bin/cling <<EOF
#include <iostream>
std::cout << "hello world" << std::endl
EOF
)
echo "$output" | grep -q "Type C++ code and press enter to run it"
echo "$output" | grep -q "hello world"
runHook postCheck
'';
dontInstall = true;
}
|