Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support versioned dylibs #90260

Closed
wants to merge 2 commits into from
Closed

Conversation

sp1ritCS
Copy link

Right now, rustc fails when trying to link against a versioned dylib crate (e.g. libsomecrate.so.0.1). This can happen if you use mesonbuild/meson as build system rather than cargo and you add a library (a dylib for cargo) as dependency.

note: extern location for somerandom is of an unknown type: subprojects/dep/libsomecrate.so.0.1
  = help: file name should be lib*.rlib or lib*..so

This patch tries to address this by replacing the simple ends_with dll_suffix check with a better one.

Right now, rustc fails when trying to link against a versioned dylib
crate (e.g. libsomecrate.so.0.1).
This patch tries to address this by replacing the simple ends_with
dll_suffix check with a better one.
@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @wesleywiser (or someone else) soon.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 25, 2021
compiler/rustc_metadata/src/locator.rs Outdated Show resolved Hide resolved
compiler/rustc_metadata/src/locator.rs Outdated Show resolved Hide resolved
@sp1ritCS
Copy link
Author

sp1ritCS commented Oct 25, 2021

Something that I've missed during my short period of testing, is that this will end up with a link flag like -lsomerandom. This will however not work if libsomerandom.so (symlinked to ...so.0.1) is not in the LD path.

@wesleywiser can you point me to the right direction regarding how NativeLibs name and verbatim are set, as rustc uses that to determine the final link flag

Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name))

@rust-log-analyzer

This comment has been minimized.

@petrochenkov petrochenkov self-assigned this Oct 26, 2021
@rust-log-analyzer

This comment has been minimized.

Due to the fact that if we were not using verbatim linking, linking
against a versioned crate will only work if a unversioned symlink to
the versioned one is part of the searchpath.
This is "preliminary" as right now it only uses the whole filename
for GNU-style linkers. It should however, be expanded to any linker
that supports verbatim linking.

Also added suggestions from @wesleywiser.
@apiraino apiraino added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Oct 28, 2021
@joshtriplett
Copy link
Member

Why does meson include a suffix here? That seems like it gives the impression that there's meaningful library versioning and compatibility.

@sp1ritCS
Copy link
Author

sp1ritCS commented Nov 1, 2021

Why does meson include a suffix here? That seems like it gives the impression that there's meaningful library versioning and compatibility.

it does so for any shared_library() regardless of language

@bjorn3
Copy link
Member

bjorn3 commented Nov 1, 2021

Can you set version to an empty string to disable this? Or will meson give something like libfoo.so. in that case?

@sp1ritCS
Copy link
Author

sp1ritCS commented Nov 1, 2021

Can you set version to an empty string to disable this? Or will meson give something like libfoo.so. in that case?

no, its quite strict about that.

ERROR: Invalid Shared library version "". Must be of the form X.Y.Z where all three are numbers. Y and Z are optional.

@joshtriplett
Copy link
Member

joshtriplett commented Nov 2, 2021

That doesn't seem like an issue we should be working around, here. dylibs don't have version numbers; they're just a .so. rustc is expecting that suffix for a reason.

As an example, Debian ships a dynamic libstd for Rust programs to use, but it has an SONAME with a hash in it, and no version number: libstd-80e93fdce0e07191.so.

If we were to change this to work around the issue, I don't think we should just change the expected suffix to omit this error. At most, I think we should offer a --force-something option or similar to force the format and change the error into a warning, but keep the warning. (In which case, we could just ignore the suffix entirely, and assume the user has told us what format it's in.)

@sp1ritCS
Copy link
Author

sp1ritCS commented Nov 3, 2021

dylibs don't have version numbers; they're just a .so
[...]
we could just ignore the suffix entirely

well, exactly because file-extensions inherently don't mean anything on POSIX, someone (I assume the GNU Developers) figured they can use the suffix for versioning. Thus relying on the suffix is inherently flawed in POSIX environments.

