aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTing-Wei Lan <lantw@src.gnome.org>2018-04-22 22:38:18 +0800
committerNirbheek Chauhan <nirbheek.chauhan@gmail.com>2018-07-01 21:54:09 +0000
commitcb36add970d448f8b4ace7e4dc6028e5441bccd7 (patch)
tree886ea5b0eeb6b9ecf91b4cd34cbf465884a95a77
parentcb2e4877da1469098a5e252385a3aa7f63b18026 (diff)
downloadmeson-cb36add970d448f8b4ace7e4dc6028e5441bccd7.zip
meson-cb36add970d448f8b4ace7e4dc6028e5441bccd7.tar.gz
meson-cb36add970d448f8b4ace7e4dc6028e5441bccd7.tar.bz2
gnome: Distinguish between internal and external linker flags
When an older version of the library being built is installed in the same prefix as external dependencies, we have to be careful to construct the linker or compiler command line. If a -L flag from external dependencoes comes before a -L flag pointing to builddir, it is possible for the linker to load older libraries from the installation prefix instead of the newly built ones, which is likely to cause undefined reference error. Since the order of dependencies is not significant, we cannot expect internal dependencies to appear before external dependencies when recursively iterating the list of dependencies. To make it harder to make mistakes, linker flags come from internal and external dependencies are now stored in different order sets. Code using _get_dependencies_flags are expected to follow the order when constructing linker command line: 1. Internal linker flags 2. LDFLAGS set by users 3. External linker flags It is similar to what automake and libtool do for autotools projects.
-rw-r--r--mesonbuild/modules/gnome.py61
-rw-r--r--test cases/frameworks/22 gir link order/fake-gthread/fake-gthread.c6
-rw-r--r--test cases/frameworks/22 gir link order/fake-gthread/fake-gthread.h6
-rw-r--r--test cases/frameworks/22 gir link order/fake-gthread/meson.build12
-rw-r--r--test cases/frameworks/22 gir link order/get-prgname/get-prgname.c8
-rw-r--r--test cases/frameworks/22 gir link order/get-prgname/get-prgname.h6
-rw-r--r--test cases/frameworks/22 gir link order/get-prgname/meson.build13
-rw-r--r--test cases/frameworks/22 gir link order/meson-sample.c48
-rw-r--r--test cases/frameworks/22 gir link order/meson-sample.h17
-rw-r--r--test cases/frameworks/22 gir link order/meson.build41
10 files changed, 194 insertions, 24 deletions
diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py
index 3f6f449..c45d29d 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -316,7 +316,8 @@ class GnomeModule(ExtensionModule):
def _get_dependencies_flags(self, deps, state, depends, include_rpath=False,
use_gir_args=False):
cflags = OrderedSet()
- ldflags = OrderedSet()
+ internal_ldflags = OrderedSet()
+ external_ldflags = OrderedSet()
gi_includes = OrderedSet()
deps = mesonlib.listify(deps, unholder=True)
@@ -326,17 +327,19 @@ class GnomeModule(ExtensionModule):
for lib in dep.libraries:
if hasattr(lib, 'held_object'):
lib = lib.held_object
- ldflags.update(self._get_link_args(state, lib, depends, include_rpath))
+ internal_ldflags.update(self._get_link_args(state, lib, depends, include_rpath))
libdepflags = self._get_dependencies_flags(lib.get_external_deps(), state, depends, include_rpath,
use_gir_args)
cflags.update(libdepflags[0])
- ldflags.update(libdepflags[1])
- gi_includes.update(libdepflags[2])
+ internal_ldflags.update(libdepflags[1])
+ external_ldflags.update(libdepflags[2])
+ gi_includes.update(libdepflags[3])
extdepflags = self._get_dependencies_flags(dep.ext_deps, state, depends, include_rpath,
use_gir_args)
cflags.update(extdepflags[0])
- ldflags.update(extdepflags[1])
- gi_includes.update(extdepflags[2])
+ internal_ldflags.update(extdepflags[1])
+ external_ldflags.update(extdepflags[2])
+ gi_includes.update(extdepflags[3])
for source in dep.sources:
if hasattr(source, 'held_object'):
source = source.held_object
@@ -351,9 +354,9 @@ class GnomeModule(ExtensionModule):
# For PkgConfigDependency only:
getattr(dep, 'is_libtool', False)):
lib_dir = os.path.dirname(lib)
- ldflags.update(["-L%s" % lib_dir])
+ external_ldflags.update(["-L%s" % lib_dir])
if include_rpath:
- ldflags.update(['-Wl,-rpath {}'.format(lib_dir)])
+ external_ldflags.update(['-Wl,-rpath {}'.format(lib_dir)])
libname = os.path.basename(lib)
if libname.startswith("lib"):
libname = libname[3:]
@@ -362,7 +365,7 @@ class GnomeModule(ExtensionModule):
# Hack to avoid passing some compiler options in
if lib.startswith("-W"):
continue
- ldflags.update([lib])
+ external_ldflags.update([lib])
if isinstance(dep, PkgConfigDependency):
girdir = dep.get_pkgconfig_variable("girdir", {'default': ''})
@@ -376,14 +379,17 @@ class GnomeModule(ExtensionModule):
continue
if gir_has_extra_lib_arg(self.interpreter) and use_gir_args:
- fixed_ldflags = OrderedSet()
- for ldflag in ldflags:
- if ldflag.startswith("-l"):
- fixed_ldflags.add(ldflag.replace('-l', '--extra-library=', 1))
- else:
- fixed_ldflags.add(ldflag)
- ldflags = fixed_ldflags
- return cflags, ldflags, gi_includes
+ def fix_ldflags(ldflags):
+ fixed_ldflags = OrderedSet()
+ for ldflag in ldflags:
+ if ldflag.startswith("-l"):
+ fixed_ldflags.add(ldflag.replace('-l', '--extra-library=', 1))
+ else:
+ fixed_ldflags.add(ldflag)
+ return fixed_ldflags
+ internal_ldflags = fix_ldflags(internal_ldflags)
+ external_ldflags = fix_ldflags(external_ldflags)
+ return cflags, internal_ldflags, external_ldflags, gi_includes
@FeatureNewKwargs('build target', '0.40.0', ['build_by_default'])
@permittedKwargs({'sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix',
@@ -487,7 +493,8 @@ class GnomeModule(ExtensionModule):
'Gir includes must be str, GirTarget, or list of them')
cflags = []
- ldflags = []
+ internal_ldflags = []
+ external_ldflags = []
for lang, compiler in girtarget.compilers.items():
# XXX: Can you use g-i with any other language?
if lang in ('c', 'cpp', 'objc', 'objcpp', 'd'):
@@ -504,7 +511,7 @@ class GnomeModule(ExtensionModule):
sanitize = state.environment.coredata.base_options['b_sanitize'].value
cflags += compilers.sanitizer_compile_args(sanitize)
if 'address' in sanitize.split(','):
- ldflags += ['-lasan']
+ external_ldflags += ['-lasan']
# FIXME: Linking directly to libasan is not recommended but g-ir-scanner
# does not understand -f LDFLAGS. https://bugzilla.gnome.org/show_bug.cgi?id=783892
# ldflags += compilers.sanitizer_link_args(sanitize)
@@ -565,10 +572,11 @@ class GnomeModule(ExtensionModule):
# ldflags will be misinterpreted by gir scanner (showing
# spurious dependencies) but building GStreamer fails if they
# are not used here.
- dep_cflags, dep_ldflags, gi_includes = self._get_dependencies_flags(deps, state, depends,
- use_gir_args=True)
+ dep_cflags, dep_internal_ldflags, dep_external_ldflags, gi_includes = \
+ self._get_dependencies_flags(deps, state, depends, use_gir_args=True)
cflags += list(dep_cflags)
- ldflags += list(dep_ldflags)
+ internal_ldflags += list(dep_internal_ldflags)
+ external_ldflags += list(dep_external_ldflags)
scan_command += ['--cflags-begin']
scan_command += cflags
scan_command += state.environment.coredata.get_external_args(lang)
@@ -578,7 +586,7 @@ class GnomeModule(ExtensionModule):
# ones.
if isinstance(girtarget, build.SharedLibrary):
scan_command += ["-L@PRIVATE_OUTDIR_ABS_%s@" % girtarget.get_id()]
- scan_command += list(ldflags)
+ scan_command += list(internal_ldflags)
for i in gi_includes:
scan_command += ['--add-include-path=%s' % i]
@@ -606,6 +614,7 @@ class GnomeModule(ExtensionModule):
for link_arg in state.environment.coredata.get_external_link_args(lang):
if link_arg.startswith('-L'):
scan_command.append(link_arg)
+ scan_command += list(external_ldflags)
scankwargs = {'output': girfile,
'command': scan_command,
@@ -832,7 +841,8 @@ This will become a hard error in the future.''')
def _get_build_args(self, kwargs, state, depends):
args = []
deps = extract_as_list(kwargs, 'dependencies', unholder=True)
- cflags, ldflags, gi_includes = self._get_dependencies_flags(deps, state, depends, include_rpath=True)
+ cflags, internal_ldflags, external_ldflags, gi_includes = \
+ self._get_dependencies_flags(deps, state, depends, include_rpath=True)
inc_dirs = mesonlib.extract_as_list(kwargs, 'include_directories')
for incd in inc_dirs:
if not isinstance(incd.held_object, (str, build.IncludeDirs)):
@@ -840,7 +850,10 @@ This will become a hard error in the future.''')
'Gir include dirs should be include_directories().')
cflags.update(get_include_args(inc_dirs))
cflags.update(state.environment.coredata.get_external_args('c'))
+ ldflags = OrderedSet()
+ ldflags.update(internal_ldflags)
ldflags.update(state.environment.coredata.get_external_link_args('c'))
+ ldflags.update(external_ldflags)
if cflags:
args += ['--cflags=%s' % ' '.join(cflags)]
if ldflags:
diff --git a/test cases/frameworks/22 gir link order/fake-gthread/fake-gthread.c b/test cases/frameworks/22 gir link order/fake-gthread/fake-gthread.c
new file mode 100644
index 0000000..fae9c38
--- /dev/null
+++ b/test cases/frameworks/22 gir link order/fake-gthread/fake-gthread.c
@@ -0,0 +1,6 @@
+#include "fake-gthread.h"
+
+int fake_gthread_fake_function (void)
+{
+ return 7;
+}
diff --git a/test cases/frameworks/22 gir link order/fake-gthread/fake-gthread.h b/test cases/frameworks/22 gir link order/fake-gthread/fake-gthread.h
new file mode 100644
index 0000000..52b5472
--- /dev/null
+++ b/test cases/frameworks/22 gir link order/fake-gthread/fake-gthread.h
@@ -0,0 +1,6 @@
+#ifndef FAKE_GTHREAD_H
+#define FAKE_GTHREAD_H
+
+int fake_gthread_fake_function (void);
+
+#endif /* FAKE_GTHREAD_H */
diff --git a/test cases/frameworks/22 gir link order/fake-gthread/meson.build b/test cases/frameworks/22 gir link order/fake-gthread/meson.build
new file mode 100644
index 0000000..693e8e0
--- /dev/null
+++ b/test cases/frameworks/22 gir link order/fake-gthread/meson.build
@@ -0,0 +1,12 @@
+fake_gthread_sources = ['fake-gthread.c', 'fake-gthread.h']
+fake_gthread_lib = shared_library(
+ 'gthread-2.0',
+ sources : fake_gthread_sources,
+ install : false,
+)
+
+fake_gthread_includes = include_directories('.')
+fake_gthread = declare_dependency(
+ include_directories : fake_gthread_includes,
+ link_with : fake_gthread_lib,
+)
diff --git a/test cases/frameworks/22 gir link order/get-prgname/get-prgname.c b/test cases/frameworks/22 gir link order/get-prgname/get-prgname.c
new file mode 100644
index 0000000..356b45e
--- /dev/null
+++ b/test cases/frameworks/22 gir link order/get-prgname/get-prgname.c
@@ -0,0 +1,8 @@
+#include "get-prgname.h"
+
+#include <glib.h>
+
+const char *get_prgname_get_name (void)
+{
+ return g_get_prgname ();
+}
diff --git a/test cases/frameworks/22 gir link order/get-prgname/get-prgname.h b/test cases/frameworks/22 gir link order/get-prgname/get-prgname.h
new file mode 100644
index 0000000..cb5118e
--- /dev/null
+++ b/test cases/frameworks/22 gir link order/get-prgname/get-prgname.h
@@ -0,0 +1,6 @@
+#ifndef GET_PRGNAME_H
+#define GET_PRGNAME_H
+
+const char *get_prgname_get_name (void);
+
+#endif /* GET_PRGNAME_H */
diff --git a/test cases/frameworks/22 gir link order/get-prgname/meson.build b/test cases/frameworks/22 gir link order/get-prgname/meson.build
new file mode 100644
index 0000000..6a7489d
--- /dev/null
+++ b/test cases/frameworks/22 gir link order/get-prgname/meson.build
@@ -0,0 +1,13 @@
+get_prgname_sources = ['get-prgname.c', 'get-prgname.h']
+get_prgname_lib = shared_library(
+ 'get-prgname',
+ sources : get_prgname_sources,
+ dependencies : [glib],
+ install : false,
+)
+
+get_prgname_includes = include_directories('.')
+get_prgname = declare_dependency(
+ include_directories : get_prgname_includes,
+ link_with : get_prgname_lib,
+)
diff --git a/test cases/frameworks/22 gir link order/meson-sample.c b/test cases/frameworks/22 gir link order/meson-sample.c
new file mode 100644
index 0000000..7c6442a
--- /dev/null
+++ b/test cases/frameworks/22 gir link order/meson-sample.c
@@ -0,0 +1,48 @@
+#include "meson-sample.h"
+
+#include "get-prgname.h"
+#include "fake-gthread.h"
+
+struct _MesonSample {
+ GObject parent_instance;
+};
+
+G_DEFINE_TYPE (MesonSample, meson_sample, G_TYPE_OBJECT)
+
+/**
+ * meson_sample_new:
+ *
+ * Allocates a new #MesonSample.
+ *
+ * Returns: (transfer full): a #MesonSample.
+ */
+MesonSample *
+meson_sample_new (void)
+{
+ return g_object_new (MESON_TYPE_SAMPLE, NULL);
+}
+
+static void
+meson_sample_class_init (MesonSampleClass *klass)
+{
+}
+
+static void
+meson_sample_init (MesonSample *self)
+{
+}
+
+/**
+ * meson_sample_print_message:
+ * @self: a #MesonSample.
+ *
+ * Prints a message.
+ */
+void
+meson_sample_print_message (MesonSample *self)
+{
+ g_return_if_fail (MESON_IS_SAMPLE (self));
+
+ g_print ("Message: %s\n", get_prgname_get_name ());
+ g_print ("Message: %d\n", fake_gthread_fake_function ());
+}
diff --git a/test cases/frameworks/22 gir link order/meson-sample.h b/test cases/frameworks/22 gir link order/meson-sample.h
new file mode 100644
index 0000000..2c28401
--- /dev/null
+++ b/test cases/frameworks/22 gir link order/meson-sample.h
@@ -0,0 +1,17 @@
+#ifndef MESON_SAMPLE_H
+#define MESON_SAMPLE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MESON_TYPE_SAMPLE (meson_sample_get_type())
+
+G_DECLARE_FINAL_TYPE (MesonSample, meson_sample, MESON, SAMPLE, GObject)
+
+MesonSample *meson_sample_new (void);
+void meson_sample_print_message (MesonSample *self);
+
+G_END_DECLS
+
+#endif /* MESON_SAMPLE_H */
diff --git a/test cases/frameworks/22 gir link order/meson.build b/test cases/frameworks/22 gir link order/meson.build
new file mode 100644
index 0000000..224eaf6
--- /dev/null
+++ b/test cases/frameworks/22 gir link order/meson.build
@@ -0,0 +1,41 @@
+project('gir link order', 'c')
+
+if not dependency('glib-2.0', required : false).found()
+ error('MESON_SKIP_TEST glib not found.')
+endif
+
+gnome = import('gnome')
+glib = dependency('glib-2.0')
+gobject = dependency('gobject-2.0')
+
+# get-prgname is a shared library which uses a function from glib-2.0. It is
+# used to introduce external -L flags which may cause -L order problems.
+subdir('get-prgname')
+
+# fake-gthread is a shared library which has the same name as gthread-2.0 from
+# GLib. This is used to simulate the case where an older or unrelated version
+# of a library is already installed on the system. Our meson sample library
+# defined below uses a function from fake-gthread. If meson messes up -L order,
+# the linker will find libgthread-2.0.so installed on the system and fail to
+# find the symbol our meson sample library uses.
+subdir('fake-gthread')
+
+meson_sample_sources = ['meson-sample.c', 'meson-sample.h']
+meson_sample_lib = shared_library(
+ 'sample',
+ sources : meson_sample_sources,
+ dependencies : [gobject, get_prgname, fake_gthread],
+ install : false,
+)
+
+gnome.generate_gir(
+ meson_sample_lib,
+ sources : meson_sample_sources,
+ nsversion : '1.0',
+ namespace : 'Meson',
+ symbol_prefix : 'meson',
+ identifier_prefix : 'Meson',
+ includes : ['GObject-2.0'],
+ install : false,
+ build_by_default: true,
+)