Skip to content

Commit

Permalink
improve handling of libraries used in .gir targets
Browse files Browse the repository at this point in the history
.gir targets rely on libraries that are compiled and linked in the same
way as they would be under Meson. VLS now does a few more things to
attempt to get these linker arguments correct. First, we fix our logic
that analyzes inputs to a .gir target, since Meson 0.55 changed build
paths. Second, we guess whether a library target depends on another
library target from its include flags, as the linker flags are not
present in the Meson introspection or compile commands.

This fixes the failure with Vala test no. 11 in the Meson source code.
  • Loading branch information
Prince781 committed Sep 21, 2020
1 parent c448868 commit 485fcf6
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 11 deletions.
36 changes: 25 additions & 11 deletions src/projects/buildtask.vala
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ class Vls.BuildTask : BuildTarget {
// we don't need to add arg to arguments here since we've probably already substituted
// the arguments in [compiler] and [args] from the sources, unless this is
// a C code target
if (language == "c")
if (language == "c") {
if (arguments.length > 0)
exe_name += " ";
exe_name += arg;
arguments += arg;
}
input.add (File.new_for_commandline_arg_and_cwd (arg, build_dir));
}

Expand Down Expand Up @@ -87,9 +91,11 @@ class Vls.BuildTask : BuildTarget {
output.add (File.new_for_commandline_arg_and_cwd (@"$library_name.vapi", directory));
}
} else if (cmd_basename == "glib-mkenums" || cmd_basename == "g-ir-scanner") {
File output_file;
// just assume the target is well-formed here
if (target_output_files.length >= 1) {
output.add (File.new_for_path (target_output_files[0]));
output_file = File.new_for_path (target_output_files[0]);
output.add (output_file);
if (target_output_files.length > 1)
warning ("BuildTask(%s): too many output files for %s target, assuming first file (%s) is output",
id, cmd_basename, target_output_files[0]);
Expand All @@ -105,14 +111,10 @@ class Vls.BuildTask : BuildTarget {
// for g-ir-scanner, look for --library [library name] and add this to our input
string? last_arg = null;
string? gir_library_name = null;
string? gir_library_dir = null;
// TODO: handle g-ir-scanner when it's being used with static libraries
File? gir_library_dir = output_file.get_parent ();
foreach (string arg in arguments) {
if (last_arg == "--library") {
if (last_arg == "--library")
gir_library_name = arg;
} else if (arg.has_prefix ("-L")) { // XXX: will -L be different on Windows, other operating systems?
gir_library_dir = arg.substring (2);
}
last_arg = arg;
}

Expand All @@ -123,12 +125,24 @@ class Vls.BuildTask : BuildTarget {
bool success = false;
File? library_file = null;
foreach (string shlib_suffix in new string[]{"so", "dll"}) {
library_file = File.new_for_commandline_arg_and_cwd (@"lib$gir_library_name.$shlib_suffix", gir_library_dir);
library_file = gir_library_dir.get_child (@"lib$gir_library_name.$shlib_suffix");
if (library_file.query_exists ()) {
input.add (library_file);
debug ("BuildTask(%s) found input %s", id, library_file.get_path ());
success = true;
break;
}

// Meson 0.55: try also looking for directory with .p suffix,
// which will indicate where the library file is expected to be.
File libdir = gir_library_dir.get_child (@"lib$gir_library_name.$shlib_suffix.p");
if (libdir.query_exists ()) {
input.add (library_file);
debug ("BuildTask(%s) found input %s", id, library_file.get_path ());
success = true;
break;
}

tried.add (library_file);
}
if (!success) {
Expand All @@ -146,7 +160,7 @@ class Vls.BuildTask : BuildTarget {
// sometimes there can be symlinks to symlinks,
// such as libthing.so -> libthing.so.0 -> libthing.so.0.0.0
while (info.get_is_symlink ()) {
real_file = File.new_for_commandline_arg_and_cwd (info.get_symlink_target (), gir_library_dir);
real_file = gir_library_dir.get_child (info.get_symlink_target ());
try {
info = real_file.query_info ("standard::*", FileQueryInfoFlags.NONE);
} catch (Error e) {
Expand All @@ -166,7 +180,7 @@ class Vls.BuildTask : BuildTarget {
}
}
} else {
warning ("BuildTask(%s): g-ir-scanner --library without link dir (-L)", id);
warning ("BuildTask(%s): could not get directory for .gir file", id);
}
} else {
warning ("BuildTask(%s): could not get library for g-ir-scanner task", id);
Expand Down
39 changes: 39 additions & 0 deletions src/projects/mesonproject.vala
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ class Vls.MesonProject : Project {
}
var root_dir = File.new_for_path (root_path);
int elem_idx = -1;
// include paths for internal libraries
var internal_lib_c_includes = new HashMap<File, Meson.TargetInfo> (Util.file_hash, Util.file_equal);
foreach (Json.Node elem_node in tg_json_root.get_array ().get_elements ()) {
elem_idx++;
var meson_target_info = Json.gobject_deserialize (typeof (Meson.TargetInfo), elem_node) as Meson.TargetInfo?;
Expand Down Expand Up @@ -367,6 +369,43 @@ class Vls.MesonProject : Project {
// the order of link args tends to be very important, so we cannot use a HashSet
var link_args = new ArrayList<string> ();

// HACK: Guess the internal dependencies of this target based on the include
// flags. For example, if this target is a shared library compiled against
// another library, we want to make sure that the linker args reflect this.
// This would be especially important if this shared library is later processed
// by g-ir-scanner, where that would fail if this shared library was not properly
// linked.
// This is a hack because this information is not specified in either
// compile_commands.json or in the Meson targets introspection info.
foreach (string arg in first_source.parameters) {
MatchInfo match_info;
if (!/-I(.*)/.match (arg, 0, out match_info))
continue;
File include_dir = File.new_for_path ((!) match_info.fetch (1));

// check for other shared library corresponding to include_dir
foreach (var entry in internal_lib_c_includes) {
if (Util.file_equal (entry.key, include_dir) ||
entry.key.get_relative_path (include_dir) != null) {
var libs = new ArrayList<string>.wrap (first_source.sources);
foreach (string lib in entry.value.filename) {
debug ("MesonProject: adding internal link arg `%s' to C target %s", lib, meson_target_info.id);
libs.add (lib);
}
first_source.sources = libs.to_array ();
}
}

// now associate include_dir with this library target (if it is one)
if (meson_target_info.target_type == "shared library" && meson_target_info.filename != null) {
foreach (string filename in meson_target_info.filename) {
File file = File.new_for_commandline_arg_and_cwd (filename, target_build_dir);
if (Util.file_equal (include_dir, file) || include_dir.get_relative_path (file) != null)
internal_lib_c_includes[include_dir] = meson_target_info;
}
}
}

// Find all of the dependencies we need based on the compiler
// arguments we're using so far. If our target uses all of the include arguments that
// a raw dependency requires, then that dependency probably belongs to our target.
Expand Down

0 comments on commit 485fcf6

Please sign in to comment.