Letting the user specify the format works, but to me it seems somewhat unnecessary, because having the version suffix behind the extension is just the common way to do dynamic versioning since decades.
Additionally using a hash instead of a version suffix is inherently worse, as it strips away one of the benefits of dynamically linking the crates in the first place (not having to rebuilt everything dependent on it if no interfaces change [bugfix, etc.]) and a version suffix is far more human readable (and in case of failure easier fixable) than a hash.

@bjorn3
Copy link
Member

bjorn3 commented Nov 3, 2021

Additionally using a hash instead of a version suffix is inherently worse, as it strips away one of the benefits of dynamically linking the crates in the first place (not having to rebuilt everything dependent on it if no interfaces change [bugfix, etc.]) and a version suffix is far more human readable (and in case of failure easier fixable) than a hash.

The crate version is inherently meaningless wrt to the abi in rust. Any change to the imlementation of a crate will change it's SVH (semantic version hash) and potentially the rest of the crate metadata. This is not only when changing the actual source files (which a human readable version could account for) but also the set of --cfg's or almost any other commandline argument, any read env var, ... This is because any #[inline] and generic function has to be part of the ABI by definition. The SVH ensures that you don't try to use an incompatible ABI. It isn't ever shown to the user. Also note that the "hash" in say libstd-abcd1234.so doesn't have to be a hash. Cargo currently does use a hash (that isn't identical to the SVH and for example doesn't depend on the actual crate source), but any string can be passed to -Cextra-filename. By default nothing is used at all.

well, exactly because file-extensions inherently don't mean anything on POSIX, someone (I assume the GNU Developers) figured they can use the suffix for versioning. Thus relying on the suffix is inherently flawed in POSIX environments.

This is not true. Many programs rely on the file extension. Take for example your editor determining which language to use for syntax highlighting, your file explorer chosing which application to open your files with or even gcc determining which compiler it needs to use. (the C compiler, C++, Pascal, Fortran, ...) It is true that sometimes the extension doesn't matter and instead magic bytes are used, but this is not always possible (think text file) or unambiguous (think .docx or .odt files, both of which are zip files) Rustc needs the file extension to distinguish between rust metadata files (.rmeta), rust libraries (.rlib), non-rust static libraries (.a) and dynamic libraries (.so/.dylib) (honestly it may have been a good idea to use a different extension for rust dylibs to alow both the dylib and cdylib crate types at the same time and to avoid accidentally trying to use a non-rust dylib as a rust dylib)

@sp1ritCS
Copy link
Author

sp1ritCS commented Nov 4, 2021

honestly it may have been a good idea to use a different extension for rust dylibs to alow both the dylib and cdylib crate types at the same time and to avoid accidentally trying to use a non-rust dylib as a rust dylib

it might have, because I've noticed there's quite often confusion between dylib and cdylib crates, however I fear that on systems where the dynamic object loader cares about file-extensions (win nt) it'd cause a lot of trouble.

@bjorn3
Copy link
Member

bjorn3 commented Nov 4, 2021

I guess so. Nothing we can do about it now anyway.

@petrochenkov
Copy link
Contributor

petrochenkov commented Nov 26, 2021

