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

Store stdlibs dict at precompile time #2916

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

IanButterworth
Copy link
Member

Part of addressing #2771

@KristofferC what would be a simple PackageCompiler test for this?

@yuyichao
Copy link

yuyichao commented Jan 3, 2022

👎 stdlib is currently the ONLY location one could install packages systemwise. This will break that.

@staticfloat
Copy link
Member

@yuyichao could using a layered depot path satisfy that for you? E.g. define JULIA_DEPOT_PATH such that it points to a system-wide depot as a fallback location?

@yuyichao
Copy link

ENV would not work since it's not going to work reliably systemwise.
And I don't believe the depot path is used when loading modules, it's used to load precompiled files and that works just fine. Adding another default systemwise path in the modules loading paths would be fine, as long as it's treated similar to stdlib by Pkg, as non-writable location.

@staticfloat
Copy link
Member

staticfloat commented Jan 19, 2022

ENV would not work since it's not going to work reliably systemwise.

In lab environments, I think it is pretty normal to require users to setup some kind of systemwide environment variables. If this is your own setup, putting it into /etc/profile or something similar would work reliably.

And I don't believe the depot path is used when loading modules, it's used to load precompiled files and that works just fine.

See if the following works for your purposes:

#!/bin/sh

# Disable automatic precompilation to showcase that when we load
# a package from the "outer" depot, its precompiled file written to
# the "inner" depot.
export JULIA_PKG_PRECOMPILE_AUTO=0

# Cleanup any previous runs of this script
sudo rm -rf depot_outer depot_inner

# Install Bzip2_jll to the "outer" depot
echo "Installing to outer depot..."
JULIA_DEPOT_PATH="depot_outer" julia -e 'using Pkg; Pkg.add("Bzip2_jll")'

# Remove environments, as we don't want Julia to try and modify them
# I consider this something of a bug; Julia should not be loading the `Project.toml`
# file of other depots as read/write, even if it never writes to it.
rm -rf depot_outer/environments

# Remove registries, as we want users to manage their own registries
rm -rf depot_outer/registries

# Make outer depot no longer writable by us
sudo chown root:root -R depot_outer

# Install CodecBzip2_jll to the "inner" depot, note that Bzip2_jll is not installed again
echo "Installing to inner depot..."
JULIA_DEPOT_PATH="depot_inner:depot_outer" julia -e 'using Pkg; Pkg.add("CodecBzip2")'

# Prove that we can load CodecBzip2, which will load Bzip2_jll from the outer depot
JULIA_DEPOT_PATH="depot_inner:depot_outer" julia -e 'using CodecBzip2; @show Base.pathof(CodecBzip2); @show CodecBzip2.libbzip2'

When installing packages, Julia only ever writes to the first element in JULIA_DEPOT_PATH; all other depots will be treated as read-only (modulo the one bug I point out in the code sample above) so I think this could work well for you, and decouple your workflow from Pkg internals a bit.

@yuyichao
Copy link

In lab environments, I think it is pretty normal to require users to setup some kind of systemwide environment variables. If this is your own setup, putting it into /etc/profile or something similar would work reliably.

It's neither. A system package usually don't and shouldn't require env to work by default. And /etc/profile still won't work for things like sudo.

See if the following works for your purposes:

AFAICT, after the environment is deleted, the depot_outer stops working.

@yuyichao
Copy link

i.e.

yuyichao% JULIA_DEPOT_PATH="depot_inner:depot_outer" julia -e 'using Bzip2_jll'
ERROR: ArgumentError: Package Bzip2_jll not found in current path.
- Run `import Pkg; Pkg.add("Bzip2_jll")` to install the Bzip2_jll package.
Stacktrace:
 [1] macro expansion
   @ ./loading.jl:1036 [inlined]
 [2] macro expansion
   @ ./lock.jl:221 [inlined]
 [3] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1017

@staticfloat
Copy link
Member

What version of Julia are you using?

@yuyichao
Copy link

