diff options
authorBoris Kolpackov <boris@codesynthesis.com>2020-07-10 07:25:34 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-07-10 11:07:49 +0200
commitb92a060879caf1de82a60ff2980f70ac165ec1a8 (patch)
parentfefcedab45d3e35782943faeee49478b5737c424 (diff)
Add support for project-local importation
An import without a project name or with the same name as the importing project's is now treated as importation from the same project. For example, given the libhello project that exports the lib{hello} target, a buildfile for an executable in the same project instead of doing something like this: include ../libhello/ exe{hello}: ../libhello/lib{hello} Can now do this: import lib = libhello%lib{hello} Or: import lib = lib{hello} And then: exe{hello}: $lib Note that a target in project-local importation must still be exported in the project's export stub. In other words, project-local importation goes through the same mechanisms as normal import.
2 files changed, 47 insertions, 11 deletions
diff --git a/doc/manual.cli b/doc/manual.cli
index ba0aa63..483c61d 100644
--- a/doc/manual.cli
+++ b/doc/manual.cli
@@ -2601,6 +2601,34 @@ If no \c{export} directive is executed in an export stub then the build system
assumes that the target is not exported by the project and issues appropriate
+Let's revisit the executable \c{buildfile} with which we started this section.
+Recall that it is for an executable that depends on a library which resides
+in the same project:
+include ../libhello/ # Include lib{hello}.
+exe{hello}: {hxx cxx}{**} ../libhello/lib{hello}
+If \c{lib{hello\}} is exported by this project, then instead of manually
+including its \c{buildfile} we can use \i{project-local importation}:
+import lib = lib{hello}
+exe{hello}: {hxx cxx}{**} $lib
+The main advantage of project-local importation over inclusion is the ability
+to move things around without having to adjust locations in multiple places
+(the only place we need to do it is the export stub). This advantage becomes
+noticeable in more complex projects with a large number of components.
+\N|An import is project-local if the target being imported has no project
+name. Note that the target must still be exported in the project's export
+stub. In other words, project-local importation use the same mechanism as the
+normal import.|
\h#intro-lib|Library Exportation and Versioning|
diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx
index 7ca8a91..f91dbbd 100644
--- a/libbuild2/file.cxx
+++ b/libbuild2/file.cxx
@@ -1838,6 +1838,9 @@ namespace build2
tracer trace ("import_search");
+ context& ctx (ibase.ctx);
+ scope& iroot (*ibase.root_scope ());
// Depending on the target, we have four cases:
// 1. Ad hoc import: target is unqualified and is either absolute or is a
@@ -1847,9 +1850,8 @@ namespace build2
// (e.g., because they don't know where it is), then they will have to
// specify it with an explicit dir{} target type.
- // 2. Project-local import: target is unqualified.
- //
- // Note: this is still a TODO.
+ // 2. Project-local import: target is unqualified or the project name is
+ // the same as the importing project's.
// 3. Project-less import: target is empty-qualified.
@@ -1869,9 +1871,19 @@ namespace build2
return make_pair (move (tgt), optional<dir_path> (tgt.dir));
- fail (loc) << "importation of an unqualified target " << tgt <<
- info << "use empty project qualification to import a target "
- << "without a project";
+ {
+ // Project-local import.
+ //
+ const project_name& pn (project (iroot));
+ if (pn.empty ())
+ fail (loc) << "project-local importation of target " << tgt
+ << " from an unnamed project";
+ tgt.proj = pn;
+ return make_pair (move (tgt), optional<dir_path> (iroot.out_path ()));
+ }
// If the project name is empty then we simply return it as is to let
@@ -1886,15 +1898,11 @@ namespace build2
if (tgt.absolute ())
fail (loc) << "absolute directory in imported target " << tgt;
- context& ctx (ibase.ctx);
- // Otherwise, get the project name and convert the target to unqualified.
+ // Get the project name and convert the target to unqualified.
project_name proj (move (*tgt.proj));
tgt.proj = nullopt;
- scope& iroot (*ibase.root_scope ());
// Figure out the imported project's out_root.
optional<dir_path> out_root;