rustc has two ways to lookup crates:

  • By exact path --extern name=EXACT_PATH, we just take the path and load it. This way is used e.g. for direct cargo dependencies. (See fn find_commandline_library, it's not modified by this PR.)
  • By name, we go though all search directories, collect candidate files with names libXXXXXX(-suffix).so, and try to load them as crates. This way is usually used for indirect dependencies, and for direct dependencies in exceptional cases, for libstd and libcore in particular. (See fn find_library_crate, it's modified by this PR.)

The first way has the same restrictions on file extensions as the second way, but they seem artificial.
We can just accept any file names in the EXACT_PATH, and pass them to the linker verbatim if they don't match the libSOMETHING.so pattern.
Recognizing the .so.1.2.3 pattern specific (or not specific) to Meson isn't even required, it just falls under the category "any non-libSOMETHING.so path, use verbatim".

I feel somewhat skeptical about recognizing the .so.1.2.3 syntax specifically though.
What other tools recognize it? Do dynamic linkers recognize it, for example?
What if some next build system comes up with its own new naming scheme, should rustc support it as well?

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 26, 2021
@bjorn3
Copy link
Member

bjorn3 commented Nov 26, 2021

The first way has the same restrictions on file extensions as the second way, but they seem artificial.

Allowing them for the first way would result in confusing errors when using a crate that has such a dependency as dependency. Indirect dependencies use the second way for lookup.

@sp1ritCS
Copy link
Author

sp1ritCS commented Dec 4, 2021

I feel somewhat skeptical about recognizing the .so.1.2.3 syntax specifically though.
What other tools recognize it? Do dynamic linkers recognize it, for example?
What if some next build system comes up with its own new naming scheme, should rustc support it as well?

well, almost all libraries are stored like this in linux (a libname.so.1.2.3, with symlinks to it: libname.so.1 and libname.so, with the second one usually provided by its devel package), so yeah the dynamic linker uses it.
This is also not just meson, but is the default since GNU autotools. So thus far the three major (c/xx) build systems (autotools, cmake, meson) are using it.

this obv. throws up the question how precompiled rust dependencies could be stored system wide

@bjorn3
Copy link
Member

bjorn3 commented Dec 4, 2021

this obv. throws up the question how precompiled rust dependencies could be stored system wide

For libstd and libtest this is libstd-<hash>.so and libtest-<hash>.so. The hash is calculated by cargo to be unique for each combination of rustc version, crate version and a couple of other properties. Currently cargo doesn't allow the same for user crates, but if you are using an alternative build system you could implement it for said build system.

In rust a human readable version string doesn't make sense the way it does in C. In C it is possible to precisely determine which changes break ABI compatibility and changing the compiler version doesn't usually change the ABI. For rustc changing the compiler version or even a single byte in the crate source will break ABI and rustc will give you an error when trying to compile. Only changing the compiler version is currently guaranteed to give an error at runtime, but any source changes may do this too or cause corruption.

@JohnCSimon
Copy link
Member

Ping from triage:
@sp1ritCS I can't tell what this PR is waiting on. Can you please post your status?

When it's ready for review send a message containing
@rustbot ready to switch to S-waiting-on-review

@sp1ritCS
Copy link
Author

@JohnCSimon

I was wanting to implement what @joshtriplett suggested:

At most, I think we should offer a --force-something option or similar to force the format

maybe along the lines of allowing something like --extern dylib:/path/to/dylib.so.any.ext to force a dependency being of a specific kind. I also wanted to test @eli-schwartz

Well, uh. Actually it already does do that, and yes even in your development tree.

again, because when I tested it I must have done something wrong, because it didn't for me or otherwise no error wouldn't even have occurred.

but so far I just haven't found the time to do so :/

@joshtriplett
Copy link
Member

Thank you for the response, @eli-schwartz; much appreciated.

It sounds like it is possible to build a shared library with meson that doesn't have a version number appended, and to reference such a shared library, which would be the correct answer for a Rust dylib library (since there's currently no ABI that would allow for a meaningfully versioned shared library).

Given that, it doesn't sound like we'd need to support the versioned case, unless I've missed something here.

@sp1ritCS I would suggest first confirming with current meson that it's possible to build and consume an unversioned shared library. Assuming it is, I think this can be closed, unless there's a specific use case motivating the force option.

@sp1ritCS
Copy link
Author

@joshtriplett

So I've re-tested rustc 1.58.0 with meson 0.60.3.

It sounds like it is possible to build a shared library with meson that doesn't have a version number appended

it is, when soversion is not set. However I want to have versioned dylibs to allow for having multiple versions of the same dependency installed, to accommodate breaking changes in them for different dependents that have fixed a specific version.

to allow that I see three different possibilities:

  • in meson implement that it symlinks a libname.so to the libname.so.ver in the build dir, which it doesn't seem to do (at least for me). But that would require installing the symlink on the system too, but the versionless symlink was traditionally only provided my package-devel packages. That would also break mult-version installs, as there can obv. only ever be a single non-versioned symlink in /usr/lib64/.
  • implement some way of forcing rustc to linking a given file as dylib and then implementing that meson uses that when a dependency is a shared_library
  • Use the versioned dylib detection from this PR and don't do anything on meson. (but that would then only work on dylibs that are named the way dylibs are traditionally, unlike with the possibility above, where the suffix could be anything)

@bjorn3
Copy link
Member

bjorn3 commented Jan 31, 2022

However I want to have versioned dylibs to allow for having multiple versions of the same dependency installed, to accommodate breaking changes in them for different dependents that have fixed a specific version.

The way cargo handles this is by naming them like libfoo-1234.so and libfoo-4321.so (where 1234 and 4321 are hashes in cargo, though they could possibly be manually chosen in your case. you could even put the version name there, so eg libfoo-0.1.0.so and libfoo-0.2.0.so instead of libfoo.so.0.1.0 and libfoo.so.0.2.0). This avoids the need for soname as the initial name was already different.

@eli-schwartz
Copy link

  • in meson implement that it symlinks a libname.so to the libname.so.ver in the build dir, which it doesn't seem to do (at least for me).

Meson very explicitly creates such a symlink, see https://github.com/mesonbuild/meson/blob/7528c69fcca63889d67c1d6c2463c9e9485585a8/mesonbuild/backend/ninjabackend.py#L3088-L3101

    def generate_shlib_aliases(self, target, outdir):
        aliases = target.get_aliases()
        for alias, to in aliases.items():
            aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias)
            try:
                os.remove(aliasfile)
            except Exception:
                pass
            try:
                os.symlink(to, aliasfile)
            except NotImplementedError:
                mlog.debug("Library versioning disabled because symlinks are not supported.")
            except OSError:
                mlog.debug("Library versioning disabled because we do not have symlink creation privileges.")
  • But that would require installing the symlink on the system too, but the versionless symlink was traditionally only provided my package-devel packages.