contabo2:~                                                                                    
yuyichao% export JULIA_PKG_PRECOMPILE_AUTO=0
contabo2:~                                                                                    
yuyichao% JULIA_DEPOT_PATH="depot_outer" julia -e 'using Pkg; Pkg.add("Bzip2_jll")'
  Installing known registries into `depot_outer`
    Updating registry at `depot_outer/registries/General.toml`
   Resolving package versions...
   Installed Bzip2_jll ─── v1.0.8+0
   Installed Preferences ─ v1.2.3
   Installed JLLWrappers ─ v1.4.0
  Downloaded artifact: Bzip2
    Updating `~/depot_outer/environments/v1.8/Project.toml`
  [6e34b625] + Bzip2_jll v1.0.8+0
    Updating `~/depot_outer/environments/v1.8/Manifest.toml`
  [692b3bcd] + JLLWrappers v1.4.0
  [21216c6a] + Preferences v1.2.3
  [6e34b625] + Bzip2_jll v1.0.8+0
  [0dad84c5] + ArgTools v1.1.1
  [56f22d72] + Artifacts
  [2a0f44e3] + Base64
  [ade2ca70] + Dates
  [f43a241f] + Downloads v1.6.0
  [7b1f6079] + FileWatching
  [b77e0a4c] + InteractiveUtils
  [b27032c2] + LibCURL v0.6.3
  [76f85450] + LibGit2
  [8f399da3] + Libdl
  [56ddb016] + Logging
  [d6f4376e] + Markdown
  [ca575930] + NetworkOptions v1.2.0
  [44cfe95a] + Pkg v1.8.0
  [de0858da] + Printf
  [3fa0cd96] + REPL
  [9a3f8284] + Random
  [ea8e919c] + SHA v0.7.0
  [9e88b42a] + Serialization
  [6462fe0b] + Sockets
  [fa267f1f] + TOML v1.0.0
  [a4e569a6] + Tar v1.10.0
  [cf7118a7] + UUIDs
  [4ec0a83e] + Unicode
  [deac9b47] + LibCURL_jll v7.73.0+4
  [29816b5a] + LibSSH2_jll v1.9.1+2
  [c8ffd9c3] + MbedTLS_jll v2.24.0+2
  [14a3606d] + MozillaCACerts_jll v2020.7.22
  [83775a58] + Zlib_jll v1.2.12+1
  [8e850ede] + nghttp2_jll v1.41.0+1
  [3f19e933] + p7zip_jll v16.2.1+1
contabo2:~
yuyichao% JULIA_DEPOT_PATH="depot_outer" julia -e 'using Bzip2_jll'
contabo2:~
yuyichao% JULIA_DEPOT_PATH="depot_inner:depot_outer" julia -e 'using Bzip2_jll'
contabo2:~
yuyichao% rm -rf depot_outer/environments
contabo2:~
yuyichao% rm -rf depot_outer/registries
contabo2:~
yuyichao% sudo chown root:root -R depot_outer
contabo2:~
yuyichao% JULIA_DEPOT_PATH="depot_inner:depot_outer" julia -e 'using Bzip2_jll'
ERROR: ArgumentError: Package Bzip2_jll not found in current path.
- Run `import Pkg; Pkg.add("Bzip2_jll")` to install the Bzip2_jll package.
Stacktrace:
 [1] macro expansion
   @ ./loading.jl:1036 [inlined]
 [2] macro expansion
   @ ./lock.jl:221 [inlined]
 [3] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1017
contabo2:~
yuyichao% JULIA_DEPOT_PATH="depot_outer" julia -e 'using Bzip2_jll'
ERROR: ArgumentError: Package Bzip2_jll not found in current path.
- Run `import Pkg; Pkg.add("Bzip2_jll")` to install the Bzip2_jll package.
Stacktrace:
 [1] macro expansion
   @ ./loading.jl:1036 [inlined]
 [2] macro expansion
   @ ./lock.jl:221 [inlined]
 [3] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1017

@yuyichao
Copy link

Julia Version 1.8.0-DEV.1345
Commit 5864e4341b0* (2022-01-19 06:23 UTC)

@yuyichao
Copy link

And to be clear, your command did produce the result you were claiming, but with it importing Bzip2_jll still doesn't work.

@staticfloat
Copy link
Member

Ah, I see. I thought you meant my script was giving that error. Yes, this is also expected, because Bzip2_jll isn't directly added to the user (inner) depot. If you Pkg.add() it, you'll see that it gets added to the user's environment, but the package source itself doesn't get installed within the user's depot because the packages/artifacts are already available in the system (outer) depot.

@yuyichao
Copy link

