diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2024-11-20 12:06:08 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2024-11-20 12:06:08 +0200 |
commit | d282f0b8d41b7b8f584dff215fc892367895af3b (patch) | |
tree | bd7c4d68940c148077c06f02c352469959bc112d | |
parent | 096362fa82e7ab390078089e4dbbf04da66c79e0 (diff) |
Handle config.import.*.<name>.lib in cc::search_library()
In particular, this provides support for using prefixed/suffixed installed
libraries (GH issue #449).
-rw-r--r-- | NEWS | 29 | ||||
-rw-r--r-- | libbuild2/cc/common.cxx | 56 | ||||
-rw-r--r-- | libbuild2/file.cxx | 86 |
3 files changed, 114 insertions, 57 deletions
@@ -1,3 +1,32 @@ +Version 0.18.0 + + * Ability to override imported installed library path/name. + + Specifically, the config.import.<proj>.<name>.{lib,liba,libs} variables + can be used to specify alternative location and/or name for an installed + library. This, in particular, can be useful when trying to use a library + installed with a prefix or suffix. For example, if the library was + installed with the `D` suffix: + + config.import.libfoo.foo.lib=fooD + + For the config.*.lib variable, the valid values are a simple path (which + is used as a library name base), an absolute directory (which is used as a + library location), or both. For example: + + config.import.libfoo.foo.lib=/tmp/lib/ + config.import.libfoo.foo.lib=/tmp/lib/fooD + + For the config.*.{liba,libs} variables, the valid values are a simple name + (which is used as a library name), or an absolute path (which is used as a + library location and name). For example: + + config.import.libfoo.foo.libs=libfooD.so + config.import.libfoo.foo.liba=/tmp/lib/libfooD.a + + Note that on Windows, the shared library name/path should refer to the + import library, not the DLL. + Version 0.17.0 * C++20 modules support improvements: diff --git a/libbuild2/cc/common.cxx b/libbuild2/cc/common.cxx index 0589c30..ae89a85 100644 --- a/libbuild2/cc/common.cxx +++ b/libbuild2/cc/common.cxx @@ -950,22 +950,35 @@ namespace build2 const prerequisite_key& p, bool exist) const { + assert (p.scope != nullptr && (!exist || act)); + tracer trace (x, "search_library"); - assert (p.scope != nullptr && (!exist || act)); + context& ctx (p.scope->ctx); + const scope& rs (*p.scope->root_scope ()); - // Import phase 1 may pass us a user-specified path with a relative - // directory (same semantics as in lookup_import() below). + // Note: since we are searching for a (presumably) installed library, + // utility libraries do not apply. // - { - const dir_path& d (*p.tk.dir); + bool l (p.is_a<lib> ()); + const string& name (*p.tk.name); + const optional<string>& ext (l ? nullopt : p.tk.ext); // Only liba/libs. - if (!d.empty ()) - fail << "relative path in imported " << p; - } + // Import phase 1 may pass us a path specified by the user with + // config.import.<proj>.<name>.<type>. The possible cases are: + // + // 1. Empty or relative directory for liba{} and libs{} (absolute would + // be taken care of by phase 1 since these tragets are path-based). + // + // 2. Empty, relative, or absolute directory for lib{} (since it's not a + // path-based target). + // + const dir_path& dir (*p.tk.dir); - context& ctx (p.scope->ctx); - const scope& rs (*p.scope->root_scope ()); + // Same semantics as in lookup_import() below. + // + if (!dir.empty () && dir.relative ()) + fail << "relative path in imported " << p; // Here is the problem: we may be building for two different toolchains // simultaneously that use the same installed library. But our search is @@ -977,17 +990,6 @@ namespace build2 ? cpath : cast<process_path> (rs["bin.ld.path"])); - // @@ This is hairy enough to warrant a separate implementation for - // Windows. - - // Note: since we are searching for a (presumably) installed library, - // utility libraries do not apply. - // - bool l (p.is_a<lib> ()); - const optional<string>& ext (l ? nullopt : p.tk.ext); // Only liba/libs. - - const string& name (*p.tk.name); - // If this prerequisite is project-qualified do an ad hoc check for // config.import.<proj>.<name>.{liba,libs} which can be used to specify // different path (see import_search() for background). Note that for @@ -1106,14 +1108,16 @@ namespace build2 // const char* e (""); + an = dir; // Empty or absolute. + if (tsys == "win32-msvc") { - an = path (name); + an /= path (name); e = "lib"; } else { - an = path ("lib" + name); + an /= path ("lib" + name); e = "a"; } @@ -1142,14 +1146,16 @@ namespace build2 { const char* e (""); + sn = dir; + if (tsys == "win32-msvc") { - sn = path (name); + sn /= path (name); e = "dll.lib"; } else { - sn = path ("lib" + name); + sn /= path ("lib" + name); if (tsys == "darwin") e = "dylib"; else if (tsys == "mingw32") e = "dll.a"; // See search code below. diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx index 8e3b2a4..a6b62c0 100644 --- a/libbuild2/file.cxx +++ b/libbuild2/file.cxx @@ -2359,8 +2359,19 @@ namespace build2 { string on (move (tgt.value)); // Original name as imported. - tgt.dir = p->directory (); - tgt.value = p->leaf ().string (); + // Keep the original name if the path is (syntactically) to + // directory. + // + if (p->to_directory ()) + { + tgt.dir = path_cast<dir_path> (*p); + tgt.value = on; + } + else + { + tgt.dir = p->directory (); + tgt.value = p->leaf ().string (); + } // If the path is relative, then keep it project-qualified // assuming import phase 2 knows what to do with it. Think: @@ -2379,48 +2390,59 @@ namespace build2 tgt.proj = move (proj); else { - // Enter the target and assign its path (this will most commonly - // be some out of project file). - // - // @@ Should we check that the file actually exists (and cache - // the extracted timestamp)? Or just let things take their - // natural course? - // name n (tgt); const target_type* tt (ibase.find_target_type (n, loc).first); if (tt == nullptr) fail (loc) << "unknown target type " << n.type << " in " << n; - // Note: not using the extension extracted by find_target_type() - // to be consistent with import phase 2. - // - target& t (insert_target (trace, ctx, *tt, *p).first); - - // Load the metadata, similar to import phase 2. + // If this is not a path-based target, then delegate to import + // phase 2 as above (see cc::search_library() for an example). // - if (meta) + if (!tt->is_a<path_target> ()) { - if (exe* e = t.is_a<exe> ()) + tgt.proj = move (proj); + } + else + { + // Enter the target and assign its path (this will most + // commonly be some out of project file). + // + // @@ Should we check that the file actually exists (and cache + // the extracted timestamp)? Or just let things take their + // natural course? + // + + // Note: not using the extension extracted by + // find_target_type() to be consistent with import phase 2. + // + target& t (insert_target (trace, ctx, *tt, *p).first); + + // Load the metadata, similar to import phase 2. + // + if (meta) { - if (!e->vars[ctx.var_export_metadata].defined ()) + if (exe* e = t.is_a<exe> ()) { - optional<string> md; + if (!e->vars[ctx.var_export_metadata].defined ()) { - auto df = make_diag_frame ( - [&proj, tt, &on] (const diag_record& dr) - { - import_suggest ( - dr, proj, tt, on, false, "alternative "); - }); - - md = extract_metadata (e->process_path (), - *meta, - false /* optional */, - loc); + optional<string> md; + { + auto df = make_diag_frame ( + [&proj, tt, &on] (const diag_record& dr) + { + import_suggest ( + dr, proj, tt, on, false, "alternative "); + }); + + md = extract_metadata (e->process_path (), + *meta, + false /* optional */, + loc); + } + + parse_metadata (*e, move (*md), loc); } - - parse_metadata (*e, move (*md), loc); } } } |