This is completely wrong and invalid.

You are making statements that are highly dependent on which particular Linux distro you use, and doesn't apply to people like me, who do not use Debian. My distro does not have devel packages, the versionless symlink is traditionally provided by the same package that provides the main library file.

Even then, meson provides and installs the symlink. Debian uses the symlink that meson installs. Just like they use the symlinks that CMake or autotools would install.

It's just that Debian happens to put some of the installed files in one dpkg archive, and some of them in a different dpkg archive. But that is a pointless implementation detail that has no earthly relevance here.

If you are compiling against a library I presume you would of course install the devel package on Debian.

That would also break mult-version installs, as there can obv. only ever be a single non-versioned symlink in /usr/lib64/.

Implying that CMake and autotools are also breaking multi-version installs? Why has that never been a problem anywhere other in the 21st century computing experience other than this one ticket in this one (rust) project for this one (you) participant in the ticket?

(Multi-version installs just have the unversioned symlink point at the version of the library which the headers correspond to. You can also only have a single non-versioned set of headers in /usr/include, after all.)

Meson's behavior of creating symlinks in the install tree is absolutely required, because if Meson did not do this (and CMake did, and autotools did, and it is a mandatory requirement of every single project using shared libraries with versions, and also a mandatory requirement of every single project such as a distro that builds and packages "software")...

... then Meson would be a joke of a build system, and no one would use something that doesn't even get the basic fundamentals of a build system correct. :)

