From 11d123332d5242c419b4cc3ae0e0df4102ab189a Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 23 Feb 2021 10:38:34 -0800 Subject: ninjabackend: fix linking dynamic c libraries with rust The correct name is "dylib" not "shared" --- mesonbuild/backend/ninjabackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 05427d3..cd7f450 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1610,7 +1610,7 @@ int dummy; args += ['--extern', '{}={}'.format(d.name, os.path.join(d.subdir, d.filename))] else: # Rust uses -l for non rust dependencies, but we still need to add (shared|static)=foo - _type = 'static' if d.typename == 'static library' else 'shared' + _type = 'static' if d.typename == 'static library' else 'dylib' args += ['-l', f'{_type}={d.name}'] if d.typename == 'static library': external_deps.extend(d.external_deps) -- cgit v1.1 From e7e04c814ba8f513deb7b67d298277e083cd1514 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 23 Feb 2021 11:05:47 -0800 Subject: Add a rust test for internal c linkage We have code to support this, but no tests. That seems pretty bad. And better yet, it doesn't work on MSVC in some cases. --- mesonbuild/backend/ninjabackend.py | 17 ++++++++++----- test cases/rust/16 internal c dependencies/lib.c | 6 ++++++ test cases/rust/16 internal c dependencies/lib.h | 22 +++++++++++++++++++ test cases/rust/16 internal c dependencies/main.rs | 9 ++++++++ .../rust/16 internal c dependencies/meson.build | 14 ++++++++++++ test cases/rust/16 internal c dependencies/test.py | 25 ++++++++++++++++++++++ 6 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 test cases/rust/16 internal c dependencies/lib.c create mode 100644 test cases/rust/16 internal c dependencies/lib.h create mode 100644 test cases/rust/16 internal c dependencies/main.rs create mode 100644 test cases/rust/16 internal c dependencies/meson.build create mode 100755 test cases/rust/16 internal c dependencies/test.py diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index cd7f450..3749ff7 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1608,12 +1608,19 @@ int dummy; # dependency, so that collisions with libraries in rustc's # sysroot don't cause ambiguity args += ['--extern', '{}={}'.format(d.name, os.path.join(d.subdir, d.filename))] + elif d.typename == 'static library': + # Rustc doesn't follow Meson's convention that static libraries + # are called .a, and implementation libraries are .lib, so we + # have to manually handle that. + if rustc.linker.id == 'link': + args += ['-C', f'link-arg={self.get_target_filename_for_linking(d)}'] + else: + args += ['-l', f'static={d.name}'] + external_deps.extend(d.external_deps) else: - # Rust uses -l for non rust dependencies, but we still need to add (shared|static)=foo - _type = 'static' if d.typename == 'static library' else 'dylib' - args += ['-l', f'{_type}={d.name}'] - if d.typename == 'static library': - external_deps.extend(d.external_deps) + # Rust uses -l for non rust dependencies, but we still need to + # add dylib=foo + args += ['-l', f'dylib={d.name}'] for e in external_deps: for a in e.get_link_args(): if a.endswith(('.dll', '.so', '.dylib')): diff --git a/test cases/rust/16 internal c dependencies/lib.c b/test cases/rust/16 internal c dependencies/lib.c new file mode 100644 index 0000000..e852de6 --- /dev/null +++ b/test cases/rust/16 internal c dependencies/lib.c @@ -0,0 +1,6 @@ +#include +#include "lib.h" + +void c_func(void) { + printf("This is a " MODE " C library\n"); +} diff --git a/test cases/rust/16 internal c dependencies/lib.h b/test cases/rust/16 internal c dependencies/lib.h new file mode 100644 index 0000000..847bd16 --- /dev/null +++ b/test cases/rust/16 internal c dependencies/lib.h @@ -0,0 +1,22 @@ +#pragma once + +#if defined _WIN32 || defined __CYGWIN__ + #if defined BUILDING_ADDER + #define DLL_PUBLIC __declspec(dllexport) + #else + #define DLL_PUBLIC __declspec(dllimport) + #endif +#else + #if defined __GNUC__ + #if defined BUILDING_ADDER + #define DLL_PUBLIC __attribute__ ((visibility("default"))) + #else + #define DLL_PUBLIC + #endif + #else + #pragma message("Compiler does not support symbol visibility.") + #define DLL_PUBLIC + #endif +#endif + +DLL_PUBLIC void c_func(void); diff --git a/test cases/rust/16 internal c dependencies/main.rs b/test cases/rust/16 internal c dependencies/main.rs new file mode 100644 index 0000000..5383599 --- /dev/null +++ b/test cases/rust/16 internal c dependencies/main.rs @@ -0,0 +1,9 @@ +extern "C" { + fn c_func(); +} + +fn main() { + unsafe { + c_func(); + } +} diff --git a/test cases/rust/16 internal c dependencies/meson.build b/test cases/rust/16 internal c dependencies/meson.build new file mode 100644 index 0000000..c7476d7 --- /dev/null +++ b/test cases/rust/16 internal c dependencies/meson.build @@ -0,0 +1,14 @@ +project('internal dependencies', 'c', 'rust') + +test_prog = find_program('test.py') + +static = static_library('static', 'lib.c', c_args : '-DMODE="static"') +exe = executable('static', 'main.rs', link_with : static) +test('static linkage', test_prog, args : [exe, 'This is a static C library']) + +# Shared linkage with rust doesn't work on macOS with meson, yet +if host_machine.system() != 'darwin' + shared = shared_library('shared', 'lib.c', c_args : '-DMODE="shared"') + exe = executable('shared', 'main.rs', link_with : shared) + test('shared linkage', test_prog, args : [exe, 'This is a shared C library']) +endif diff --git a/test cases/rust/16 internal c dependencies/test.py b/test cases/rust/16 internal c dependencies/test.py new file mode 100755 index 0000000..dacec12 --- /dev/null +++ b/test cases/rust/16 internal c dependencies/test.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +import argparse +import subprocess +import sys + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument('command') + parser.add_argument('expected') + args = parser.parse_args() + + out = subprocess.run(args.command, stdout=subprocess.PIPE) + actual = out.stdout.decode().strip() + + if args.expected != actual: + print('expected:', args.expected, file=sys.stderr) + print('actual: ', actual, file=sys.stderr) + sys.exit(1) + sys.exit(0) + + +if __name__ == "__main__": + main() -- cgit v1.1