Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cling: tidy/simplify + add experimental libc++ support #247253

Merged
merged 3 commits into from
Aug 19, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 67 additions & 34 deletions pkgs/development/interpreters/cling/default.nix
Original file line number Diff line number Diff line change
@@ -1,20 +1,39 @@
{ lib
, stdenv
, python3
, libffi
, git
, cmake
, zlib
, fetchgit
{ cmake
, fetchFromGitHub
, makeWrapper
, runCommand
, fetchgit
, git
, lib
, libffi
, llvmPackages_9
, glibc
, 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
thomasjm marked this conversation as resolved.
Show resolved Hide resolved

# 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
Expand Down Expand Up @@ -58,7 +77,7 @@ let
];

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

strictDeps = true;

Expand All @@ -69,6 +88,7 @@ let
"-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"
Expand All @@ -78,14 +98,22 @@ let
# see cling/tools/CMakeLists.txt
"-DCLING_INCLUDE_TESTS=ON"
"-DCLANG-TOOLS=OFF"
# "--trace-expand"
] ++ 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/";
Expand All @@ -95,44 +123,49 @@ let
};
};

# 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)
# 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/cling.compilerIncludeFlags 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. Both of these use Cling as a library by linking against
# libclingJupyter.so, so the makeWrapper approach to wrapping the binary doesn't work.
# 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)
# (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"
"-I" "${lib.getDev unwrapped}/include"
"-I" "${lib.getLib unwrapped}/lib/clang/9.0.1/include"
];

# Autodetect the include paths for the compiler used to build Cling, in the same way Cling does at
# https://github.com/root-project/cling/blob/v0.7/lib/Interpreter/CIFactory.cpp#L107:L111
# Note: it would be nice to just put the compiler in Cling's PATH and let it do this by itself, but
# unfortunately passing -nostdinc/-nostdinc++ disables Cling's autodetection logic.
compilerIncludeFlags = runCommand "compiler-include-flags.txt" {} ''
export LC_ALL=C
${stdenv.cc}/bin/c++ -xc++ -E -v /dev/null 2>&1 | sed -n -e '/^.include/,''${' -e '/^ \/.*++/p' -e '}' > tmp
sed -e 's/^/-isystem /' -i tmp
tr '\n' ' ' < tmp > $out
'';
# cling includes
"-isystem" "${lib.getDev unwrapped}/include"
];

in

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