Skip to content
Merged
Show file tree
Hide file tree
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
7 changes: 7 additions & 0 deletions c/parallel.v2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ if (CCCL_C_PARALLEL_V2_LIBRARY_OUTPUT_DIRECTORY)
)
endif()

if (UNIX AND NOT APPLE)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note the equivalent for $ORIGIN on macos is @loader_path

set_target_properties(
cccl.c.parallel.v2
PROPERTIES BUILD_RPATH_USE_ORIGIN ON INSTALL_RPATH "$ORIGIN"
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
endif()

cccl_get_cub()
cccl_get_cudatoolkit()
cccl_get_thrust()
Expand Down
244 changes: 44 additions & 200 deletions c/parallel.v2/src/hostjit/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,77 +1,49 @@
cmake_minimum_required(VERSION 3.30)

# --------------------------------------------------------------------------
# LLVM/Clang/LLD — fetched via CPM as static libraries
# --------------------------------------------------------------------------
# CPM.cmake is at the cccl repo root: cccl/cmake/CPM.cmake
# From c/parallel.v2/src/hostjit/ that's ../../../../cmake/CPM.cmake
set(_cccl_cmake_dir "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake")
if (EXISTS "${_cccl_cmake_dir}/CPM.cmake")
include("${_cccl_cmake_dir}/CPM.cmake")
else()
message(FATAL_ERROR "CPM.cmake not found at ${_cccl_cmake_dir}/CPM.cmake")
# Find CUDA toolkit (may already be found by parent)
if (NOT CUDAToolkit_FOUND)
find_package(CUDAToolkit)
endif()
Comment on lines +3 to 6

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to guard here, find_package() will exit early if it is already found


if (MSVC AND CMAKE_BUILD_TYPE STREQUAL "Debug")
message(
FATAL_ERROR
"hostjit does not support Debug builds on Windows. "
"The statically-linked LLVM Debug build is too large and causes stack "
"overflows at runtime. Use MinSizeRel, Release, or RelWithDebInfo instead."
# CCCL_SOURCE_DIR points to the cccl repo root
# From c/parallel.v2/src/hostjit -> c/parallel.v2/src -> c/parallel.v2 -> c -> cccl
cmake_path(GET CMAKE_CURRENT_SOURCE_DIR PARENT_PATH _src_dir) # c/parallel.v2/src
cmake_path(GET _src_dir PARENT_PATH _c_parallel_dir) # c/parallel.v2
cmake_path(GET _c_parallel_dir PARENT_PATH _c_dir) # c
cmake_path(GET _c_dir PARENT_PATH _cccl_root) # cccl
set(_hostjit_include_dir "${CMAKE_CURRENT_SOURCE_DIR}/include")

set(LIBNVCC_CPM_CMAKE_PATH "${_cccl_root}/cmake/CPM.cmake")
set(LIBNVCC_HEADER_INSTALL_DESTINATION "cuda/cccl/headers/libnvcc")
set(LIBNVCC_CLANG_HEADER_INSTALL_DESTINATION "cuda/cccl/headers/clang")
Comment on lines +17 to +18

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: Preserve a standard install location for the new public C API header. This override replaces libnvcc’s default include/libnvcc destination with the Python header layout, so non-Python C consumers may not get <libnvcc/libnvcc.h> on the normal include path. Install to both locations or scope this override to Python packaging. As per path instructions, c/**/*: Focus on C API/ABI stability.

Source: Path instructions

if (CCCL_C_PARALLEL_V2_LIBRARY_OUTPUT_DIRECTORY)
set(
LIBNVCC_LIBRARY_OUTPUT_DIRECTORY
"${CCCL_C_PARALLEL_V2_LIBRARY_OUTPUT_DIRECTORY}"
)
endif()

set(HOSTJIT_LLVM_VERSION "llvmorg-22.1.1" CACHE STRING "LLVM git tag to fetch")

# List options must be set before CPMAddPackage
set(LLVM_ENABLE_PROJECTS "clang;lld" CACHE STRING "" FORCE)
set(LLVM_TARGETS_TO_BUILD "X86;NVPTX" CACHE STRING "" FORCE)
add_subdirectory(libnvcc)

CPMAddPackage(
NAME llvm_project
GIT_REPOSITORY https://github.com/llvm/llvm-project.git
GIT_TAG ${HOSTJIT_LLVM_VERSION}
GIT_SHALLOW ON
SOURCE_SUBDIR llvm
EXCLUDE_FROM_ALL YES
OPTIONS
"LLVM_BUILD_LLVM_C_DYLIB OFF"
"LLVM_BUILD_TOOLS OFF"
"LLVM_BUILD_UTILS OFF"
"LLVM_BUILD_RUNTIME OFF"
"LLVM_BUILD_RUNTIMES OFF"
"LLVM_INCLUDE_BENCHMARKS OFF"
"LLVM_INCLUDE_DOCS OFF"
"LLVM_INCLUDE_EXAMPLES OFF"
"LLVM_INCLUDE_RUNTIMES OFF"
"LLVM_INCLUDE_TESTS OFF"
"LLVM_INCLUDE_TOOLS ON"
"LLVM_INCLUDE_UTILS OFF"
"LLVM_ENABLE_ZLIB OFF"
"LLVM_ENABLE_ZSTD OFF"
"LLVM_ENABLE_TERMINFO OFF"
"LLVM_ENABLE_BINDINGS OFF"
"CLANG_BUILD_TOOLS OFF"
"CLANG_ENABLE_ARCMT OFF"
"CLANG_ENABLE_STATIC_ANALYZER OFF"
# Windows does not have an RPATH equivalent. Keep libnvcc.dll in the same
# runtime directory as CCCL's tests/executables so the loader can find it at
# process startup when no explicit library output directory was requested.
if (
WIN32
AND NOT CCCL_C_PARALLEL_V2_LIBRARY_OUTPUT_DIRECTORY
AND DEFINED CCCL_EXECUTABLE_OUTPUT_DIR
)

# Ensure the clang resource directory exists
file(
MAKE_DIRECTORY "${llvm_project_BINARY_DIR}/lib/clang/${LLVM_VERSION_MAJOR}"
)

# Find CUDA toolkit (may already be found by parent)
if (NOT CUDAToolkit_FOUND)
find_package(CUDAToolkit)
set_target_properties(
libnvcc
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CCCL_EXECUTABLE_OUTPUT_DIR}"
)
endif()

# --------------------------------------------------------------------------
# hostjit library
# --------------------------------------------------------------------------
add_library(
cccl.c.parallel.v2.hostjit_lib
compiler.cpp
config.cpp
loader.cpp
jit_compiler.cpp
Expand All @@ -82,129 +54,42 @@ add_library(
codegen/cub_call.cpp
)

# CCCL_SOURCE_DIR points to the cccl repo root
# From c/parallel.v2/src/hostjit -> c/parallel.v2/src -> c/parallel.v2 -> c -> cccl
cmake_path(GET CMAKE_CURRENT_SOURCE_DIR PARENT_PATH _src_dir) # c/parallel.v2/src
cmake_path(GET _src_dir PARENT_PATH _c_parallel_dir) # c/parallel.v2
cmake_path(GET _c_parallel_dir PARENT_PATH _c_dir) # c
cmake_path(GET _c_dir PARENT_PATH _cccl_root) # cccl

target_include_directories(
cccl.c.parallel.v2.hostjit_lib
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${_c_parallel_dir}/include
${llvm_project_SOURCE_DIR}/llvm/include
${llvm_project_BINARY_DIR}/include
${llvm_project_SOURCE_DIR}/clang/include
${llvm_project_BINARY_DIR}/tools/clang/include
${llvm_project_SOURCE_DIR}/lld/include
${llvm_project_BINARY_DIR}/tools/lld/include
PUBLIC ${_hostjit_include_dir} ${_c_parallel_dir}/include
)

target_compile_definitions(
cccl.c.parallel.v2.hostjit_lib
PRIVATE
CCCL_C_EXPERIMENTAL=1
CCCL_SOURCE_DIR="${_cccl_root}"
CLANG_RESOURCE_DIR="${llvm_project_BINARY_DIR}/lib/clang/${LLVM_VERSION_MAJOR}"
CLANG_HEADERS_DIR="${llvm_project_SOURCE_DIR}/clang/lib/Headers"
HOSTJIT_INCLUDE_DIR="${CMAKE_CURRENT_SOURCE_DIR}/include"
HOSTJIT_INCLUDE_DIR="${_hostjit_include_dir}"
)

if (CUDAToolkit_FOUND)
target_include_directories(
if (DEFINED CLANG_HEADERS_DIR)
target_compile_definitions(
cccl.c.parallel.v2.hostjit_lib
PUBLIC ${CUDAToolkit_INCLUDE_DIRS}
PRIVATE CLANG_HEADERS_DIR="${CLANG_HEADERS_DIR}"
)
endif()

if (CUDAToolkit_FOUND)
cmake_path(GET CUDAToolkit_BIN_DIR PARENT_PATH CUDA_TOOLKIT_ROOT_FROM_CMAKE)
target_compile_definitions(
cccl.c.parallel.v2.hostjit_lib
PRIVATE
CUDA_TOOLKIT_PATH="${CUDA_TOOLKIT_ROOT_FROM_CMAKE}"
CUDA_SDK_VERSION="${CUDAToolkit_VERSION_MAJOR}.0"
PRIVATE CUDA_TOOLKIT_PATH="${CUDA_TOOLKIT_ROOT_FROM_CMAKE}"
)
endif()

# Link against LLVM/Clang/LLD
target_link_libraries(
cccl.c.parallel.v2.hostjit_lib
PUBLIC
# LLVM
LLVMCore
LLVMSupport
LLVMIRReader
LLVMMC
LLVMObject
LLVMX86CodeGen
LLVMX86AsmParser
LLVMX86Desc
LLVMX86Info
LLVMNVPTXCodeGen
LLVMNVPTXDesc
LLVMNVPTXInfo
LLVMLinker
LLVMPasses
# Clang
clangAST
clangBasic
clangCodeGen
clangDriver
clangFrontend
clangFrontendTool
clangLex
clangParse
clangSema
clangEdit
clangAnalysis
clangRewrite
clangSerialization
# LLD
$<IF:$<PLATFORM_ID:Windows>,lldCOFF,lldELF>
lldCommon
)

if (NOT WIN32)
target_link_libraries(cccl.c.parallel.v2.hostjit_lib PUBLIC dl)
endif()

target_link_libraries(cccl.c.parallel.v2.hostjit_lib PUBLIC libnvcc)

if (CUDAToolkit_FOUND)
target_link_libraries(
cccl.c.parallel.v2.hostjit_lib
PUBLIC CUDA::cuda_driver CUDA::cudart
)
if (WIN32)
# On Windows, static CUDA libs are built with /MT which conflicts with
# the project's dynamic CRT (/MD). Use dynamic variants instead.
target_link_libraries(
cccl.c.parallel.v2.hostjit_lib
PUBLIC CUDA::nvJitLink CUDA::nvfatbin
)
else()
# Prefer static CUDA libs on Linux for self-contained binaries. If the
# toolchain (e.g. lite/pip CUDA installs or some Docker images) only ships
# the dynamic variants, fall back to those rather than failing configure.
foreach (_cudalib nvJitLink nvptxcompiler nvfatbin)
if (TARGET "CUDA::${_cudalib}_static")
target_link_libraries(
cccl.c.parallel.v2.hostjit_lib
PUBLIC "CUDA::${_cudalib}_static"
)
elseif (TARGET "CUDA::${_cudalib}")
target_link_libraries(
cccl.c.parallel.v2.hostjit_lib
PUBLIC "CUDA::${_cudalib}"
)
else()
message(
FATAL_ERROR
"hostjit needs CUDA::${_cudalib}[_static] but neither variant was "
"found by FindCUDAToolkit. Install the full CUDA toolkit "
"(libnvjitlink-dev / libnvfatbin-dev or equivalent)."
)
endif()
endforeach()
endif()
target_link_libraries(cccl.c.parallel.v2.hostjit_lib PUBLIC CUDA::cudart)
endif()

if (NOT MSVC)
Expand All @@ -216,49 +101,8 @@ set_target_properties(
PROPERTIES CXX_STANDARD 20 POSITION_INDEPENDENT_CODE ON
)

# --------------------------------------------------------------------------
# Install clang headers into wheel (for self-sufficient packaging)
# --------------------------------------------------------------------------
# Clang CUDA headers we still use from the LLVM source tree.
# We DON'T install device_functions, math, or libdevice_declares — our local
# copies in cuda_minimal/ replace them.
set(
_clang_cuda_headers_needed
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/__clang_cuda_math_forward_declares.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/__clang_cuda_builtin_vars.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/__clang_cuda_cmath.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/__clang_cuda_intrinsics.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/__clang_cuda_complex_builtins.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/__clang_cuda_texture_intrinsics.h"
)
install(
FILES ${_clang_cuda_headers_needed}
DESTINATION "cuda/cccl/headers/clang"
)

# Clang builtin C headers needed by our stubs and CUDA toolkit headers.
file(
GLOB _clang_stddef_headers
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/__stddef_*.h"
)
set(
_clang_c_headers
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/limits.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/stddef.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/stdint.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/__stddef_header_macro.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/float.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/__float_header_macro.h"
"${llvm_project_SOURCE_DIR}/clang/lib/Headers/inttypes.h"
${_clang_stddef_headers}
)
install(FILES ${_clang_c_headers} DESTINATION "cuda/cccl/headers/clang")

# Hostjit's minimal CUDA runtime headers (replacements for upstream clang headers)
set(
_hostjit_cuda_minimal_dir
"${CMAKE_CURRENT_SOURCE_DIR}/include/hostjit/cuda_minimal"
)
set(_hostjit_cuda_minimal_dir "${_hostjit_include_dir}/hostjit/cuda_minimal")
file(GLOB _hostjit_cuda_minimal_headers "${_hostjit_cuda_minimal_dir}/*.h")
install(
FILES ${_hostjit_cuda_minimal_headers}
Expand All @@ -274,7 +118,7 @@ install(
)

# On Windows with multi-config generators (Visual Studio), exclude hostjit
# targets from Debug builds — the LLVM Debug build causes stack overflows.
# targets that depend on libnvcc from Debug builds.
if (MSVC)
set_target_properties(
cccl.c.parallel.v2.hostjit_lib
Expand Down
27 changes: 21 additions & 6 deletions c/parallel.v2/src/hostjit/codegen/bitcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,31 @@ bool BitcodeCollector::compile_and_add(const char* source, size_t source_size, c
return true;
}

hostjit::CUDACompiler compiler;
std::string src(source, source_size);
auto result = compiler.compileToDeviceBitcode(src, config_);
if (!result.success)
auto path = make_temp_path("cccl_" + name + "_", unique_id_, ".bc");

std::vector<std::string> options;
config_.appendCommandLineArguments(options);
Comment thread
miscco marked this conversation as resolved.
auto option_ptrs = hostjit::detail::make_libnvcc_option_ptrs(options);

hostjit::detail::LibnvccProgramGuard program;
auto create_result = libnvccCreateProgram(&program.program, src.c_str(), "input.cu");
if (create_result != LIBNVCC_SUCCESS)
{
fprintf(stderr, "\nERROR compiling %s to bitcode: %s\n", name.c_str(), result.diagnostics.c_str());
fprintf(stderr, "\nERROR creating libnvcc program for %s: %s\n", name.c_str(), libnvccGetErrorString(create_result));
return false;
}
auto path = make_temp_path("cccl_" + name + "_", unique_id_, ".bc");
if (write_file(result.bitcode.data(), result.bitcode.size(), path))

auto result = libnvccCompileProgramToDeviceBitcode(
program.program, path.c_str(), static_cast<int>(option_ptrs.size()), option_ptrs.data());
if (result != LIBNVCC_SUCCESS)
{
auto log = hostjit::detail::get_libnvcc_program_log(program.program);
fprintf(stderr, "\nERROR compiling %s to bitcode: %s\n", name.c_str(), log.c_str());
return false;
}

if (std::filesystem::exists(path))
{
config_.device_bitcode_files.push_back(path);
temp_paths_.push_back(path);
Expand Down
Loading
Loading