diff --git a/dqclibs/libs/CMakeLists.txt b/dqclibs/libs/CMakeLists.txt index e28ce61..4523f74 100644 --- a/dqclibs/libs/CMakeLists.txt +++ b/dqclibs/libs/CMakeLists.txt @@ -107,6 +107,19 @@ elseif (APPLE) set(CMAKE_SKIP_BUILD_RPATH True) set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) set(CMAKE_INSTALL_RPATH "@loader_path") + # Stamp each library's install name as @loader_path/.dylib rather than + # the @rpath/.dylib that CMAKE_MACOSX_RPATH gives by default. + # + # With an @rpath install name, dyld satisfies a dependency from ANY already + # loaded image whose install name matches -- it does not consult this + # target's LC_RPATH first. pyscf ships libcgto/libnp_helper/libcvhf/libpbc + # with exactly these names, so importing pyscf and dqclibs into one process + # cross-links the two stacks according to import order. Observed: a dlopen + # failure one way (missing _GTO_aopair_lazy_contract), and the other way a + # SIGSEGV in the FT lattice-sum driver plus PBC integrals silently returning + # wrong numbers. pyscf itself is immune precisely because it uses + # @loader_path here. + set(CMAKE_INSTALL_NAME_DIR "@loader_path") else () set(CMAKE_SKIP_BUILD_RPATH True) set(CMAKE_BUILD_WITH_INSTALL_RPATH True) diff --git a/dqclibs/libs/libcint/CMakeLists.txt b/dqclibs/libs/libcint/CMakeLists.txt index e7f6ba3..cc307a7 100644 --- a/dqclibs/libs/libcint/CMakeLists.txt +++ b/dqclibs/libs/libcint/CMakeLists.txt @@ -146,6 +146,28 @@ set_target_properties(cint PROPERTIES SOVERSION ${cint_SOVERSION} # LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR} ) +if (APPLE) + # Stamp the install name as @loader_path/libcint..dylib. + # + # WHY POST_BUILD and not INSTALL_NAME_DIR: this target is built through + # ExternalProject_Add straight into CMAKE_LIBRARY_OUTPUT_DIRECTORY, with no + # install() step that would re-stamp it, so INSTALL_NAME_DIR never applies. + # Setting MACOSX_RPATH OFF instead makes cmake fall back to the absolute + # build-tree path, which is worse than the @rpath it replaces. Rewriting the + # id after the link is the only form that survives both. + # + # It matters because every other dqclibs library links this one, and pyscf + # ships identically-named libraries: an @rpath id lets dyld satisfy the + # dependency from whichever image loaded first, which silently corrupts PBC + # integrals. libcint.dylib / libcint.4.dylib / libcint.4.0.7.dylib also all + # share this single id, so they collide with each other too. + add_custom_command(TARGET cint POST_BUILD + COMMAND install_name_tool -id + "@loader_path/libcint.${cint_SOVERSION}.dylib" $ + COMMAND codesign -f -s - $ || true + VERBATIM) +endif () + target_link_libraries(cint ${BLAS_LIBRARIES}) if(QUADMATH_FOUND) target_link_libraries(cint quadmath)