From b9c4fc728c6e34cedb387d6844f21456c38ad269 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 30 Sep 2017 16:08:41 +0300 Subject: Moved prebuilt object test under unittests. --- run_project_tests.py | 8 +++--- run_unittests.py | 37 ++++++++++++++++++++++++++ test cases/prebuilt/1 object/main.c | 5 ---- test cases/prebuilt/1 object/meson.build | 25 ----------------- test cases/prebuilt/1 object/source.c | 8 ------ test cases/unit/14 prebuilt object/main.c | 5 ++++ test cases/unit/14 prebuilt object/meson.build | 25 +++++++++++++++++ test cases/unit/14 prebuilt object/source.c | 8 ++++++ 8 files changed, 78 insertions(+), 43 deletions(-) delete mode 100644 test cases/prebuilt/1 object/main.c delete mode 100644 test cases/prebuilt/1 object/meson.build delete mode 100644 test cases/prebuilt/1 object/source.c create mode 100644 test cases/unit/14 prebuilt object/main.c create mode 100644 test cases/unit/14 prebuilt object/meson.build create mode 100644 test cases/unit/14 prebuilt object/source.c diff --git a/run_project_tests.py b/run_project_tests.py index 426e2c7..03dc8be 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -642,9 +642,8 @@ def generate_prebuilt(): object_suffix = 'obj' else: object_suffix = 'o' - objectfile = generate_pb_object(compiler, object_suffix) stlibfile = generate_pb_static(compiler, object_suffix, static_suffix) - return objectfile, stlibfile + return stlibfile def check_meson_commands_work(): global backend, meson_command, compile_commands, test_commands, install_commands @@ -684,14 +683,13 @@ if __name__ == '__main__': os.chdir(script_dir) check_format() check_meson_commands_work() - pbfiles = generate_prebuilt() + pbfile = generate_prebuilt() try: all_tests = detect_tests_to_run() (passing_tests, failing_tests, skipped_tests) = run_tests(all_tests, 'meson-test-run', options.extra_args) except StopException: pass - for f in pbfiles: - os.unlink(f) + os.unlink(pbfile) print('\nTotal passed tests:', green(str(passing_tests))) print('Total failed tests:', red(str(failing_tests))) print('Total skipped tests:', yellow(str(skipped_tests))) diff --git a/run_unittests.py b/run_unittests.py index b217714..e307626 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1298,6 +1298,43 @@ int main(int argc, char **argv) { for i in targets: self.assertPathExists(os.path.join(testdir, i)) + def detect_prebuild_env(self): + if mesonbuild.mesonlib.is_windows(): + object_suffix = 'obj' + else: + object_suffix = 'o' + static_suffix = 'a' + if shutil.which('cl'): + compiler = 'cl' + static_suffix = 'lib' + elif shutil.which('cc'): + compiler = 'cc' + elif shutil.which('gcc'): + compiler = 'gcc' + else: + raise RuntimeError("Could not find C compiler.") + return (compiler, object_suffix, static_suffix) + + def pbcompile(self, compiler, source, objectfile): + if compiler == 'cl': + cmd = [compiler, '/nologo', '/Fo' + objectfile, '/c', source] + else: + cmd = [compiler, '-c', source, '-o', objectfile] + subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + + def test_prebuilt_object(self): + (compiler, object_suffix, static_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) + self.pbcompile(compiler, source, objectfile) + try: + self.init(tdir) + self.build() + self.run_tests() + finally: + os.unlink(objectfile) class FailureTests(BasePlatformTests): ''' diff --git a/test cases/prebuilt/1 object/main.c b/test cases/prebuilt/1 object/main.c deleted file mode 100644 index 480bda5..0000000 --- a/test cases/prebuilt/1 object/main.c +++ /dev/null @@ -1,5 +0,0 @@ -int func(); - -int main(int argc, char **argv) { - return func() == 42 ? 0 : 99; -} diff --git a/test cases/prebuilt/1 object/meson.build b/test cases/prebuilt/1 object/meson.build deleted file mode 100644 index 92f966b..0000000 --- a/test cases/prebuilt/1 object/meson.build +++ /dev/null @@ -1,25 +0,0 @@ -# This test is on its own because it is special. -# To run the test you need the prebuilt object -# file for the given platform. -# -# Combined with cross compilation this would make -# the state space explode so let's just keep this -# in its own subdir so it's not run during cross -# compilation tests. - -project('prebuilt object', 'c') - -if host_machine.system() == 'windows' - prebuilt = 'prebuilt.obj' -else - prebuilt = 'prebuilt.o' -endif - -# Remember: do not put source.c in this -# declaration. run_tests.py generates the -# prebuilt object before running this test. - -e = executable('prog', 'main.c', -objects : prebuilt) - -test('objtest', e) diff --git a/test cases/prebuilt/1 object/source.c b/test cases/prebuilt/1 object/source.c deleted file mode 100644 index f39b4f3..0000000 --- a/test cases/prebuilt/1 object/source.c +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Compile this manually on new platforms and add the - * object file to revision control and Meson configuration. - */ - -int func() { - return 42; -} diff --git a/test cases/unit/14 prebuilt object/main.c b/test cases/unit/14 prebuilt object/main.c new file mode 100644 index 0000000..480bda5 --- /dev/null +++ b/test cases/unit/14 prebuilt object/main.c @@ -0,0 +1,5 @@ +int func(); + +int main(int argc, char **argv) { + return func() == 42 ? 0 : 99; +} diff --git a/test cases/unit/14 prebuilt object/meson.build b/test cases/unit/14 prebuilt object/meson.build new file mode 100644 index 0000000..92f966b --- /dev/null +++ b/test cases/unit/14 prebuilt object/meson.build @@ -0,0 +1,25 @@ +# This test is on its own because it is special. +# To run the test you need the prebuilt object +# file for the given platform. +# +# Combined with cross compilation this would make +# the state space explode so let's just keep this +# in its own subdir so it's not run during cross +# compilation tests. + +project('prebuilt object', 'c') + +if host_machine.system() == 'windows' + prebuilt = 'prebuilt.obj' +else + prebuilt = 'prebuilt.o' +endif + +# Remember: do not put source.c in this +# declaration. run_tests.py generates the +# prebuilt object before running this test. + +e = executable('prog', 'main.c', +objects : prebuilt) + +test('objtest', e) diff --git a/test cases/unit/14 prebuilt object/source.c b/test cases/unit/14 prebuilt object/source.c new file mode 100644 index 0000000..f39b4f3 --- /dev/null +++ b/test cases/unit/14 prebuilt object/source.c @@ -0,0 +1,8 @@ +/* + * Compile this manually on new platforms and add the + * object file to revision control and Meson configuration. + */ + +int func() { + return 42; +} -- cgit v1.1 From ac79eebc2f4564642ae2ddedf05c4abb45f69634 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 30 Sep 2017 16:34:30 +0300 Subject: Moved prebuilt static library under unit tests. --- run_project_tests.py | 70 ++++++---------------- run_unittests.py | 24 +++++++- test cases/prebuilt/2 static/libdir/best.c | 3 - test cases/prebuilt/2 static/libdir/best.h | 3 - test cases/prebuilt/2 static/libdir/meson.build | 5 -- test cases/prebuilt/2 static/main.c | 7 --- test cases/prebuilt/2 static/meson.build | 5 -- test cases/unit/15 prebuilt static/libdir/best.c | 3 + test cases/unit/15 prebuilt static/libdir/best.h | 3 + .../unit/15 prebuilt static/libdir/meson.build | 5 ++ test cases/unit/15 prebuilt static/main.c | 7 +++ test cases/unit/15 prebuilt static/meson.build | 5 ++ 12 files changed, 63 insertions(+), 77 deletions(-) delete mode 100644 test cases/prebuilt/2 static/libdir/best.c delete mode 100644 test cases/prebuilt/2 static/libdir/best.h delete mode 100644 test cases/prebuilt/2 static/libdir/meson.build delete mode 100644 test cases/prebuilt/2 static/main.c delete mode 100644 test cases/prebuilt/2 static/meson.build create mode 100644 test cases/unit/15 prebuilt static/libdir/best.c create mode 100644 test cases/unit/15 prebuilt static/libdir/best.h create mode 100644 test cases/unit/15 prebuilt static/libdir/meson.build create mode 100644 test cases/unit/15 prebuilt static/main.c create mode 100644 test cases/unit/15 prebuilt static/meson.build diff --git a/run_project_tests.py b/run_project_tests.py index 03dc8be..17e095b 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -124,6 +124,8 @@ print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ do_debug = not {'MESON_PRINT_TEST_OUTPUT', 'TRAVIS', 'APPVEYOR'}.isdisjoint(os.environ) no_meson_log_msg = 'No meson-log.txt found.' +system_compiler = None + meson_command = os.path.join(os.getcwd(), 'meson') if not os.path.exists(meson_command): meson_command += '.py' @@ -141,9 +143,6 @@ def stop_handler(signal, frame): signal.signal(signal.SIGINT, stop_handler) signal.signal(signal.SIGTERM, stop_handler) -# Needed when running cross tests because we don't generate prebuilt files -compiler = None - def setup_commands(optbackend): global do_debug, backend, backend_flags global compile_commands, clean_commands, test_commands, install_commands, uninstall_commands @@ -451,7 +450,6 @@ def detect_tests_to_run(): ('failing-meson', 'failing', False), ('failing-build', 'failing build', False), ('failing-tests', 'failing tests', False), - ('prebuilt', 'prebuilt', False), ('platform-osx', 'osx', not mesonlib.is_osx()), ('platform-windows', 'windows', not mesonlib.is_windows() and not mesonlib.is_cygwin()), @@ -485,7 +483,7 @@ def run_tests(all_tests, log_name_base, extra_args): return _run_tests(all_tests, log_name_base, extra_args) def _run_tests(all_tests, log_name_base, extra_args): - global stop, executor, futures + global stop, executor, futures, system_compiler xmlname = log_name_base + '.xml' junit_root = ET.Element('testsuites') conf_time = 0 @@ -532,7 +530,7 @@ def _run_tests(all_tests, log_name_base, extra_args): should_fail = False if name.startswith('failing'): should_fail = name.split('failing-')[1] - result = executor.submit(run_test, skipped, t, extra_args, compiler, backend, backend_flags, commands, should_fail) + result = executor.submit(run_test, skipped, t, extra_args, system_compiler, backend, backend_flags, commands, should_fail) futures.append((testname, t, result)) for (testname, t, result) in futures: sys.stdout.flush() @@ -600,51 +598,6 @@ def check_format(): fullname = os.path.join(root, file) check_file(fullname) -def pbcompile(compiler, source, objectfile): - if compiler == 'cl': - cmd = [compiler, '/nologo', '/Fo' + objectfile, '/c', source] - else: - cmd = [compiler, '-c', source, '-o', objectfile] - subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - -def generate_pb_object(compiler, object_suffix): - source = 'test cases/prebuilt/1 object/source.c' - objectfile = 'test cases/prebuilt/1 object/prebuilt.' + object_suffix - pbcompile(compiler, source, objectfile) - return objectfile - -def generate_pb_static(compiler, object_suffix, static_suffix): - source = 'test cases/prebuilt/2 static/libdir/best.c' - objectfile = 'test cases/prebuilt/2 static/libdir/best.' + object_suffix - stlibfile = 'test cases/prebuilt/2 static/libdir/libbest.' + static_suffix - pbcompile(compiler, source, objectfile) - if compiler == 'cl': - linker = ['lib', '/NOLOGO', '/OUT:' + stlibfile, objectfile] - else: - linker = ['ar', 'csr', stlibfile, objectfile] - subprocess.check_call(linker) - os.unlink(objectfile) - return stlibfile - -def generate_prebuilt(): - global compiler - static_suffix = 'a' - if shutil.which('cl'): - compiler = 'cl' - static_suffix = 'lib' - elif shutil.which('cc'): - compiler = 'cc' - elif shutil.which('gcc'): - compiler = 'gcc' - else: - raise RuntimeError("Could not find C compiler.") - if mesonlib.is_windows(): - object_suffix = 'obj' - else: - object_suffix = 'o' - stlibfile = generate_pb_static(compiler, object_suffix, static_suffix) - return stlibfile - def check_meson_commands_work(): global backend, meson_command, compile_commands, test_commands, install_commands testdir = 'test cases/common/1 trivial' @@ -669,6 +622,18 @@ def check_meson_commands_work(): if pc.returncode != 0: raise RuntimeError('Failed to install {!r}:\n{}\n{}'.format(testdir, e, o)) + +def detect_system_compiler(): + global system_compiler + if shutil.which('cl'): + system_compiler = 'cl' + elif shutil.which('cc'): + system_compiler = 'cc' + elif shutil.which('gcc'): + system_compiler = 'gcc' + else: + raise RuntimeError("Could not find C compiler.") + if __name__ == '__main__': parser = argparse.ArgumentParser(description="Run the test suite of Meson.") parser.add_argument('extra_args', nargs='*', @@ -678,18 +643,17 @@ if __name__ == '__main__': options = parser.parse_args() setup_commands(options.backend) + detect_system_compiler() script_dir = os.path.split(__file__)[0] if script_dir != '': os.chdir(script_dir) check_format() check_meson_commands_work() - pbfile = generate_prebuilt() try: all_tests = detect_tests_to_run() (passing_tests, failing_tests, skipped_tests) = run_tests(all_tests, 'meson-test-run', options.extra_args) except StopException: pass - os.unlink(pbfile) print('\nTotal passed tests:', green(str(passing_tests))) print('Total failed tests:', red(str(failing_tests))) print('Total skipped tests:', yellow(str(skipped_tests))) diff --git a/run_unittests.py b/run_unittests.py index e307626..e821152 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1324,7 +1324,7 @@ int main(int argc, char **argv) { def test_prebuilt_object(self): - (compiler, object_suffix, static_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) @@ -1336,6 +1336,28 @@ 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] + else: + link_cmd = ['ar', 'csr', stlibfile, objectfile] + self.pbcompile(compiler, source, objectfile) + try: + subprocess.check_call(link_cmd) + finally: + os.unlink(objectfile) + try: + self.init(tdir) + self.build() + self.run_tests() + finally: + os.unlink(stlibfile) + class FailureTests(BasePlatformTests): ''' Tests that test failure conditions. Build files here should be dynamically diff --git a/test cases/prebuilt/2 static/libdir/best.c b/test cases/prebuilt/2 static/libdir/best.c deleted file mode 100644 index ab774e1..0000000 --- a/test cases/prebuilt/2 static/libdir/best.c +++ /dev/null @@ -1,3 +0,0 @@ -const char *msg() { - return "I am the best."; -} diff --git a/test cases/prebuilt/2 static/libdir/best.h b/test cases/prebuilt/2 static/libdir/best.h deleted file mode 100644 index 063017f..0000000 --- a/test cases/prebuilt/2 static/libdir/best.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -const char *msg(); diff --git a/test cases/prebuilt/2 static/libdir/meson.build b/test cases/prebuilt/2 static/libdir/meson.build deleted file mode 100644 index 8d74ccf..0000000 --- a/test cases/prebuilt/2 static/libdir/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -cc = meson.get_compiler('c') -stlib = cc.find_library('best', dirs : meson.current_source_dir()) - -best_dep = declare_dependency(dependencies : stlib, - include_directories : include_directories('.')) diff --git a/test cases/prebuilt/2 static/main.c b/test cases/prebuilt/2 static/main.c deleted file mode 100644 index d172625..0000000 --- a/test cases/prebuilt/2 static/main.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include - -int main(int argc, char **argv) { - printf("%s\n", msg()); - return 0; -} diff --git a/test cases/prebuilt/2 static/meson.build b/test cases/prebuilt/2 static/meson.build deleted file mode 100644 index 9ea1d0d..0000000 --- a/test cases/prebuilt/2 static/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -project('prebuilt static lib', 'c') - -subdir('libdir') - -test('static', executable('mainprog', 'main.c', dependencies : best_dep)) diff --git a/test cases/unit/15 prebuilt static/libdir/best.c b/test cases/unit/15 prebuilt static/libdir/best.c new file mode 100644 index 0000000..ab774e1 --- /dev/null +++ b/test cases/unit/15 prebuilt static/libdir/best.c @@ -0,0 +1,3 @@ +const char *msg() { + return "I am the best."; +} diff --git a/test cases/unit/15 prebuilt static/libdir/best.h b/test cases/unit/15 prebuilt static/libdir/best.h new file mode 100644 index 0000000..063017f --- /dev/null +++ b/test cases/unit/15 prebuilt static/libdir/best.h @@ -0,0 +1,3 @@ +#pragma once + +const char *msg(); diff --git a/test cases/unit/15 prebuilt static/libdir/meson.build b/test cases/unit/15 prebuilt static/libdir/meson.build new file mode 100644 index 0000000..8d74ccf --- /dev/null +++ b/test cases/unit/15 prebuilt static/libdir/meson.build @@ -0,0 +1,5 @@ +cc = meson.get_compiler('c') +stlib = cc.find_library('best', dirs : meson.current_source_dir()) + +best_dep = declare_dependency(dependencies : stlib, + include_directories : include_directories('.')) diff --git a/test cases/unit/15 prebuilt static/main.c b/test cases/unit/15 prebuilt static/main.c new file mode 100644 index 0000000..d172625 --- /dev/null +++ b/test cases/unit/15 prebuilt static/main.c @@ -0,0 +1,7 @@ +#include +#include + +int main(int argc, char **argv) { + printf("%s\n", msg()); + return 0; +} diff --git a/test cases/unit/15 prebuilt static/meson.build b/test cases/unit/15 prebuilt static/meson.build new file mode 100644 index 0000000..9ea1d0d --- /dev/null +++ b/test cases/unit/15 prebuilt static/meson.build @@ -0,0 +1,5 @@ +project('prebuilt static lib', 'c') + +subdir('libdir') + +test('static', executable('mainprog', 'main.c', dependencies : best_dep)) -- cgit v1.1 From a655b64989ecdce507567d9cd729a2cefaf91942 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 30 Sep 2017 18:03:56 +0300 Subject: Add an rpath entry to shared libraries that are linked from the source tree. --- mesonbuild/backend/backends.py | 17 ++++++++++ run_unittests.py | 39 ++++++++++++++++++---- test cases/unit/16 prebuilt shared/alexandria.c | 6 ++++ test cases/unit/16 prebuilt shared/alexandria.h | 20 +++++++++++ .../unit/16 prebuilt shared/another_visitor.c | 10 ++++++ test cases/unit/16 prebuilt shared/meson.build | 14 ++++++++ test cases/unit/16 prebuilt shared/patron.c | 8 +++++ 7 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 test cases/unit/16 prebuilt shared/alexandria.c create mode 100644 test cases/unit/16 prebuilt shared/alexandria.h create mode 100644 test cases/unit/16 prebuilt shared/another_visitor.c create mode 100644 test cases/unit/16 prebuilt shared/meson.build create mode 100644 test cases/unit/16 prebuilt shared/patron.c diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 12fb3eb..562e467 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -298,6 +298,22 @@ class Backend: raise MesonException(m.format(target.name)) return l + def rpaths_for_bundled_shared_libraries(self, target): + paths = [] + for dep in target.external_deps: + if isinstance(dep, dependencies.ExternalLibrary): + la = dep.link_args + if len(la) == 1 and la[0].startswith(self.environment.get_source_dir()): + # The only link argument is an absolute path to a library file. + libpath = la[0] + if not(libpath.lower().endswith('.dll') or libpath.lower().endswith('.so')): + continue + absdir = os.path.split(libpath)[0] + rel_to_src = absdir[len(self.environment.get_source_dir())+1:] + assert(not os.path.isabs(rel_to_src)) + paths.append(os.path.join(self.build_to_src, rel_to_src)) + return paths + def determine_rpath_dirs(self, target): link_deps = target.get_all_link_deps() result = [] @@ -305,6 +321,7 @@ class Backend: prospective = self.get_target_dir(ld) if prospective not in result: result.append(prospective) + result += self.rpaths_for_bundled_shared_libraries(target) return result def object_filename_from_source(self, target, source, is_unity): diff --git a/run_unittests.py b/run_unittests.py index e821152..abff78a 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1304,27 +1304,29 @@ int main(int argc, char **argv) { else: 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' else: raise RuntimeError("Could not find C compiler.") - return (compiler, object_suffix, static_suffix) + return (compiler, object_suffix, static_suffix, shared_suffix) - def pbcompile(self, compiler, source, objectfile): + def pbcompile(self, compiler, source, objectfile, extra_args=[]): if compiler == 'cl': - cmd = [compiler, '/nologo', '/Fo' + objectfile, '/c', source] + cmd = [compiler, '/nologo', '/Fo' + objectfile, '/c', source] + extra_args else: - cmd = [compiler, '-c', source, '-o', objectfile] + cmd = [compiler, '-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) @@ -1337,7 +1339,7 @@ int main(int argc, char **argv) { os.unlink(objectfile) def test_prebuilt_static_lib(self): - (compiler, object_suffix, static_suffix) = self.detect_prebuild_env() + (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) @@ -1358,6 +1360,31 @@ 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': + extra_args = [] + shlibfile = os.path.join(tdir, 'alexandria.' + shared_suffix) + link_cmd = ['link', '/NOLOGO','/DLL', '/DEBUG', '/IMPLIB:alexandria.lib' '/OUT:' + shlibfile, objectfile] + else: + extra_args = ['-fPIC'] + shlibfile = os.path.join(tdir, 'libalexandria.' + shared_suffix) + link_cmd = [compiler, '-shared', '-o', shlibfile, objectfile, '-Wl,-soname=libalexandria.so'] + self.pbcompile(compiler, source, objectfile, extra_args=extra_args) + try: + subprocess.check_call(link_cmd) + finally: + os.unlink(objectfile) + try: + self.init(tdir) + self.build() + self.run_tests() + finally: + os.unlink(shlibfile) + class FailureTests(BasePlatformTests): ''' Tests that test failure conditions. Build files here should be dynamically diff --git a/test cases/unit/16 prebuilt shared/alexandria.c b/test cases/unit/16 prebuilt shared/alexandria.c new file mode 100644 index 0000000..2d6b848 --- /dev/null +++ b/test cases/unit/16 prebuilt shared/alexandria.c @@ -0,0 +1,6 @@ +#include"alexandria.h" +#include + +void alexandria_visit() { + printf("You are surrounded by wisdom and knowledge. You feel enlightened.\n"); +} diff --git a/test cases/unit/16 prebuilt shared/alexandria.h b/test cases/unit/16 prebuilt shared/alexandria.h new file mode 100644 index 0000000..6e507c5 --- /dev/null +++ b/test cases/unit/16 prebuilt shared/alexandria.h @@ -0,0 +1,20 @@ +#pragma once + +/* Both funcs here for simplicity. */ + +#if defined _WIN32 || defined __CYGWIN__ +#if defined BUILDING_DLL + #define DLL_PUBLIC __declspec(dllexport) +#else + #define DLL_PUBLIC __declspec(dllimport) +#endif +#else + #if defined __GNUC__ + #define DLL_PUBLIC __attribute__ ((visibility("default"))) + #else + #pragma message ("Compiler does not support symbol visibility.") + #define DLL_PUBLIC + #endif +#endif + +void DLL_PUBLIC alexandria_visit(); diff --git a/test cases/unit/16 prebuilt shared/another_visitor.c b/test cases/unit/16 prebuilt shared/another_visitor.c new file mode 100644 index 0000000..18e5f15 --- /dev/null +++ b/test cases/unit/16 prebuilt shared/another_visitor.c @@ -0,0 +1,10 @@ +#include +#include + +int main(int argc, char **argv) { + printf("Ahh, another visitor. Stay a while.\n"); + printf("You enter the library.\n\n"); + alexandria_visit(); + printf("\nYou decided not to stay forever.\n"); + return 0; +} diff --git a/test cases/unit/16 prebuilt shared/meson.build b/test cases/unit/16 prebuilt shared/meson.build new file mode 100644 index 0000000..41c11c6 --- /dev/null +++ b/test cases/unit/16 prebuilt shared/meson.build @@ -0,0 +1,14 @@ +project('prebuilt shared library', 'c') + +cc = meson.get_compiler('c') +shlib = cc.find_library('alexandria', dirs : meson.current_source_dir()) + +exe = executable('patron', 'patron.c', dependencies : shlib) +test('visitation', exe) + +d = declare_dependency(dependencies : shlib) + +exe2 = executable('another_visitor', 'another_visitor.c', + dependencies : d) +test('another', exe2) + diff --git a/test cases/unit/16 prebuilt shared/patron.c b/test cases/unit/16 prebuilt shared/patron.c new file mode 100644 index 0000000..82d9678 --- /dev/null +++ b/test cases/unit/16 prebuilt shared/patron.c @@ -0,0 +1,8 @@ +#include +#include + +int main(int argc, char **argv) { + printf("You are standing outside the Great Library of Alexandria.\n"); + printf("You decide to go inside.\n\n"); + alexandria_visit(); +} -- cgit v1.1 From b3362e350ad0c8603966bc485e66af553750c648 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 30 Sep 2017 18:25:33 +0300 Subject: Added release note snippet for prebuilt shared libs. --- docs/markdown/snippets/prebuilt.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 docs/markdown/snippets/prebuilt.md diff --git a/docs/markdown/snippets/prebuilt.md b/docs/markdown/snippets/prebuilt.md new file mode 100644 index 0000000..a51176a --- /dev/null +++ b/docs/markdown/snippets/prebuilt.md @@ -0,0 +1,15 @@ +# Better support for prebuilt shared libraries + +Meson has had support for prebuilt object files and static libraries. +This release adds feature parity to shared libraries. This means +that e.g. shipping prebuilt libraries as subprojects now can +be as simple as writing a definition file that looks like this. + + project('myprebuiltlibrary', 'c') + + cc = meson.get_compiler('c') + prebuilt = cc.find_library('mylib', dirs : meson.current_source_dir()) + mydep = declare_dependency(include_directories : include_directories('.'), + dependencies : prebuilt) + +Then you can use the dependency object in the same way as any other. -- cgit v1.1 From cb64a3f07a91c01c84f80d5303aaf5f0fe5ee100 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 1 Oct 2017 01:11:02 +0300 Subject: Fix MSVC builds. --- mesonbuild/backend/backends.py | 4 +++- run_unittests.py | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 562e467..c737d49 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -306,7 +306,7 @@ class Backend: if len(la) == 1 and la[0].startswith(self.environment.get_source_dir()): # The only link argument is an absolute path to a library file. libpath = la[0] - if not(libpath.lower().endswith('.dll') or libpath.lower().endswith('.so')): + if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so']: continue absdir = os.path.split(libpath)[0] rel_to_src = absdir[len(self.environment.get_source_dir())+1:] @@ -530,6 +530,8 @@ class Backend: dirseg = os.path.join(self.environment.get_build_dir(), self.get_target_dir(ld)) if dirseg not in result: result.append(dirseg) + for deppath in self.rpaths_for_bundled_shared_libraries(target): + result.append(os.path.normpath(os.path.join(self.environment.get_build_dir(), deppath))) return result def write_benchmark_file(self, datafile): diff --git a/run_unittests.py b/run_unittests.py index abff78a..b1021e0 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1368,7 +1368,7 @@ int main(int argc, char **argv) { if compiler == 'cl': extra_args = [] shlibfile = os.path.join(tdir, 'alexandria.' + shared_suffix) - link_cmd = ['link', '/NOLOGO','/DLL', '/DEBUG', '/IMPLIB:alexandria.lib' '/OUT:' + shlibfile, objectfile] + link_cmd = ['link', '/NOLOGO','/DLL', '/DEBUG', '/IMPLIB:' + os.path.join(tdir, 'alexandria.lib'), '/OUT:' + shlibfile, objectfile] else: extra_args = ['-fPIC'] shlibfile = os.path.join(tdir, 'libalexandria.' + shared_suffix) @@ -1384,6 +1384,12 @@ int main(int argc, char **argv) { self.run_tests() finally: 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(tdir, 'alexandria.*')): + if os.path.splitext(fname)[1] not in ['.c', '.h']: + os.unlink(fname) class FailureTests(BasePlatformTests): ''' -- cgit v1.1 From 4e428614677476b55b08b152f122508582795922 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 1 Oct 2017 01:59:09 +0300 Subject: Fix tests on OSX. --- run_unittests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/run_unittests.py b/run_unittests.py index b1021e0..af1a5f2 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1372,7 +1372,9 @@ int main(int argc, char **argv) { else: extra_args = ['-fPIC'] shlibfile = os.path.join(tdir, 'libalexandria.' + shared_suffix) - link_cmd = [compiler, '-shared', '-o', shlibfile, objectfile, '-Wl,-soname=libalexandria.so'] + link_cmd = [compiler, '-shared', '-o', shlibfile, objectfile] + if not mesonbuild.mesonlib.is_osx(): + link_cmd += ['-Wl,-soname=libalexandria.so'] self.pbcompile(compiler, source, objectfile, extra_args=extra_args) try: subprocess.check_call(link_cmd) -- cgit v1.1 From 3a63f0d63c7795c3f1562eb9a7c1c439c384fb47 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Tue, 26 Sep 2017 16:43:42 +0530 Subject: interpreter: Add a new ObjectHolder class Sets the held_object property and also implements a readable repr() --- mesonbuild/interpreter.py | 135 ++++++++++++++++++++++++---------------------- 1 file changed, 72 insertions(+), 63 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 7641514..0e8d301 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -48,6 +48,14 @@ def stringifyUserArguments(args): raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.') +class ObjectHolder: + def __init__(self, obj): + self.held_object = obj + + def __repr__(self): + return ''.format(self.held_object) + + class TryRunResultHolder(InterpreterObject): def __init__(self, res): super().__init__() @@ -117,17 +125,18 @@ class RunProcess(InterpreterObject): def stderr_method(self, args, kwargs): return self.stderr -class ConfigureFileHolder(InterpreterObject): +class ConfigureFileHolder(InterpreterObject, ObjectHolder): def __init__(self, subdir, sourcename, targetname, configuration_data): InterpreterObject.__init__(self) - self.held_object = build.ConfigureFile(subdir, sourcename, targetname, configuration_data) + ObjectHolder.__init__(self, build.ConfigureFile(subdir, sourcename, + targetname, configuration_data)) -class EnvironmentVariablesHolder(MutableInterpreterObject): +class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder): def __init__(self): - super().__init__() - self.held_object = build.EnvironmentVariables() + MutableInterpreterObject.__init__(self) + ObjectHolder.__init__(self, build.EnvironmentVariables()) self.methods.update({'set': self.set_method, 'append': self.append_method, 'prepend': self.prepend_method, @@ -158,11 +167,11 @@ class EnvironmentVariablesHolder(MutableInterpreterObject): self.add_var(self.held_object.prepend, args, kwargs) -class ConfigurationDataHolder(MutableInterpreterObject): +class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder): def __init__(self): - super().__init__() + MutableInterpreterObject.__init__(self) self.used = False # These objects become immutable after use in configure_file. - self.held_object = build.ConfigurationData() + ObjectHolder.__init__(self, build.ConfigurationData()) self.methods.update({'set': self.set_method, 'set10': self.set10_method, 'set_quoted': self.set_quoted_method, @@ -242,10 +251,10 @@ class ConfigurationDataHolder(MutableInterpreterObject): # Interpreter objects can not be pickled so we must have # these wrappers. -class DependencyHolder(InterpreterObject): +class DependencyHolder(InterpreterObject, ObjectHolder): def __init__(self, dep): InterpreterObject.__init__(self) - self.held_object = dep + ObjectHolder.__init__(self, dep) self.methods.update({'found': self.found_method, 'type_name': self.type_name_method, 'version': self.version_method, @@ -272,10 +281,10 @@ class DependencyHolder(InterpreterObject): raise InterpreterException('Variable name must be a string.') return self.held_object.get_pkgconfig_variable(varname) -class InternalDependencyHolder(InterpreterObject): +class InternalDependencyHolder(InterpreterObject, ObjectHolder): def __init__(self, dep): InterpreterObject.__init__(self) - self.held_object = dep + ObjectHolder.__init__(self, dep) self.methods.update({'found': self.found_method, 'version': self.version_method, }) @@ -286,10 +295,10 @@ class InternalDependencyHolder(InterpreterObject): def version_method(self, args, kwargs): return self.held_object.get_version() -class ExternalProgramHolder(InterpreterObject): +class ExternalProgramHolder(InterpreterObject, ObjectHolder): def __init__(self, ep): InterpreterObject.__init__(self) - self.held_object = ep + ObjectHolder.__init__(self, ep) self.methods.update({'found': self.found_method, 'path': self.path_method}) @@ -308,10 +317,10 @@ class ExternalProgramHolder(InterpreterObject): def get_name(self): return self.held_object.get_name() -class ExternalLibraryHolder(InterpreterObject): +class ExternalLibraryHolder(InterpreterObject, ObjectHolder): def __init__(self, el): InterpreterObject.__init__(self) - self.held_object = el + ObjectHolder.__init__(self, el) self.methods.update({'found': self.found_method}) def found(self): @@ -332,11 +341,11 @@ class ExternalLibraryHolder(InterpreterObject): def get_exe_args(self): return self.held_object.get_exe_args() -class GeneratorHolder(InterpreterObject): +class GeneratorHolder(InterpreterObject, ObjectHolder): def __init__(self, interpreter, args, kwargs): - super().__init__() + InterpreterObject.__init__(self) self.interpreter = interpreter - self.held_object = build.Generator(args, kwargs) + ObjectHolder.__init__(self, build.Generator(args, kwargs)) self.methods.update({'process': self.process_method}) def process_method(self, args, kwargs): @@ -345,13 +354,13 @@ class GeneratorHolder(InterpreterObject): return GeneratedListHolder(gl) -class GeneratedListHolder(InterpreterObject): +class GeneratedListHolder(InterpreterObject, ObjectHolder): def __init__(self, arg1, extra_args=[]): - super().__init__() + InterpreterObject.__init__(self) if isinstance(arg1, GeneratorHolder): - self.held_object = build.GeneratedList(arg1.held_object, extra_args) + ObjectHolder.__init__(self, build.GeneratedList(arg1.held_object, extra_args)) else: - self.held_object = arg1 + ObjectHolder.__init__(self, arg1) def __repr__(self): r = '<{}: {!r}>' @@ -360,14 +369,15 @@ class GeneratedListHolder(InterpreterObject): def add_file(self, a): self.held_object.add_file(a) -class BuildMachine(InterpreterObject): +class BuildMachine(InterpreterObject, ObjectHolder): def __init__(self, compilers): self.compilers = compilers InterpreterObject.__init__(self) - self.held_object = environment.MachineInfo(environment.detect_system(), - environment.detect_cpu_family(self.compilers), - environment.detect_cpu(self.compilers), - sys.byteorder) + held_object = environment.MachineInfo(environment.detect_system(), + environment.detect_cpu_family(self.compilers), + environment.detect_cpu(self.compilers), + sys.byteorder) + ObjectHolder.__init__(self, held_object) self.methods.update({'system': self.system_method, 'cpu_family': self.cpu_family_method, 'cpu': self.cpu_method, @@ -388,7 +398,7 @@ class BuildMachine(InterpreterObject): # This class will provide both host_machine and # target_machine -class CrossMachineInfo(InterpreterObject): +class CrossMachineInfo(InterpreterObject, ObjectHolder): def __init__(self, cross_info): InterpreterObject.__init__(self) minimum_cross_info = {'cpu', 'cpu_family', 'endian', 'system'} @@ -397,10 +407,11 @@ class CrossMachineInfo(InterpreterObject): 'Machine info is currently {}\n'.format(cross_info) + 'but is missing {}.'.format(minimum_cross_info - set(cross_info))) self.info = cross_info - self.held_object = environment.MachineInfo(cross_info['system'], - cross_info['cpu_family'], - cross_info['cpu'], - cross_info['endian']) + minfo = environment.MachineInfo(cross_info['system'], + cross_info['cpu_family'], + cross_info['cpu'], + cross_info['endian']) + ObjectHolder.__init__(self, minfo) self.methods.update({'system': self.system_method, 'cpu': self.cpu_method, 'cpu_family': self.cpu_family_method, @@ -419,10 +430,10 @@ class CrossMachineInfo(InterpreterObject): def endian_method(self, args, kwargs): return self.held_object.endian -class IncludeDirsHolder(InterpreterObject): +class IncludeDirsHolder(InterpreterObject, ObjectHolder): def __init__(self, idobj): - super().__init__() - self.held_object = idobj + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, idobj) class Headers(InterpreterObject): @@ -447,10 +458,10 @@ class Headers(InterpreterObject): def get_custom_install_dir(self): return self.custom_install_dir -class DataHolder(InterpreterObject): +class DataHolder(InterpreterObject, ObjectHolder): def __init__(self, data): - super().__init__() - self.held_object = data + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, data) def get_source_subdir(self): return self.held_object.source_subdir @@ -495,20 +506,20 @@ class Man(InterpreterObject): def get_sources(self): return self.sources -class GeneratedObjectsHolder(InterpreterObject): +class GeneratedObjectsHolder(InterpreterObject, ObjectHolder): def __init__(self, held_object): - super().__init__() - self.held_object = held_object + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, held_object) -class TargetHolder(InterpreterObject): - def __init__(self): - super().__init__() +class TargetHolder(InterpreterObject, ObjectHolder): + def __init__(self, target, interp): + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, target) + self.interpreter = interp class BuildTargetHolder(TargetHolder): def __init__(self, target, interp): - super().__init__() - self.held_object = target - self.interpreter = interp + super().__init__(target, interp) self.methods.update({'extract_objects': self.extract_objects_method, 'extract_all_objects': self.extract_all_objects_method, 'get_id': self.get_id_method, @@ -566,16 +577,14 @@ class JarHolder(BuildTargetHolder): def __init__(self, target, interp): super().__init__(target, interp) -class CustomTargetIndexHolder(InterpreterObject): +class CustomTargetIndexHolder(InterpreterObject, ObjectHolder): def __init__(self, object_to_hold): - super().__init__() - self.held_object = object_to_hold + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, object_to_hold) class CustomTargetHolder(TargetHolder): - def __init__(self, object_to_hold, interp): - super().__init__() - self.held_object = object_to_hold - self.interpreter = interp + def __init__(self, target, interp): + super().__init__(target, interp) self.methods.update({'full_path': self.full_path_method, }) @@ -596,10 +605,10 @@ class CustomTargetHolder(TargetHolder): def __delitem__(self, index): raise InterpreterException('Cannot delete a member of a CustomTarget') -class RunTargetHolder(InterpreterObject): +class RunTargetHolder(InterpreterObject, ObjectHolder): def __init__(self, name, command, args, dependencies, subdir): - super().__init__() - self.held_object = build.RunTarget(name, command, args, dependencies, subdir) + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, build.RunTarget(name, command, args, dependencies, subdir)) def __repr__(self): r = '<{} {}: {}>' @@ -625,11 +634,11 @@ class Test(InterpreterObject): def get_name(self): return self.name -class SubprojectHolder(InterpreterObject): +class SubprojectHolder(InterpreterObject, ObjectHolder): def __init__(self, subinterpreter): - super().__init__() - self.held_object = subinterpreter + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, subinterpreter) self.methods.update({'get_variable': self.get_variable_method, }) @@ -1056,11 +1065,11 @@ ModuleState = namedtuple('ModuleState', [ 'man', 'global_args', 'project_args', 'build_machine', 'host_machine', 'target_machine']) -class ModuleHolder(InterpreterObject): +class ModuleHolder(InterpreterObject, ObjectHolder): def __init__(self, modname, module, interpreter): InterpreterObject.__init__(self) + ObjectHolder.__init__(self, module) self.modname = modname - self.held_object = module self.interpreter = interpreter def method_call(self, method_name, args, kwargs): -- cgit v1.1 From b0c40737bf87754e42dbef045a36d4615de247c5 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Tue, 26 Sep 2017 16:48:11 +0530 Subject: tests/7 gnome: Test that GIR deps are flattened --- test cases/frameworks/7 gnome/gir/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test cases/frameworks/7 gnome/gir/meson.build b/test cases/frameworks/7 gnome/gir/meson.build index 3598b66..a91cb97 100644 --- a/test cases/frameworks/7 gnome/gir/meson.build +++ b/test cases/frameworks/7 gnome/gir/meson.build @@ -27,7 +27,7 @@ gnome.generate_gir( identifier_prefix : 'Meson', includes : ['GObject-2.0', 'MesonDep1-1.0'], # dep1_dep pulls in dep2_dep for us - dependencies : [fake_dep, dep1_dep], + dependencies : [[fake_dep, dep1_dep]], install : true, build_by_default : true, # Test that unknown kwargs do not crash the parser. -- cgit v1.1 From 26dada37978198eab24d05c5c28f4774bfd222e8 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Tue, 26 Sep 2017 17:03:22 +0530 Subject: gnome: Flatten and unholder all dependencies Otherwise lists-of-lists get ignored instead --- mesonbuild/modules/gnome.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index d1d7013..844da64 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -20,7 +20,7 @@ import os import copy import subprocess from . import ModuleReturnValue -from ..mesonlib import MesonException, OrderedSet, Popen_safe +from ..mesonlib import MesonException, OrderedSet, unholder_array, Popen_safe from ..dependencies import Dependency, PkgConfigDependency, InternalDependency from .. import mlog from .. import mesonlib @@ -323,11 +323,9 @@ class GnomeModule(ExtensionModule): cflags = OrderedSet() ldflags = OrderedSet() gi_includes = OrderedSet() - deps = mesonlib.listify(deps) + deps = unholder_array(deps) for dep in deps: - if hasattr(dep, 'held_object'): - dep = dep.held_object if isinstance(dep, InternalDependency): cflags.update(get_include_args(dep.include_directories)) for lib in dep.libraries: @@ -378,7 +376,7 @@ class GnomeModule(ExtensionModule): elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): cflags.update(get_include_args(dep.get_include_dirs())) else: - mlog.log('dependency %s not handled to build gir files' % dep) + mlog.log('dependency {!r} not handled to build gir files'.format(dep)) continue if gir_has_extra_lib_arg() and use_gir_args: @@ -525,9 +523,8 @@ class GnomeModule(ExtensionModule): else: raise MesonException('Gir export packages must be str or list') - deps = mesonlib.extract_as_list(kwargs, 'dependencies', pop = True) deps = (girtarget.get_all_link_deps() + girtarget.get_external_deps() + - deps) + unholder_array(kwargs.pop('dependencies', []))) # Need to recursively add deps on GirTarget sources from our # dependencies and also find the include directories needed for the # typelib generation custom target below. @@ -794,7 +791,8 @@ This will become a hard error in the future.''') def _get_build_args(self, kwargs, state): args = [] - cflags, ldflags, gi_includes = self._get_dependencies_flags(kwargs.get('dependencies', []), state, include_rpath=True) + deps = unholder_array(kwargs.get('dependencies', [])) + cflags, ldflags, gi_includes = self._get_dependencies_flags(deps, state, 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)): -- cgit v1.1 From 24e0774acee5036a9556360fef0fe2e76ea30e02 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sun, 1 Oct 2017 12:18:57 +0530 Subject: Always flatten in listify() since we always want that All our kwargs take lists that must be flattened Closes https://github.com/mesonbuild/meson/issues/2408 --- mesonbuild/mesonlib.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 71134a8..95af3ea 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -200,15 +200,7 @@ def classify_unity_sources(compilers, sources): return compsrclist def flatten(item): - if not isinstance(item, list): - return [item] - result = [] - for i in item: - if isinstance(i, list): - result += flatten(i) - else: - result.append(i) - return result + return listify(item, flatten=True) def is_osx(): return platform.system().lower() == 'darwin' @@ -475,23 +467,33 @@ def replace_if_different(dst, dst_tmp): os.unlink(dst_tmp) -def listify(*args): +def listify(item, flatten=True): ''' Returns a list with all args embedded in a list if they are not of type list. This function preserves order. ''' - if len(args) == 1: # Special case with one single arg - return args[0] if type(args[0]) is list else [args[0]] - return [item if type(item) is list else [item] for item in args] + if not isinstance(item, list): + return [item] + result = [] + if flatten: + for i in item: + if isinstance(i, list): + result += listify(i, flatten=True) + else: + result.append(i) + else: + for i in item: + result.append(i) + return result -def extract_as_list(dict_object, *keys, pop = False): +def extract_as_list(dict_object, *keys, pop=False): ''' Extracts all values from given dict_object and listifies them. ''' if pop: - return listify(*[dict_object.pop(key, []) for key in keys]) - return listify(*[dict_object.get(key, []) for key in keys]) + return flatten([dict_object.pop(key, []) for key in keys]) + return flatten([dict_object.get(key, []) for key in keys]) def typeslistify(item, types): -- cgit v1.1 From 488e57332f2264594ec8e05369664c6a7833f692 Mon Sep 17 00:00:00 2001 From: Niklas Claesson Date: Wed, 6 Sep 2017 23:53:49 +0200 Subject: VisualC: Add support for msvc toolset version --- mesonbuild/compilers/c.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 82b1ef0..d4da2da 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -1056,3 +1056,29 @@ class VisualStudioCCompiler(CCompiler): # and the can not be called. return None return vs32_instruction_set_args.get(instruction_set, None) + + def get_toolset_version(self): + # See boost/config/compiler/visualc.cpp for up to date mapping + try: + version = int(''.join(self.version.split('.')[0:2])) + except: + return None + if version < 1310: + return '7.0' + elif version < 1400: + return '7.1' # (Visual Studio 2003) + elif version < 1500: + return '8.0' # (Visual Studio 2005) + elif version < 1600: + return '9.0' # (Visual Studio 2008) + elif version < 1700: + return '10.0' # (Visual Studio 2010) + elif version < 1800: + return '11.0' # (Visual Studio 2012) + elif version < 1900: + return '12.0' # (Visual Studio 2013) + elif version < 1910: + return '14.0' # (Visual Studio 2015) + elif version < 1920: + return '14.1' # (Visual Studio 2017) + return None -- cgit v1.1 From 09ccd0eeaad402f1e7e5b18bd1ad168a9db2998b Mon Sep 17 00:00:00 2001 From: Niklas Claesson Date: Thu, 14 Sep 2017 10:05:37 +0200 Subject: C/C++: Get default include dirs from compilers --- mesonbuild/compilers/c.py | 8 ++++++++ mesonbuild/compilers/compilers.py | 39 +++++++++++++++++++++++++++++++++++++++ mesonbuild/dependencies/misc.py | 13 +------------ 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index d4da2da..3f9ba5c 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -172,6 +172,9 @@ class CCompiler(Compiler): def get_linker_search_args(self, dirname): return ['-L' + dirname] + def get_default_include_dirs(self): + return [] + def gen_import_library_args(self, implibname): """ The name of the outputted import library @@ -1082,3 +1085,8 @@ class VisualStudioCCompiler(CCompiler): elif version < 1920: return '14.1' # (Visual Studio 2017) return None + + def get_default_include_dirs(self): + if 'INCLUDE' not in os.environ: + return [] + return os.environ['INCLUDE'].split(os.pathsep) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 89208e0..3f088b0 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -13,6 +13,7 @@ # limitations under the License. import contextlib, os.path, re, tempfile +import subprocess from ..linkers import StaticLinker from .. import coredata @@ -917,6 +918,35 @@ def get_largefile_args(compiler): # those features explicitly. return [] +# TODO: The result from calling compiler should be cached. So that calling this +# function multiple times don't add latency. +def gnulike_default_include_dirs(compiler, lang): + if lang == 'cpp': + lang = 'c++' + p = subprocess.Popen( + compiler + ['-x{}'.format(lang), '-E', '-v', '-'], + stdin=subprocess.DEVNULL, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + stderr = p.stderr.read().decode('utf-8') + parse_state = 0 + paths = [] + for line in stderr.split('\n'): + if parse_state == 0: + if line == '#include "..." search starts here:': + parse_state = 1 + elif parse_state == 1: + if line == '#include <...> search starts here:': + parse_state = 2 + else: + paths.append(line[1:]) + elif parse_state == 2: + if line == 'End of search list.': + break + else: + paths.append(line[1:]) + return paths class GnuCompiler: # Functionality that is common to all GNU family compilers. @@ -998,6 +1028,9 @@ class GnuCompiler: def get_instruction_set_args(self, instruction_set): return gnulike_instruction_set_args.get(instruction_set, None) + def get_default_include_dirs(self): + return gnulike_default_include_dirs(self.exelist, self.language) + class ClangCompiler: def __init__(self, clang_type): @@ -1082,6 +1115,9 @@ class ClangCompiler: def get_instruction_set_args(self, instruction_set): return gnulike_instruction_set_args.get(instruction_set, None) + def get_default_include_dirs(self): + return gnulike_default_include_dirs(self.exelist, self.language) + # Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1 class IntelCompiler: @@ -1132,3 +1168,6 @@ class IntelCompiler: # if self.icc_type == ICC_OSX: # return ['-bundle'] return ['-shared'] + + def get_default_include_dirs(self): + return gnulike_default_include_dirs(self.exelist, self.language) diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index c2b6dbd..61d0d77 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -116,18 +116,7 @@ class BoostDependency(ExternalDependency): # and http://stackoverflow.com/questions/37218953/isystem-on-a-system-include-directory-causes-errors # for more details - # TODO: The correct solution would probably be to ask the - # compiler for it's default include paths (ie: "gcc -xc++ -E - # -v -") and avoid including those with -isystem - - # For now, use -isystem for all includes except for some - # typical defaults (which don't need to be included at all - # since they are in the default include paths). These typical - # defaults include the usual directories at the root of the - # filesystem, but also any path that ends with those directory - # names in order to handle cases like cross-compiling where we - # might have a different sysroot. - if not include_dir.endswith(('/usr/include', '/usr/local/include')): + if include_dir and include_dir not in self.compiler.get_default_include_dirs(): args.append("".join(self.compiler.get_include_args(include_dir, True))) return args -- cgit v1.1 From bbdba876afa8adfaf3e1d1985908326443875860 Mon Sep 17 00:00:00 2001 From: Niklas Claesson Date: Wed, 6 Sep 2017 23:54:49 +0200 Subject: Boost: Improve search algorithm The new implementation will correctly pick boost from 3 possible locations on windows and two locations on posix compatible OSs. The new search algorithm also differentiates between debug and release builds of Boost and multi or single threading builds. It was also decided to map "Meson modules" to Boost software libraries and not Boost modules since it there are a lot of options regarding linking. Some modules can even be used either as headers-only or with dynamic linking. This commit also fixes a bug that prevented header-only use on Windows. Fixes: #2274 #2239 #1803 #669 --- .appveyor.yml | 2 - docs/markdown/Dependencies.md | 15 +- .../001-boost-platform-improvement.md | 10 + mesonbuild/dependencies/misc.py | 413 +++++++++++++++------ test cases/frameworks/1 boost/meson.build | 5 +- test cases/frameworks/1 boost/nolinkexe.cc | 12 - tools/boost_names.py | 180 +++++++++ 7 files changed, 502 insertions(+), 135 deletions(-) create mode 100644 docs/markdown/Release-notes-for-0.43.0/001-boost-platform-improvement.md delete mode 100644 test cases/frameworks/1 boost/nolinkexe.cc create mode 100755 tools/boost_names.py diff --git a/.appveyor.yml b/.appveyor.yml index 60a6fd3..4dc3f50 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -59,8 +59,6 @@ init: install: - cmd: set "ORIG_PATH=%PATH%" - # Boost 1.56.0: https://www.appveyor.com/docs/build-environment/#boost - #- cmd: set "BOOST_ROOT=C:\Libraries\boost" # Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219 - cmd: set "MESON_FIXED_NINJA=1" - ps: (new-object net.webclient).DownloadFile('http://nirbheek.in/files/binaries/ninja/win32/ninja.exe', 'C:\projects\meson\ninja.exe') diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md index 187c4fe..c46334c 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -50,8 +50,16 @@ pkg-config files. Meson has autodetection support for some of these. ## Boost ## Boost is not a single dependency but rather a group of different -libraries. To use Boost with Meson, simply list which Boost modules -you would like to use. +libraries. To use Boost headers-only libraries, simply add Boost as a +dependency. + +```meson +boost_dep = dependency('boost') +exe = executable('myprog', 'file.cc', dependencies : boost_dep) +``` + +To link against boost with Meson, simply list which libraries you would like to +use. ```meson boost_dep = dependency('boost', modules : ['thread', 'utility']) @@ -65,6 +73,9 @@ If your boost headers or libraries are in non-standard locations you can set the BOOST_ROOT, BOOST_INCLUDEDIR, and/or BOOST_LIBRARYDIR environment variables. +You can set the argument `threading` to `single` to use boost libraries that +has been compiled for single-threaded use instead. + ## GTest and GMock ## GTest and GMock come as sources that must be compiled as part of your diff --git a/docs/markdown/Release-notes-for-0.43.0/001-boost-platform-improvement.md b/docs/markdown/Release-notes-for-0.43.0/001-boost-platform-improvement.md new file mode 100644 index 0000000..2cd44ce --- /dev/null +++ b/docs/markdown/Release-notes-for-0.43.0/001-boost-platform-improvement.md @@ -0,0 +1,10 @@ +## Portability improvements to Boost Dependency + +The Boost dependency has been improved to better detect the various ways to +install boost on multiple platforms. At the same time the `modules` semantics +for the dependency has been changed. Previously it was allowed to specify +header directories as `modules` but it wasn't required. Now, modules are only +used to specify libraries that require linking. + +This is a breaking change and the fix is to remove all modules that aren't +found. diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 61d0d77..a0d5e47 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -18,7 +18,6 @@ import glob import os import re import shlex -import stat import shutil import sysconfig @@ -30,77 +29,153 @@ from ..environment import detect_cpu_family from .base import DependencyException, DependencyMethods from .base import ExternalDependency, ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency +# On windows 3 directory layouts are supported: +# * The default layout (versioned) installed: +# - $BOOST_ROOT/include/boost-x_x/boost/*.hpp +# - $BOOST_ROOT/lib/*.lib +# * The non-default layout (system) installed: +# - $BOOST_ROOT/include/boost/*.hpp +# - $BOOST_ROOT/lib/*.lib +# * The pre-built binaries from sf.net: +# - $BOOST_ROOT/boost/*.hpp +# - $BOOST_ROOT/lib-/*.lib where arch=32/64 and compiler=msvc-14.1 +# +# Library names supported: +# - libboost_--mt-gd-x_x.lib (static) +# - boost_--mt-gd-x_x.lib|.dll (shared) +# - libboost_.lib (static) +# - boost_.lib|.dll (shared) +# where compiler is vc141 for example. +# +# NOTE: -gb means runtime and build time debugging is on +# -mt means threading=multi +# +# The `modules` argument accept library names. This is because every module that +# has libraries to link against also has multiple options regarding how to +# link. See for example: +# * http://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/boost_test/usage_variants.html +# * http://www.boost.org/doc/libs/1_65_1/doc/html/stacktrace/configuration_and_build.html +# * http://www.boost.org/doc/libs/1_65_1/libs/math/doc/html/math_toolkit/main_tr1.html class BoostDependency(ExternalDependency): - # Some boost libraries have different names for - # their sources and libraries. This dict maps - # between the two. - name2lib = {'test': 'unit_test_framework'} - def __init__(self, environment, kwargs): super().__init__('boost', environment, 'cpp', kwargs) + self.need_static_link = ['boost_exception', 'boost_test_exec_monitor'] + self.is_debug = environment.cmd_line_options.buildtype.startswith('debug') + threading = kwargs.get("threading", "multi") + self.is_multithreading = threading == "multi" + + self.requested_modules = self.get_requested(kwargs) + + self.boost_root = None + self.boost_roots = [] + self.incdir = None self.libdir = None - try: + + if 'BOOST_ROOT' in os.environ: self.boost_root = os.environ['BOOST_ROOT'] + self.boost_roots = [self.boost_root] if not os.path.isabs(self.boost_root): raise DependencyException('BOOST_ROOT must be an absolute path.') - except KeyError: - self.boost_root = None + if 'BOOST_INCLUDEDIR' in os.environ: + self.incdir = os.environ['BOOST_INCLUDEDIR'] + if 'BOOST_LIBRARYDIR' in os.environ: + self.libdir = os.environ['BOOST_LIBRARYDIR'] + + if self.want_cross and self.boost_root is None and self.incdir is None: + raise DependencyException('BOOST_ROOT or BOOST_INCLUDEDIR is needed while cross-compiling') + if self.boost_root is None: - if self.want_cross: - if 'BOOST_INCLUDEDIR' in os.environ: - self.incdir = os.environ['BOOST_INCLUDEDIR'] - else: - raise DependencyException('BOOST_ROOT or BOOST_INCLUDEDIR is needed while cross-compiling') if mesonlib.is_windows(): - self.boost_root = self.detect_win_root() - self.incdir = self.boost_root + self.boost_roots = self.detect_win_roots() else: - if 'BOOST_INCLUDEDIR' in os.environ: - self.incdir = os.environ['BOOST_INCLUDEDIR'] - else: - self.incdir = '/usr/include' + self.boost_roots = self.detect_nix_roots() + + if self.boost_root is None and not self.boost_roots: + self.log_fail() + return + + if self.incdir is None: + if mesonlib.is_windows(): + self.incdir = self.detect_win_incdir() + else: + self.incdir = self.detect_nix_incdir() + + if self.incdir is None: + self.log_fail() + return + + mlog.debug('Boost library root dir is', mlog.bold(self.boost_root)) + mlog.debug('Boost include directory is', mlog.bold(self.incdir)) - if 'BOOST_LIBRARYDIR' in os.environ: - self.libdir = os.environ['BOOST_LIBRARYDIR'] - else: - self.incdir = os.path.join(self.boost_root, 'include') - self.boost_inc_subdir = os.path.join(self.incdir, 'boost') - mlog.debug('Boost library root dir is', self.boost_root) - self.src_modules = {} self.lib_modules = {} - self.lib_modules_mt = {} self.detect_version() - self.requested_modules = self.get_requested(kwargs) - module_str = ', '.join(self.requested_modules) if self.is_found: - self.detect_src_modules() self.detect_lib_modules() + mlog.debug('Boost library directory is', mlog.bold(self.libdir)) self.validate_requested() - if self.boost_root is not None: - info = self.version + ', ' + self.boost_root - else: - info = self.version - mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info) + self.log_success() + else: + self.log_fail() + + def log_fail(self): + module_str = ', '.join(self.requested_modules) + mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO')) + + def log_success(self): + module_str = ', '.join(self.requested_modules) + if self.boost_root: + info = self.version + ', ' + self.boost_root else: - mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO')) + info = self.version + mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info) + + def detect_nix_roots(self): + return ['/usr/local', '/usr'] - def detect_win_root(self): - globtext = 'c:\\local\\boost_*' + def detect_win_roots(self): + res = [] + # Where boost documentation says it should be + globtext = 'C:\\Program Files\\boost\\boost_*' files = glob.glob(globtext) - if len(files) > 0: - return files[0] - return 'C:\\' + res.extend(files) + + # Where boost built from source actually installs it + if os.path.isdir('C:\\Boost'): + res.append('C:\\Boost') + + # Where boost prebuilt binaries are + globtext = 'C:\\local\\boost_*' + files = glob.glob(globtext) + res.extend(files) + return res + + def detect_nix_incdir(self): + for root in self.boost_roots: + incdir = os.path.join(root, 'include', 'boost') + if os.path.isdir(incdir): + return os.path.join(root, 'include') + return None + + # FIXME: Should pick a version that matches the requested version + # Returns the folder that contains the boost folder. + def detect_win_incdir(self): + for root in self.boost_roots: + globtext = os.path.join(root, 'include', 'boost-*') + incdirs = glob.glob(globtext) + if len(incdirs) > 0: + return incdirs[0] + incboostdir = os.path.join(root, 'include', 'boost') + if os.path.isdir(incboostdir): + return os.path.join(root, 'include') + incboostdir = os.path.join(root, 'boost') + if os.path.isdir(incboostdir): + return root + return None def get_compile_args(self): args = [] - if self.boost_root is not None: - if mesonlib.is_windows(): - include_dir = self.boost_root - else: - include_dir = os.path.join(self.boost_root, 'include') - else: - include_dir = self.incdir + include_dir = self.incdir # Use "-isystem" when including boost headers instead of "-I" # to avoid compiler warnings/failures when "-Werror" is used @@ -125,19 +200,23 @@ class BoostDependency(ExternalDependency): for c in candidates: if not isinstance(c, str): raise DependencyException('Boost module argument is not a string.') + if 'boost_' + c not in BOOST_LIBS: + raise DependencyException('Dependency {} not found. It is not a valid boost library.'.format(c)) return candidates def validate_requested(self): for m in self.requested_modules: - if m not in self.src_modules and m not in self.lib_modules and m + '-mt' not in self.lib_modules_mt: - msg = 'Requested Boost module {!r} not found' + if 'boost_' + m not in self.lib_modules: + msg = 'Requested Boost library {!r} not found' raise DependencyException(msg.format(m)) def detect_version(self): try: - ifile = open(os.path.join(self.boost_inc_subdir, 'version.hpp')) + ifile = open(os.path.join(self.incdir, 'boost', 'version.hpp')) except FileNotFoundError: return + except TypeError: + return with ifile: for line in ifile: if line.startswith("#define") and 'BOOST_LIB_VERSION' in line: @@ -147,12 +226,6 @@ class BoostDependency(ExternalDependency): self.is_found = True return - def detect_src_modules(self): - for entry in os.listdir(self.boost_inc_subdir): - entry = os.path.join(self.boost_inc_subdir, entry) - if stat.S_ISDIR(os.stat(entry).st_mode): - self.src_modules[os.path.split(entry)[-1]] = True - def detect_lib_modules(self): if mesonlib.is_windows(): return self.detect_lib_modules_win() @@ -160,32 +233,79 @@ class BoostDependency(ExternalDependency): def detect_lib_modules_win(self): arch = detect_cpu_family(self.env.coredata.compilers) - # Guess the libdir - if arch == 'x86': - gl = 'lib32*' - elif arch == 'x86_64': - gl = 'lib64*' - else: - # Does anyone do Boost cross-compiling to other archs on Windows? - gl = None - # See if the libdir is valid - if gl: - libdir = glob.glob(os.path.join(self.boost_root, gl)) - else: - libdir = [] - # Can't find libdir, bail - if not libdir: + compiler_ts = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version().split('.') + compiler = 'vc{}{}'.format(compiler_ts[0], compiler_ts[1]) + if not self.libdir: + # The libdirs in the distributed binaries + if arch == 'x86': + gl = 'lib32*' + elif arch == 'x86_64': + gl = 'lib64*' + else: + # Does anyone do Boost cross-compiling to other archs on Windows? + gl = None + if self.boost_root: + roots = [self.boost_root] + else: + roots = self.boost_roots + for root in roots: + # The default libdir when building + libdir = os.path.join(root, 'lib') + if os.path.isdir(libdir): + self.libdir = libdir + break + if gl: + tmp = glob.glob(os.path.join(root, gl)) + if len(tmp) > 0: + # FIXME: Should pick the correct version + self.libdir = tmp[0] + break + + if not self.libdir: return - libdir = libdir[0] - # Don't override what was set in the environment - if self.libdir: - self.libdir = libdir - globber = 'libboost_*-gd-*.lib' if self.static else 'boost_*-gd-*.lib' # FIXME - for entry in glob.glob(os.path.join(libdir, globber)): + + for name in self.need_static_link: + libname = "lib{}".format(name) + '-' + compiler + if self.is_multithreading: + libname = libname + '-mt' + if self.is_debug: + libname = libname + '-gd' + libname = libname + "-{}.lib".format(self.version.replace('.', '_')) + if os.path.isfile(os.path.join(self.libdir, libname)): + modname = libname.split('-', 1)[0][3:] + self.lib_modules[modname] = libname + else: + libname = "lib{}.lib".format(name) + if os.path.isfile(os.path.join(self.libdir, libname)): + self.lib_modules[name[3:]] = libname + + # globber1 applies to a layout=system installation + # globber2 applies to a layout=versioned installation + globber1 = 'libboost_*' if self.static else 'boost_*' + globber2 = globber1 + '-' + compiler + if self.is_multithreading: + globber2 = globber2 + '-mt' + if self.is_debug: + globber2 = globber2 + '-gd' + globber2 = globber2 + '-{}'.format(self.version.replace('.', '_')) + globber2_matches = glob.glob(os.path.join(self.libdir, globber2 + '.lib')) + for entry in globber2_matches: (_, fname) = os.path.split(entry) - base = fname.split('_', 1)[1] - modname = base.split('-', 1)[0] - self.lib_modules_mt[modname] = fname + modname = fname.split('-', 1) + if len(modname) > 1: + modname = modname[0] + else: + modname = modname.split('.', 1)[0] + if self.static: + modname = modname[3:] + self.lib_modules[modname] = fname + if len(globber2_matches) == 0: + for entry in glob.glob(os.path.join(self.libdir, globber1 + '.lib')): + (_, fname) = os.path.split(entry) + modname = fname.split('.', 1)[0] + if self.static: + modname = modname[3:] + self.lib_modules[modname] = fname def detect_lib_modules_nix(self): if self.static: @@ -203,25 +323,32 @@ class BoostDependency(ExternalDependency): else: libdirs = [os.path.join(self.boost_root, 'lib')] for libdir in libdirs: + for name in self.need_static_link: + libname = 'lib{}.a'.format(name) + if os.path.isfile(os.path.join(libdir, libname)): + self.lib_modules[name] = libname for entry in glob.glob(os.path.join(libdir, globber)): lib = os.path.basename(entry) - name = lib.split('.')[0].split('_', 1)[-1] + name = lib.split('.')[0][3:] # I'm not 100% sure what to do here. Some distros # have modules such as thread only as -mt versions. - if entry.endswith('-mt.{}'.format(libsuffix)): - self.lib_modules_mt[name] = True - else: - self.lib_modules[name] = True + # On debian all packages are built threading=multi + # but not suffixed with -mt. + # FIXME: implement detect_lib_modules_{debian, redhat, ...} + if self.is_multithreading and mesonlib.is_debianlike(): + self.lib_modules[name] = lib + elif self.is_multithreading and entry.endswith('-mt.{}'.format(libsuffix)): + self.lib_modules[name] = lib + elif not entry.endswith('-mt.{}'.format(libsuffix)): + self.lib_modules[name] = lib def get_win_link_args(self): args = [] # TODO: should this check self.libdir? - if self.boost_root: + if self.libdir: args.append('-L' + self.libdir) - for module in self.requested_modules: - module = BoostDependency.name2lib.get(module, module) - if module in self.lib_modules_mt: - args.append(self.lib_modules_mt[module]) + for lib in self.requested_modules: + args.append(self.lib_modules['boost_' + lib]) return args def get_link_args(self): @@ -232,33 +359,14 @@ class BoostDependency(ExternalDependency): args.append('-L' + os.path.join(self.boost_root, 'lib')) elif self.libdir: args.append('-L' + self.libdir) - for module in self.requested_modules: - module = BoostDependency.name2lib.get(module, module) - libname = 'boost_' + module + for lib in self.requested_modules: # The compiler's library detector is the most reliable so use that first. - default_detect = self.compiler.find_library(libname, self.env, []) + default_detect = self.compiler.find_library('boost_' + lib, self.env, []) if default_detect is not None: - if module == 'unit_testing_framework': - emon_args = self.compiler.find_library('boost_test_exec_monitor') - else: - emon_args = None args += default_detect - if emon_args is not None: - args += emon_args - elif module in self.lib_modules or module in self.lib_modules_mt: - linkcmd = '-l' + libname - args.append(linkcmd) - # FIXME a hack, but Boost's testing framework has a lot of - # different options and it's hard to determine what to do - # without feedback from actual users. Update this - # as we get more bug reports. - if module == 'unit_testing_framework': - args.append('-lboost_test_exec_monitor') - elif module + '-mt' in self.lib_modules_mt: - linkcmd = '-lboost_' + module + '-mt' + elif lib in self.lib_modules: + linkcmd = '-l' + lib args.append(linkcmd) - if module == 'unit_testing_framework': - args.append('-lboost_test_exec_monitor-mt') return args def get_sources(self): @@ -653,3 +761,78 @@ class CupsDependency(ExternalDependency): return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG, DependencyMethods.EXTRAFRAMEWORK] else: return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG] + +# Generated with boost_names.py +BOOST_LIBS = [ + 'boost_atomic', + 'boost_chrono', + 'boost_chrono', + 'boost_container', + 'boost_context', + 'boost_coroutine', + 'boost_date_time', + 'boost_exception', + 'boost_fiber', + 'boost_filesystem', + 'boost_graph', + 'boost_iostreams', + 'boost_locale', + 'boost_log', + 'boost_log_setup', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_mpi', + 'boost_random', + 'boost_regex', + 'boost_serialization', + 'boost_wserialization', + 'boost_signals', + 'boost_stacktrace_noop', + 'boost_stacktrace_backtrace', + 'boost_stacktrace_addr2line', + 'boost_stacktrace_basic', + 'boost_stacktrace_windbg', + 'boost_stacktrace_windbg_cached', + 'boost_system', + 'boost_prg_exec_monitor', + 'boost_test_exec_monitor', + 'boost_unit_test_framework', + 'boost_thread', + 'boost_timer', + 'boost_type_erasure', + 'boost_wave' +] diff --git a/test cases/frameworks/1 boost/meson.build b/test cases/frameworks/1 boost/meson.build index 6f25f8b..b73f93a 100644 --- a/test cases/frameworks/1 boost/meson.build +++ b/test cases/frameworks/1 boost/meson.build @@ -9,21 +9,18 @@ add_project_arguments(['-DBOOST_LOG_DYN_LINK'], # within one project. The need to be independent of each other. # Use one without a library dependency and one with it. -nolinkdep = dependency('boost', modules: 'utility') linkdep = dependency('boost', modules : ['thread', 'system']) staticdep = dependency('boost', modules : ['thread', 'system'], static : true) -testdep = dependency('boost', modules : 'test') +testdep = dependency('boost', modules : ['unit_test_framework']) nomoddep = dependency('boost') extralibdep = dependency('boost', modules : ['thread', 'system', 'log_setup', 'log']) -nolinkexe = executable('nolinkedexe', 'nolinkexe.cc', dependencies : nolinkdep) linkexe = executable('linkedexe', 'linkexe.cc', dependencies : linkdep) staticexe = executable('staticlinkedexe', 'linkexe.cc', dependencies : staticdep) unitexe = executable('utf', 'unit_test.cpp', dependencies: testdep) nomodexe = executable('nomod', 'nomod.cpp', dependencies : nomoddep) extralibexe = executable('extralibexe', 'extralib.cpp', dependencies : extralibdep) -test('Boost nolinktest', nolinkexe) test('Boost linktest', linkexe) test('Boost statictest', staticexe) test('Boost UTF test', unitexe) diff --git a/test cases/frameworks/1 boost/nolinkexe.cc b/test cases/frameworks/1 boost/nolinkexe.cc deleted file mode 100644 index 7b6c6d9..0000000 --- a/test cases/frameworks/1 boost/nolinkexe.cc +++ /dev/null @@ -1,12 +0,0 @@ -#include - -class MyClass : boost::noncopyable { -public: - MyClass() {}; - ~MyClass() {}; -}; - -int main(int argc, char **argv) { - MyClass obj; - return 0; -} diff --git a/tools/boost_names.py b/tools/boost_names.py new file mode 100755 index 0000000..9ac16bb --- /dev/null +++ b/tools/boost_names.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 + +# Copyright 2017 Niklas Claesson + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This is two implementations for how to get module names from the boost +sources. One relies on json metadata files in the sources, the other relies on +the folder names. + +Run the tool in the boost directory and append the stdout to the misc.py: + +boost/$ path/to/meson/tools/boost_names.py >> path/to/meson/dependencies/misc.py +""" + +import sys +import os +import collections +import pprint +import json +import re + +Module = collections.namedtuple('Module', ['dirname', 'name', 'libnames']) +Module.__repr__ = lambda self: str((self.dirname, self.name, self.libnames)) + +LIBS = 'libs' + +manual_map = { + 'callable_traits': 'Call Traits', + 'crc': 'CRC', + 'dll': 'DLL', + 'gil': 'GIL', + 'graph_parallel': 'GraphParallel', + 'icl': 'ICL', + 'io': 'IO State Savers', + 'msm': 'Meta State Machine', + 'mpi': 'MPI', + 'mpl': 'MPL', + 'multi_array': 'Multi-Array', + 'multi_index': 'Multi-Index', + 'numeric': 'Numeric Conversion', + 'ptr_container': 'Pointer Container', + 'poly_collection': 'PolyCollection', + 'qvm': 'QVM', + 'throw_exception': 'ThrowException', + 'tti': 'TTI', + 'vmd': 'VMD', +} + +extra = [ + Module('utility', 'Compressed Pair', []), + Module('core', 'Enable If', []), + Module('functional', 'Functional/Factory', []), + Module('functional', 'Functional/Forward', []), + Module('functional', 'Functional/Hash', []), + Module('functional', 'Functional/Overloaded Function', []), + Module('utility', 'Identity Type', []), + Module('utility', 'In Place Factory, Typed In Place Factory', []), + Module('numeric', 'Interval', []), + Module('math', 'Math Common Factor', []), + Module('math', 'Math Octonion', []), + Module('math', 'Math Quaternion', []), + Module('math', 'Math/Special Functions', []), + Module('math', 'Math/Statistical Distributions', []), + Module('bind', 'Member Function', []), + Module('algorithm', 'Min-Max', []), + Module('numeric', 'Odeint', []), + Module('utility', 'Operators', []), + Module('core', 'Ref', []), + Module('utility', 'Result Of', []), + Module('algorithm', 'String Algo', []), + Module('core', 'Swap', []), + Module('', 'Tribool', []), + Module('numeric', 'uBLAS', []), + Module('utility', 'Value Initialized', []), +] + +# Cannot find the following modules in the documentation of boost +not_modules = ['beast', 'logic', 'mp11', 'winapi'] + +def eprint(message): + print(message, file=sys.stderr) + +def get_library_names(jamfile): + libs = [] + with open(jamfile) as jamfh: + jam = jamfh.read() + res = re.finditer(r'^lib[\s]+([A-Za-z0-9_]+)([^;]*);', jam, re.MULTILINE | re.DOTALL) + for matches in res: + if ':' in matches.group(2): + libs.append(matches.group(1)) + return libs + +def exists(modules, module): + return len([x for x in modules if x.dirname == module.dirname]) != 0 + +def get_modules(init=extra): + modules = init + for directory in os.listdir(LIBS): + if not os.path.isdir(os.path.join(LIBS, directory)): + continue + if directory in not_modules: + continue + jamfile = os.path.join(LIBS, directory, 'build', 'Jamfile.v2') + if os.path.isfile(jamfile): + libs = get_library_names(jamfile) + else: + libs = [] + if directory in manual_map.keys(): + modname = manual_map[directory] + else: + modname = directory.replace('_', ' ').title() + modules.append(Module(directory, modname, libs)) + return modules + +def get_modules_2(): + modules = [] + for (root, dirs, files) in os.walk(LIBS): + for f in files: + if f == "libraries.json": + projectdir = os.path.dirname(root) + + jamfile = os.path.join(projectdir, 'build', 'Jamfile.v2') + if os.path.isfile(jamfile): + libs = get_library_names(jamfile) + else: + libs = [] + + # Get metadata for module + jsonfile = os.path.join(root, f) + with open(jsonfile) as jsonfh: + boost_modules = json.loads(jsonfh.read()) + if(isinstance(boost_modules, dict)): + boost_modules = [boost_modules] + for boost_module in boost_modules: + modules.append(Module(boost_module['key'], boost_module['name'], libs)) + + # Some subprojects do not have meta directory with json file. Find those + jsonless_modules = [x for x in get_modules([]) if not exists(modules, x)] + for module in jsonless_modules: + eprint("WARNING: {} does not have meta/libraries.json. Will guess pretty name '{}'".format(module.dirname, module.name)) + modules.extend(jsonless_modules) + + return modules + +def main(args): + if not os.path.isdir(LIBS): + eprint("ERROR: script must be run in boost source directory") + + # It will pick jsonless algorithm if 1 is given as argument + impl = 0 + if len(args) > 1: + if args[1] == '1': + impl = 1 + + if impl == 1: + modules = get_modules() + else: + modules = get_modules_2() + + sorted_modules = sorted(modules, key=lambda module: module.name.lower()) + sorted_modules = [x[2] for x in sorted_modules if x[2]] + sorted_modules = sum(sorted_modules, []) + sorted_modules = [x for x in sorted_modules if x.startswith('boost')] + + pp = pprint.PrettyPrinter() + pp.pprint(sorted_modules) + +if __name__ == '__main__': + main(sys.argv) -- cgit v1.1 From 4df86505608d768344078916d7d6f241de0e5f5a Mon Sep 17 00:00:00 2001 From: Niklas Claesson Date: Wed, 6 Sep 2017 23:55:08 +0200 Subject: Appveyor: Enable Boost tests where possible --- .appveyor.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 4dc3f50..d150c42 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,10 +19,12 @@ environment: - arch: x86 compiler: msvc2015 backend: ninja + BOOST_ROOT: C:\Libraries\Boost_1_59_0 - arch: x86 compiler: msvc2015 backend: vs2015 + BOOST_ROOT: C:\Libraries\Boost_1_59_0 - arch: x64 compiler: cygwin @@ -36,11 +38,13 @@ environment: compiler: msvc2017 backend: ninja APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + BOOST_ROOT: C:\Libraries\Boost_1_64_0 - arch: x64 compiler: msvc2017 backend: vs2017 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + BOOST_ROOT: C:\Libraries\Boost_1_64_0 platform: - x64 @@ -66,6 +70,10 @@ install: # For all other archs (including, say, arm), use the x64 python. - cmd: if %arch%==x86 (set MESON_PYTHON_PATH=C:\python34) else (set MESON_PYTHON_PATH=C:\python34-x64) + # Set paths for BOOST dll files + - cmd: if %compiler%==msvc2015 ( if %arch%==x86 ( set "PATH=%PATH%;C:\Libraries\boost_1_59_0\lib32-msvc-14.0" ) else ( set "PATH=%PATH%;C:\Libraries\boost_1_59_0\lib64-msvc-14.0" ) ) + - cmd: if %compiler%==msvc2017 ( if %arch%==x86 ( set "PATH=%PATH%;C:\Libraries\boost_1_64_0\lib32-msvc-14.1" ) else ( set "PATH=%PATH%;C:\Libraries\boost_1_64_0\lib64-msvc-14.1" ) ) + # Set paths and config for each build type. - cmd: if %compiler%==msvc2010 ( call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %arch% ) - cmd: if %compiler%==msvc2015 ( call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %arch% ) -- cgit v1.1 From bb0e18b73885de374f8461c0e4f3c911fded1e46 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sun, 1 Oct 2017 12:39:39 +0530 Subject: Use listify and extract_as_list everywhere They now flatten by default and unhold objects if required Includes unit tests. --- mesonbuild/build.py | 25 ++++++-------------- mesonbuild/dependencies/base.py | 6 ++--- mesonbuild/dependencies/dev.py | 4 ++-- mesonbuild/interpreter.py | 49 ++++++++++++++------------------------- mesonbuild/mesonlib.py | 51 ++++++++++++++++++++--------------------- mesonbuild/modules/gnome.py | 10 ++++---- run_unittests.py | 45 +++++++++++++++++++++++++++++++++++- 7 files changed, 103 insertions(+), 87 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 5f5dd6b..9837d5a 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -20,7 +20,7 @@ from . import environment from . import dependencies from . import mlog from .mesonlib import File, MesonException, listify, extract_as_list -from .mesonlib import flatten, typeslistify, stringlistify, classify_unity_sources +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 .compilers import is_object, clike_langs, sort_clike, lang_suffixes @@ -682,7 +682,7 @@ class BuildTarget(Target): if 'd' in self.compilers: self.add_compiler_args('d', self.compilers['d'].get_feature_args(dfeatures)) - self.link_args = flatten(kwargs.get('link_args', [])) + self.link_args = extract_as_list(kwargs, 'link_args') for i in self.link_args: if not isinstance(i, str): raise InvalidArguments('Link_args arguments must be strings.') @@ -856,9 +856,7 @@ You probably should put it in link_with instead.''') return self.external_deps def link(self, target): - for t in flatten(target): - if hasattr(t, 'held_object'): - t = t.held_object + for t in listify(target, unholder=True): if not t.is_linkable_target(): raise InvalidArguments('Link target {!r} is not linkable.'.format(t)) if isinstance(self, SharedLibrary) and isinstance(t, StaticLibrary) and not t.pic: @@ -870,9 +868,7 @@ You probably should put it in link_with instead.''') self.link_targets.append(t) def link_whole(self, target): - for t in flatten(target): - if hasattr(t, 'held_object'): - t = t.held_object + for t in listify(target, unholder=True): if not isinstance(t, StaticLibrary): raise InvalidArguments('{!r} is not a static library.'.format(t)) if isinstance(self, SharedLibrary) and not t.pic: @@ -915,7 +911,7 @@ You probably should put it in link_with instead.''') self.include_dirs += ids def add_compiler_args(self, language, args): - args = flatten(args) + args = listify(args) for a in args: if not isinstance(a, (str, File)): raise InvalidArguments('A non-string passed to compiler args.') @@ -1546,11 +1542,9 @@ class CustomTarget(Target): return deps def flatten_command(self, cmd): - cmd = listify(cmd) + cmd = listify(cmd, unholder=True) final_cmd = [] for c in cmd: - if hasattr(c, 'held_object'): - c = c.held_object if isinstance(c, str): final_cmd.append(c) elif isinstance(c, File): @@ -1573,12 +1567,7 @@ class CustomTarget(Target): def process_kwargs(self, kwargs): super().process_kwargs(kwargs) - sources = flatten(kwargs.get('input', [])) - self.sources = [] - for s in sources: - if hasattr(s, 'held_object'): - s = s.held_object - self.sources.append(s) + self.sources = extract_as_list(kwargs, 'input', unholder=True) if 'output' not in kwargs: raise InvalidArguments('Missing keyword argument "output".') self.outputs = listify(kwargs['output']) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 7c7f986..0d9742d 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -23,7 +23,7 @@ from enum import Enum from .. import mlog from .. import mesonlib -from ..mesonlib import MesonException, Popen_safe, flatten, version_compare_many, listify +from ..mesonlib import MesonException, Popen_safe, version_compare_many, listify # These must be defined in this file to avoid cyclical references. @@ -586,7 +586,7 @@ class ExtraFrameworkDependency(ExternalDependency): def get_dep_identifier(name, kwargs, want_cross): # Need immutable objects since the identifier will be used as a dict key - version_reqs = flatten(kwargs.get('version', [])) + version_reqs = listify(kwargs.get('version', [])) if isinstance(version_reqs, list): version_reqs = frozenset(version_reqs) identifier = (name, version_reqs, want_cross) @@ -599,7 +599,7 @@ def get_dep_identifier(name, kwargs, want_cross): continue # All keyword arguments are strings, ints, or lists (or lists of lists) if isinstance(value, list): - value = frozenset(flatten(value)) + value = frozenset(listify(value)) identifier += (key, value) return identifier diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index d2dd107..387300a 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -21,7 +21,7 @@ import shutil from .. import mlog from .. import mesonlib -from ..mesonlib import version_compare, Popen_safe +from ..mesonlib import version_compare, Popen_safe, stringlistify, extract_as_list from .base import DependencyException, ExternalDependency, PkgConfigDependency class GTestDependency(ExternalDependency): @@ -185,7 +185,7 @@ class LLVMDependency(ExternalDependency): raise DependencyException('Could not generate modules for LLVM.') self.modules = shlex.split(out) - modules = mesonlib.stringlistify(mesonlib.flatten(kwargs.get('modules', []))) + modules = stringlistify(extract_as_list(kwargs, 'modules')) for mod in sorted(set(modules)): if mod not in self.modules: mlog.log('LLVM module', mod, 'found:', mlog.red('NO')) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 0e8d301..b938080 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1560,12 +1560,11 @@ class Interpreter(InterpreterBase): version = kwargs.get('version', self.project_version) if not isinstance(version, str): raise InterpreterException('Version must be a string.') - incs = extract_as_list(kwargs, 'include_directories') - libs = extract_as_list(kwargs, 'link_with') + incs = extract_as_list(kwargs, 'include_directories', unholder=True) + libs = extract_as_list(kwargs, 'link_with', unholder=True) sources = extract_as_list(kwargs, 'sources') - sources = self.source_strings_to_files(self.flatten(sources)) - deps = self.flatten(kwargs.get('dependencies', [])) - deps = listify(deps) + sources = listify(self.source_strings_to_files(sources), unholder=True) + deps = extract_as_list(kwargs, 'dependencies', unholder=True) compile_args = mesonlib.stringlistify(kwargs.get('compile_args', [])) link_args = mesonlib.stringlistify(kwargs.get('link_args', [])) final_deps = [] @@ -1577,13 +1576,8 @@ class Interpreter(InterpreterBase): if not isinstance(d, (dependencies.Dependency, dependencies.ExternalLibrary, dependencies.InternalDependency)): raise InterpreterException('Dependencies must be external deps') final_deps.append(d) - dep = dependencies.InternalDependency(version, - mesonlib.unholder_array(incs), - compile_args, - link_args, - mesonlib.unholder_array(libs), - mesonlib.unholder_array(sources), - final_deps) + dep = dependencies.InternalDependency(version, incs, compile_args, + link_args, libs, sources, final_deps) return DependencyHolder(dep) @noKwargs @@ -1638,7 +1632,7 @@ class Interpreter(InterpreterBase): 'or not executable'.format(cmd)) cmd = prog expanded_args = [] - for a in mesonlib.flatten(cargs): + for a in listify(cargs): if isinstance(a, str): expanded_args.append(a) elif isinstance(a, mesonlib.File): @@ -2308,11 +2302,7 @@ to directly access options of other subprojects.''') raise InterpreterException('Run_target needs at least one positional argument.') cleaned_args = [] - for i in mesonlib.flatten(all_args): - try: - i = i.held_object - except AttributeError: - pass + for i in listify(all_args, unholder=True): if not isinstance(i, (str, build.BuildTarget, build.CustomTarget, dependencies.ExternalProgram, mesonlib.File)): mlog.debug('Wrong type:', str(i)) raise InterpreterException('Invalid argument to run_target.') @@ -2383,11 +2373,10 @@ to directly access options of other subprojects.''') par = kwargs.get('is_parallel', True) if not isinstance(par, bool): raise InterpreterException('Keyword argument is_parallel must be a boolean.') - cmd_args = extract_as_list(kwargs, 'args') + cmd_args = extract_as_list(kwargs, 'args', unholder=True) for i in cmd_args: - if not isinstance(i, (str, mesonlib.File, TargetHolder)): + if not isinstance(i, (str, mesonlib.File, build.Target)): raise InterpreterException('Command line arguments must be strings, files or targets.') - cmd_args = mesonlib.unholder_array(cmd_args) env = self.unpack_env_kwarg(kwargs) should_fail = kwargs.get('should_fail', False) if not isinstance(should_fail, bool): @@ -2805,7 +2794,8 @@ different subdirectory. elif isinstance(s, str): s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s) else: - raise InterpreterException("Source item is not string or File-type object.") + raise InterpreterException('Source item is {!r} instead of ' + 'string or File-type object'.format(s)) results.append(s) return results @@ -2831,7 +2821,7 @@ different subdirectory. if not args: raise InterpreterException('Target does not have a name.') name = args[0] - sources = args[1:] + sources = listify(args[1:]) if self.environment.is_cross_build(): if kwargs.get('native', False): is_cross = False @@ -2839,19 +2829,14 @@ different subdirectory. is_cross = True else: is_cross = False - try: - kw_src = self.flatten(kwargs['sources']) - kw_src = listify(kw_src) - except KeyError: - kw_src = [] - sources += kw_src + if 'sources' in kwargs: + sources += listify(kwargs['sources']) sources = self.source_strings_to_files(sources) - objs = self.flatten(kwargs.get('objects', [])) - kwargs['dependencies'] = self.flatten(kwargs.get('dependencies', [])) + objs = extract_as_list(kwargs, 'objects') + kwargs['dependencies'] = extract_as_list(kwargs, 'dependencies') if 'extra_files' in kwargs: ef = extract_as_list(kwargs, 'extra_files') kwargs['extra_files'] = self.source_strings_to_files(ef) - objs = listify(objs) self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources) if targetholder is ExecutableHolder: targetclass = build.Executable diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 95af3ea..5c4c374 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -199,9 +199,6 @@ def classify_unity_sources(compilers, sources): compsrclist[comp].append(src) return compsrclist -def flatten(item): - return listify(item, flatten=True) - def is_osx(): return platform.system().lower() == 'darwin' @@ -466,34 +463,45 @@ def replace_if_different(dst, dst_tmp): else: os.unlink(dst_tmp) - -def listify(item, flatten=True): +def listify(item, flatten=True, unholder=False): ''' - Returns a list with all args embedded in a list if they are not of type list. + Returns a list with all args embedded in a list if they are not a list. This function preserves order. + @flatten: Convert lists of lists to a flat list + @unholder: Replace each item with the object it holds, if required + + Note: unholding only works recursively when flattening ''' if not isinstance(item, list): + if unholder and hasattr(item, 'held_object'): + item = item.held_object return [item] result = [] - if flatten: - for i in item: - if isinstance(i, list): - result += listify(i, flatten=True) - else: - result.append(i) - else: - for i in item: + for i in item: + if unholder and hasattr(i, 'held_object'): + i = i.held_object + if flatten and isinstance(i, list): + result += listify(i, flatten=True, unholder=unholder) + else: result.append(i) return result -def extract_as_list(dict_object, *keys, pop=False): +def extract_as_list(dict_object, *keys, pop=False, **kwargs): ''' Extracts all values from given dict_object and listifies them. ''' + result = [] + fetch = dict_object.get if pop: - return flatten([dict_object.pop(key, []) for key in keys]) - return flatten([dict_object.get(key, []) for key in keys]) + fetch = dict_object.pop + # If there's only one key, we don't return a list with one element + if len(keys) == 1: + return listify(fetch(keys[0], []), **kwargs) + # Return a list of values corresponding to *keys + for key in keys: + result.append(listify(fetch(key, []), **kwargs)) + return result def typeslistify(item, types): @@ -752,15 +760,6 @@ def windows_proof_rmtree(f): # Try one last time and throw if it fails. shutil.rmtree(f) -def unholder_array(entries): - result = [] - entries = flatten(entries) - for e in entries: - if hasattr(e, 'held_object'): - e = e.held_object - result.append(e) - return result - class OrderedSet(collections.MutableSet): """A set that preserves the order in which items are added, by first insertion. diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 844da64..be29db9 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -20,7 +20,7 @@ import os import copy import subprocess from . import ModuleReturnValue -from ..mesonlib import MesonException, OrderedSet, unholder_array, Popen_safe +from ..mesonlib import MesonException, OrderedSet, Popen_safe, extract_as_list from ..dependencies import Dependency, PkgConfigDependency, InternalDependency from .. import mlog from .. import mesonlib @@ -323,7 +323,7 @@ class GnomeModule(ExtensionModule): cflags = OrderedSet() ldflags = OrderedSet() gi_includes = OrderedSet() - deps = unholder_array(deps) + deps = mesonlib.listify(deps, unholder=True) for dep in deps: if isinstance(dep, InternalDependency): @@ -415,7 +415,7 @@ class GnomeModule(ExtensionModule): raise MesonException('gobject-introspection dependency was not found, gir cannot be generated.') ns = kwargs.pop('namespace') nsversion = kwargs.pop('nsversion') - libsources = mesonlib.flatten(kwargs.pop('sources')) + libsources = mesonlib.extract_as_list(kwargs, 'sources', pop=True) girfile = '%s-%s.gir' % (ns, nsversion) srcdir = os.path.join(state.environment.get_source_dir(), state.subdir) builddir = os.path.join(state.environment.get_build_dir(), state.subdir) @@ -524,7 +524,7 @@ class GnomeModule(ExtensionModule): raise MesonException('Gir export packages must be str or list') deps = (girtarget.get_all_link_deps() + girtarget.get_external_deps() + - unholder_array(kwargs.pop('dependencies', []))) + extract_as_list(kwargs, 'dependencies', pop=True, unholder=True)) # Need to recursively add deps on GirTarget sources from our # dependencies and also find the include directories needed for the # typelib generation custom target below. @@ -791,7 +791,7 @@ This will become a hard error in the future.''') def _get_build_args(self, kwargs, state): args = [] - deps = unholder_array(kwargs.get('dependencies', [])) + deps = extract_as_list(kwargs, 'dependencies', unholder=True) cflags, ldflags, gi_includes = self._get_dependencies_flags(deps, state, include_rpath=True) inc_dirs = mesonlib.extract_as_list(kwargs, 'include_directories') for incd in inc_dirs: diff --git a/run_unittests.py b/run_unittests.py index b217714..7ae9947 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -31,6 +31,7 @@ import mesonbuild.compilers import mesonbuild.environment import mesonbuild.mesonlib import mesonbuild.coredata +from mesonbuild.interpreter import ObjectHolder from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree from mesonbuild.environment import Environment from mesonbuild.dependencies import DependencyException @@ -62,7 +63,6 @@ def get_soname(fname): def get_rpath(fname): return get_dynamic_section_entry(fname, r'(?:rpath|runpath)') - class InternalTests(unittest.TestCase): def test_version_number(self): @@ -398,6 +398,49 @@ class InternalTests(unittest.TestCase): self.assertEqual(forced_value, desired_value) + def test_listify(self): + listify = mesonbuild.mesonlib.listify + # Test sanity + self.assertEqual([1], listify(1)) + self.assertEqual([], listify([])) + self.assertEqual([1], listify([1])) + # Test flattening + self.assertEqual([1, 2, 3], listify([1, [2, 3]])) + self.assertEqual([1, 2, 3], listify([1, [2, [3]]])) + self.assertEqual([1, [2, [3]]], listify([1, [2, [3]]], flatten=False)) + # Test flattening and unholdering + holder1 = ObjectHolder(1) + holder3 = ObjectHolder(3) + self.assertEqual([holder1], listify(holder1)) + self.assertEqual([holder1], listify([holder1])) + self.assertEqual([holder1, 2], listify([holder1, 2])) + self.assertEqual([holder1, 2, 3], listify([holder1, 2, [3]])) + self.assertEqual([1], listify(holder1, unholder=True)) + self.assertEqual([1], listify([holder1], unholder=True)) + self.assertEqual([1, 2], listify([holder1, 2], unholder=True)) + self.assertEqual([1, 2, 3], listify([holder1, 2, [holder3]], unholder=True)) + # Unholding doesn't work recursively when not flattening + self.assertEqual([1, [2], [holder3]], listify([holder1, [2], [holder3]], unholder=True, flatten=False)) + + def test_extract_as_list(self): + extract = mesonbuild.mesonlib.extract_as_list + # Test sanity + kwargs = {'sources': [1, 2, 3]} + self.assertEqual([1, 2, 3], extract(kwargs, 'sources')) + self.assertEqual(kwargs, {'sources': [1, 2, 3]}) + self.assertEqual([1, 2, 3], extract(kwargs, 'sources', pop=True)) + self.assertEqual(kwargs, {}) + # Test unholding + holder3 = ObjectHolder(3) + kwargs = {'sources': [1, 2, holder3]} + self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True)) + self.assertEqual(kwargs, {'sources': [1, 2, holder3]}) + self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True, pop=True)) + self.assertEqual(kwargs, {}) + # Test listification + kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]} + self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources')) + class BasePlatformTests(unittest.TestCase): def setUp(self): -- cgit v1.1 From a9258923fac2ab145a94f7c72cc5c0127d50bfe2 Mon Sep 17 00:00:00 2001 From: Alexis Jeandet Date: Sun, 1 Oct 2017 16:18:31 +0200 Subject: Added include directory argument for Qt's Moc which is needed to build plugins. Signed-off-by: Alexis Jeandet --- docs/markdown/Qt5-module.md | 8 +++++--- mesonbuild/modules/qt4.py | 10 ++++++---- mesonbuild/modules/qt5.py | 10 ++++++---- test cases/frameworks/4 qt/meson.build | 10 ++++++++++ test cases/frameworks/4 qt/plugin/plugin.cpp | 7 +++++++ test cases/frameworks/4 qt/plugin/plugin.h | 11 +++++++++++ test cases/frameworks/4 qt/plugin/plugin.json | 3 +++ .../frameworks/4 qt/pluginInterface/plugin_if.h | 21 +++++++++++++++++++++ 8 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 test cases/frameworks/4 qt/plugin/plugin.cpp create mode 100644 test cases/frameworks/4 qt/plugin/plugin.h create mode 100644 test cases/frameworks/4 qt/plugin/plugin.json create mode 100644 test cases/frameworks/4 qt/pluginInterface/plugin_if.h diff --git a/docs/markdown/Qt5-module.md b/docs/markdown/Qt5-module.md index 7082309..a8ad73d 100644 --- a/docs/markdown/Qt5-module.md +++ b/docs/markdown/Qt5-module.md @@ -5,17 +5,19 @@ tools and steps required for Qt. The module has one method. ## preprocess -This method takes four keyword arguments, `moc_headers`, +This method takes five keyword arguments, `moc_headers`, `moc_sources`, `ui_files` and `qresources` which define the files that -require preprocessing with `moc`, `uic` and `rcc`. It returns an +require preprocessing with `moc`, `uic` and `rcc` and 'include_directories' which might be needed by moc. It returns an opaque object that should be passed to a main build target. A simple example would look like this: ```meson qt5 = import('qt5') qt5_dep = dependency('qt5', modules: ['Core', 'Gui']) -moc_files = qt5.preprocess(moc_headers : 'myclass.h') +inc = include_directories('includes') +moc_files = qt5.preprocess(moc_headers : 'myclass.h', include_directories: inc) executable('myprog', 'main.cpp', 'myclass.cpp', moc_files, + include_directories: inc, dependencies : qt5_dep) ``` diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py index a63aff8..4ab07b9 100644 --- a/mesonbuild/modules/qt4.py +++ b/mesonbuild/modules/qt4.py @@ -21,6 +21,7 @@ from . import ExtensionModule import xml.etree.ElementTree as ET from . import ModuleReturnValue from ..interpreterbase import permittedKwargs +from . import get_include_args class Qt4Module(ExtensionModule): tools_detected = False @@ -97,10 +98,10 @@ class Qt4Module(ExtensionModule): except Exception: return [] - @permittedKwargs({'moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'}) + @permittedKwargs({'moc_headers', 'moc_sources', 'include_directories', 'ui_files', 'qresources', 'method'}) def preprocess(self, state, args, kwargs): - rcc_files, ui_files, moc_headers, moc_sources, sources \ - = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', pop = True) + rcc_files, ui_files, moc_headers, moc_sources, sources, include_directories \ + = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', 'include_directories', pop = True) sources += args[1:] method = kwargs.get('method', 'auto') self._detect_tools(state.environment, method) @@ -133,9 +134,10 @@ class Qt4Module(ExtensionModule): ui_gen = build.Generator([self.uic], ui_kwargs) ui_output = ui_gen.process_files('Qt4 ui', ui_files, state) sources.append(ui_output) + inc = get_include_args(include_dirs=include_directories) if len(moc_headers) > 0: moc_kwargs = {'output': 'moc_@BASENAME@.cpp', - 'arguments': ['@INPUT@', '-o', '@OUTPUT@']} + 'arguments': inc + ['@INPUT@', '-o', '@OUTPUT@']} moc_gen = build.Generator([self.moc], moc_kwargs) moc_output = moc_gen.process_files('Qt4 moc header', moc_headers, state) sources.append(moc_output) diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py index 08ce662..001caa7 100644 --- a/mesonbuild/modules/qt5.py +++ b/mesonbuild/modules/qt5.py @@ -21,6 +21,7 @@ from . import ExtensionModule import xml.etree.ElementTree as ET from . import ModuleReturnValue from ..interpreterbase import permittedKwargs +from . import get_include_args class Qt5Module(ExtensionModule): tools_detected = False @@ -103,10 +104,10 @@ class Qt5Module(ExtensionModule): except Exception: return [] - @permittedKwargs({'moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'}) + @permittedKwargs({'moc_headers', 'moc_sources', 'include_directories', 'ui_files', 'qresources', 'method'}) def preprocess(self, state, args, kwargs): - rcc_files, ui_files, moc_headers, moc_sources, sources \ - = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', pop = True) + rcc_files, ui_files, moc_headers, moc_sources, sources, include_directories \ + = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', 'include_directories', pop = True) sources += args[1:] method = kwargs.get('method', 'auto') self._detect_tools(state.environment, method) @@ -139,9 +140,10 @@ class Qt5Module(ExtensionModule): ui_gen = build.Generator([self.uic], ui_kwargs) ui_output = ui_gen.process_files('Qt5 ui', ui_files, state) sources.append(ui_output) + inc = get_include_args(include_dirs=include_directories) if len(moc_headers) > 0: moc_kwargs = {'output': 'moc_@BASENAME@.cpp', - 'arguments': ['@INPUT@', '-o', '@OUTPUT@']} + 'arguments': inc + ['@INPUT@', '-o', '@OUTPUT@']} moc_gen = build.Generator([self.moc], moc_kwargs) moc_output = moc_gen.process_files('Qt5 moc header', moc_headers, state) sources.append(moc_output) diff --git a/test cases/frameworks/4 qt/meson.build b/test cases/frameworks/4 qt/meson.build index d9cab6f..c6f108b 100644 --- a/test cases/frameworks/4 qt/meson.build +++ b/test cases/frameworks/4 qt/meson.build @@ -70,5 +70,15 @@ foreach qt : ['qt4', 'qt5'] dependencies : qtcore) test(qt + 'maninclude', qtmaninclude) + + # building Qt plugins implies to give include path to moc + plugin_includes = include_directories('pluginInterface', 'plugin') + pluginpreprocess = qtmodule.preprocess( + moc_headers : 'plugin/plugin.h', + include_directories : plugin_includes + ) + plugin = library('plugin', 'plugin/plugin.cpp', pluginpreprocess, + include_directories : plugin_includes, + dependencies : qtcore) endif endforeach diff --git a/test cases/frameworks/4 qt/plugin/plugin.cpp b/test cases/frameworks/4 qt/plugin/plugin.cpp new file mode 100644 index 0000000..eeae98d --- /dev/null +++ b/test cases/frameworks/4 qt/plugin/plugin.cpp @@ -0,0 +1,7 @@ +#include "plugin.h" +#include + +QString plugin1::getResource() +{ + return "hello world"; +} diff --git a/test cases/frameworks/4 qt/plugin/plugin.h b/test cases/frameworks/4 qt/plugin/plugin.h new file mode 100644 index 0000000..1138f41 --- /dev/null +++ b/test cases/frameworks/4 qt/plugin/plugin.h @@ -0,0 +1,11 @@ +#pragma once +#include + +class plugin1:public QObject,public PluginInterface +{ + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID "demo.PluginInterface" FILE "plugin.json") +public: + QString getResource() override; +}; diff --git a/test cases/frameworks/4 qt/plugin/plugin.json b/test cases/frameworks/4 qt/plugin/plugin.json new file mode 100644 index 0000000..6c6a011 --- /dev/null +++ b/test cases/frameworks/4 qt/plugin/plugin.json @@ -0,0 +1,3 @@ +{ + "name" : "Plugin1" +} diff --git a/test cases/frameworks/4 qt/pluginInterface/plugin_if.h b/test cases/frameworks/4 qt/pluginInterface/plugin_if.h new file mode 100644 index 0000000..97d2800 --- /dev/null +++ b/test cases/frameworks/4 qt/pluginInterface/plugin_if.h @@ -0,0 +1,21 @@ +#ifndef PLUGIN_IF_H +#define PLUGIN_IF_H + +#include +#include + +/** + * @brief Interface for a plugin + */ +class PluginInterface +{ +public: + virtual ~PluginInterface() = default; + + /// Initializes the plugin + virtual QString getResource() = 0; +}; + +Q_DECLARE_INTERFACE(PluginInterface, "demo.PluginInterface") + +#endif -- cgit v1.1 From 893d101fff01d72e8df055491d8e609eb0fd8575 Mon Sep 17 00:00:00 2001 From: Patrick Griffis Date: Sun, 13 Aug 2017 12:43:21 -0400 Subject: gnome: Add header kwarg to generate_gir() This is a commonly used flag so lets make it more obvious. --- docs/markdown/Gnome-module.md | 4 ++++ mesonbuild/modules/gnome.py | 8 +++++++- test cases/frameworks/7 gnome/gir/dep1/meson.build | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/markdown/Gnome-module.md b/docs/markdown/Gnome-module.md index 99a9c8e..d87e108 100644 --- a/docs/markdown/Gnome-module.md +++ b/docs/markdown/Gnome-module.md @@ -81,6 +81,10 @@ tool so see its documentation for more information. * `includes`: list of gir names to be included, can also be a GirTarget +* `header`: *(Added 0.43.0)* name of main c header to include for the library, e.g. `glib.h` + +* `dependencies`: deps to use during introspection scanning + * `include_directories`: extra include paths to look for gir files * `install`: if true, install the generated files diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index d1d7013..fa2bbb4 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -394,7 +394,7 @@ class GnomeModule(ExtensionModule): @permittedKwargs({'sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix', 'export_packages', 'includes', 'dependencies', 'link_with', 'include_directories', 'install', 'install_dir_gir', 'install_dir_typelib', 'extra_args', - 'packages', 'build_by_default'}) + 'packages', 'header', 'build_by_default'}) def generate_gir(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gir takes one argument') @@ -429,6 +429,12 @@ class GnomeModule(ExtensionModule): scan_command += ['--no-libtool', '--namespace=' + ns, '--nsversion=' + nsversion, '--warn-all', '--output', '@OUTPUT@'] + header = kwargs.pop('header', None) + if header: + if not isinstance(header, str): + raise MesonException('header must be a string') + scan_command += ['--c-include=' + header] + extra_args = mesonlib.stringlistify(kwargs.pop('extra_args', [])) scan_command += extra_args scan_command += ['-I' + srcdir, diff --git a/test cases/frameworks/7 gnome/gir/dep1/meson.build b/test cases/frameworks/7 gnome/gir/dep1/meson.build index 75dd731..baa0b1d 100644 --- a/test cases/frameworks/7 gnome/gir/dep1/meson.build +++ b/test cases/frameworks/7 gnome/gir/dep1/meson.build @@ -19,6 +19,7 @@ dep1gir = gnome.generate_gir( namespace : 'MesonDep1', symbol_prefix : 'meson', identifier_prefix : 'Meson', + header: 'dep1.h', includes : ['GObject-2.0', 'MesonDep2-1.0'], dependencies : [dep2_dep], install : true -- cgit v1.1 From ec45c29c9ddd5d848eb1555cdc09246d8900afec Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Mon, 2 Oct 2017 00:56:38 +0300 Subject: Add rpath entries for all found libraries outside of system libraries. --- docs/markdown/snippets/prebuilt.md | 13 +++++++++---- mesonbuild/backend/backends.py | 11 ++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/docs/markdown/snippets/prebuilt.md b/docs/markdown/snippets/prebuilt.md index a51176a..19741c4 100644 --- a/docs/markdown/snippets/prebuilt.md +++ b/docs/markdown/snippets/prebuilt.md @@ -1,9 +1,14 @@ -# Better support for prebuilt shared libraries +# Better support for shared libraries in non-system paths Meson has had support for prebuilt object files and static libraries. -This release adds feature parity to shared libraries. This means -that e.g. shipping prebuilt libraries as subprojects now can -be as simple as writing a definition file that looks like this. +This release adds feature parity to shared libraries that are either +in non-standard system paths or shipped as part of your project. On +systems that support rpath, Meson automatically adds rpath entries +to built targets using manually found external libraries. + +This means that e.g. supporting prebuilt libraries shipped with your +source or provided by subprojects or wrap definitions by writing a +build file like this: project('myprebuiltlibrary', 'c') diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index c737d49..e0e2abc 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -303,13 +303,16 @@ class Backend: for dep in target.external_deps: if isinstance(dep, dependencies.ExternalLibrary): la = dep.link_args - if len(la) == 1 and la[0].startswith(self.environment.get_source_dir()): + if len(la) == 1 and os.path.isabs(la[0]): # The only link argument is an absolute path to a library file. libpath = la[0] + if libpath.startswith(('/usr/lib', '/lib')): + # No point in adding system paths. + continue if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so']: continue absdir = os.path.split(libpath)[0] - rel_to_src = absdir[len(self.environment.get_source_dir())+1:] + rel_to_src = absdir[len(self.environment.get_source_dir()) + 1:] assert(not os.path.isabs(rel_to_src)) paths.append(os.path.join(self.build_to_src, rel_to_src)) return paths @@ -321,7 +324,9 @@ class Backend: prospective = self.get_target_dir(ld) if prospective not in result: result.append(prospective) - result += self.rpaths_for_bundled_shared_libraries(target) + for rp in self.rpaths_for_bundled_shared_libraries(target): + if rp not in result: + result += [rp] return result def object_filename_from_source(self, target, source, is_unity): -- cgit v1.1 From 35313c2a850020dc2d98c1aa5b2f4340e49f01d6 Mon Sep 17 00:00:00 2001 From: Mohammed Sadiq Date: Mon, 2 Oct 2017 16:05:10 +0530 Subject: docs: Fix typo Remove the quote before parens --- docs/markdown/Reference-manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index f37fb34..3bdd3c5 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1614,7 +1614,7 @@ during tests. It should be passed as the `env` keyword argument to tests. It has the following methods. - `append(varname, value)` appends the given value to the old value of - the environment variable, e.g. `env.append'('FOO', 'BAR', separator + the environment variable, e.g. `env.append('FOO', 'BAR', separator : ';')` produces `BOB;BAR` if `FOO` had the value `BOB` and plain `BAR` if the value was not defined. If the separator is not specified explicitly, the default path separator for the host -- cgit v1.1 From a28db4577a36bf53f09e439f2032f28eb9cd7079 Mon Sep 17 00:00:00 2001 From: xarkes Date: Mon, 2 Oct 2017 21:18:36 +0200 Subject: Fix typo and clarify library documentation --- docs/markdown/Reference-manual.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 3bdd3c5..86ad15e 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -820,10 +820,11 @@ static with only one option. The keyword arguments for this are the same as for [`executable`](#executable) with the following additions: -- `name_prefix` the string that will be used as the suffix for the +- `name_suffix` the string that will be used as the suffix for the target by overriding the default (only used for libraries). By default this is `lib` on all platforms and compilers except with - MSVC where it is omitted. + MSVC where it is omitted and set to `a` to avoid potential name clash + with shared libraries (which also generates `lib` files). - `rust_crate_type` specifies the crate type for Rust libraries. Defaults to `dylib` for shared libraries and `rlib` for static libraries. -- cgit v1.1 From f10b15930bb40424df0d0254ea5576b24b3c10df Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Tue, 3 Oct 2017 05:49:24 +0000 Subject: Update Reference-manual.md Fix documentation breakage from https://github.com/mesonbuild/meson/pull/2415 --- docs/markdown/Reference-manual.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 86ad15e..0cc6771 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -820,11 +820,18 @@ static with only one option. The keyword arguments for this are the same as for [`executable`](#executable) with the following additions: +- `name_prefix` the string that will be used as the prefix for the + target output filename by overriding the default (only used for + libraries). By default this is `lib` on all platforms and compilers + except with MSVC where it is omitted to follow convention. - `name_suffix` the string that will be used as the suffix for the - target by overriding the default (only used for libraries). By - default this is `lib` on all platforms and compilers except with - MSVC where it is omitted and set to `a` to avoid potential name clash - with shared libraries (which also generates `lib` files). + target output filename by overriding the default (see also: + [executable()](#executable)). By default, for shared libraries this + is `dylib` on macOS, `dll` on Windows, and `so` everywhere else. + For static libraries, it is `a` everywhere. By convention MSVC + static libraries use the `lib` suffix, but we use `a` to avoid a + potential name clash with shared libraries which also generate + `xxx.lib` import files. - `rust_crate_type` specifies the crate type for Rust libraries. Defaults to `dylib` for shared libraries and `rlib` for static libraries. -- cgit v1.1 From 0c3d58baba4a61558ed9b4905f26155a3e95cf6c Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Tue, 3 Oct 2017 06:57:46 +0000 Subject: Update Reference-manual.md --- docs/markdown/Reference-manual.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 0cc6771..14097ed 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -823,7 +823,8 @@ The keyword arguments for this are the same as for [`executable`](#executable) w - `name_prefix` the string that will be used as the prefix for the target output filename by overriding the default (only used for libraries). By default this is `lib` on all platforms and compilers - except with MSVC where it is omitted to follow convention. + except with MSVC shared libraries where it is omitted to follow + convention. - `name_suffix` the string that will be used as the suffix for the target output filename by overriding the default (see also: [executable()](#executable)). By default, for shared libraries this -- cgit v1.1