diff options
-rw-r--r-- | build2/install/init.cxx | 6 | ||||
-rw-r--r-- | build2/install/rule.cxx | 86 |
2 files changed, 60 insertions, 32 deletions
diff --git a/build2/install/init.cxx b/build2/install/init.cxx index bfe3c7c..f91e9dc 100644 --- a/build2/install/init.cxx +++ b/build2/install/init.cxx @@ -189,8 +189,10 @@ namespace build2 // way we distinguish between the two is via the presence/absence of // the trailing directory separator. // - v.insert<path> ("install"); - v.insert<string> ("install.mode"); + v.insert<path> ("install", false, variable_visibility::project); + v.insert<string> ("install.mode", false, variable_visibility::project); + v.insert<bool> ("install.subdirs", false, + variable_visibility::project); } // Register our alias and file rules. diff --git a/build2/install/rule.cxx b/build2/install/rule.cxx index dcb6686..bef874a 100644 --- a/build2/install/rule.cxx +++ b/build2/install/rule.cxx @@ -23,7 +23,7 @@ namespace build2 // template <typename P, typename T> static const P* - lookup (T& t, const string& var) + lookup_install (T& t, const string& var) { auto l (t[var]); @@ -86,7 +86,7 @@ namespace build2 // First determine if this target should be installed (called // "installable" for short). // - if (lookup<path> (t, "install") == nullptr) + if (lookup_install<path> (t, "install") == nullptr) // If this is the update pre-operation, signal that we don't match so // that some other rule can take care of it. // @@ -236,8 +236,8 @@ namespace build2 // If not NULL, then point to the corresponding install.* value. // - const string* sudo = nullptr; - const path* cmd = nullptr; + const string* sudo = nullptr; + const path* cmd = nullptr; const strings* options = nullptr; const string* mode = nullptr; const string* dir_mode = nullptr; @@ -256,6 +256,36 @@ namespace build2 using install_dirs = vector<install_dir>; + // Calculate a subdirectory based on l's location (*.subdirs) and if not + // empty add it to install_dirs. Return the new last element. + // + static install_dir& + resolve_subdir (install_dirs& rs, target& t, scope& s, const lookup& l) + { + // Find the scope from which this value came and use as a base + // to calculate the subdirectory. + // + for (const scope* p (&s); p != nullptr; p = p->parent_scope ()) + { + if (l.belongs (*p)) // Ok since no target/type in lookup. + { + // The target can be in out or src. + // + const dir_path& d ( + (t.out.empty () ? t.dir : t.out).leaf (p->out_path ())); + + // Add it as another leading directory rather than modifying + // the last one directly; somehow, it feels right. + // + if (!d.empty ()) + rs.emplace_back (rs.back ().dir / d, rs.back ()); + break; + } + } + + return rs.back (); + } + // Resolve installation directory name to absolute directory path. Return // all the super-directories leading up to the destination (last). // @@ -274,7 +304,8 @@ namespace build2 // const string& sn (*d.begin ()); const string var ("install." + sn); - if (const dir_path* dn = lookup<dir_path> (t.base_scope (), var)) + if (const dir_path* dn = + lookup_install<dir_path> (t.base_scope (), var)) { rs = resolve (t, *dn, &var); d = rs.back ().dir / dir_path (++d.begin (), d.end ()); @@ -301,28 +332,7 @@ namespace build2 if (auto l = s[*var + ".subdirs"]) { if (cast<bool> (l)) - { - // Find the scope from which this value came and use as a base - // to calculate the subdirectory. - // - for (const scope* p (&s); p != nullptr; p = p->parent_scope ()) - { - if (l.belongs (*p)) // Ok since no target/type in lookup. - { - // The target can be in out or src. - // - const dir_path& d ( - (t.out.empty () ? t.dir : t.out).leaf (p->out_path ())); - - // Add it as another leading directory rather than modifying - // the last one directly; somehow, it feels right. - // - rs.emplace_back (r->dir / d, rs.back ()); - r = &rs.back (); - break; - } - } - } + r = &resolve_subdir (rs, t, s, l); } } @@ -567,6 +577,14 @@ namespace build2 // install_dirs ids (resolve (t, d)); + // Handle install.subdirs if one was specified. + // + if (auto l = t["install.subdirs"]) + { + if (cast<bool> (l)) + resolve_subdir (ids, t, t.base_scope (), l); + } + // Create leading directories. Note that we are using the leading // directory (if there is one) for the creation information (mode, // sudo, etc). @@ -595,7 +613,7 @@ namespace build2 // for (target* m (t.member); m != nullptr; m = m->member) { - if (const path* p = lookup<path> (*m, "install")) + if (const path* p = lookup_install<path> (*m, "install")) install_target (static_cast<file&> (*m), *p, false); } @@ -733,7 +751,7 @@ namespace build2 if (verb == 1 && verbose) { if (t != nullptr) - text << "uninstall " << t; + text << "uninstall " << *t; else text << "uninstall " << relf; } @@ -802,6 +820,14 @@ namespace build2 // install_dirs ids (resolve (t, d)); + // Handle install.subdirs if one was specified. + // + if (auto l = t["install.subdirs"]) + { + if (cast<bool> (l)) + resolve_subdir (ids, t, t.base_scope (), l); + } + // Remove extras and the target itself. // const install_dir& id (ids.back ()); @@ -838,7 +864,7 @@ namespace build2 // for (target* m (t.member); m != nullptr; m = m->member) { - if (const path* p = lookup<path> (*m, "install")) + if (const path* p = lookup_install<path> (*m, "install")) r |= uninstall_target (static_cast<file&> (*m), *p, r != target_state::changed); |