aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-08-23 14:43:27 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-08-23 14:43:27 +0200
commitfeb55ebfdc536c32de2c173d108df5ee0004da44 (patch)
tree2f3cc4c9656c3308398bad1dd333c762aed403a4
parent5e2f713a1828f2795b85f5343f62ecafff0d475a (diff)
Add support for installing into a different file name
Now the install variable is a path, not dir_path. If it is a directory (ends with a trailing slash), then the target is installed into this directory with the same name. Otherwise, the entire path is used as the installation destination.
-rw-r--r--build2/install/init.cxx8
-rw-r--r--build2/install/rule.cxx73
-rw-r--r--build2/install/utility6
3 files changed, 56 insertions, 31 deletions
diff --git a/build2/install/init.cxx b/build2/install/init.cxx
index 221cfcf..e301f08 100644
--- a/build2/install/init.cxx
+++ b/build2/install/init.cxx
@@ -183,7 +183,13 @@ namespace build2
// Note: not overridable.
//
- v.insert<dir_path> ("install");
+ // The install variable is a path, not dir_path, since it can be used
+ // to both specify the target directory (to install with the same file
+ // name) or target file (to install with a different name). And the
+ // 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");
}
diff --git a/build2/install/rule.cxx b/build2/install/rule.cxx
index 7365cae..257f14b 100644
--- a/build2/install/rule.cxx
+++ b/build2/install/rule.cxx
@@ -21,8 +21,8 @@ namespace build2
// if the value is the special 'false' name (which means do not install).
// T is either scope or target.
//
- template <typename T>
- static const dir_path*
+ template <typename P, typename T>
+ static const P*
lookup (T& t, const string& var)
{
auto l (t[var]);
@@ -30,7 +30,7 @@ namespace build2
if (!l)
return nullptr;
- const dir_path& r (cast<dir_path> (l));
+ const P& r (cast<P> (l));
return r.simple () && r.string () == "false" ? nullptr : &r;
}
@@ -61,9 +61,11 @@ namespace build2
// the install module (and therefore has no file_rule registered).
// The typical example would be the 'tests' subproject.
//
+ // Note: not the same as lookup() above.
+ //
auto l (pt["install"]);
- if (l && cast<dir_path> (l).string () == "false")
+ if (l && cast<path> (l).string () == "false")
{
l5 ([&]{trace << "ignoring " << pt;});
continue;
@@ -84,7 +86,7 @@ namespace build2
// First determine if this target should be installed (called
// "installable" for short).
//
- if (lookup (t, "install") == nullptr)
+ if (lookup<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.
//
@@ -149,7 +151,7 @@ namespace build2
// See if we were explicitly instructed not to touch this target.
//
auto l ((*pt)["install"]);
- if (l && cast<dir_path> (l).string () == "false")
+ if (l && cast<path> (l).string () == "false")
continue;
build2::match (a, *pt);
@@ -266,14 +268,14 @@ namespace build2
//
const string& sn (*d.begin ());
const string var ("install." + sn);
- if (const dir_path* dn = lookup (t.base_scope (), var))
+ if (const dir_path* dn = lookup<dir_path> (t.base_scope (), var))
{
rs = resolve (t, *dn, &var);
d = rs.back ().dir / dir_path (++d.begin (), d.end ());
rs.emplace_back (move (d.normalize ()), rs.back ());
}
else
- fail << "unknown installation directory name " << sn <<
+ fail << "unknown installation directory name '" << sn << "'" <<
info << "did you forget to specify config." << var << "?";
}
@@ -436,21 +438,28 @@ namespace build2
}
}
- // install <file> <dir>
+ // install <file> <dir>/
+ // install <file> <file>
//
// If verbose is false, then only print the command at verbosity level 2
// or higher.
//
static void
- install (const install_dir& base, file& t, bool verbose = true)
+ install (const install_dir& base,
+ const path& name,
+ file& t,
+ bool verbose = true)
{
path relf (relative (t.path ()));
- dir_path reld (
+ path reld (
cast<string> ((*global_scope)["build.host.class"]) == "windows"
? msys_path (base.dir)
: relative (base.dir));
+ if (!name.empty ())
+ reld /= name;
+
cstrings args;
if (base.sudo != nullptr)
@@ -496,8 +505,11 @@ namespace build2
file& t (static_cast<file&> (xt));
assert (!t.path ().empty ()); // Should have been assigned by update.
- auto install_target = [](file& t, const dir_path& d, bool verbose)
+ auto install_target = [](file& t, const path& p, bool verbose)
{
+ bool n (!p.to_directory ());
+ dir_path d (n ? p.directory () : path_cast<dir_path> (p));
+
// Resolve target directory.
//
install_dirs ids (resolve (t, d));
@@ -516,7 +528,7 @@ namespace build2
if (auto l = t["install.mode"])
id.mode = &cast<string> (l);
- install (id, t, verbose);
+ install (id, n ? p.leaf () : path (), t, verbose);
};
// First handle installable prerequisites.
@@ -527,14 +539,14 @@ namespace build2
//
for (target* m (t.member); m != nullptr; m = m->member)
{
- if (const dir_path* d = lookup (*m, "install"))
- install_target (static_cast<file&> (*m), *d, false);
+ if (const path* p = lookup<path> (*m, "install"))
+ install_target (static_cast<file&> (*m), *p, false);
}
// Finally install the target itself (since we got here we know the
// install variable is there).
//
- install_target (t, cast<dir_path> (t["install"]), true);
+ install_target (t, cast<path> (t["install"]), true);
return (r |= target_state::changed);
}
@@ -638,7 +650,8 @@ namespace build2
return r;
}
- // uninstall <file> <dir>
+ // uninstall <file> <dir>/
+ // uninstall <file> <file>
//
// Return false if nothing has been removed (i.e., the file does not
// exist).
@@ -647,9 +660,12 @@ namespace build2
// or higher.
//
static bool
- uninstall (const install_dir& base, file& t, bool verbose = true)
+ uninstall (const install_dir& base,
+ const path& name,
+ file& t,
+ bool verbose = true)
{
- path f (base.dir / t.path ().leaf ());
+ path f (base.dir / (name.empty () ? t.path ().leaf () : name));
try
{
@@ -721,18 +737,22 @@ namespace build2
file& t (static_cast<file&> (xt));
assert (!t.path ().empty ()); // Should have been assigned by update.
- auto uninstall_target = [](file& t, const dir_path& d, bool verbose)
+ auto uninstall_target = [](file& t, const path& p, bool verbose)
-> target_state
{
+ bool n (!p.to_directory ());
+ dir_path d (n ? p.directory () : path_cast<dir_path> (p));
+
// Resolve target directory.
//
install_dirs ids (resolve (t, d));
// Remove the target itself.
//
- target_state r (uninstall (ids.back (), t, verbose)
- ? target_state::changed
- : target_state::unchanged);
+ target_state r (
+ uninstall (ids.back (), n ? p.leaf () : path (), t, verbose)
+ ? target_state::changed
+ : target_state::unchanged);
// Clean up empty leading directories (in reverse).
//
@@ -751,8 +771,7 @@ namespace build2
// Reverse order of installation: first the target itself (since we got
// here we know the install variable is there).
//
- target_state r (
- uninstall_target (t, cast<dir_path> (t["install"]), true));
+ target_state r (uninstall_target (t, cast<path> (t["install"]), true));
// Then installable ad hoc group members, if any. To be anally precise
// we would have to do it in reverse, but that's not easy (it's a
@@ -760,9 +779,9 @@ namespace build2
//
for (target* m (t.member); m != nullptr; m = m->member)
{
- if (const dir_path* d = lookup (*m, "install"))
+ if (const path* p = lookup<path> (*m, "install"))
r |= uninstall_target (static_cast<file&> (*m),
- *d,
+ *p,
r != target_state::changed);
}
diff --git a/build2/install/utility b/build2/install/utility
index a50ab9b..618b243 100644
--- a/build2/install/utility
+++ b/build2/install/utility
@@ -21,14 +21,14 @@ namespace build2
{
auto r (s.target_vars[tt]["*"].insert ("install"));
if (r.second) // Already set by the user?
- r.first.get () = move (d);
+ r.first.get () = path_cast<path> (move (d));
}
template <typename T>
inline void
install_path (scope& s, dir_path d)
{
- return install_path (T::static_type, s, d);
+ return install_path (T::static_type, s, move (d));
}
inline void
@@ -43,7 +43,7 @@ namespace build2
inline void
install_mode (scope& s, string m)
{
- return install_mode (T::static_type, s, m);
+ return install_mode (T::static_type, s, move (m));
}
}
}