Skip to content

[mlir] Don't set RPATH for libMLIR #121180

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

makslevental
Copy link
Contributor

@makslevental makslevental commented Dec 27, 2024

By default llvm_add_library calls llvm_setup_rpath, which has the strange effect that even libs inside of install/lib have non-empty self-referential RPATHs; e.g., on Mac

$ llvm-install/lib/libMLIR.dylib | grep RPATH -A4
          cmd LC_RPATH
      cmdsize 32
         path @loader_path/../lib (offset 12)

which is bad/awkward if you want to move libMLIR (like into a wheel...).

Now possibly we want to do this for all shlibs but I think we definitely want to do this for libMLIR because it should have no runtime lib deps.

By default [`llvm_add_library`](https://github.com/llvm/llvm-project/blob/94837c8b5761d20310947be5d2e1e568f67e8c0c/llvm/cmake/modules/AddLLVM.cmake#L681) calls `llvm_setup_rpath`, which has the strange effect that even libs inside of `install/lib` have non-empty self-referential `RPATH`s; e.g., on Mac


```
$ llvm-install/lib/libMLIR.dylib | grep RPATH -A4
          cmd LC_RPATH
      cmdsize 32
         path @loader_path/../lib (offset 12)
```

which is bad/awkward if you want to move `libMLIR` (like into a wheel...).

Now possibly we want to do this for all shlibs but I think we definitely want to do this for `libMLIR` because it should have no runtime lib deps (at least until [this](#108253) lands).
@llvmbot llvmbot added mlir:core MLIR Core Infrastructure mlir labels Dec 27, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 27, 2024

@llvm/pr-subscribers-mlir-core

Author: Maksim Levental (makslevental)

Changes

By default llvm_add_library calls llvm_setup_rpath, which has the strange effect that even libs inside of install/lib have non-empty self-referential RPATHs; e.g., on Mac

$ llvm-install/lib/libMLIR.dylib | grep RPATH -A4
          cmd LC_RPATH
      cmdsize 32
         path @<!-- -->loader_path/../lib (offset 12)

which is bad/awkward if you want to move libMLIR (like into a wheel...).

Now possibly we want to do this for all shlibs but I think we definitely want to do this for libMLIR because it should have no runtime lib deps (at least until this lands).


Full diff: https://github.com/llvm/llvm-project/pull/121180.diff

1 Files Affected:

  • (modified) mlir/tools/mlir-shlib/CMakeLists.txt (+1)
diff --git a/mlir/tools/mlir-shlib/CMakeLists.txt b/mlir/tools/mlir-shlib/CMakeLists.txt
index a33c70c5807bea..293409a51f27ef 100644
--- a/mlir/tools/mlir-shlib/CMakeLists.txt
+++ b/mlir/tools/mlir-shlib/CMakeLists.txt
@@ -35,6 +35,7 @@ if(LLVM_BUILD_LLVM_DYLIB)
     MLIR
     SHARED
     EXCLUDE_FROM_LIBMLIR
+    NO_INSTALL_RPATH
     ${INSTALL_WITH_TOOLCHAIN}
     mlir-shlib.cpp
     ${_OBJECTS}

@llvmbot
Copy link
Member

llvmbot commented Dec 27, 2024

@llvm/pr-subscribers-mlir

Author: Maksim Levental (makslevental)

Changes

By default llvm_add_library calls llvm_setup_rpath, which has the strange effect that even libs inside of install/lib have non-empty self-referential RPATHs; e.g., on Mac

$ llvm-install/lib/libMLIR.dylib | grep RPATH -A4
          cmd LC_RPATH
      cmdsize 32
         path @<!-- -->loader_path/../lib (offset 12)

which is bad/awkward if you want to move libMLIR (like into a wheel...).

Now possibly we want to do this for all shlibs but I think we definitely want to do this for libMLIR because it should have no runtime lib deps (at least until this lands).


Full diff: https://github.com/llvm/llvm-project/pull/121180.diff

1 Files Affected:

  • (modified) mlir/tools/mlir-shlib/CMakeLists.txt (+1)
diff --git a/mlir/tools/mlir-shlib/CMakeLists.txt b/mlir/tools/mlir-shlib/CMakeLists.txt
index a33c70c5807bea..293409a51f27ef 100644
--- a/mlir/tools/mlir-shlib/CMakeLists.txt
+++ b/mlir/tools/mlir-shlib/CMakeLists.txt
@@ -35,6 +35,7 @@ if(LLVM_BUILD_LLVM_DYLIB)
     MLIR
     SHARED
     EXCLUDE_FROM_LIBMLIR
+    NO_INSTALL_RPATH
     ${INSTALL_WITH_TOOLCHAIN}
     mlir-shlib.cpp
     ${_OBJECTS}

@makslevental
Copy link
Contributor Author

ah shoot it libMLIR actually does have a runtime dep on libLLVM

/Users/mlevental/dev_projects/eudsl/llvm-install/lib/libMLIR.dylib:
        @rpath/libMLIR.dylib (compatibility version 0.0.0, current version 0.0.0)
        @rpath/libLLVM.dylib (compatibility version 1.0.0, current version 20.0.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1800.105.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)

@makslevental
Copy link
Contributor Author

makslevental commented Dec 27, 2024

FYI I cooked this up as a workaround:

if(APPLE OR UNIX)
  set(_origin_prefix "\$ORIGIN")
  if(APPLE)
    set(_origin_prefix "@loader_path")
  endif()
  if (STANDALONE_BUILD)
    get_target_property(_mlir_loc MLIR LOCATION)
    get_target_property(_llvm_loc LLVM LOCATION)
  else()
    set(_mlir_loc "$<TARGET_FILE:MLIR>")
    set(_llvm_loc "$<TARGET_FILE:LLVM>")
  endif()
  set(_old_rpath "${_origin_prefix}/../lib${LLVM_LIBDIR_SUFFIX}")
  if(APPLE)
    execute_process(COMMAND install_name_tool -rpath "${_old_rpath}" ${_origin_prefix} "${_mlir_loc}" ERROR_VARIABLE rpath_err)
    execute_process(COMMAND install_name_tool -rpath "${_old_rpath}" ${_origin_prefix} "${_llvm_loc}" ERROR_VARIABLE rpath_err)
    # maybe already updated...
    if (rpath_err AND NOT rpath_err MATCHES "no LC_RPATH load command with path: ${_old_rpath}")
      message(FATAL_ERROR "couldn't update rpath because: ${rpath_err}")
    endif()
  else()
    # sneaky sneaky - undocumented
    file(RPATH_CHANGE FILE "${_mlir_loc}" OLD_RPATH "${_old_rpath}" NEW_RPATH "${_origin_prefix}")
    file(RPATH_CHANGE FILE "${_llvm_loc}" OLD_RPATH "${_old_rpath}" NEW_RPATH "${_origin_prefix}")
  endif()
endif()

@jpienaar
Copy link
Member

Where is the workaround for?

The runtime dep there is, is this due to LLVM dialect/conversions or what? (Basically, do you know if it's real or we are just linking in more than we should there and could refactor build rule)

@makslevental
Copy link
Contributor Author

Where is the workaround for?

The workaround is for moving these libs from out of the /lib - libMLIR should expect libLLVM in the current current dir and libLLVM has no dependencies on other libs (outside of libc) so it also shouldn't be expecting anything in ../lib

The runtime dep there is, is this due to LLVM dialect/conversions or what? (Basically, do you know if it's real or we are just linking in more than we should there and could refactor build rule)

Ya the dep is real probably because of conversions to llvmir but the problem is also real: you cannot move libMLIR even if you move libLLVM too because of the relative rpath

Copy link
Member

@carlocab carlocab left a comment

Choose a reason for hiding this comment

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

ah shoot it libMLIR actually does have a runtime dep on libLLVM

/Users/mlevental/dev_projects/eudsl/llvm-install/lib/libMLIR.dylib:
        @rpath/libMLIR.dylib (compatibility version 0.0.0, current version 0.0.0)
        @rpath/libLLVM.dylib (compatibility version 1.0.0, current version 20.0.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1800.105.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)

Yes, this will break installations configured with LLVM_LINK_LLVM_DYLIB on macOS.

Is there any reason why you can't invoke install_name_tool for yourself if you want to package libMLIR into a wheel?

@makslevental
Copy link
Contributor Author

Is there any reason why you can't invoke install_name_tool for yourself if you want to package libMLIR into a wheel?

I can and did (see my workaround above). My point is possibly this doesn't make sense - why would you have an rpath for the libs themselves that was relative to the install ../lib instead of just ORIGIN/loader_path.

@carlocab
Copy link
Member

carlocab commented Dec 29, 2024

I can and did (see my workaround above).

I did see the comment, but it was not clear whether this was something you wanted to add somewhere here, or something else.

You could probably also skip all that and just build with CMAKE_INSTALL_RPATH=@loader_path. (You might need to make that CMAKE_INSTALL_RPATH='@loader_path;@loader_path/../lib', since I'm not sure if setting this will override the value that LLVM sets. I don't think it does, though.)

My point is possibly this doesn't make sense - why would you have an rpath for the libs themselves that was relative to the install ../lib instead of just ORIGIN/loader_path.

This is a pretty standard idiom for rpaths. For example, it allows you to use the same rpath regardless of whether you're creating an executable you install into bin or for a library you install into lib.

See:

❯ otool -L bin/clang
bin/clang:
	@rpath/libclang-cpp.dylib (compatibility version 0.0.0, current version 0.0.0)
	@rpath/libLLVM.dylib (compatibility version 1.0.0, current version 19.1.6)
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1800.101.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)
❯ otool -l bin/clang | rg -A2 LC_RPATH
          cmd LC_RPATH
      cmdsize 32
         path @loader_path/../lib (offset 12)

@makslevental
Copy link
Contributor Author

makslevental commented Dec 29, 2024

You could probably also skip all that and just build with CMAKE_INSTALL_RPATH=@loader_path. (You might need to make that CMAKE_INSTALL_RPATH='@

that would override the paths for bin/* which of course will break them

This is a pretty standard idiom for rpaths. For example, it allows you to use the same rpath regardless of whether you're creating an executable you install into bin or for a library you install into lib.

The question is very simple: why would you set rpaths for lib/* at all when you could just leave them as ORIGIN/loader_path because they're all already in each other's ORIGIN/loader_path..........

@carlocab
Copy link
Member

The question is very simple

Well, that seems rather rude and condescending. Given that, this is going to be my last reply here.

I tried to give you an answer above, but that seems unacceptable for some reason that's not been explained. My only other suggestion is to look at llvm_setup_rpath, which provides unified handling for rpaths of executables and libraries.

@makslevental
Copy link
Contributor Author

Well, that seems rather rude and condescending

I'm sorry I wasn't trying to be rude. I was trying to restate that my question is exactly asking why we do unified handling for rpaths of executables and libraries, ie why we've made the current design choice we have.

@ScottTodd ScottTodd removed their request for review February 24, 2025 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mlir:core MLIR Core Infrastructure mlir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants