diff --git a/.appveyor.yml b/.appveyor.yml index c0edf5c8c..22a58123d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -89,6 +89,8 @@ install: # but they have a broken certificate (on Windows) and an HSTS policy that # forces usage of HTTPS, so we mirror our own copy. - ps: If($Env:compiler -eq 'msys2-mingw') {(new-object Net.WebClient).DownloadFile('https://nirbheek.in/files/meson/get-pip.py', 'C:\projects\meson\get-pip.py')} + # pkg-config is needed for the pkg-config tests on msvc + - ps: If($Env:compiler.StartsWith('msvc')) {(new-object net.webclient).DownloadFile('http://nirbheek.in/files/binaries/pkg-config/win32/pkg-config.exe', 'C:\projects\meson\pkg-config.exe')} - cmd: if %compiler%==msys2-mingw ( %PYTHON% "C:\projects\meson\get-pip.py" ) - cmd: if %compiler%==cygwin ( call ci\appveyor-install.bat ) - ps: | diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 12f4bdb6e..5f552c251 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -22,7 +22,7 @@ from . import mlog from .mesonlib import File, MesonException, listify, extract_as_list from .mesonlib import typeslistify, stringlistify, classify_unity_sources from .mesonlib import get_filenames_templates_dict, substitute_values -from .environment import for_windows, for_darwin, for_cygwin +from .mesonlib import for_windows, for_darwin, for_cygwin from .compilers import is_object, clike_langs, sort_clike, lang_suffixes known_basic_kwargs = {'install': True, diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 3f9ba5cc4..9e857127f 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -17,6 +17,7 @@ import subprocess, os.path, tempfile from .. import mlog from .. import coredata from ..mesonlib import EnvironmentException, version_compare, Popen_safe, listify +from ..mesonlib import for_windows, for_darwin, for_cygwin from .compilers import ( GCC_MINGW, @@ -710,7 +711,45 @@ class CCompiler(Compiler): return False raise RuntimeError('BUG: {!r} check failed unexpectedly'.format(n)) - def find_library(self, libname, env, extra_dirs): + def get_library_naming(self, env, libtype): + ''' + Get library prefixes and suffixes for the target platform ordered by + priority + ''' + stlibext = ['a'] + # We've always allowed libname to be both `foo` and `libfoo`, + # and now people depend on it + prefixes = ['lib', ''] + # Library suffixes and prefixes + if for_darwin(env.is_cross_build(), env): + shlibext = ['dylib'] + elif for_windows(env.is_cross_build(), env): + if self.id == 'msvc': + shlibext = ['lib'] + else: + shlibext = ['dll', 'dll.a', 'lib'] + # Yep, static libraries can also be foo.lib + stlibext += ['lib'] + elif for_cygwin(env.is_cross_build(), env): + shlibext = ['dll', 'dll.a'] + prefixes = ['cyg'] + prefixes + else: + # Linux/BSDs + shlibext = ['so'] + # Search priority + if libtype in ('default', 'shared-static'): + suffixes = shlibext + stlibext + elif libtype == 'static-shared': + suffixes = stlibext + shlibext + elif libtype == 'shared': + suffixes = shlibext + elif libtype == 'static': + suffixes = stlibext + else: + raise AssertionError('BUG: unknown libtype {!r}'.format(libtype)) + return prefixes, suffixes + + def find_library(self, libname, env, extra_dirs, libtype='default'): # These libraries are either built-in or invalid if libname in self.ignore_libs: return [] @@ -720,21 +759,21 @@ class CCompiler(Compiler): extra_dirs = [extra_dirs] # Gcc + co seem to prefer builtin lib dirs to -L dirs. # Only try to find std libs if no extra dirs specified. - if not extra_dirs: + if not extra_dirs and libtype == 'default': args = ['-l' + libname] if self.links(code, env, extra_args=args): return args - # Not found? Try to find the library file itself. + # Not found or we want to use a specific libtype? Try to find the + # library file itself. extra_dirs += self.get_library_dirs() - suffixes = ['so', 'dylib', 'lib', 'dll', 'a'] + prefixes, suffixes = self.get_library_naming(env, libtype) + # Triply-nested loop! for d in extra_dirs: for suffix in suffixes: - trial = os.path.join(d, 'lib' + libname + '.' + suffix) - if os.path.isfile(trial): - return [trial] - trial2 = os.path.join(d, libname + '.' + suffix) - if os.path.isfile(trial2): - return [trial2] + for prefix in prefixes: + trial = os.path.join(d, prefix + libname + '.' + suffix) + if os.path.isfile(trial): + return [trial] return None def thread_flags(self): diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 2ac345f1d..fcc74b538 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -16,9 +16,10 @@ # Custom logic for several other packages are in separate files. import os -import shutil -import stat import sys +import stat +import shlex +import shutil from enum import Enum from .. import mlog @@ -258,8 +259,10 @@ class PkgConfigDependency(ExternalDependency): return s.format(self.__class__.__name__, self.name, self.is_found, self.version_reqs) - def _call_pkgbin(self, args): - p, out = Popen_safe([self.pkgbin] + args, env=os.environ)[0:2] + def _call_pkgbin(self, args, env=None): + if not env: + env = os.environ + p, out = Popen_safe([self.pkgbin] + args, env=env)[0:2] return p.returncode, out.strip() def _set_cargs(self): @@ -267,19 +270,39 @@ class PkgConfigDependency(ExternalDependency): if ret != 0: raise DependencyException('Could not generate cargs for %s:\n\n%s' % (self.name, out)) - self.compile_args = out.split() + self.compile_args = shlex.split(out) def _set_libs(self): + env = None libcmd = [self.name, '--libs'] if self.static: libcmd.append('--static') - ret, out = self._call_pkgbin(libcmd) + # Force pkg-config to output -L fields even if they are system + # paths so we can do manual searching with cc.find_library() later. + env = os.environ.copy() + env['PKG_CONFIG_ALLOW_SYSTEM_LIBS'] = '1' + ret, out = self._call_pkgbin(libcmd, env=env) if ret != 0: raise DependencyException('Could not generate libs for %s:\n\n%s' % (self.name, out)) self.link_args = [] - for lib in out.split(): - if lib.endswith(".la"): + libpaths = [] + for lib in shlex.split(out): + # If we want to use only static libraries, we have to look for the + # file ourselves instead of depending on the compiler to find it + # with -lfoo or foo.lib. However, we can only do this if we already + # have some library paths gathered. + if self.static: + if lib.startswith('-L'): + libpaths.append(lib[2:]) + continue + elif lib.startswith('-l') and libpaths: + args = self.compiler.find_library(lib[2:], self.env, libpaths, libtype='static') + if not args or len(args) < 1: + raise DependencyException('Static library not found for {!r}' + ''.format(lib[2:])) + lib = args[0] + elif lib.endswith(".la"): shared_libname = self.extract_libtool_shlib(lib) shared_lib = os.path.join(os.path.dirname(lib), shared_libname) if not os.path.exists(shared_lib): diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 8f183e54d..3412dc655 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -23,8 +23,9 @@ from collections import OrderedDict from .. import mlog from .. import mesonlib -from ..mesonlib import MesonException, Popen_safe, version_compare, extract_as_list -from ..environment import for_windows, detect_cpu +from ..mesonlib import MesonException, Popen_safe, version_compare +from ..mesonlib import extract_as_list, for_windows +from ..environment import detect_cpu from .base import DependencyException, DependencyMethods from .base import ExternalDependency, ExternalProgram diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 7f07c8d1d..d9146eba3 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -219,46 +219,6 @@ def detect_system(): return 'cygwin' return system - -def for_windows(is_cross, env): - """ - Host machine is windows? - - Note: 'host' is the machine on which compiled binaries will run - """ - if not is_cross: - return mesonlib.is_windows() - elif env.cross_info.has_host(): - return env.cross_info.config['host_machine']['system'] == 'windows' - return False - - -def for_cygwin(is_cross, env): - """ - Host machine is cygwin? - - Note: 'host' is the machine on which compiled binaries will run - """ - if not is_cross: - return mesonlib.is_cygwin() - elif env.cross_info.has_host(): - return env.cross_info.config['host_machine']['system'] == 'cygwin' - return False - - -def for_darwin(is_cross, env): - """ - Host machine is Darwin (iOS/OS X)? - - Note: 'host' is the machine on which compiled binaries will run - """ - if not is_cross: - return mesonlib.is_osx() - elif env.cross_info.has_host(): - return env.cross_info.config['host_machine']['system'] == 'darwin' - return False - - def search_version(text): # Usually of the type 4.1.4 but compiler output may contain # stuff like this: @@ -550,9 +510,9 @@ class Environment: cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler return cls(ccache + compiler, version, gtype, is_cross, exe_wrap, defines) if 'clang' in out: - if 'Apple' in out or for_darwin(want_cross, self): + if 'Apple' in out or mesonlib.for_darwin(want_cross, self): cltype = CLANG_OSX - elif 'windows' in out or for_windows(want_cross, self): + elif 'windows' in out or mesonlib.for_windows(want_cross, self): cltype = CLANG_WIN else: cltype = CLANG_STANDARD diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 5c4c3747b..f74c6c17b 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -219,6 +219,42 @@ def is_cygwin(): def is_debianlike(): return os.path.isfile('/etc/debian_version') +def for_windows(is_cross, env): + """ + Host machine is windows? + + Note: 'host' is the machine on which compiled binaries will run + """ + if not is_cross: + return is_windows() + elif env.cross_info.has_host(): + return env.cross_info.config['host_machine']['system'] == 'windows' + return False + +def for_cygwin(is_cross, env): + """ + Host machine is cygwin? + + Note: 'host' is the machine on which compiled binaries will run + """ + if not is_cross: + return is_cygwin() + elif env.cross_info.has_host(): + return env.cross_info.config['host_machine']['system'] == 'cygwin' + return False + +def for_darwin(is_cross, env): + """ + Host machine is Darwin (iOS/OS X)? + + Note: 'host' is the machine on which compiled binaries will run + """ + if not is_cross: + return is_osx() + elif env.cross_info.has_host(): + return env.cross_info.config['host_machine']['system'] == 'darwin' + return False + def exe_exists(arglist): try: p = subprocess.Popen(arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 8383a3aaa..52f3a502e 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -13,6 +13,7 @@ # limitations under the License. import os +from pathlib import PurePath from .. import build from .. import mesonlib @@ -42,20 +43,34 @@ class PkgConfigModule(ExtensionModule): mlog.warning(msg.format(l.name, 'name_prefix', l.name, pcfile)) return l.name + def _escape(self, value): + ''' + We cannot use shlex.quote because it quotes with ' and " which does not + work with pkg-config and pkgconf at all. + ''' + # We should always write out paths with / because pkg-config requires + # spaces to be quoted with \ and that messes up on Windows: + # https://bugs.freedesktop.org/show_bug.cgi?id=103203 + if isinstance(value, PurePath): + value = value.as_posix() + return value.replace(' ', '\ ') + def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, url, version, pcfile, pub_reqs, priv_reqs, conflicts, priv_libs, extra_cflags, variables): coredata = state.environment.get_coredata() outdir = state.environment.scratch_dir fname = os.path.join(outdir, pcfile) + prefix = PurePath(coredata.get_builtin_option('prefix')) + # These always return paths relative to prefix + libdir = PurePath(coredata.get_builtin_option('libdir')) + incdir = PurePath(coredata.get_builtin_option('includedir')) with open(fname, 'w') as ofile: - ofile.write('prefix=%s\n' % coredata.get_builtin_option('prefix')) - # '${prefix}' is ignored if the second path is absolute (see - # 'os.path.join' for details) - ofile.write('libdir=%s\n' % os.path.join('${prefix}', coredata.get_builtin_option('libdir'))) - ofile.write('includedir=%s\n' % os.path.join('${prefix}', coredata.get_builtin_option('includedir'))) + ofile.write('prefix={}\n'.format(self._escape(prefix))) + ofile.write('libdir={}\n'.format(self._escape('${prefix}' / libdir))) + ofile.write('includedir={}\n'.format(self._escape('${prefix}' / incdir))) for k, v in variables: - ofile.write('%s=%s\n' % (k, v)) + ofile.write('{}={}\n'.format(k, self._escape(v))) ofile.write('\n') ofile.write('Name: %s\n' % name) if len(description) > 0: @@ -83,7 +98,7 @@ class PkgConfigModule(ExtensionModule): if install_dir is False: continue if isinstance(install_dir, str): - yield '-L${prefix}/%s ' % install_dir + yield '-L${prefix}/%s ' % self._escape(install_dir) else: # install_dir is True yield '-L${libdir}' lname = self._get_lname(l, msg, pcfile) @@ -103,10 +118,10 @@ class PkgConfigModule(ExtensionModule): if h == '.': ofile.write('-I${includedir}') else: - ofile.write(os.path.join('-I${includedir}', h)) + ofile.write(self._escape(PurePath('-I${includedir}') / h)) for f in extra_cflags: ofile.write(' ') - ofile.write(f) + ofile.write(self._escape(f)) ofile.write('\n') def process_libs(self, libs): diff --git a/run_unittests.py b/run_unittests.py index ce1bf0692..80c58ea0c 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1389,34 +1389,34 @@ int main(int argc, char **argv) { self.assertPathExists(os.path.join(testdir, i)) def detect_prebuild_env(self): + env = Environment('', self.builddir, self.meson_command, + get_fake_options(self.prefix), []) + cc = env.detect_c_compiler(False) if mesonbuild.mesonlib.is_windows(): object_suffix = 'obj' - else: + shared_suffix = 'dll' + elif mesonbuild.mesonlib.is_cygwin(): object_suffix = 'o' - static_suffix = 'a' - shared_suffix = 'so' - if shutil.which('cl'): - compiler = 'cl' - static_suffix = 'lib' shared_suffix = 'dll' - elif shutil.which('cc'): - compiler = 'cc' - elif shutil.which('gcc'): - compiler = 'gcc' + elif mesonbuild.mesonlib.is_osx(): + object_suffix = 'o' + shared_suffix = 'dylib' else: - raise RuntimeError("Could not find C compiler.") - return (compiler, object_suffix, static_suffix, shared_suffix) + object_suffix = 'o' + shared_suffix = 'so' + return (cc, object_suffix, shared_suffix) def pbcompile(self, compiler, source, objectfile, extra_args=[]): - if compiler == 'cl': - cmd = [compiler, '/nologo', '/Fo' + objectfile, '/c', source] + extra_args + cmd = compiler.get_exelist() + if compiler.id == 'msvc': + cmd += ['/nologo', '/Fo' + objectfile, '/c', source] + extra_args else: - cmd = [compiler, '-c', source, '-o', objectfile] + extra_args + cmd += ['-c', source, '-o', objectfile] + extra_args subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def test_prebuilt_object(self): - (compiler, object_suffix, _, _) = self.detect_prebuild_env() + (compiler, object_suffix, _) = self.detect_prebuild_env() tdir = os.path.join(self.unit_test_dir, '14 prebuilt object') source = os.path.join(tdir, 'source.c') objectfile = os.path.join(tdir, 'prebuilt.' + object_suffix) @@ -1428,21 +1428,27 @@ int main(int argc, char **argv) { finally: os.unlink(objectfile) - def test_prebuilt_static_lib(self): - (compiler, object_suffix, static_suffix, _) = self.detect_prebuild_env() - tdir = os.path.join(self.unit_test_dir, '15 prebuilt static') - source = os.path.join(tdir, 'libdir/best.c') - objectfile = os.path.join(tdir, 'libdir/best.' + object_suffix) - stlibfile = os.path.join(tdir, 'libdir/libbest.' + static_suffix) - if compiler == 'cl': - link_cmd = ['lib', '/NOLOGO', '/OUT:' + stlibfile, objectfile] + def build_static_lib(self, compiler, source, objectfile, outfile, extra_args=None): + if extra_args is None: + extra_args = [] + if compiler.id == 'msvc': + link_cmd = ['lib', '/NOLOGO', '/OUT:' + outfile, objectfile] else: - link_cmd = ['ar', 'csr', stlibfile, objectfile] - self.pbcompile(compiler, source, objectfile) + link_cmd = ['ar', 'csr', outfile, objectfile] + self.pbcompile(compiler, source, objectfile, extra_args=extra_args) try: subprocess.check_call(link_cmd) finally: os.unlink(objectfile) + + def test_prebuilt_static_lib(self): + (cc, object_suffix, _) = self.detect_prebuild_env() + tdir = os.path.join(self.unit_test_dir, '15 prebuilt static') + source = os.path.join(tdir, 'libdir/best.c') + objectfile = os.path.join(tdir, 'libdir/best.' + object_suffix) + stlibfile = os.path.join(tdir, 'libdir/libbest.a') + self.build_static_lib(cc, source, objectfile, stlibfile) + # Run the test try: self.init(tdir) self.build() @@ -1450,26 +1456,37 @@ int main(int argc, char **argv) { finally: os.unlink(stlibfile) - def test_prebuilt_shared_lib(self): - (compiler, object_suffix, _, shared_suffix) = self.detect_prebuild_env() - tdir = os.path.join(self.unit_test_dir, '16 prebuilt shared') - source = os.path.join(tdir, 'alexandria.c') - objectfile = os.path.join(tdir, 'alexandria.' + object_suffix) - if compiler == 'cl': + def build_shared_lib(self, compiler, source, objectfile, outfile, impfile, extra_args=None): + if extra_args is None: extra_args = [] - shlibfile = os.path.join(tdir, 'alexandria.' + shared_suffix) - link_cmd = ['link', '/NOLOGO','/DLL', '/DEBUG', '/IMPLIB:' + os.path.join(tdir, 'alexandria.lib'), '/OUT:' + shlibfile, objectfile] + if compiler.id == 'msvc': + link_cmd = ['link', '/NOLOGO', '/DLL', '/DEBUG', + '/IMPLIB:' + impfile, '/OUT:' + outfile, objectfile] else: - extra_args = ['-fPIC'] - shlibfile = os.path.join(tdir, 'libalexandria.' + shared_suffix) - link_cmd = [compiler, '-shared', '-o', shlibfile, objectfile] + extra_args += ['-fPIC'] + link_cmd = compiler.get_exelist() + ['-shared', '-o', outfile, objectfile] if not mesonbuild.mesonlib.is_osx(): - link_cmd += ['-Wl,-soname=libalexandria.so'] + link_cmd += ['-Wl,-soname=' + os.path.basename(outfile)] self.pbcompile(compiler, source, objectfile, extra_args=extra_args) try: subprocess.check_call(link_cmd) finally: os.unlink(objectfile) + + def test_prebuilt_shared_lib(self): + (cc, object_suffix, shared_suffix) = self.detect_prebuild_env() + tdir = os.path.join(self.unit_test_dir, '16 prebuilt shared') + source = os.path.join(tdir, 'alexandria.c') + objectfile = os.path.join(tdir, 'alexandria.' + object_suffix) + impfile = os.path.join(tdir, 'alexandria.lib') + if cc.id == 'msvc': + shlibfile = os.path.join(tdir, 'alexandria.' + shared_suffix) + elif is_cygwin(): + shlibfile = os.path.join(tdir, 'cygalexandria.' + shared_suffix) + else: + shlibfile = os.path.join(tdir, 'libalexandria.' + shared_suffix) + self.build_shared_lib(cc, source, objectfile, shlibfile, impfile) + # Run the test try: self.init(tdir) self.build() @@ -1483,6 +1500,68 @@ int main(int argc, char **argv) { if os.path.splitext(fname)[1] not in ['.c', '.h']: os.unlink(fname) + def test_pkgconfig_static(self): + ''' + Test that the we only use static libraries when `static: true` is + passed to dependency() with pkg-config. Can't be an ordinary test + because we need to build libs and try to find them from meson.build + ''' + if not shutil.which('pkg-config'): + raise unittest.SkipTest('pkg-config not found') + (cc, objext, shext) = self.detect_prebuild_env() + testdir = os.path.join(self.unit_test_dir, '17 pkgconfig static') + source = os.path.join(testdir, 'foo.c') + objectfile = os.path.join(testdir, 'foo.' + objext) + stlibfile = os.path.join(testdir, 'libfoo.a') + impfile = os.path.join(testdir, 'foo.lib') + if cc.id == 'msvc': + shlibfile = os.path.join(testdir, 'foo.' + shext) + elif is_cygwin(): + shlibfile = os.path.join(testdir, 'cygfoo.' + shext) + else: + shlibfile = os.path.join(testdir, 'libfoo.' + shext) + # Build libs + self.build_static_lib(cc, source, objectfile, stlibfile, extra_args=['-DFOO_STATIC']) + self.build_shared_lib(cc, source, objectfile, shlibfile, impfile) + # Run test + os.environ['PKG_CONFIG_LIBDIR'] = self.builddir + try: + self.init(testdir) + self.build() + self.run_tests() + finally: + os.unlink(stlibfile) + os.unlink(shlibfile) + if mesonbuild.mesonlib.is_windows(): + # Clean up all the garbage MSVC writes in the + # source tree. + for fname in glob(os.path.join(testdir, 'foo.*')): + if os.path.splitext(fname)[1] not in ['.c', '.h', '.in']: + os.unlink(fname) + + def test_pkgconfig_gen_escaping(self): + if not shutil.which('pkg-config'): + raise unittest.SkipTest('pkg-config not found') + testdir = os.path.join(self.common_test_dir, '51 pkgconfig-gen') + prefix = '/usr/with spaces' + libdir = 'lib' + self.init(testdir, extra_args=['--prefix=' + prefix, + '--libdir=' + libdir]) + # Find foo dependency + os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir + env = FakeEnvironment() + kwargs = {'required': True, 'silent': True} + foo_dep = PkgConfigDependency('libfoo', env, kwargs) + # Ensure link_args are properly quoted + libdir = PurePath(prefix) / PurePath(libdir) + link_args = ['-L' + libdir.as_posix(), '-lfoo'] + self.assertEqual(foo_dep.get_link_args(), link_args) + # Ensure include args are properly quoted + incdir = PurePath(prefix) / PurePath('include') + cargs = ['-I' + incdir.as_posix()] + self.assertEqual(foo_dep.get_compile_args(), cargs) + + class FailureTests(BasePlatformTests): ''' Tests that test failure conditions. Build files here should be dynamically @@ -1539,6 +1618,8 @@ class FailureTests(BasePlatformTests): def test_dependency(self): if not shutil.which('pkg-config'): raise unittest.SkipTest('pkg-config not found') + if subprocess.call(['pkg-config', '--exists', 'zlib']) != 0: + raise unittest.SkipTest('zlib not found with pkg-config') a = (("dependency('zlib', method : 'fail')", "'fail' is invalid"), ("dependency('zlib', static : '1')", "[Ss]tatic.*boolean"), ("dependency('zlib', version : 1)", "[Vv]ersion.*string or list"), @@ -1722,12 +1803,12 @@ class LinuxlikeTests(BasePlatformTests): env = FakeEnvironment() kwargs = {'required': True, 'silent': True} os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir - simple_dep = PkgConfigDependency('libfoo', env, kwargs) - self.assertTrue(simple_dep.found()) - self.assertEqual(simple_dep.get_version(), '1.0') - self.assertIn('-lfoo', simple_dep.get_link_args()) - self.assertEqual(simple_dep.get_pkgconfig_variable('foo'), 'bar') - self.assertPathEqual(simple_dep.get_pkgconfig_variable('datadir'), '/usr/data') + foo_dep = PkgConfigDependency('libfoo', env, kwargs) + self.assertTrue(foo_dep.found()) + self.assertEqual(foo_dep.get_version(), '1.0') + self.assertIn('-lfoo', foo_dep.get_link_args()) + self.assertEqual(foo_dep.get_pkgconfig_variable('foo'), 'bar') + self.assertPathEqual(foo_dep.get_pkgconfig_variable('datadir'), '/usr/data') def test_vala_c_warnings(self): ''' diff --git a/test cases/unit/17 pkgconfig static/foo.c b/test cases/unit/17 pkgconfig static/foo.c new file mode 100644 index 000000000..bf7fbddf3 --- /dev/null +++ b/test cases/unit/17 pkgconfig static/foo.c @@ -0,0 +1,8 @@ +int power_level (void) +{ +#ifdef FOO_STATIC + return 9001; +#else + return 8999; +#endif +} diff --git a/test cases/unit/17 pkgconfig static/foo.pc.in b/test cases/unit/17 pkgconfig static/foo.pc.in new file mode 100644 index 000000000..94d803154 --- /dev/null +++ b/test cases/unit/17 pkgconfig static/foo.pc.in @@ -0,0 +1,10 @@ +prefix=@PREFIX@ +libdir=${prefix} +includedir=${prefix}/include +datadir=${prefix}/data + +Name: libfoo +Description: A foo library. +Version: 1.0 +Libs: -L${libdir} -lfoo +Cflags: -I${includedir} diff --git a/test cases/unit/17 pkgconfig static/include/foo.h b/test cases/unit/17 pkgconfig static/include/foo.h new file mode 100644 index 000000000..88ef55494 --- /dev/null +++ b/test cases/unit/17 pkgconfig static/include/foo.h @@ -0,0 +1,3 @@ +#pragma once + +int power_level (void); diff --git a/test cases/unit/17 pkgconfig static/main.c b/test cases/unit/17 pkgconfig static/main.c new file mode 100644 index 000000000..cc4649f71 --- /dev/null +++ b/test cases/unit/17 pkgconfig static/main.c @@ -0,0 +1,14 @@ +#include +#include + +int +main (int argc, char * argv[]) +{ + int value = power_level (); + if (value < 9000) { + printf ("Power level is %i\n", value); + return 1; + } + printf ("IT'S OVER 9000!!!\n"); + return 0; +} diff --git a/test cases/unit/17 pkgconfig static/meson.build b/test cases/unit/17 pkgconfig static/meson.build new file mode 100644 index 000000000..caeb4aae2 --- /dev/null +++ b/test cases/unit/17 pkgconfig static/meson.build @@ -0,0 +1,23 @@ +project('pkg-config static', 'c') + +if build_machine.system() != 'windows' + prefix = meson.source_root() +else + # pkg-config files should not use paths with \ + prefix_parts = meson.source_root().split('\\') + prefix = '/'.join(prefix_parts) +endif + +# Escape spaces +prefix_parts = prefix.split(' ') +prefix = '\ '.join(prefix_parts) + +conf = configuration_data() +conf.set('PREFIX', prefix) +configure_file(input : 'foo.pc.in', + output : 'foo.pc', + configuration : conf) + +foo_dep = dependency('foo', static : true) + +test('footest', executable('foomain', 'main.c', dependencies : foo_dep))