From f303ec225c294c695711bead8310d3a7b23baade Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 15 Aug 2019 08:57:50 +0200 Subject: Implement libs_paths symlinking support on Windows Also, temporarily enable libs_paths::link on Windows for testing. --- build2/cc/link-rule.cxx | 34 ++++++++++++++++++++++++++-------- libbuild2/algorithm.cxx | 12 +++--------- libbuild2/install/rule.cxx | 44 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 20 deletions(-) diff --git a/build2/cc/link-rule.cxx b/build2/cc/link-rule.cxx index c9e4ee3..f2ee33f 100644 --- a/build2/cc/link-rule.cxx +++ b/build2/cc/link-rule.cxx @@ -413,6 +413,10 @@ namespace build2 append_ext (ip); li.derive_path (move (ip), tsys == "mingw32" ? "a" : "lib"); } + + //@@ TMP + lk = b; + append_ext (lk); } else if (!v.empty ()) { @@ -2823,7 +2827,8 @@ namespace build2 if (lt.shared_library ()) { - // For shared libraries we may need to create a bunch of symlinks. + // For shared libraries we may need to create a bunch of symlinks (or + // fallback to hardlinks/copies on Windows). // auto ln = [] (const path& f, const path& l) { @@ -2835,16 +2840,29 @@ namespace build2 try { - // The -f part. - // - if (file_exists (l, false /* follow_symlinks */)) - try_rmfile (l); + try + { + // The -f part. + // + if (file_exists (l, false /* follow_symlinks */)) + try_rmfile (l); - mksymlink (f, l); + mkanylink (f, l, true /* copy */); + } + catch (system_error& e) + { + throw pair (entry_type::symlink, + move (e)); + } } - catch (const system_error& e) + catch (const pair& e) { - fail << "unable to create symlink " << l << ": " << e; + const char* w (e.first == entry_type::regular ? "copy" : + e.first == entry_type::symlink ? "symlink" : + e.first == entry_type::other ? "hardlink" : + nullptr); + + fail << "unable to make " << w << ' ' << l << ": " << e.second; } }; diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index 75b0f5a..50db5d3 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -1270,15 +1270,9 @@ namespace build2 } catch (const pair& e) { - const char* w (nullptr); - switch (e.first) - { - case entry_type::regular: w = "copy"; break; - case entry_type::symlink: w = "symlink"; break; - case entry_type::other: w = "hardlink"; break; - default: assert (false); - } - + const char* w (e.first == entry_type::regular ? "copy" : + e.first == entry_type::symlink ? "symlink" : + e.first == entry_type::other ? "hardlink" : nullptr); print (); fail << "unable to make " << w << ' ' << l << ": " << e.second; } diff --git a/libbuild2/install/rule.cxx b/libbuild2/install/rule.cxx index 0b34832..90ee7cb 100644 --- a/libbuild2/install/rule.cxx +++ b/libbuild2/install/rule.cxx @@ -834,8 +834,10 @@ namespace build2 // We can create a symlink directly without calling ln. This, however, // won't work if we have sudo. Also, we would have to deal with existing // destinations (ln's -f takes care of that). So we are just going to - // always use ln. + // always (sudo or not) use ln unless we are on Windows, where we will + // use mkanylink(). // +#ifndef _WIN32 const char* args_a[] = { base.sudo != nullptr ? base.sudo->c_str () : nullptr, "ln", @@ -855,6 +857,40 @@ namespace build2 if (!dry_run) run (pp, args); +#else + if (verb >= 2) + text << "ln -sf " << target.string () << ' ' << rell.string (); + else if (verb && verbose) + text << "install " << rell << " -> " << target; + + if (!dry_run) + try + { + try + { + // The -f part. + // + if (file_exists (target, false /* follow_symlinks */)) + try_rmfile (target); + + mkanylink (target, rell, true /* copy */); + } + catch (system_error& e) + { + throw pair (entry_type::symlink, + move (e)); + } + } + catch (const pair& e) + { + const char* w (e.first == entry_type::regular ? "copy" : + e.first == entry_type::symlink ? "symlink" : + e.first == entry_type::other ? "hardlink" : + nullptr); + + fail << "unable to make " << w << ' ' << target << ": " << e.second; + } +#endif } target_state file_rule:: @@ -1001,7 +1037,8 @@ namespace build2 // have sudo. So we are going to do it both ways. // // While there is no sudo on Windows, deleting things that are being - // used can get complicated. So we will always use rm/rmdir there. + // used can get complicated. So we will always use rm/rmdir from + // MSYS2/Cygwin which go above and beyond to accomplish the mission. // #ifndef _WIN32 if (base.sudo == nullptr) @@ -1090,7 +1127,8 @@ namespace build2 text << "uninstall " << relf; } - // The same story as with uninstall -d. + // The same story as with uninstall -d (on Windows rm is also from + // MSYS2/Cygwin). // #ifndef _WIN32 if (base.sudo == nullptr) -- cgit v1.1