So, they are definitely there at install time (except on systems where symlink creation does not work, in which case Meson logs an informative error to the console, and autotools maybe just logs ln: failed to create symbolic link '/XXXX': Permission denied, not sure what it would log on platforms where symlinks are not implemented).

They are also there at build time, which isn't strictly required in order to get the basic fundamentals of a build system correct, but, Meson does it anyway for robustness purposes, e.g. to support building against uninstalled projects (that is also why we create foo-uninstalled.pc files to export the uninstalled versions of pkg-config dependencies). Again, this gets done for any platform where symlink creation succeeds, and on failure will log a message to builddir/meson-logs/meson-log.txt.

So, I really do not understand under what conditions you are getting "the alias symlink is not created". Do you have a sample project that you've verified the issue with? What operating system are you using?

How do I replicate your issue? I confess I'm utterly unable to get Meson to not create a symlink.

@sp1ritCS
Copy link
Author

sp1ritCS commented Jan 31, 2022

It's just that Debian happens to put some of the installed files in one dpkg archive, and some of them in a different dpkg archive. But that is a pointless implementation detail that has no earthly relevance here.

Well, it has. Assuming the dpkg archives are named correctly, it is usually possible to install multiple liblibrary-X packages together, but just having the latest library-devel installed. On some Distros (I'd assume ones that use pacman), like the one you use yourself, this is just not possible as there are conflicting files like the unversioned symlink and the pkg-config and headerfiles which are provided by the separate library-devel package on most dpkg and rpm based distros.

If you are compiling against a library I presume you would of course install the devel package on Debian.

I was thinking that compiling against a outdated library would only occur in separate chroots/VMs/containers that have the minimal dependency footprint to build whatever package is required, so installing an outdated library-devel package there would not be an issue. But now do realize that that is flawed, as there (a) are users that want to build dependents on their system directly and (b) there are cases where two dependencies depend on the same crate but with different versions in rust. I wouldn't know how to solve that.

Implying that CMake and autotools are also breaking multi-version installs?

yes, just running make install will not allow multi versioning. I've never said that it wouldn't. multi-versioning will have to be provided by dpkg/rpm by splitting subpackages that do not share common files between versions.

How do I replicate your issue? I confess I'm utterly unable to get Meson to not create a symlink.

I'll attach my test tree I created today. It's basically just a modified version of the meson rust executable template and a subproject with the meson rust library template, but as shared- instead of static_library and with a soversion set. Commenting out subprojects/demolib/meson.build:ln6 removes the versioned symlink and then it works. Otherwise it throws me:

ninja: Entering directory `_build/'
[2/3] Compiling Rust source ../subprojects/demolib/demolib_test.rs
FAILED: subprojects/demolib/demolib_test 
rustc -C linker=cc --color=always --crate-type bin -W warnings -g --crate-name demolib_test --emit dep-info=subprojects/demolib/demolib_test.d --emit link -o subprojects/demolib/demolib_test --extern demolib=subprojects/demolib/libdemolib.so.0 -L subprojects/demolib -C prefer-dynamic -C 'link-arg=-Wl,-rpath,$ORIGIN/:/usr/lib' -C link-arg=-Wl,-rpath-link,/home/florian/workspace/rtest/_build/subprojects/demolib:/usr/lib ../subprojects/demolib/demolib_test.rs
error[E0463]: can't find crate for `demolib`
 --> ../subprojects/demolib/demolib_test.rs:1:1
  |
1 | extern crate demolib;
  | ^^^^^^^^^^^^^^^^^^^^^ can't find crate
  |
  = note: extern location for demolib is of an unknown type: subprojects/demolib/libdemolib.so.0
  = help: file name should be lib*.rlib or lib*..so

error: aborting due to previous error

For more information about this error, try `rustc --explain E0463`.
[3/3] Compiling Rust source ../rdemo.rs
FAILED: rdemo 
rustc -C linker=cc --color=always --crate-type bin -W warnings -g --crate-name rdemo --emit dep-info=rdemo.d --emit link -o rdemo --extern demolib=subprojects/demolib/libdemolib.so.0 -L subprojects/demolib -C prefer-dynamic -C 'link-arg=-Wl,-rpath,$ORIGIN/subprojects/demolib:/usr/lib' -C link-arg=-Wl,-rpath-link,/home/florian/workspace/rtest/_build/subprojects/demolib:/usr/lib ../rdemo.rs
error[E0463]: can't find crate for `demolib`
 --> ../rdemo.rs:5:26
  |
5 |     println!("Demo: {}", demolib::dem_func());
  |                          ^^^^^^^ can't find crate
  |
  = note: extern location for demolib is of an unknown type: subprojects/demolib/libdemolib.so.0
  = help: file name should be lib*.rlib or lib*..so

error: aborting due to previous error

For more information about this error, try `rustc --explain E0463`.
ninja: build stopped: subcommand failed.

and the symlink is nowhere to be found in the builddir (the log also doesn't contain anything suspicious):

_build/
├── build.ninja
├── compile_commands.json
├── meson-info
│   ├── intro-benchmarks.json
│   ├── intro-buildoptions.json
│   ├── intro-buildsystem_files.json
│   ├── intro-dependencies.json
│   ├── intro-installed.json
│   ├── intro-install_plan.json
│   ├── intro-projectinfo.json
│   ├── intro-targets.json
│   ├── intro-tests.json
│   └── meson-info.json
├── meson-logs
│   └── meson-log.txt
├── meson-private
│   ├── build.dat
│   ├── cmd_line.txt
│   ├── coredata.dat
│   ├── install.dat
│   ├── meson_benchmark_setup.dat
│   ├── meson.lock
│   ├── meson_test_setup.dat
│   ├── rusttest
│   └── sanity.rs
├── rdemo.p
└── subprojects
    └── demolib
        ├── demolib_test.p
        ├── libdemolib.so.0
        └── libdemolib.so.0.p

rtest.tar.gz

@eli-schwartz
Copy link

eli-schwartz commented Jan 31, 2022

Thank you for the test case! I've reproduced the issue, it is absolutely a bug in meson, and I have written a fix. (It is specific to the versioned dylib itself being built with specific languages, in this case rust -- C/C++ dylibs generate symlinks just fine.)

eli-schwartz added a commit to eli-schwartz/meson that referenced this pull request Jan 31, 2022
Basically the last thing we did during target processing was to generate
shlib symlinks for e.g. libfoo.so -> libfoo.so.1.

In some cases we would dispatch to another function and return early,
though, which meant we never got far enough to generate the symlinks.
This then led to breakage when people tried to compile against libfoo.so

This surely breaks -uninstalled.pc usage, and also caused problems in
rust-lang/rust#90260
@eli-schwartz
Copy link

Note that even with the restoration of the symlink, I guess either rustc or meson would need to resolve subprojects/demolib/libdemolib.so.0 to subprojects/demolib/libdemolib.so, but at least one aspect of this is fixed.

eli-schwartz added a commit to eli-schwartz/meson that referenced this pull request Feb 1, 2022
Basically the last thing we did during target processing was to generate
shlib symlinks for e.g. libfoo.so -> libfoo.so.1.

In some cases we would dispatch to another function and return early,
though, which meant we never got far enough to generate the symlinks.
This then led to breakage when people tried to compile against libfoo.so

This surely breaks -uninstalled.pc usage, and also caused problems in
rust-lang/rust#90260
@sp1ritCS
Copy link
Author

sp1ritCS commented Feb 1, 2022

So I've tried implementing a way to force rustc to treat a specific --extern as one kind of dependency. See: sp1ritCS@49e1fd8 .

One can get meson to use this with the following simple change:

diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 75dd535e8..2b7bfeab4 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1716,10 +1716,10 @@ class NinjaBackend(backends.Backend):
         for d in target.link_targets:
             linkdirs.add(d.subdir)
             if d.uses_rust():
-                # specify `extern CRATE_NAME=OUTPUT_FILE` for each Rust
+                # specify `extern kind:CRATE_NAME=OUTPUT_FILE` for each Rust
                 # 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))]
+                args += ['--extern', '{}:{}={}'.format(d.rust_crate_type, 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 import libraries are .lib, so we have to

with that, the demo I've sent builds perfectly (and runs after having added the libstd to the ld searchpath :))

@eli-schwartz
Copy link

That sounds great, either your patch or one to use the unversioned symlink will be more than welcome as a Meson PR.

@bors
Copy link
Contributor

bors commented Feb 5, 2022

☔ The latest upstream changes (presumably #93655) made this pull request unmergeable. Please resolve the merge conflicts.

nirbheek pushed a commit to mesonbuild/meson that referenced this pull request Feb 14, 2022
Basically the last thing we did during target processing was to generate
shlib symlinks for e.g. libfoo.so -> libfoo.so.1.

In some cases we would dispatch to another function and return early,
though, which meant we never got far enough to generate the symlinks.
This then led to breakage when people tried to compile against libfoo.so

This surely breaks -uninstalled.pc usage, and also caused problems in
rust-lang/rust#90260
@JohnCSimon JohnCSimon added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 6, 2022
@Dylan-DPC
Copy link
Member

@sp1ritCS any updates on this?

@sp1ritCS
Copy link
Author

sp1ritCS commented Mar 7, 2022

@Dylan-DPC I expect a comment regarding

So I've tried implementing a way to force rustc to treat a specific --extern as one kind of dependency. See: sp1ritCS@49e1fd8 .

if the Rust developers consider this adequate.

@JohnCSimon JohnCSimon added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. I-needs-decision Issue: In need of a decision. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 23, 2022
@sp1ritCS
Copy link
Author

@Dylan-DPC has there been any change since I wrote that last comment, or how is the status of this?

@petrochenkov
Copy link
Contributor

petrochenkov commented May 17, 2022

I would still prefer for rustc to not be aware of the .so.0.1 naming scheme and for this problem to be solved elsewhere.

@sp1ritCS
Copy link
Author

sp1ritCS commented May 18, 2022

that is what I implemented in that linked commit. it allows crates to be tagged with --extern dylib:name=path/to/crate.whatever

@petrochenkov
Copy link
Contributor

in that linked commit

Do you mean sp1ritCS@49e1fd8?
It will work for direct dependencies, but not for indirect dependencies (#90260 (comment), #90260 (comment)).
It also won't work with pipelined builds when you first find a rmeta file, but then actually link to a dylib.

A higher level build system would be a better place for addressing this than rustc, it can use whatever naming it wants and then satisfy rustc with symlinks.
People has been doing it for much weirder things than .so.0.1 - #75548.

The PR is sitting for too long with a I-needs-decision label, so I'm just going to make that decision and close it.

@sp1ritCS
Copy link
Author

A higher level build system would be a better place for addressing this than rustc, it can use whatever naming it wants [...]

that is part of the problem. rustc is already quite high-level, given that it invokes the linker itself. If rustc could just output object files and let them be linked by a higher level build system, like a normal compiler, this wouldn't be an issue in the first place.

It will work for direct dependencies, but not for indirect dependencies

to my understanding, it does actually work with indirect dependencies, if they are also specified with --extern, liked pkg-config would do.

@bjorn3
Copy link
Member

bjorn3 commented May 18, 2022

--extern declares direct dependencies. -L is for indirect dependencies. --extern is not always suitable. For example you can't have two --extern for different versions of the same library without renaming either. You can easily have two different versions of indirect dependencies without renaming. It also makes it easy to accidentally use said indirect dependency directly without declaring the dependency in the build system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-needs-decision Issue: In need of a decision. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.