--- a/src/Pure/System/executable.scala Mon Oct 12 07:25:38 2020 +0000
+++ b/src/Pure/System/executable.scala Mon Oct 12 15:58:37 2020 +0200
@@ -9,30 +9,61 @@
object Executable
{
- def libraries(path: Path, mingw: MinGW = MinGW.none): List[Path] =
+ def libraries_closure(exe_path0: Path,
+ mingw: MinGW = MinGW.none,
+ filter: String => Boolean = _ => true): List[String] =
{
- val path1 = path.expand
- val dir = path1.dir
- val exe = path1.base
+ val exe_path = exe_path0.expand
+ val exe_dir = exe_path.dir
+ val exe = exe_path.base
- def command_output(cmd: String): List[String] =
+ val ldd_lines =
{
- val script = mingw.bash_script(cmd + " " + File.bash_path(exe))
- Library.split_lines(Isabelle_System.bash(script, cwd = dir.file).check.out)
+ val ldd = if (Platform.is_macos) "otool -L" else "ldd"
+ val script = mingw.bash_script(ldd + " " + File.bash_path(exe))
+ Library.split_lines(Isabelle_System.bash(script, cwd = exe_dir.file).check.out)
}
- if (Platform.is_macos) {
- val Pattern = """^\s*(.+)\s+\(.*\)$""".r
- for { Pattern(a) <- command_output("otool -L") } yield {
- Library.try_unprefix("@executable_path/", a) match {
- case None => Path.explode(a)
- case Some(b) => dir + Path.explode(b)
- }
+ def lib_name(lib: String): String =
+ Library.take_prefix[Char](_ != '.',
+ Library.take_suffix[Char](_ != '/', lib.toList)._2)._1.mkString
+
+ val libs =
+ if (Platform.is_macos) {
+ val Pattern = """^\s*(/.+)\s+\(.*\)$""".r
+ for {
+ Pattern(lib) <- ldd_lines
+ if !lib.startsWith("@executable_path/") && filter(lib_name(lib))
+ } yield lib
+ }
+ else {
+ val Pattern = """^.*=>\s*(/.+)\s+\(.*\)$""".r
+ val prefix =
+ mingw.root match {
+ case None => ""
+ case Some(path) => path.absolute.implode
+ }
+ for { Pattern(lib) <- ldd_lines if filter(lib_name(lib)) }
+ yield prefix + lib
+ }
+
+ if (libs.nonEmpty) {
+ libs.foreach(lib => File.copy(Path.explode(lib), exe_dir))
+
+ if (Platform.is_linux) {
+ // requires "LDFLAGS=-Wl,-rpath,_DUMMY_"
+ Isabelle_System.bash("chrpath -r '$ORIGIN' " + File.bash_path(exe_path)).check
+ }
+ else if (Platform.is_macos) {
+ val script =
+ ("install_name_tool" ::
+ libs.map(file => "-change " + Bash.string(file) + " " +
+ Bash.string("@executable_path/" + Path.explode(file).file_name) + " " +
+ File.bash_path(exe))).mkString(" ")
+ Isabelle_System.bash(script, cwd = exe_dir.file).check
}
}
- else {
- val Pattern = """^.*=>\s*(.+)\s+\(.*\)$""".r
- for { Pattern(a) <- command_output("ldd") } yield Path.explode(a)
- }
+
+ libs
}
}