From c10c90efd41294eca8dad0bd3a20abead33032c2 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 23 Oct 2024 10:50:47 +0200 Subject: Add config.cc.compiledb= shortcut for placing file into source directory --- libbuild2/cc/init.cxx | 112 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 7 deletions(-) (limited to 'libbuild2/cc') diff --git a/libbuild2/cc/init.cxx b/libbuild2/cc/init.cxx index 1ddeca8..d691bc5 100644 --- a/libbuild2/cc/init.cxx +++ b/libbuild2/cc/init.cxx @@ -107,6 +107,36 @@ namespace build2 return r; } + // Detect if just in the [@] form is actually . + // We assume it is and not if it contains a directory + // component or is the special directory name (`.`/`..`) . If that's the + // case, return canonicalized name representing . See the call site + // in core_config_init() below for background. + // + static optional + compiledb_name_to_path (const name& n) + { + if (n.directory ()) + return n; + + if (n.file ()) + { + if (!n.dir.empty () || + path_traits::find_separator (n.value) != string::npos) + { + name r (n); + r.canonicalize (); + return r; + } + else if (n.value == "." || n.value == "..") + { + return name (dir_path (n.value)); + } + } + + return nullopt; + } + // Custom save function that completes relative paths in the // config.cc.compiledb and config.cc.compiledb.name values. // @@ -118,6 +148,26 @@ namespace build2 { const names& ns (v.as ()); // Value is untyped. + // Detect and handle the case where just is actually . + // + if (ns.size () == 1) + { + const name& n (ns.back ()); + + if (optional otn = compiledb_name_to_path (n)) + { + name& tn (*otn); + + if (tn.dir.relative ()) + tn.dir.complete (); + + tn.dir.normalize (); + + storage.push_back (move (tn)); + return make_pair (names_view (storage), "="); + } + } + if (find_if (ns.begin (), ns.end (), [] (const name& n) {return n.pair;}) == ns.end ()) { @@ -188,11 +238,11 @@ namespace build2 // // See the manual for the semantics. // - // config.cc.compiledb -- [@] (untyped) - // config.cc.compiledb.name -- [@]... (untyped) - // config.cc.compiledb.filter -- [@]... - // config.cc.compiledb.filter.input -- [@]... - // config.cc.compiledb.filter.output -- [@]... + // config.cc.compiledb -- [@]| (untyped) + // config.cc.compiledb.name -- [@]... (untyped) + // config.cc.compiledb.filter -- [@]... + // config.cc.compiledb.filter.input -- [@]... + // config.cc.compiledb.filter.output -- [@]... // vp.insert ("config.cc.compiledb"); vp.insert ("config.cc.compiledb.name"); @@ -601,6 +651,12 @@ namespace build2 if (!i->simple () || i->empty ()) fail (loc) << "invalid compilation database name '" << *i << "'"; + // Don't allow names that have (or are) directory components. + // + if (compiledb_name_to_path (*i)) + fail (loc) << "directory component in compilation database name '" + << *i << "'"; + string n (i->value); path p; @@ -760,9 +816,51 @@ namespace build2 // Make sure it's one name/path. // - if (ns.empty () || ns.size () != (ns.front ().pair ? 2 : 1)) + size_t n (ns.size ()); + if (n == 0 || n != (ns.front ().pair ? 2 : 1)) fail (loc) << "invalid compilation database name '" << ns << "'"; + // Detect and translate just which is actually to the + // @ form: + // + // - The part is the name of the directory where the database + // file will reside (typically project/repository or package + // name). + // + // - If is a directory, then the database name is + // compile_commands.json. + // + names tns; + if (n == 1) + { + const name& n (ns.front ()); + + if (optional otn = compiledb_name_to_path (n)) + { + name& tn (*otn); + + // Note: the add_cdbs() call below completes and normalizes the + // path but we need to do it earlier in order to be able to + // derive the name (the last component can be `.`/`..`). + // + if (tn.dir.relative ()) + tn.dir.complete (); + + tn.dir.normalize (); + + if (!exists (tn.dir)) + fail (loc) << "compilation database directory " << tn.dir + << " does not exist"; + + if (tn.value.empty ()) + tn.value = "compile_commands.json"; + + tns.push_back (name (tn.dir.leaf ().string ())); + tns.back ().pair = '@'; + tns.push_back (move (tn)); + } + } + // We inject the database directly into the outer amalgamation's // module, as-if config.cc.compiledb.name was specified in its // scope. Unless there isn't one, in which case it's us. @@ -773,7 +871,7 @@ namespace build2 // enable_filter = add_cdbs ( (p.second != nullptr ? *p.second : m).cdb_names_, - ns, + tns.empty () ? ns : tns, p.first->out_path ()); } -- cgit v1.1