diff --git a/java/README.md b/java/README.md index 730eeadb10a..afd69df11ef 100644 --- a/java/README.md +++ b/java/README.md @@ -87,24 +87,18 @@ within the libcudf build environment. ## Statically Linking the CUDA Runtime -If you use the default cmake options libcudart will be dynamically linked to libcudf -which is included. If you do this the resulting jar will have a classifier associated with it -because that jar can only be used with a single version of the CUDA runtime. - -There is experimental work to try and remove that requirement but it is not fully functional -you can build cuDF with `-DCUDA_STATIC_RUNTIME=ON` when running cmake, and similarly -`-DCUDA_STATIC_RUNTIME=ON` when running Maven. This will statically link in the CUDA runtime -and result in a jar with no classifier that should run on any host that has a version of the -driver new enough to support the runtime that this was built with. - -To build the Java bindings with a statically-linked CUDA runtime, use a build command like: -``` -mvn clean install -DCUDA_STATIC_RUNTIME=ON -``` - -You will get errors if the CUDA runtime linking is not consistent. We tried to detect these -up front and stop the build early if there is a mismatch, but there may be some cases we missed -and this can result in some very hard to debug errors. +If you use the default cmake options libcudart will be dynamically linked to libcudf and libcudfjni. +To build with a static CUDA runtime, build libcudf with the `-DCUDA_STATIC_RUNTIME=ON` as a cmake +parameter, and similarly build with `-DCUDA_STATIC_RUNTIME=ON` when building the Java bindings +with Maven. + +### Building with a libcudf Archive + +When statically linking the CUDA runtime, it is recommended to build cuDF as an archive rather than +a shared library, as this allows the Java bindings to only have a single shared library that uses +the CUDA runtime. To build libcudf as an archive, specify `-DBUILD_SHARED_LIBS=OFF` as a cmake +parameter when building libcudf, then specify `-DCUDF_JNI_LIBCUDF_STATIC=ON` when building the Java +bindings with Maven. ## Per-thread Default Stream diff --git a/java/ci/build-in-docker.sh b/java/ci/build-in-docker.sh index df4ca853398..a99b6900830 100755 --- a/java/ci/build-in-docker.sh +++ b/java/ci/build-in-docker.sh @@ -22,6 +22,7 @@ gcc --version PARALLEL_LEVEL=${PARALLEL_LEVEL:-4} SKIP_JAVA_TESTS=${SKIP_JAVA_TESTS:-true} BUILD_CPP_TESTS=${BUILD_CPP_TESTS:-OFF} +ENABLE_CUDA_STATIC_RUNTIME=${ENABLE_CUDA_STATIC_RUNTIME:-ON} ENABLE_PTDS=${ENABLE_PTDS:-ON} RMM_LOGGING_LEVEL=${RMM_LOGGING_LEVEL:-OFF} ENABLE_NVTX=${ENABLE_NVTX:-ON} @@ -36,6 +37,7 @@ OUT_PATH="$WORKSPACE/$OUT" echo "SIGN_FILE: $SIGN_FILE,\ SKIP_JAVA_TESTS: $SKIP_JAVA_TESTS,\ BUILD_CPP_TESTS: $BUILD_CPP_TESTS,\ + ENABLE_CUDA_STATIC_RUNTIME: $ENABLE_CUDA_STATIC_RUNTIME,\ ENABLED_PTDS: $ENABLE_PTDS,\ ENABLE_NVTX: $ENABLE_NVTX,\ ENABLE_GDS: $ENABLE_GDS,\ @@ -52,13 +54,26 @@ export LIBCUDF_KERNEL_CACHE_PATH=/rapids rm -rf "$WORKSPACE/cpp/build" mkdir -p "$WORKSPACE/cpp/build" cd "$WORKSPACE/cpp/build" -cmake .. -DUSE_NVTX=$ENABLE_NVTX -DCUDF_USE_ARROW_STATIC=ON -DCUDF_ENABLE_ARROW_S3=OFF -DBUILD_TESTS=$BUILD_CPP_TESTS -DPER_THREAD_DEFAULT_STREAM=$ENABLE_PTDS -DRMM_LOGGING_LEVEL=$RMM_LOGGING_LEVEL +cmake .. -DUSE_NVTX=$ENABLE_NVTX \ + -DCUDF_USE_ARROW_STATIC=ON \ + -DCUDF_ENABLE_ARROW_S3=OFF \ + -DBUILD_TESTS=$BUILD_CPP_TESTS \ + -DPER_THREAD_DEFAULT_STREAM=$ENABLE_PTDS \ + -DRMM_LOGGING_LEVEL=$RMM_LOGGING_LEVEL \ + -DBUILD_SHARED_LIBS=OFF make -j$PARALLEL_LEVEL make install DESTDIR=$INSTALL_PREFIX ###### Build cudf jar ###### -BUILD_ARG="-Dmaven.repo.local=\"$WORKSPACE/.m2\" -DskipTests=$SKIP_JAVA_TESTS -DPER_THREAD_DEFAULT_STREAM=$ENABLE_PTDS -DRMM_LOGGING_LEVEL=$RMM_LOGGING_LEVEL -DUSE_GDS=$ENABLE_GDS -Dtest=*,!CuFileTest" +BUILD_ARG="-Dmaven.repo.local=\"$WORKSPACE/.m2\"\ + -DskipTests=$SKIP_JAVA_TESTS\ + -DPER_THREAD_DEFAULT_STREAM=$ENABLE_PTDS\ + -DCUDA_STATIC_RUNTIME=$ENABLE_CUDA_STATIC_RUNTIME\ + -DCUDF_JNI_LIBCUDF_STATIC=ON\ + -DRMM_LOGGING_LEVEL=$RMM_LOGGING_LEVEL\ + -DUSE_GDS=$ENABLE_GDS -Dtest=*,!CuFileTest" + if [ "$SIGN_FILE" == true ]; then # Build javadoc and sources only when SIGN_FILE is true BUILD_ARG="$BUILD_ARG -Prelease" diff --git a/java/pom.xml b/java/pom.xml index c5a3bc64fad..ec6968ca761 100755 --- a/java/pom.xml +++ b/java/pom.xml @@ -169,6 +169,7 @@ OFF ALL ON + OFF ${project.build.directory}/cmake-build 1.7.30 0.15.1 @@ -390,6 +391,7 @@ + $sout err> $serr") } - def libcudart = ~/libcudart\\.so\\.(.*)\\s+=>.*/ - def cm = libcudart.matcher(sout) + def nvccout = new StringBuffer(), nvccerr = new StringBuffer() + def nvccproc = 'nvcc --version'.execute() + nvccproc.consumeProcessOutput(nvccout, nvccerr) + nvccproc.waitForOrKill(10000) + def cudaPattern = ~/Cuda compilation tools, release ([0-9]+)/ + def cm = cudaPattern.matcher(nvccout) if (cm.find()) { - if (pom.properties['CUDA_STATIC_RUNTIME'] == 'ON') { - fail("found libcudart when we expect to be statically linked to it") - } def classifier = 'cuda' + cm.group(1) - .replaceFirst(/\\./, '-') // First . becomes a - - .replaceAll(/\\..*$/, '') // Drop all of the subversions from cuda - .replaceAll(/-0$/, '') // If it is a X.0 version, like 10.0 drop the .0 pom.properties['cuda.classifier'] = classifier - println 'WARNING FOUND libcudart this means your jar will only work against a single version of the cuda runtime ' + classifier - } else if (pom.properties['CUDA_STATIC_RUNTIME'] == 'OFF') { - fail('could not find libcudart when we expect to be dynamically linked to it') } else { - pom.properties['cuda.classifier'] = '' - } - - if (pom.properties['CUDA_STATIC_RUNTIME'] == 'ON') { - println 'WARNING RUNNING WITH STATIC LINKING DOES NOT FULLY WORK. USE WITH CAUTION.' + fail('could not find CUDA version') } diff --git a/java/src/main/native/CMakeLists.txt b/java/src/main/native/CMakeLists.txt index a5a6646c7e6..327445bdf0e 100755 --- a/java/src/main/native/CMakeLists.txt +++ b/java/src/main/native/CMakeLists.txt @@ -39,6 +39,7 @@ option(PER_THREAD_DEFAULT_STREAM "Build with per-thread default stream" OFF) option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) option(USE_GDS "Build with GPUDirect Storage (GDS)/cuFile support" OFF) option(CUDF_JNI_ARROW_STATIC "Statically link Arrow" ON) +option(CUDF_JNI_LIBCUDF_STATIC "Link with libcudf.a" OFF) message(VERBOSE "CUDF_JNI: Build with NVTX support: ${USE_NVTX}") message(VERBOSE "CUDF_JNI: Configure CMake to build tests: ${BUILD_TESTS}") @@ -46,6 +47,7 @@ message(VERBOSE "CUDF_JNI: Build with per-thread default stream: ${PER_THREAD_DE message(VERBOSE "CUDF_JNI: Statically link the CUDA runtime: ${CUDA_STATIC_RUNTIME}") message(VERBOSE "CUDF_JNI: Build with GPUDirect Storage support: ${USE_GDS}") message(VERBOSE "CUDF_JNI: Build with static Arrow library: ${CUDF_JNI_ARROW_STATIC}") +message(VERBOSE "CUDF_JNI: Link with libcudf statically: ${CUDF_JNI_LIBCUDF_STATIC}") set(CUDF_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../../../../cpp") if(DEFINED ENV{CUDF_CPP_BUILD_DIR}) @@ -85,7 +87,7 @@ endif() rapids_cmake_build_type("Release") # ################################################################################################## -# * Thrust/CUB/libcudacxx +# * Thrust/CUB # ------------------------------------------------------------------------------------ find_path( THRUST_INCLUDE "thrust" @@ -102,19 +104,6 @@ find_path( message(STATUS "CUB: CUB_INCLUDE set to ${CUB_INCLUDE}") -find_path(LIBCUDACXX_INCLUDE "cuda" HINTS "$ENV{CUDF_ROOT}/_deps/libcudacxx-src/include" - "${CUDF_CPP_BUILD_DIR}/_deps/libcudacxx-src/include" -) - -message(STATUS "LIBCUDACXX: LIBCUDACXX_INCLUDE set to ${LIBCUDACXX_INCLUDE}") - -find_path( - SPDLOG_INCLUDE "spdlog" - HINTS "${CUDF_CPP_BUILD_DIR}/_deps/spdlog-src/include" "$ENV{RMM_ROOT}/_deps/spdlog-src/include" - "$ENV{RMM_ROOT}/include" "$ENV{CONDA_PREFIX}/include" -) - -message(STATUS "SPDLOG: SPDLOG_INCLUDE set to ${SPDLOG_INCLUDE}") # ################################################################################################## # * CUDF ------------------------------------------------------------------------------------------ @@ -139,6 +128,14 @@ find_path( message(STATUS "RMM: RMM_INCLUDE set to ${RMM_INCLUDE}") +find_path( + SPDLOG_INCLUDE "spdlog" + HINTS "${CUDF_CPP_BUILD_DIR}/_deps/spdlog-src/include" "$ENV{RMM_ROOT}/_deps/spdlog-src/include" + "$ENV{RMM_ROOT}/include" "$ENV{CONDA_PREFIX}/include" +) + +message(STATUS "SPDLOG: SPDLOG_INCLUDE set to ${SPDLOG_INCLUDE}") + # ################################################################################################## # * ARROW ----------------------------------------------------------------------------------------- @@ -236,6 +233,18 @@ add_library( src/check_nvcomp_output_sizes.cu ) +if(CUDF_JNI_LIBCUDF_STATIC) + # When linking against libcudf.a, the JNI library will include the old libcudf.so. For + # backwards-compatibility for software that expects to find libcudf.so in the JVM environment + # after cudf has loaded, the JNI code and libcudf.a will be combined into libcudf.so. A stub + # library will be created for libcudfjni.so that will simply require libcudf.so for backwards + # compatibility with software that expects to find libcudfjni.so at runtime. + set_target_properties(cudfjni PROPERTIES OUTPUT_NAME "cudf") + add_library(cudfjnistub SHARED src/emptyfile.cpp) + set_target_properties(cudfjnistub PROPERTIES OUTPUT_NAME "cudfjni") + target_link_libraries(cudfjnistub -Wl,--no-as-needed cudfjni -Wl,--as-needed) +endif() + # ################################################################################################## # * include paths --------------------------------------------------------------------------------- @@ -310,7 +319,14 @@ target_compile_definitions(cudfjni PUBLIC SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${RMM # ################################################################################################## # * link libraries -------------------------------------------------------------------------------- -target_link_libraries(cudfjni PRIVATE ${NVCOMP_LIBRARY} ${CUDF_LIB} ${ARROW_LIBRARY}) +set(CUDF_LINK ${CUDF_LIB}) +if(CUDF_JNI_LIBCUDF_STATIC) + set(CUDF_LINK -Wl,--whole-archive ${CUDF_LIB} -Wl,--no-whole-archive) +endif() + +target_link_libraries( + cudfjni PRIVATE ${CUDF_LINK} ${NVCOMP_LIBRARY} ${ARROW_LIBRARY} CUDA::cuda_driver +) # ################################################################################################## # * cudart options -------------------------------------------------------------------------------- diff --git a/java/src/main/native/src/emptyfile.cpp b/java/src/main/native/src/emptyfile.cpp new file mode 100644 index 00000000000..67fa3acd739 --- /dev/null +++ b/java/src/main/native/src/emptyfile.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Intentionally empty