diff --git a/buildlib/pr/main.yml b/buildlib/pr/main.yml index 0e087877a5b..ae212ced0d7 100644 --- a/buildlib/pr/main.yml +++ b/buildlib/pr/main.yml @@ -482,6 +482,32 @@ stages: dependsOn: [Basic_compile] jobs: - template: cuda/cuda.yml + - job: soname_suffix_cuda_ib + displayName: SONAME suffix and deepbind on CUDA/IB + pool: + name: MLNX + demands: + - ucx_gpu_test -equals yes + container: ubuntu2404_doca31_gpunetio + workspace: + clean: all + timeoutInMinutes: 120 + + steps: + - checkout: self + clean: true + fetchDepth: 100 + retryCountOnTaskFailure: 5 + + - bash: | + ./buildlib/tools/builds.sh + displayName: Build SONAME suffix with CUDA/IB + env: + BUILD_ID: "$(Build.BuildId)-$(Build.BuildNumber)" + build_mode: soname_suffix + soname_suffix_check_hw: yes + ucx_gpu: yes + EXECUTOR_NUMBER: $(AZP_AGENT_ID) - stage: AddressSanitizer diff --git a/buildlib/tools/builds.sh b/buildlib/tools/builds.sh index aa308502102..abe3c2dc32d 100755 --- a/buildlib/tools/builds.sh +++ b/buildlib/tools/builds.sh @@ -18,7 +18,7 @@ build_mode=${build_mode:-} build_mode=${build_mode:-long} case "${build_mode}" in -long|short|sanity|compilers) +long|short|sanity|compilers|soname_suffix) ;; *) azure_log_error "Unsupported build mode: ${build_mode}" @@ -507,6 +507,8 @@ check_no_gga() { fi } +source ${realdir}/soname-build.sh + az_init_modules prepare_build @@ -537,11 +539,15 @@ long) 'build_no_openmp' \ 'build_gcc_debug_opt_with_dndebug' \ 'build_clang' \ - 'build_armclang') + 'build_armclang'\ + 'build_soname_suffix') ;; compilers) tests=('build_icc' 'build_pgi') ;; +soname_suffix) + tests=('build_soname_suffix') + ;; esac num_tests=${#tests[@]} diff --git a/buildlib/tools/soname-build.sh b/buildlib/tools/soname-build.sh new file mode 100644 index 00000000000..d3d96334009 --- /dev/null +++ b/buildlib/tools/soname-build.sh @@ -0,0 +1,202 @@ +# +# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# See file LICENSE for terms. +# + +check_elf_soname() { + lib_path=$1 + soname=$2 + + if [ ! -f "$lib_path" ]; then + azure_log_error "Missing library $lib_path" + exit 1 + fi + + if ! readelf -d "$lib_path" | grep -q "Library soname: \\[$soname\\]"; then + azure_log_error "Library $lib_path does not have SONAME $soname" + exit 1 + fi +} + +check_elf_needed() { + binary_path=$1 + needed=$2 + + if [ ! -f "$binary_path" ]; then + azure_log_error "Missing binary $binary_path" + exit 1 + fi + + if ! readelf -d "$binary_path" | grep -q "Shared library: \\[$needed\\]"; then + azure_log_error "Binary $binary_path is not linked to $needed" + exit 1 + fi +} + +check_linker_symlink() { + link_path=$1 + target_pattern=$2 + + if [ ! -L "$link_path" ]; then + azure_log_error "Missing linker symlink $link_path" + exit 1 + fi + + if ! readlink "$link_path" | grep -q "$target_pattern"; then + azure_log_error "Linker symlink $link_path does not point to $target_pattern" + exit 1 + fi +} + +check_uct_module_linkage() { + module=$1 + suffix=$2 + module_path="${ucx_inst}/lib/ucx/libuct_${module}-${suffix}.so.0.0.0" + shift 2 + + check_elf_soname "$module_path" "libuct_${module}-${suffix}.so.0" + for needed in "$@"; do + check_elf_needed "$module_path" "$needed" + done +} + +build_soname_suffix() { + suffix=ci + foreign_build_dir=${ucx_build_dir}/foreign + foreign_inst=${ucx_build_dir}/foreign-install + soname_suffix_check_hw=${soname_suffix_check_hw:-no} + common_soname_config_args=( + --without-java + --without-go + --without-rocm + --without-xpmem + --without-knem + --disable-doxygen-doc + ) + + if [ "${soname_suffix_check_hw}" = "yes" ]; then + echo "==== Enable CUDA and IB for SONAME suffix build ====" + cuda_local_dir="/usr/local/cuda" + have_gdrcopy=no + + if ! nvidia-smi -L; then + azure_log_error "SONAME suffix CUDA/IB check requires a GPU" + exit 1 + fi + + if [ ! -d /dev/infiniband ]; then + azure_log_error "SONAME suffix CUDA/IB check requires IB devices" + exit 1 + fi + + if [ -d "$cuda_local_dir" ] && + find "$cuda_local_dir" -name 'libcudart.so.1[2-9]*' | grep -q .; then + common_soname_config_args+=(--with-cuda=$cuda_local_dir) + elif az_module_load $CUDA_MODULE; then + common_soname_config_args+=(--with-cuda) + else + azure_log_error "SONAME suffix CUDA/IB check requires CUDA" + exit 1 + fi + + if [ -w "/dev/gdrdrv" ] && az_module_load $GDRCOPY_MODULE; then + have_gdrcopy=yes + common_soname_config_args+=(--with-gdrcopy) + else + common_soname_config_args+=(--without-gdrcopy) + fi + + common_soname_config_args+=(--with-verbs --with-rdmacm) + else + common_soname_config_args+=( + --without-verbs + --without-rdmacm + --without-cuda + ) + fi + + echo "==== Build foreign UCX without SONAME suffix ====" + mkdir -p $foreign_build_dir + pushd $foreign_build_dir + ${WORKSPACE}/contrib/configure-release --prefix=$foreign_inst \ + "${common_soname_config_args[@]}" + $MAKEP + $MAKEP install + popd + + echo "==== Build with SONAME suffix and module deepbind ====" + ${WORKSPACE}/contrib/configure-release --prefix=$ucx_inst \ + --enable-gtest \ + --enable-test-apps \ + --with-soname-suffix=$suffix \ + --enable-module-deepbind \ + "${common_soname_config_args[@]}" + $MAKEP + $MAKEP install + + grep "#define UCX_MODULE_FILE_SUFFIX \"-$suffix\"" config.h + grep "#define UCX_MODULE_DLOPEN_DEEPBIND 1" config.h + grep " -lucp-${suffix}" "${ucx_inst}/lib/pkgconfig/ucx.pc" + grep " -lucs-${suffix} -lucm-${suffix}" \ + "${ucx_inst}/lib/pkgconfig/ucx-ucs.pc" + grep " -luct-${suffix}" "${ucx_inst}/lib/pkgconfig/ucx-uct.pc" + for lib in ucs ucp uct; do + grep "lib${lib}-${suffix}.so" \ + "${ucx_inst}/lib/cmake/ucx/ucx-targets.cmake" + done + if [ "${soname_suffix_check_hw}" = "yes" ]; then + grep "#define HAVE_CUDA 1" config.h + grep "#define HAVE_IB 1" config.h + fi + + for lib in ucm ucs uct ucp; do + check_elf_soname \ + "${ucx_inst}/lib/lib${lib}-${suffix}.so.0.0.0" \ + "lib${lib}-${suffix}.so.0" + check_linker_symlink \ + "${ucx_inst}/lib/lib${lib}.so" \ + "lib${lib}-${suffix}\\.so" + done + + check_uct_module_linkage cma $suffix \ + "libuct-${suffix}.so.0" \ + "libucs-${suffix}.so.0" + if [ "${soname_suffix_check_hw}" = "yes" ]; then + for module in cuda ib rdmacm; do + check_uct_module_linkage $module $suffix \ + "libuct-${suffix}.so.0" \ + "libucs-${suffix}.so.0" + done + if [ "${have_gdrcopy}" = "yes" ]; then + check_uct_module_linkage cuda_gdrcopy $suffix \ + "libuct_cuda-${suffix}.so.0" + fi + fi + check_elf_soname \ + "${ucx_build_dir}/test/gtest/ucs/test_module/.libs/libtest_module-${suffix}.so.0.0.0" \ + "libtest_module-${suffix}.so.0" + check_elf_needed \ + "${ucx_inst}/lib/libucp-${suffix}.so.0.0.0" \ + "libuct-${suffix}.so.0" + check_elf_needed \ + "${ucx_inst}/lib/libucp-${suffix}.so.0.0.0" \ + "libucs-${suffix}.so.0" + for lib in ucp uct ucs; do + check_elf_needed \ + "${ucx_inst}/bin/ucx_info" \ + "lib${lib}-${suffix}.so.0" + done + check_elf_needed \ + "${ucx_build_dir}/test/apps/.libs/libtest_ucx_isolation_plugin.so" \ + "libucp-${suffix}.so.0" + + LD_LIBRARY_PATH="${ucx_inst}/lib:${foreign_inst}/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}" \ + "${ucx_build_dir}/test/apps/test_ucx_dlopen_isolation" \ + "${foreign_inst}/lib/libucp.so.0.0.0" \ + "${ucx_build_dir}/test/apps/.libs/libtest_ucx_isolation_plugin.so" \ + "$suffix" deepbind + + GTEST_FILTER=test_sys.module_file_suffix:test_sys.module \ + $MAKE -C test/gtest test +} diff --git a/cmake/ucx-targets.cmake.in b/cmake/ucx-targets.cmake.in index a38daba0c49..1b799a7ea70 100644 --- a/cmake/ucx-targets.cmake.in +++ b/cmake/ucx-targets.cmake.in @@ -11,7 +11,7 @@ if(NOT TARGET ucx::ucs) add_library(ucx::ucs SHARED IMPORTED) set_target_properties(ucx::ucs PROPERTIES - IMPORTED_LOCATION "@libdir@/libucs.so" + IMPORTED_LOCATION "@libdir@/libucs@UCX_LIBRARY_FILE_SUFFIX@.so" INTERFACE_INCLUDE_DIRECTORIES "@includedir@" ) endif() @@ -20,7 +20,7 @@ if(NOT TARGET ucx::ucp) add_library(ucx::ucp SHARED IMPORTED) set_target_properties(ucx::ucp PROPERTIES - IMPORTED_LOCATION "@libdir@/libucp.so" + IMPORTED_LOCATION "@libdir@/libucp@UCX_LIBRARY_FILE_SUFFIX@.so" INTERFACE_INCLUDE_DIRECTORIES "@includedir@" ) endif() @@ -29,7 +29,7 @@ if(NOT TARGET ucx::uct) add_library(ucx::uct SHARED IMPORTED) set_target_properties(ucx::uct PROPERTIES - IMPORTED_LOCATION "@libdir@/libuct.so" + IMPORTED_LOCATION "@libdir@/libuct@UCX_LIBRARY_FILE_SUFFIX@.so" INTERFACE_INCLUDE_DIRECTORIES "@includedir@" ) endif() diff --git a/configure.ac b/configure.ac index 7e553edafd7..ae9c4d78bc3 100644 --- a/configure.ac +++ b/configure.ac @@ -72,6 +72,43 @@ AC_SUBST(EXTRA_VERSION) AC_SUBST(SCM_VERSION) AC_SUBST(SOVERSION) +UCX_LT_RELEASE= +UCX_LIBRARY_FILE_SUFFIX= +ucx_soname_suffix_summary="" +ucx_module_deepbind_summary="no" +AC_ARG_WITH([soname-suffix], + AS_HELP_STRING([--with-soname-suffix=SUFFIX], + [Append SUFFIX to UCX installed shared library names and SONAMEs. Disabled by default. [default=NO]]), + [], [with_soname_suffix=no]) +AS_IF([test "x$with_soname_suffix" != xno], + [AS_IF([test "x$with_soname_suffix" = xyes], + [AC_MSG_ERROR([--with-soname-suffix requires an explicit suffix value])]) + case "$with_soname_suffix" in + @<:@A-Za-z0-9@:>@*) ;; + *) AC_MSG_ERROR([--with-soname-suffix must start with a letter or digit]) ;; + esac + case "$with_soname_suffix" in + *@<:@!A-Za-z0-9_-@:>@*) + AC_MSG_ERROR([--with-soname-suffix must contain only letters, digits, underscores, and dashes]) + ;; + esac + UCX_LIBRARY_FILE_SUFFIX="-$with_soname_suffix" + UCX_LT_RELEASE="-release $with_soname_suffix" + AC_DEFINE_UNQUOTED([UCX_MODULE_FILE_SUFFIX], + ["$UCX_LIBRARY_FILE_SUFFIX"], + [Suffix appended to private UCX module file names]) + ucx_soname_suffix_summary="$with_soname_suffix"]) +AC_SUBST([UCX_LT_RELEASE]) +AC_SUBST([UCX_LIBRARY_FILE_SUFFIX]) + +AC_ARG_ENABLE([module-deepbind], + AS_HELP_STRING([--enable-module-deepbind], + [Load UCX modules with RTLD_DEEPBIND. Intended for private UCX bundles. Disabled by default. [default=NO]]), + [], [enable_module_deepbind=no]) +AS_IF([test "x$enable_module_deepbind" = xyes], + [AS_IF([test "x$with_soname_suffix" = xno], + [AC_MSG_ERROR([--enable-module-deepbind requires --with-soname-suffix])])]) + AC_PROG_CC AC_PROG_CXX AC_OPENMP @@ -87,6 +124,14 @@ AC_FUNC_STRERROR_R AC_PATH_TOOL([PKG_CONFIG], [pkg-config], [pkg-config]) +AS_IF([test "x$enable_module_deepbind" = xyes], + [AC_CHECK_DECLS([RTLD_DEEPBIND], + [AC_DEFINE([UCX_MODULE_DLOPEN_DEEPBIND], [1], + [Load UCX modules with RTLD_DEEPBIND]) + ucx_module_deepbind_summary="yes"], + [AC_MSG_ERROR([--enable-module-deepbind requires RTLD_DEEPBIND support from ])], + [[#include ]])]) + # # Define SHARED_LIB preprocessor macro when building a shared library @@ -435,6 +480,8 @@ AC_MSG_NOTICE([ Multi-thread: ${mt_enable}]) AC_MSG_NOTICE([ MPI tests: ${mpi_enable}]) AC_MSG_NOTICE([ VFS support: ${vfs_enable}]) AC_MSG_NOTICE([ Devel headers: ${enable_devel_headers}]) +AC_MSG_NOTICE([ SONAME suffix: ${ucx_soname_suffix_summary}]) +AC_MSG_NOTICE([ Module deepbind: ${ucx_module_deepbind_summary}]) AC_MSG_NOTICE([io_demo CUDA support: ${with_iodemo_cuda}]) AC_MSG_NOTICE([ Bindings: <$(echo ${build_bindings}|tr ':' ' ') >]) AC_MSG_NOTICE([ UCS modules: <$(echo ${ucs_modules}|tr ':' ' ') >]) diff --git a/src/tools/perf/cuda/Makefile.am b/src/tools/perf/cuda/Makefile.am index 61541586233..0b146a5eaa6 100644 --- a/src/tools/perf/cuda/Makefile.am +++ b/src/tools/perf/cuda/Makefile.am @@ -9,7 +9,8 @@ if HAVE_CUDA module_LTLIBRARIES = libucx_perftest_cuda.la libucx_perftest_cuda_la_CPPFLAGS = $(BASE_CPPFLAGS) $(CUDA_CPPFLAGS) libucx_perftest_cuda_la_CFLAGS = $(BASE_CFLAGS) $(CUDA_CFLAGS) $(LT_CFLAGS) -libucx_perftest_cuda_la_LDFLAGS = $(CUDA_LDFLAGS) -version-info $(SOVERSION) +libucx_perftest_cuda_la_LDFLAGS = $(CUDA_LDFLAGS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) libucx_perftest_cuda_la_LIBADD = $(CUDART_LIBS) libucx_perftest_cuda_la_SOURCES = cuda_alloc.c diff --git a/src/tools/perf/mad/Makefile.am b/src/tools/perf/mad/Makefile.am index 346021cf787..ce02247fc19 100644 --- a/src/tools/perf/mad/Makefile.am +++ b/src/tools/perf/mad/Makefile.am @@ -10,7 +10,8 @@ module_LTLIBRARIES = libucx_perftest_mad.la libucx_perftest_mad_la_CPPFLAGS = $(BASE_CPPFLAGS) libucx_perftest_mad_la_CFLAGS = $(BASE_CFLAGS) $(MAD_CFLAGS) \ $(OPENMP_CFLAGS) $(LT_CFLAGS) -libucx_perftest_mad_la_LDFLAGS = $(MAD_LDFLAGS) -version-info $(SOVERSION) +libucx_perftest_mad_la_LDFLAGS = $(MAD_LDFLAGS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) libucx_perftest_mad_la_LIBADD = $(MAD_LIBS) libucx_perftest_mad_la_SOURCES = perftest_mad.c diff --git a/src/tools/perf/rocm/Makefile.am b/src/tools/perf/rocm/Makefile.am index 7ad7ca10fd9..ec198223b73 100644 --- a/src/tools/perf/rocm/Makefile.am +++ b/src/tools/perf/rocm/Makefile.am @@ -11,6 +11,7 @@ libucx_perftest_rocm_la_CPPFLAGS = $(BASE_CPPFLAGS) $(HIP_CPPFLAGS) libucx_perftest_rocm_la_CFLAGS = $(BASE_CFLAGS) $(HIP_CFLAGS) \ $(LT_CFLAGS) libucx_perftest_rocm_la_LDFLAGS = $(HIP_LDFLAGS) $(HIP_LIBS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) \ $(patsubst %, -Xlinker %, -L$(ROCM_ROOT)/lib -rpath $(ROCM_ROOT)/hip/lib -rpath $(ROCM_ROOT)/lib) \ $(patsubst %, -Xlinker %, --enable-new-dtags) \ $(patsubst %, -Xlinker %, -rpath $(ROCM_ROOT)/lib64) diff --git a/src/tools/perf/ze/Makefile.am b/src/tools/perf/ze/Makefile.am index c09c7c84e5d..830bc3aa47d 100644 --- a/src/tools/perf/ze/Makefile.am +++ b/src/tools/perf/ze/Makefile.am @@ -10,7 +10,8 @@ module_LTLIBRARIES = libucx_perftest_ze.la libucx_perftest_ze_la_CPPFLAGS = $(BASE_CPPFLAGS) $(ZE_CPPFLAGS) libucx_perftest_ze_la_CFLAGS = $(BASE_CFLAGS) $(ZE_CFLAGS) \ $(LT_CFLAGS) -libucx_perftest_ze_la_LDFLAGS = $(ZE_LDFLAGS) $(ZE_LIBS) -version-info $(SOVERSION) +libucx_perftest_ze_la_LDFLAGS = $(ZE_LDFLAGS) $(ZE_LIBS) \ + -version-info $(SOVERSION) $(UCX_LT_RELEASE) libucx_perftest_ze_la_SOURCES = ze_alloc.c include $(top_srcdir)/config/module.am diff --git a/src/ucm/Makefile.am b/src/ucm/Makefile.am index 7866aa0ac13..285dfac144f 100644 --- a/src/ucm/Makefile.am +++ b/src/ucm/Makefile.am @@ -11,7 +11,7 @@ SUBDIRS = . cuda rocm ze lib_LTLIBRARIES = libucm.la libucm_ladir = $(includedir)/ucm libucm_la_LDFLAGS = $(UCM_MODULE_LDFLAGS) \ - -ldl -version-info $(SOVERSION) + -ldl -version-info $(SOVERSION) $(UCX_LT_RELEASE) libucm_la_CPPFLAGS = $(BASE_CPPFLAGS) -DUCM_MALLOC_PREFIX=ucm_dl libucm_la_CFLAGS = $(BASE_CFLAGS) $(CFLAGS_NO_DEPRECATED) \ $(LT_CFLAGS) diff --git a/src/ucm/cuda/Makefile.am b/src/ucm/cuda/Makefile.am index e8eda0f5065..d60e4dfd79c 100644 --- a/src/ucm/cuda/Makefile.am +++ b/src/ucm/cuda/Makefile.am @@ -12,7 +12,7 @@ libucm_cuda_la_CFLAGS = $(BASE_CFLAGS) $(CUDA_CFLAGS) $(LT_CFLAGS) libucm_cuda_la_LIBADD = ../libucm.la $(CUDA_LIBS) $(CUDART_LIBS) libucm_cuda_la_LDFLAGS = $(UCM_MODULE_LDFLAGS) \ $(patsubst %, -Xlinker %, $(CUDA_LDFLAGS)) \ - -version-info $(SOVERSION) + -version-info $(SOVERSION) $(UCX_LT_RELEASE) noinst_HEADERS = \ cudamem.h diff --git a/src/ucm/rocm/Makefile.am b/src/ucm/rocm/Makefile.am index 57545b3567f..dabe8c2c3fc 100644 --- a/src/ucm/rocm/Makefile.am +++ b/src/ucm/rocm/Makefile.am @@ -13,6 +13,7 @@ libucm_rocm_la_CFLAGS = $(BASE_CFLAGS) $(ROCM_CFLAGS) $(LT_CFLAGS) libucm_rocm_la_LIBADD = ../libucm.la libucm_rocm_la_LDFLAGS = $(UCM_MODULE_LDFLAGS) \ $(ROCM_LDFLAGS) $(ROCM_LIBS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) \ $(patsubst %, -Xlinker %, -L$(ROCM_ROOT)/lib -rpath $(ROCM_ROOT)/hip/lib -rpath $(ROCM_ROOT)/lib) \ $(patsubst %, -Xlinker %, --enable-new-dtags) \ $(patsubst %, -Xlinker %, -rpath $(ROCM_ROOT)/lib64) diff --git a/src/ucm/ze/Makefile.am b/src/ucm/ze/Makefile.am index 208ab94633d..8dc07ece95c 100644 --- a/src/ucm/ze/Makefile.am +++ b/src/ucm/ze/Makefile.am @@ -12,7 +12,7 @@ libucm_ze_la_CFLAGS = $(BASE_CFLAGS) $(ZE_CFLAGS) $(LT_CFLAGS) libucm_ze_la_LIBADD = ../libucm.la $(ZE_LIBS) libucm_ze_la_LDFLAGS = $(UCM_MODULE_LDFLAGS) \ $(patsubst %, -Xlinker %, $(ZE_LDFLAGS)) \ - -version-info $(SOVERSION) + -version-info $(SOVERSION) $(UCX_LT_RELEASE) noinst_HEADERS = \ zemem.h diff --git a/src/ucp/Makefile.am b/src/ucp/Makefile.am index 0d570535234..4886d0975cd 100644 --- a/src/ucp/Makefile.am +++ b/src/ucp/Makefile.am @@ -10,7 +10,7 @@ lib_LTLIBRARIES = libucp.la libucp_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) libucp_la_LIBS = libucp_la_CPPFLAGS = $(BASE_CPPFLAGS) -libucp_la_LDFLAGS = -ldl -version-info $(SOVERSION) +libucp_la_LDFLAGS = -ldl -version-info $(SOVERSION) $(UCX_LT_RELEASE) libucp_la_LIBADD = ../ucs/libucs.la ../uct/libuct.la libucp_ladir = $(includedir)/ucp diff --git a/src/ucs/Makefile.am b/src/ucs/Makefile.am index 96460695743..fd3b47e498b 100644 --- a/src/ucs/Makefile.am +++ b/src/ucs/Makefile.am @@ -16,7 +16,7 @@ libucs_la_CPPFLAGS = $(BASE_CPPFLAGS) $(BFD_CPPFLAGS) \ -DUCX_MODULE_DIR=\"$(moduledir)\" \ -DUCX_CONFIG_DIR=\"$(ucx_config_dir)\" libucs_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) -libucs_la_LDFLAGS = -ldl $(BFD_LDFLAGS) -version-info $(SOVERSION) +libucs_la_LDFLAGS = -ldl $(BFD_LDFLAGS) -version-info $(SOVERSION) $(UCX_LT_RELEASE) libucs_ladir = $(includedir)/ucs libucs_la_LIBADD = $(LIBM) $(top_builddir)/src/ucm/libucm.la $(BFD_LIBS) @@ -130,6 +130,7 @@ noinst_HEADERS = \ sys/compiler.h \ sys/lib.h \ sys/module.h \ + sys/module_int.h \ sys/sys.h \ sys/iovec.h \ sys/iovec.inl \ diff --git a/src/ucs/signal/Makefile.am b/src/ucs/signal/Makefile.am index 96a6e8079e5..9b3da4fc551 100644 --- a/src/ucs/signal/Makefile.am +++ b/src/ucs/signal/Makefile.am @@ -8,6 +8,6 @@ lib_LTLIBRARIES = libucs_signal.la libucs_signal_la_CPPFLAGS = $(BASE_CPPFLAGS) libucs_signal_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) -libucs_signal_la_LDFLAGS = -version-info $(SOVERSION) +libucs_signal_la_LDFLAGS = -version-info $(SOVERSION) $(UCX_LT_RELEASE) libucs_signal_la_LIBADD = $(top_builddir)/src/ucs/libucs.la libucs_signal_la_SOURCES = signal.c diff --git a/src/ucs/sys/module.c b/src/ucs/sys/module.c index 2489d5429dd..49eb5b3cdd3 100644 --- a/src/ucs/sys/module.c +++ b/src/ucs/sys/module.c @@ -13,6 +13,7 @@ #endif #include "module.h" +#include "module_int.h" #include #include @@ -245,6 +246,9 @@ static int ucs_module_flags_to_dlopen_mode(unsigned flags) } else { mode |= RTLD_LOCAL; } +#if defined(UCX_MODULE_DLOPEN_DEEPBIND) && defined(RTLD_DEEPBIND) + mode |= RTLD_DEEPBIND; +#endif return mode; } @@ -324,6 +328,7 @@ static void ucs_module_load_from_dir(const char *dir, const char *framework, } ucs_module_filename_to_base(entry->d_name, base, sizeof(base)); + ucs_module_normalize_base(base, prefix); if (strchr(base + prefix_len, '_') != NULL) { ucs_module_debug("module name contains '_': %s, skipping", base + prefix_len); continue; diff --git a/src/ucs/sys/module_int.h b/src/ucs/sys/module_int.h new file mode 100644 index 00000000000..c83011704fe --- /dev/null +++ b/src/ucs/sys/module_int.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) NVIDIA CORPORATION & AFFILIATES, 2026. ALL RIGHTS RESERVED. + * + * See file LICENSE for terms. + */ + +#ifndef UCS_MODULE_INT_H_ +#define UCS_MODULE_INT_H_ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + + +static inline void ucs_module_normalize_base(char *base, const char *prefix) +{ +#ifdef UCX_MODULE_FILE_SUFFIX + size_t prefix_len = strlen(prefix); + size_t suffix_len = strlen(UCX_MODULE_FILE_SUFFIX); + size_t base_len = strlen(base); + + /* + * Module files are first filtered by the lib_ prefix. Strip + * the configured private file suffix only for bases that still match that + * framework prefix after removing the shared-library extension. + */ + if ((base_len > (prefix_len + suffix_len)) && + !strncmp(base, prefix, prefix_len) && + !strcmp(base + base_len - suffix_len, UCX_MODULE_FILE_SUFFIX)) { + base[base_len - suffix_len] = '\0'; + } +#endif +} + + +#endif diff --git a/src/ucs/ucx-ucs.pc.in b/src/ucs/ucx-ucs.pc.in index 7b952bd3b51..6fecede7b29 100644 --- a/src/ucs/ucx-ucs.pc.in +++ b/src/ucs/ucx-ucs.pc.in @@ -14,5 +14,5 @@ Name: @PACKAGE@-ucs Description: Unified Communication X Library UCS module Version: @VERSION@ Cflags: -I${includedir} -Libs: -L${libdir} -lucs -lucm +Libs: -L${libdir} -lucs@UCX_LIBRARY_FILE_SUFFIX@ -lucm@UCX_LIBRARY_FILE_SUFFIX@ Libs.private: -Wl,--undefined=ucs_init @BFD_LIBS@ @BFD_LDFLAGS@ @BFD_DEPS@ -ldl -lrt -lm -pthread diff --git a/src/ucs/vfs/fuse/Makefile.am b/src/ucs/vfs/fuse/Makefile.am index bb4c555f7db..07ccd999a5c 100644 --- a/src/ucs/vfs/fuse/Makefile.am +++ b/src/ucs/vfs/fuse/Makefile.am @@ -12,7 +12,8 @@ libucs_fuse_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) libucs_fuse_la_LIBADD = $(FUSE3_LIBS) \ $(top_builddir)/src/ucs/vfs/sock/libucs_vfs_sock.la \ $(top_builddir)/src/ucs/libucs.la -libucs_fuse_la_LDFLAGS = $(FUSE3_LDFLAGS) -version-info $(SOVERSION) +libucs_fuse_la_LDFLAGS = $(FUSE3_LDFLAGS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) libucs_fuse_la_SOURCES = vfs_fuse.c PKG_CONFIG_NAME=fuse diff --git a/src/uct/Makefile.am b/src/uct/Makefile.am index 66a19b22df1..5c28b4b6eb3 100644 --- a/src/uct/Makefile.am +++ b/src/uct/Makefile.am @@ -13,7 +13,7 @@ lib_LTLIBRARIES = libuct.la libuct_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) libuct_la_CPPFLAGS = $(BASE_CPPFLAGS) libuct_la_LIBADD = $(top_builddir)/src/ucs/libucs.la -libuct_la_LDFLAGS = -ldl -version-info $(SOVERSION) +libuct_la_LDFLAGS = -ldl -version-info $(SOVERSION) $(UCX_LT_RELEASE) libuct_ladir = $(includedir)/uct nobase_dist_libuct_la_HEADERS = \ diff --git a/src/uct/cuda/Makefile.am b/src/uct/cuda/Makefile.am index f161fa60b63..bd11d39fd09 100644 --- a/src/uct/cuda/Makefile.am +++ b/src/uct/cuda/Makefile.am @@ -10,7 +10,8 @@ SUBDIRS = . gdr_copy module_LTLIBRARIES = libuct_cuda.la libuct_cuda_la_CPPFLAGS = $(BASE_CPPFLAGS) $(CUDA_CPPFLAGS) libuct_cuda_la_CFLAGS = $(BASE_CFLAGS) $(CUDA_CFLAGS) $(LT_CFLAGS) -libuct_cuda_la_LDFLAGS = $(CUDA_LDFLAGS) -version-info $(SOVERSION) +libuct_cuda_la_LDFLAGS = $(CUDA_LDFLAGS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) libuct_cuda_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la \ $(CUDA_LIBS) $(NVML_LIBS) diff --git a/src/uct/cuda/gdr_copy/Makefile.am b/src/uct/cuda/gdr_copy/Makefile.am index 06ad3dfb9bc..ef36786afbb 100644 --- a/src/uct/cuda/gdr_copy/Makefile.am +++ b/src/uct/cuda/gdr_copy/Makefile.am @@ -8,7 +8,9 @@ if HAVE_GDR_COPY module_LTLIBRARIES = libuct_cuda_gdrcopy.la libuct_cuda_gdrcopy_la_CPPFLAGS = $(BASE_CPPFLAGS) $(GDR_COPY_CPPFLAGS) libuct_cuda_gdrcopy_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) -libuct_cuda_gdrcopy_la_LDFLAGS = $(GDR_COPY_LDFLAGS) -version-info $(SOVERSION) +libuct_cuda_gdrcopy_la_LDFLAGS = $(GDR_COPY_LDFLAGS) \ + -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) libuct_cuda_gdrcopy_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/cuda/libuct_cuda.la \ $(GDR_COPY_LIBS) diff --git a/src/uct/gaudi/Makefile.am b/src/uct/gaudi/Makefile.am index 120ce95f1b5..c43fc6c2673 100644 --- a/src/uct/gaudi/Makefile.am +++ b/src/uct/gaudi/Makefile.am @@ -12,7 +12,9 @@ libuct_gaudi_la_CPPFLAGS = $(BASE_CPPFLAGS) $(GAUDI_CPPFLAGS) libuct_gaudi_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) libuct_gaudi_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la -libuct_gaudi_la_LDFLAGS = $(GAUDI_LDFLAGS) $(GAUDI_LIBS) -version-info $(SOVERSION) +libuct_gaudi_la_LDFLAGS = $(GAUDI_LDFLAGS) $(GAUDI_LIBS) \ + -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) noinst_HEADERS = \ base/scal.h \ diff --git a/src/uct/ib/Makefile.am b/src/uct/ib/Makefile.am index 340f2ca1a82..922804b3e7b 100644 --- a/src/uct/ib/Makefile.am +++ b/src/uct/ib/Makefile.am @@ -12,7 +12,8 @@ libuct_ib_la_CPPFLAGS = $(BASE_CPPFLAGS) $(IBVERBS_CPPFLAGS) libuct_ib_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) libuct_ib_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la -libuct_ib_la_LDFLAGS = $(IBVERBS_LDFLAGS) -version-info $(SOVERSION) +libuct_ib_la_LDFLAGS = $(IBVERBS_LDFLAGS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) noinst_HEADERS = \ base/ib_device.h \ diff --git a/src/uct/ib/efa/Makefile.am b/src/uct/ib/efa/Makefile.am index 9c3a4612dee..c838de6a588 100644 --- a/src/uct/ib/efa/Makefile.am +++ b/src/uct/ib/efa/Makefile.am @@ -12,7 +12,8 @@ libuct_ib_efa_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la \ $(top_builddir)/src/uct/ib/libuct_ib.la libuct_ib_efa_la_LDFLAGS = $(EFA_LIB) $(IBVERBS_LDFLAGS) \ - -version-info $(SOVERSION) + -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) libuct_ib_efa_la_SOURCES = base/ib_efa_md.c \ srd/srd_iface.c \ diff --git a/src/uct/ib/mlx5/Makefile.am b/src/uct/ib/mlx5/Makefile.am index 5072bd92cd1..cd81f55e72e 100644 --- a/src/uct/ib/mlx5/Makefile.am +++ b/src/uct/ib/mlx5/Makefile.am @@ -10,7 +10,9 @@ SUBDIRS = . gdaki module_LTLIBRARIES = libuct_ib_mlx5.la libuct_ib_mlx5_la_CPPFLAGS = $(BASE_CPPFLAGS) $(IBVERBS_CPPFLAGS) libuct_ib_mlx5_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) -libuct_ib_mlx5_la_LDFLAGS = $(LIB_MLX5) $(IBVERBS_LDFLAGS) -version-info $(SOVERSION) +libuct_ib_mlx5_la_LDFLAGS = $(LIB_MLX5) $(IBVERBS_LDFLAGS) \ + -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) libuct_ib_mlx5_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la \ $(top_builddir)/src/uct/ib/libuct_ib.la diff --git a/src/uct/ib/mlx5/gdaki/Makefile.am b/src/uct/ib/mlx5/gdaki/Makefile.am index b61368588ba..ba0f54375c0 100644 --- a/src/uct/ib/mlx5/gdaki/Makefile.am +++ b/src/uct/ib/mlx5/gdaki/Makefile.am @@ -10,7 +10,8 @@ libuct_ib_mlx5_gda_la_CPPFLAGS = $(BASE_CPPFLAGS) $(IBVERBS_CPPFLAGS) \ $(CUDA_CPPFLAGS) libuct_ib_mlx5_gda_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) $(CUDA_CFLAGS) libuct_ib_mlx5_gda_la_LDFLAGS = $(IBVERBS_LDFLAGS) $(CUDA_LDFLAGS) \ - -version-info $(SOVERSION) + -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) libuct_ib_mlx5_gda_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la \ $(top_builddir)/src/uct/ib/libuct_ib.la \ diff --git a/src/uct/ib/rdmacm/Makefile.am b/src/uct/ib/rdmacm/Makefile.am index 8cfcf54d0d5..205ba9c55ab 100644 --- a/src/uct/ib/rdmacm/Makefile.am +++ b/src/uct/ib/rdmacm/Makefile.am @@ -19,7 +19,9 @@ if HAVE_DEVX libuct_rdmacm_la_LIBADD += $(LIB_MLX5) endif -libuct_rdmacm_la_LDFLAGS = $(IBVERBS_LDFLAGS) $(RDMACM_LDFLAGS) -version-info $(SOVERSION) +libuct_rdmacm_la_LDFLAGS = $(IBVERBS_LDFLAGS) $(RDMACM_LDFLAGS) \ + -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) noinst_HEADERS = \ rdmacm_cm.h \ diff --git a/src/uct/rocm/Makefile.am b/src/uct/rocm/Makefile.am index 310ca2e83be..6da5ec54f93 100644 --- a/src/uct/rocm/Makefile.am +++ b/src/uct/rocm/Makefile.am @@ -11,6 +11,7 @@ libuct_rocm_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) libuct_rocm_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la libuct_rocm_la_LDFLAGS = $(ROCM_LDFLAGS) $(ROCM_LIBS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) \ $(patsubst %, -Xlinker %, -L$(ROCM_ROOT)/lib -rpath $(ROCM_ROOT)/hip/lib -rpath $(ROCM_ROOT)/lib) \ $(patsubst %, -Xlinker %, --enable-new-dtags) \ $(patsubst %, -Xlinker %, -rpath $(ROCM_ROOT)/lib64) diff --git a/src/uct/sm/mm/xpmem/Makefile.am b/src/uct/sm/mm/xpmem/Makefile.am index 17d36043912..7f497bbd4c2 100644 --- a/src/uct/sm/mm/xpmem/Makefile.am +++ b/src/uct/sm/mm/xpmem/Makefile.am @@ -11,7 +11,8 @@ libuct_xpmem_la_CFLAGS = $(BASE_CFLAGS) $(XPMEM_CFLAGS) $(LT_CFLAGS) libuct_xpmem_la_CPPFLAGS = $(BASE_CPPFLAGS) libuct_xpmem_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la -libuct_xpmem_la_LDFLAGS = $(XPMEM_LIBS) -version-info $(SOVERSION) +libuct_xpmem_la_LDFLAGS = $(XPMEM_LIBS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) libuct_xpmem_la_SOURCES = mm_xpmem.c PKG_CONFIG_NAME=xpmem diff --git a/src/uct/sm/scopy/cma/Makefile.am b/src/uct/sm/scopy/cma/Makefile.am index cddba4dcd74..a9f71c3aece 100644 --- a/src/uct/sm/scopy/cma/Makefile.am +++ b/src/uct/sm/scopy/cma/Makefile.am @@ -10,7 +10,7 @@ libuct_cma_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) libuct_cma_la_CPPFLAGS = $(BASE_CPPFLAGS) libuct_cma_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la -libuct_cma_la_LDFLAGS = -version-info $(SOVERSION) +libuct_cma_la_LDFLAGS = -version-info $(SOVERSION) $(UCX_LT_RELEASE) noinst_HEADERS = \ cma_iface.h \ diff --git a/src/uct/sm/scopy/knem/Makefile.am b/src/uct/sm/scopy/knem/Makefile.am index a0ee227ca0a..3aeace057f1 100644 --- a/src/uct/sm/scopy/knem/Makefile.am +++ b/src/uct/sm/scopy/knem/Makefile.am @@ -10,7 +10,7 @@ libuct_knem_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) libuct_knem_la_CPPFLAGS = $(BASE_CPPFLAGS) $(KNEM_CPPFLAGS) libuct_knem_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la -libuct_knem_la_LDFLAGS = -version-info $(SOVERSION) $(UCT_MODULE_LDFLAGS) +libuct_knem_la_LDFLAGS = -version-info $(SOVERSION) $(UCX_LT_RELEASE) noinst_HEADERS = \ knem_ep.h \ diff --git a/src/uct/ucx-uct.pc.in b/src/uct/ucx-uct.pc.in index 55b9946fe1a..e388d24f66e 100644 --- a/src/uct/ucx-uct.pc.in +++ b/src/uct/ucx-uct.pc.in @@ -14,6 +14,6 @@ Name: @PACKAGE@-uct Description: Unified Communication X Library UCT module Version: @VERSION@ Cflags: -I${includedir} -Libs: -L${libdir} -luct +Libs: -L${libdir} -luct@UCX_LIBRARY_FILE_SUFFIX@ Libs.private: -Wl,--undefined=uct_init Requires: @PACKAGE@-ucs diff --git a/src/uct/ugni/Makefile.am b/src/uct/ugni/Makefile.am index c654131c6e3..bc1cf1d0516 100644 --- a/src/uct/ugni/Makefile.am +++ b/src/uct/ugni/Makefile.am @@ -11,7 +11,8 @@ libuct_ugni_la_CFLAGS = $(BASE_CFLAGS) $(CRAY_UGNI_CFLAGS) \ $(LT_CFLAGS) libuct_ugni_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la -libuct_ugni_la_LDFLAGS = $(CRAY_UGNI_LIBS) -version-info $(SOVERSION) +libuct_ugni_la_LDFLAGS = $(CRAY_UGNI_LIBS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) noinst_HEADERS = \ base/ugni_def.h \ diff --git a/src/uct/ze/Makefile.am b/src/uct/ze/Makefile.am index c2ef39c07b9..6b7ea473bab 100644 --- a/src/uct/ze/Makefile.am +++ b/src/uct/ze/Makefile.am @@ -13,6 +13,7 @@ libuct_ze_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) libuct_ze_la_LIBADD = $(top_builddir)/src/ucs/libucs.la \ $(top_builddir)/src/uct/libuct.la libuct_ze_la_LDFLAGS = $(ZE_LDFLAGS) $(ZE_LIBS) -version-info $(SOVERSION) \ + $(UCX_LT_RELEASE) \ $(patsubst %, -Xlinker %, -L$(ZE_ROOT)/lib -rpath $(ZE_ROOT)/hip/lib -rpath $(ZE_ROOT)/lib) \ $(patsubst %, -Xlinker %, --enable-new-dtags) \ $(patsubst %, -Xlinker %, -rpath $(ZE_ROOT)/lib64) diff --git a/test/apps/Makefile.am b/test/apps/Makefile.am index dbd98ba60a4..f6dd7d1a4aa 100644 --- a/test/apps/Makefile.am +++ b/test/apps/Makefile.am @@ -19,10 +19,20 @@ noinst_PROGRAMS = \ test_dlopen_cfg_print \ test_init_mt \ test_memtrack_limit \ - test_hooks + test_hooks \ + test_ucx_dlopen_isolation + +noinst_LTLIBRARIES = libtest_ucx_isolation_plugin.la objdir_apps = $(shell sed -n -e 's/^objdir=\(.*\)$$/\1/p' $(LIBTOOL)) +libtest_ucx_isolation_plugin_la_SOURCES = test_ucx_isolation_plugin.c +libtest_ucx_isolation_plugin_la_CPPFLAGS = $(BASE_CPPFLAGS) +libtest_ucx_isolation_plugin_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) +libtest_ucx_isolation_plugin_la_LDFLAGS = -module -avoid-version \ + -rpath $(abs_builddir) +libtest_ucx_isolation_plugin_la_LIBADD = $(top_builddir)/src/ucp/libucp.la + test_hooks_SOURCES = test_hooks.c test_hooks_CPPFLAGS = $(BASE_CPPFLAGS) \ -DLIB_PATH=$(abs_top_builddir)/src/ucs/$(objdir_apps)/libucs.so @@ -63,6 +73,11 @@ test_dlopen_cfg_print_CPPFLAGS = $(BASE_CPPFLAGS) -g \ test_dlopen_cfg_print_CFLAGS = $(BASE_CFLAGS) test_dlopen_cfg_print_LDADD = -ldl +test_ucx_dlopen_isolation_SOURCES = test_ucx_dlopen_isolation.c +test_ucx_dlopen_isolation_CPPFLAGS = $(BASE_CPPFLAGS) +test_ucx_dlopen_isolation_CFLAGS = $(BASE_CFLAGS) +test_ucx_dlopen_isolation_LDADD = -ldl + test_init_mt_SOURCES = test_init_mt.c test_init_mt_CPPFLAGS = $(BASE_CPPFLAGS) test_init_mt_CFLAGS = $(BASE_CFLAGS) $(OPENMP_CFLAGS) diff --git a/test/apps/test_ucx_dlopen_isolation.c b/test/apps/test_ucx_dlopen_isolation.c new file mode 100644 index 00000000000..a576d1bb51f --- /dev/null +++ b/test/apps/test_ucx_dlopen_isolation.c @@ -0,0 +1,188 @@ +/** + * Copyright (c) NVIDIA CORPORATION & AFFILIATES, 2026. ALL RIGHTS RESERVED. + * + * See file LICENSE for terms. + */ + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include + + +typedef const char *(*test_ucx_isolation_plugin_ucp_path_func_t)(void); +typedef int (*test_ucx_isolation_plugin_init_func_t)(void); + +typedef struct { + const char *needle; + unsigned count; +} test_ucx_dlopen_isolation_find_arg_t; + + +static int find_loaded_library(struct dl_phdr_info *info, size_t size, + void *arg) +{ + test_ucx_dlopen_isolation_find_arg_t *find_arg = arg; + + if ((info->dlpi_name != NULL) && + (strstr(info->dlpi_name, find_arg->needle) != NULL)) { + ++find_arg->count; + printf("found loaded library matching %s: %s\n", + find_arg->needle, info->dlpi_name); + } + + return 0; +} + +static int check_loaded_library(const char *needle) +{ + test_ucx_dlopen_isolation_find_arg_t find_arg = { + .needle = needle, + .count = 0 + }; + + dl_iterate_phdr(find_loaded_library, &find_arg); + if (find_arg.count == 0) { + fprintf(stderr, "could not find loaded library matching %s\n", needle); + return -1; + } + + return 0; +} + +static int make_soname(char *buffer, size_t max, const char *lib, + const char *suffix) +{ + int ret; + + ret = snprintf(buffer, max, "lib%s-%s.so.0", lib, suffix); + if ((ret < 0) || ((size_t)ret >= max)) { + fprintf(stderr, "suffix is too long: %s\n", suffix); + return -1; + } + + return 0; +} + +static void usage(const char *program) +{ + fprintf(stderr, "Usage: %s " + " [deepbind]\n", program); +} + +int main(int argc, char **argv) +{ + test_ucx_isolation_plugin_ucp_path_func_t plugin_ucp_path; + test_ucx_isolation_plugin_init_func_t plugin_init; + const char *foreign_libucp_path; + const char *plugin_path; + const char *private_suffix; + const char *ucp_path; + char private_libucp[64]; + char private_libuct[64]; + char private_libucs[64]; + int flags; + void *foreign_handle; + void *plugin_handle; + + if ((argc != 4) && (argc != 5)) { + usage(argv[0]); + return -1; + } + + foreign_libucp_path = argv[1]; + plugin_path = argv[2]; + private_suffix = argv[3]; + + flags = RTLD_NOW | RTLD_LOCAL; + if (argc == 5) { + if (strcmp(argv[4], "deepbind") != 0) { + usage(argv[0]); + return -1; + } +#ifdef RTLD_DEEPBIND + flags |= RTLD_DEEPBIND; +#else + fprintf(stderr, "RTLD_DEEPBIND is not supported on this platform\n"); + return -1; +#endif + } + + if ((make_soname(private_libucp, sizeof(private_libucp), "ucp", + private_suffix) != 0) || + (make_soname(private_libuct, sizeof(private_libuct), "uct", + private_suffix) != 0) || + (make_soname(private_libucs, sizeof(private_libucs), "ucs", + private_suffix) != 0)) { + return -1; + } + + printf("opening foreign UCX library '%s'\n", foreign_libucp_path); + foreign_handle = dlopen(foreign_libucp_path, RTLD_NOW | RTLD_GLOBAL); + if (foreign_handle == NULL) { + fprintf(stderr, "failed to open %s: %s\n", foreign_libucp_path, + dlerror()); + return -1; + } + + if (check_loaded_library("libucp.so.0") != 0) { + return -1; + } + + printf("opening UCX consumer plugin '%s'\n", plugin_path); + plugin_handle = dlopen(plugin_path, flags); + if (plugin_handle == NULL) { + fprintf(stderr, "failed to open %s: %s\n", plugin_path, dlerror()); + return -1; + } + + plugin_ucp_path = + (test_ucx_isolation_plugin_ucp_path_func_t) + dlsym(plugin_handle, "test_ucx_isolation_plugin_ucp_path"); + plugin_init = + (test_ucx_isolation_plugin_init_func_t) + dlsym(plugin_handle, "test_ucx_isolation_plugin_init"); + if ((plugin_ucp_path == NULL) || (plugin_init == NULL)) { + fprintf(stderr, "failed to resolve plugin test entry points: %s\n", + dlerror()); + return -1; + } + + ucp_path = plugin_ucp_path(); + if (ucp_path == NULL) { + fprintf(stderr, "plugin could not resolve its UCX provider path\n"); + return -1; + } + + printf("plugin UCX provider path: %s\n", ucp_path); + if (strstr(ucp_path, private_libucp) == NULL) { + fprintf(stderr, "plugin resolved UCX provider from %s, expected %s\n", + ucp_path, private_libucp); + return -1; + } + + if ((check_loaded_library(private_libucp) != 0) || + (check_loaded_library(private_libuct) != 0) || + (check_loaded_library(private_libucs) != 0) || + (check_loaded_library("libucp.so.0") != 0)) { + return -1; + } + + if (plugin_init() != 0) { + fprintf(stderr, "plugin UCX initialization failed\n"); + return -1; + } + + dlclose(plugin_handle); + dlclose(foreign_handle); + + printf("SUCCESS\n"); + return 0; +} diff --git a/test/apps/test_ucx_isolation_plugin.c b/test/apps/test_ucx_isolation_plugin.c new file mode 100644 index 00000000000..ecf94162562 --- /dev/null +++ b/test/apps/test_ucx_isolation_plugin.c @@ -0,0 +1,49 @@ +/** + * Copyright (c) NVIDIA CORPORATION & AFFILIATES, 2026. ALL RIGHTS RESERVED. + * + * See file LICENSE for terms. + */ + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + + +const char *test_ucx_isolation_plugin_ucp_path(void) +{ + const char *(*version_fn)(void) = ucp_get_version_string; + Dl_info info; + + if (!dladdr((void*)version_fn, &info) || (info.dli_fname == NULL)) { + return NULL; + } + + return info.dli_fname; +} + +int test_ucx_isolation_plugin_init(void) +{ + ucp_context_h context; + ucp_params_t params; + ucs_status_t status; + + params.field_mask = UCP_PARAM_FIELD_FEATURES; + params.features = UCP_FEATURE_TAG; + + status = ucp_init_version(UCP_API_MAJOR, UCP_API_MINOR, ¶ms, NULL, + &context); + if (status != UCS_OK) { + fprintf(stderr, "ucp_init_version() failed: %s\n", + ucs_status_string(status)); + return -1; + } + + ucp_cleanup(context); + return 0; +} diff --git a/test/gtest/ucs/test_module/Makefile.am b/test/gtest/ucs/test_module/Makefile.am index 0fc07b0a432..cbfeda09646 100644 --- a/test/gtest/ucs/test_module/Makefile.am +++ b/test/gtest/ucs/test_module/Makefile.am @@ -7,7 +7,7 @@ module_LTLIBRARIES = libtest_module.la libtest_module_la_CPPFLAGS = $(BASE_CPPFLAGS) libtest_module_la_CFLAGS = $(BASE_CFLAGS) $(LT_CFLAGS) -libtest_module_la_LDFLAGS = -version-info $(SOVERSION) +libtest_module_la_LDFLAGS = -version-info $(SOVERSION) $(UCX_LT_RELEASE) libtest_module_la_SOURCES = test_module.c include $(top_srcdir)/config/module.am diff --git a/test/gtest/ucs/test_sys.cc b/test/gtest/ucs/test_sys.cc index fd4372bbccb..942aa2a141a 100644 --- a/test/gtest/ucs/test_sys.cc +++ b/test/gtest/ucs/test_sys.cc @@ -7,6 +7,7 @@ #include extern "C" { #include +#include #include #include #include @@ -144,6 +145,24 @@ UCS_TEST_F(test_sys, module) { EXPECT_EQ(1, test_module_loaded); } +UCS_TEST_F(test_sys, module_file_suffix) { +#ifndef UCX_MODULE_FILE_SUFFIX + UCS_TEST_SKIP_R("module file suffix is not configured"); +#else + char suffixed_base[] = "libtest_module" UCX_MODULE_FILE_SUFFIX; + char plain_base[] = "libtest_module"; + char other_base[] = "libother_module" UCX_MODULE_FILE_SUFFIX; + + ucs_module_normalize_base(suffixed_base, "libtest_"); + ucs_module_normalize_base(plain_base, "libtest_"); + ucs_module_normalize_base(other_base, "libtest_"); + + EXPECT_STREQ("libtest_module", suffixed_base); + EXPECT_STREQ("libtest_module", plain_base); + EXPECT_STREQ("libother_module" UCX_MODULE_FILE_SUFFIX, other_base); +#endif +} + UCS_TEST_F(test_sys, dirname) { char path[] = "/sys/devices/pci0000:00/0000:00:00.0"; test_dirname(path, 3, "/sys"); diff --git a/ucx.pc.in b/ucx.pc.in index 703a5950bf5..d39ed3d3418 100644 --- a/ucx.pc.in +++ b/ucx.pc.in @@ -14,6 +14,6 @@ Name: @PACKAGE@ Description: Unified Communication X Library Version: @VERSION@ Cflags: -I${includedir} -Libs: -L${libdir} -lucp +Libs: -L${libdir} -lucp@UCX_LIBRARY_FILE_SUFFIX@ Libs.private: -Wl,--undefined=ucp_global_init Requires: @PACKAGE@-uct, @PACKAGE@-ucs