Well, the desired behavior, and the one achieved by placing packages in stdlib, is that when it's installed in there, user can just do using and it'll just work, without having to manually add them again. Precompilation for those packages also just work in the systemwise compiled directory, and if that one is out-of-date, one will be created in the user's directory.

@staticfloat
Copy link
Member

Well, the desired behavior, and the one achieved by placing packages in stdlib, is that when it's installed in there, user can just do using and it'll just work, without having to manually add them again.

In general, you can't just load stdlibs. e.g. If you're writing a package, you can't load an stdlib unless it's been manually added. Interactive usage allows it for convenience, but it's a shortcut.

The stdlib folder is meant for packages that ship with Julia, and we're planning on changing more than just this about them in the future. If you want this kind of functionality, I really do think it's going to require something more like multiple depots, or modifying Base.LOAD_PATH.

You can probably re-create what you want by adding push!(Base.LOAD_PATH, path_to_custom_stdlibs) to etc/startup.jl in your Julia installation; that way anyone who starts up that julia executable will be able to load those packages directly.

@yuyichao
Copy link

In general, you can't just load stdlibs. e.g. If you're writing a package, you can't load an stdlib unless it's been manually added. Interactive usage allows it for convenience, but it's a shortcut.

Unless you are talking about removing that shortcut altogether for scripts and REPL, then it is still inconvenience and undesired behavior for systemwise installed packages.
And this behavior also doesn't mean that package authors shouldn't add explicit dependencies.

If you want this kind of functionality, I really do think it's going to require something more like multiple depots, or modifying Base.LOAD_PATH.

That's exactly what I was saying that can work. A different paths that basically behaves exactly like stdlib now that's in LOAD_PATH by default. i.e. I don't want to patch julia in this regard during compilation.
Also I'd say that this functionality have existed in different forms since at least 0.3/0.4.... Removing it would be a regression.

You can probably re-create what you want by adding push!(Base.LOAD_PATH, path_to_custom_stdlibs) to etc/startup.jl in your Julia installation; that way anyone who starts up that julia executable will be able to load those packages directly.

No, startup files can be disabled as well, it is often disabled when only USER startup.jl is meant to be bypassed. This will make it harder/impossible without patching, to run some package tests that has all the dependencies already installed systemwise.

@staticfloat
Copy link
Member

You're asking for a way to ensure that Julia behaves differently than a stock Julia, without modifying Julia's source, but still persisting even when a "don't allow user customizations" option is passed. Having all three of those things is impossible. Either don't expect Julia to behave differently (e.g. only be able to load the stdlibs that it shipped with), modify Julia's source (alter the default LOAD_PATH) or customize it, and then expect breakage when you disable those customizations (alter the startup.jl).

I've given you multiple workarounds for this issue; if you don't want to take them, that's fine, but don't expect future versions of Julia to treat stdlibs in a way that is not what they're meant for. I can't say for certainty that this PR will be merged or that stdlibs will cease to function for your usecases, but your usecase is not what stdlibs were meant for, and it's not the direction that we're headed, so I'm trying to give you options for how to improve your workflow.

@yuyichao
Copy link

You're asking for a way to ensure that Julia behaves differently than a stock Julia, without modifying Julia's source, but still persisting even when a "don't allow user customizations" option is passed. Having all three of those things is impossible. Either don't expect Julia to behave differently (e.g. only be able to load the stdlibs that it shipped with), modify Julia's source (alter the default LOAD_PATH) or customize it, and then expect breakage when you disable those customizations (alter the startup.jl).

No, I'm asking for a way that behaves exactly the same as a stock julia right now and has always been possible since version 0.3-0.4. OTOH, you are saying you want to break that because now you decided that it shouldn't be supported.

but your usecase is not what stdlibs were meant for, and it's not the direction that we're headed, so I'm trying to give you options for how to improve your workflow.

And that's exactly what you've been doing. Whenever someone bring up a usecase that you don't like you simply decide that it's not a valid usecase and simply break it, no matter how easy it is to support that usecase (in this case an additional default in LOAD_PATH).

@IanButterworth IanButterworth added precompile Pkg.precompile and removed precompile Pkg.precompile labels May 3, 2023
@IanButterworth
Copy link
Member Author

@yuyichao I was just wondering whether anything has changed here regarding your usage of stdlib, and whether we can move forward with this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants