• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #38182

15 Aug 2025 03:55AM UTC coverage: 77.87% (-0.4%) from 78.28%
#38182

push

local

web-flow
🤖 [master] Bump the SparseArrays stdlib from 30201ab to bb5ecc0 (#59263)

Stdlib: SparseArrays
URL: https://github.com/JuliaSparse/SparseArrays.jl.git
Stdlib branch: main
Julia branch: master
Old commit: 30201ab
New commit: bb5ecc0
Julia version: 1.13.0-DEV
SparseArrays version: 1.13.0
Bump invoked by: @ViralBShah
Powered by:
[BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl)

Diff:
https://github.com/JuliaSparse/SparseArrays.jl/compare/30201abcb...bb5ecc091

```
$ git log --oneline 30201ab..bb5ecc0
bb5ecc0 fast quadratic form for dense matrix, sparse vectors (#640)
34ece87 Extend 3-arg `dot` to generic `HermOrSym` sparse matrices (#643)
095b685 Exclude unintended complex symmetric sparse matrices from 3-arg `dot` (#642)
8049287 Fix signature for 2-arg matrix-matrix `dot` (#641)
cff971d Make cond(::SparseMatrix, 1 / Inf) discoverable from 2-norm error (#629)
```

Co-authored-by: ViralBShah <744411+ViralBShah@users.noreply.github.com>

48274 of 61993 relevant lines covered (77.87%)

9571166.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

34.55
/base/sysinfo.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
module Sys
4
@doc """
5
Provide methods for retrieving information about hardware and the operating system.
6
""" Sys
7

8
export BINDIR,
9
       STDLIB,
10
       CPU_THREADS,
11
       CPU_NAME,
12
       WORD_SIZE,
13
       ARCH,
14
       MACHINE,
15
       KERNEL,
16
       JIT,
17
       cpu_info,
18
       cpu_summary,
19
       sysimage_target,
20
       uptime,
21
       loadavg,
22
       free_memory,
23
       total_memory,
24
       free_physical_memory,
25
       total_physical_memory,
26
       isapple,
27
       isbsd,
28
       isdragonfly,
29
       isfreebsd,
30
       islinux,
31
       isnetbsd,
32
       isopenbsd,
33
       isunix,
34
       iswindows,
35
       isjsvm,
36
       isexecutable,
37
       isreadable,
38
       iswritable,
39
       username,
40
       which,
41
       detectwsl
42

43
import ..Base: show
44

45
"""
46
    Sys.BINDIR::String
47

48
A string containing the full path to the directory containing the `julia` executable.
49
"""
50
global BINDIR::String = ccall(:jl_get_julia_bindir, Any, ())::String
51

52
"""
53
    Sys.STDLIB::String
54

55
A string containing the full path to the directory containing the `stdlib` packages.
56
"""
57
global STDLIB::String = "$BINDIR/../share/julia/stdlib/v$(VERSION.major).$(VERSION.minor)" # for bootstrap
58
# In case STDLIB change after julia is built, the variable below can be used
59
# to update cached method locations to updated ones.
60
const BUILD_STDLIB_PATH = STDLIB
61
# Similarly, this is the root of the julia repo directory that julia was built from
62
const BUILD_ROOT_PATH = "$BINDIR/../.."
63

64
# helper to avoid triggering precompile warnings
65

66
"""
67
    Sys.CPU_THREADS::Int
68

69
The number of logical CPU cores available in the system, i.e. the number of threads
70
that the CPU can run concurrently. Note that this is not necessarily the number of
71
CPU cores, for example, in the presence of
72
[hyper-threading](https://en.wikipedia.org/wiki/Hyper-threading).
73

74
See Hwloc.jl or CpuId.jl for extended information, including number of physical cores.
75
"""
76
global CPU_THREADS::Int = 1 # for bootstrap, changed on startup
77

78
"""
79
    Sys.ARCH::Symbol
80

81
A symbol representing the architecture of the build configuration.
82
"""
83
const ARCH = ccall(:jl_get_ARCH, Any, ())::Symbol
84

85

86
"""
87
    Sys.KERNEL::Symbol
88

89
A symbol representing the name of the operating system, as returned by `uname` of the build configuration.
90
"""
91
const KERNEL = ccall(:jl_get_UNAME, Any, ())::Symbol
92

93
"""
94
    Sys.MACHINE::String
95

96
A string containing the build triple.
97
"""
98
const MACHINE = Base.MACHINE::String
99

100
"""
101
    Sys.WORD_SIZE::Int
102

103
Standard word size on the current machine, in bits.
104
"""
105
const WORD_SIZE = Core.sizeof(Int) * 8
106

107
"""
108
    Sys.SC_CLK_TCK::Clong
109

110
The number of system "clock ticks" per second, corresponding to `sysconf(_SC_CLK_TCK)` on
111
POSIX systems, or `0` if it is unknown.
112

113
CPU times, e.g. as returned by `Sys.cpu_info()`, are in units of ticks, i.e. units of `1 / Sys.SC_CLK_TCK` seconds if `Sys.SC_CLK_TCK > 0`.
114
"""
115
global SC_CLK_TCK::Clong
116

117
"""
118
    Sys.CPU_NAME::String
119

120
A string representing the name of CPU.
121

122
# Examples
123
For example, `Sys.CPU_NAME` might equal `"tigerlake"` on an
124
[Intel Core "Tiger Lake" CPU](https://en.wikipedia.org/wiki/Tiger_Lake),
125
or `"apple-m1"` on an [Apple M1 CPU](https://en.wikipedia.org/wiki/Apple_M1).
126

127
Note: Included in the detailed system information via `versioninfo(verbose=true)`.
128
"""
129
global CPU_NAME::String
130

131
"""
132
    Sys.JIT::String
133

134
A string representing the specific Just-In-Time (JIT) compiler being utilized in the current runtime.
135

136
# Examples
137
Currently, this equals `"ORCJIT"` for the LLVM "ORC" ("On-Request Compilation") JIT library:
138
```jldoctest
139
julia> Sys.JIT
140
"ORCJIT"
141
```
142

143
Note: Included in the detailed system information via `versioninfo(verbose=true)`.
144
"""
145
global JIT::String
146

147
function __init__()
×
148
    env_threads = nothing
×
149
    if haskey(ENV, "JULIA_CPU_THREADS")
×
150
        env_threads = ENV["JULIA_CPU_THREADS"]
×
151
    end
152
    global CPU_THREADS = if env_threads !== nothing
×
153
        env_threads = tryparse(Int, env_threads)
×
154
        if env_threads === nothing || env_threads <= 0
×
155
            env_threads = Int(ccall(:jl_cpu_threads, Int32, ()))
×
156
            Core.print(Core.stderr, "WARNING: couldn't parse `JULIA_CPU_THREADS` environment variable. Defaulting Sys.CPU_THREADS to $env_threads.\n")
×
157
        end
158
        env_threads
×
159
    else
160
        Int(ccall(:jl_cpu_threads, Int32, ()))
×
161
    end
162
    global SC_CLK_TCK = ccall(:jl_SC_CLK_TCK, Clong, ())
×
163
    global CPU_NAME = ccall(:jl_get_cpu_name, Ref{String}, ())
×
164
    global JIT = ccall(:jl_get_JIT, Ref{String}, ())
×
165
    __init_build()
×
166
    nothing
×
167
end
168
# Populate the paths needed by sysimg compilation, e.g. `generate_precompile.jl`,
169
# without pulling in anything unnecessary like `CPU_NAME`
170
function __init_build()
×
171
    global BINDIR = ccall(:jl_get_julia_bindir, Any, ())::String
×
172
    vers = "v$(string(VERSION.major)).$(string(VERSION.minor))"
×
173
    global STDLIB = abspath(BINDIR, "..", "share", "julia", "stdlib", vers)
×
174
    nothing
×
175
end
176

177
mutable struct UV_cpu_info_t
178
    model::Ptr{UInt8}
179
    speed::Int32
180
    cpu_times!user::UInt64
181
    cpu_times!nice::UInt64
182
    cpu_times!sys::UInt64
183
    cpu_times!idle::UInt64
184
    cpu_times!irq::UInt64
185
end
186

187
"""
188
    Sys.CPUinfo
189

190
The `CPUinfo` type is a mutable struct with the following fields:
191
- `model::String`: CPU model information.
192
- `speed::Int32`: CPU speed (in MHz).
193
- `cpu_times!user::UInt64`: Time spent in user mode. CPU state shows CPU time used by user space processes.
194
- `cpu_times!nice::UInt64`: Time spent in nice mode. CPU state is a subset of the "user" state and shows the CPU time used by processes that have a positive niceness, meaning a lower priority than other tasks.
195
- `cpu_times!sys::UInt64`: Time spent in system mode. CPU state shows the amount of CPU time used by the kernel.
196
- `cpu_times!idle::UInt64`: Time spent in idle mode. CPU state shows the CPU time that's not actively being used.
197
- `cpu_times!irq::UInt64`: Time spent handling interrupts. CPU state shows the amount of time the CPU has been servicing hardware interrupts.
198

199
The times are in units of `1/Sys.SC_CLK_TCK` seconds if `Sys.SC_CLK_TCK > 0`; otherwise they are in
200
unknown units.
201

202
Note: Included in the detailed system information via `versioninfo(verbose=true)`.
203
"""
204
mutable struct CPUinfo
205
    model::String
206
    speed::Int32
207
    cpu_times!user::UInt64
208
    cpu_times!nice::UInt64
209
    cpu_times!sys::UInt64
210
    cpu_times!idle::UInt64
211
    cpu_times!irq::UInt64
212
    CPUinfo(model,speed,u,n,s,id,ir)=new(model,speed,u,n,s,id,ir)
28✔
213
end
214
CPUinfo(info::UV_cpu_info_t) = CPUinfo(unsafe_string(info.model), info.speed,
24✔
215
    info.cpu_times!user, info.cpu_times!nice, info.cpu_times!sys,
216
    info.cpu_times!idle, info.cpu_times!irq)
217

218
public CPUinfo
219

220
function _show_cpuinfo(io::IO, info::Sys.CPUinfo, header::Bool=true, prefix::AbstractString="    ")
21✔
221
    tck = SC_CLK_TCK
21✔
222
    if header
21✔
223
        println(io, info.model, ": ")
4✔
224
        print(io, " "^length(prefix))
4✔
225
        println(io, "    ", lpad("speed", 5), "    ", lpad("user", 9), "    ", lpad("nice", 9), "    ",
4✔
226
                lpad("sys", 9), "    ", lpad("idle", 9), "    ", lpad("irq", 9))
227
    end
228
    print(io, prefix)
21✔
229
    unit = tck > 0 ? " s  " : "    "
21✔
230
    tc = max(tck, 1)
21✔
231
    d(i, unit=unit) = lpad(string(round(Int64,i)), 9) * unit
105✔
232
    print(io,
21✔
233
          lpad(string(info.speed), 5), " MHz  ",
234
          d(info.cpu_times!user / tc), d(info.cpu_times!nice / tc), d(info.cpu_times!sys / tc),
235
          d(info.cpu_times!idle / tc), d(info.cpu_times!irq / tc, tck > 0 ? " s" : "  "))
236
    if tck <= 0
21✔
237
        print(io, "ticks")
×
238
    end
239
end
240

241
show(io::IO, ::MIME"text/plain", info::CPUinfo) = _show_cpuinfo(io, info, true, "    ")
1✔
242

243
function _cpu_summary(io::IO, cpu::AbstractVector{CPUinfo}, i, j)
3✔
244
    if j-i < 9
3✔
245
        header = true
3✔
246
        for x = i:j
3✔
247
            header || println(io)
37✔
248
            _show_cpuinfo(io, cpu[x], header, "#$(x-i+1) ")
20✔
249
            header = false
20✔
250
        end
37✔
251
    else
252
        summary = CPUinfo(cpu[i].model,0,0,0,0,0,0)
×
253
        count = j - i + 1
×
254
        for x = i:j
×
255
            summary.speed += cpu[i].speed
×
256
            summary.cpu_times!user += cpu[x].cpu_times!user
×
257
            summary.cpu_times!nice += cpu[x].cpu_times!nice
×
258
            summary.cpu_times!sys += cpu[x].cpu_times!sys
×
259
            summary.cpu_times!idle += cpu[x].cpu_times!idle
×
260
            summary.cpu_times!irq += cpu[x].cpu_times!irq
×
261
        end
×
262
        summary.speed = div(summary.speed,count)
×
263
        _show_cpuinfo(io, summary, true, "#1-$(count) ")
×
264
    end
265
    println(io)
3✔
266
end
267

268
"""
269
    Sys.cpu_summary(io::IO=stdout, cpu::AbstractVector{CPUinfo}=cpu_info())
270

271
Print a summary of CPU information to the `io` stream (defaulting to [`stdout`](@ref)), organizing and displaying aggregated data for CPUs with the same model, for a given array of `CPUinfo` data structures
272
describing a set of CPUs (which defaults to the return value of the [`Sys.cpu_info`](@ref) function).
273

274
The summary includes aggregated information for each distinct CPU model,
275
providing details such as average CPU speed and total time spent in different modes (user, nice, sys, idle, irq) across all cores with the same model.
276

277
Note: Included in the detailed system information via `versioninfo(verbose=true)`.
278
"""
279
function cpu_summary(io::IO=stdout, cpu::AbstractVector{CPUinfo} = cpu_info())
2✔
280
    model = cpu[1].model
5✔
281
    first = 1
3✔
282
    for i = 2:length(cpu)
3✔
283
        if model != cpu[i].model
17✔
284
            _cpu_summary(io, cpu, first, i-1)
×
285
            first = i
×
286
        end
287
    end
31✔
288
    _cpu_summary(io, cpu, first, length(cpu))
3✔
289
end
290

291
"""
292
    Sys.cpu_info()
293

294
Return a vector of `CPUinfo` objects, where each object represents information about a CPU core.
295

296
This is pretty-printed in a tabular format by `Sys.cpu_summary`, which is included in the output
297
of `versioninfo(verbose=true)`, so most users will not need to access the `CPUinfo`
298
data structures directly.
299

300
The function provides information about each CPU, including model, speed, and usage statistics such as user time, nice time, system time, idle time, and interrupt time.
301

302
"""
303
function cpu_info()
3✔
304
    UVcpus = Ref{Ptr{UV_cpu_info_t}}()
3✔
305
    count = Ref{Int32}()
3✔
306
    err = ccall(:uv_cpu_info, Int32, (Ptr{Ptr{UV_cpu_info_t}}, Ptr{Int32}), UVcpus, count)
3✔
307
    Base.uv_error("uv_cpu_info", err)
3✔
308
    cpus = Vector{CPUinfo}(undef, count[])
3✔
309
    for i = 1:length(cpus)
6✔
310
        cpus[i] = CPUinfo(unsafe_load(UVcpus[], i))
24✔
311
    end
45✔
312
    ccall(:uv_free_cpu_info, Cvoid, (Ptr{UV_cpu_info_t}, Int32), UVcpus[], count[])
3✔
313
    return cpus
3✔
314
end
315

316
"""
317
    Sys.sysimage_target()
318

319
Return the CPU target string that was used to build the current system image.
320

321
This function returns the original CPU target specification that was passed to Julia
322
when the system image was compiled. This can be useful for reproducing the same
323
system image or for understanding what CPU features were enabled during compilation.
324

325
If the system image was built with the default settings this will return `"native"`.
326

327
See also [`JULIA_CPU_TARGET`](@ref).
328
"""
329
function sysimage_target()
×
330
    return ccall(:jl_get_sysimage_cpu_target, Ref{String}, ())
×
331
end
332

333
"""
334
    Sys.uptime()
335

336
Gets the current system uptime in seconds.
337
"""
338
function uptime()
339
    uptime_ = Ref{Float64}()
3✔
340
    err = ccall(:uv_uptime, Int32, (Ptr{Float64},), uptime_)
3✔
341
    Base.uv_error("uv_uptime", err)
3✔
342
    return uptime_[]
3✔
343
end
344

345
"""
346
    Sys.loadavg()
347

348
Get the load average. See: https://en.wikipedia.org/wiki/Load_(computing).
349
"""
350
function loadavg()
351
    loadavg_ = Vector{Float64}(undef, 3)
1✔
352
    ccall(:uv_loadavg, Cvoid, (Ptr{Float64},), loadavg_)
1✔
353
    return loadavg_
×
354
end
355

356
"""
357
    Sys.free_physical_memory()
358

359
Get the free memory of the system in bytes. The entire amount may not be available to the
360
current process; use `Sys.free_memory()` for the actually available amount.
361
"""
362
free_physical_memory() = ccall(:uv_get_free_memory, UInt64, ())
×
363

364
"""
365
    Sys.total_physical_memory()
366

367
Get the total memory in RAM (including that which is currently used) in bytes. The entire
368
amount may not be available to the current process; see `Sys.total_memory()`.
369
"""
370
total_physical_memory() = ccall(:uv_get_total_memory, UInt64, ())
133✔
371

372
"""
373
    Sys.free_memory()
374

375
Get the total free memory in RAM in bytes.
376
"""
377
free_memory() = ccall(:uv_get_available_memory, UInt64, ())
2✔
378

379
"""
380
    Sys.total_memory()
381

382
Get the total memory in RAM (including that which is currently used) in bytes.
383
This amount may be constrained, e.g., by Linux control groups. For the unconstrained
384
amount, see `Sys.total_physical_memory()`.
385
"""
386
function total_memory()
387
    constrained = ccall(:uv_get_constrained_memory, UInt64, ())
133✔
388
    physical = total_physical_memory()
133✔
389
    if 0 < constrained <= physical
133✔
390
        return constrained
×
391
    else
392
        return physical
133✔
393
    end
394
end
395

396
"""
397
    Sys.get_process_title()
398

399
Get the process title. On some systems, will always return an empty string.
400
"""
401
function get_process_title()
×
402
    buf = Vector{UInt8}(undef, 512)
×
403
    err = ccall(:uv_get_process_title, Cint, (Ptr{UInt8}, Cint), buf, 512)
×
404
    Base.uv_error("get_process_title", err)
×
405
    return unsafe_string(pointer(buf))
×
406
end
407

408
"""
409
    Sys.set_process_title(title::AbstractString)
410

411
Set the process title. No-op on some operating systems.
412
"""
413
function set_process_title(title::AbstractString)
1✔
414
    err = ccall(:uv_set_process_title, Cint, (Cstring,), title)
1✔
415
    Base.uv_error("set_process_title", err)
×
416
end
417

418
"""
419
    Sys.maxrss()
420

421
Get the maximum resident set size utilized in bytes.
422
See also:
423
    - man page of `getrusage`(2) on Linux and BSD.
424
    - Windows API `GetProcessMemoryInfo`.
425
"""
426
maxrss() = ccall(:jl_maxrss, Csize_t, ())
207✔
427

428
"""
429
    Sys.isunix([os])
430

431
Predicate for testing if the OS provides a Unix-like interface.
432
See documentation in [Handling Operating System Variation](@ref).
433
"""
434
function isunix(os::Symbol)
×
435
    if iswindows(os)
×
436
        return false
×
437
    elseif islinux(os) || isbsd(os)
×
438
        return true
×
439
    elseif os === :Emscripten
×
440
        # Emscripten implements the POSIX ABI and provides traditional
441
        # Unix-style operating system functions such as file system support.
442
        # Therefore, we consider it a unix, even though this need not be
443
        # generally true for a jsvm embedding.
444
        return true
×
445
    else
446
        throw(ArgumentError("unknown operating system \"$os\""))
×
447
    end
448
end
449

450
"""
451
    Sys.islinux([os])
452

453
Predicate for testing if the OS is a derivative of Linux.
454
See documentation in [Handling Operating System Variation](@ref).
455
"""
456
islinux(os::Symbol) = (os === :Linux)
×
457

458
"""
459
    Sys.isbsd([os])
460

461
Predicate for testing if the OS is a derivative of BSD.
462
See documentation in [Handling Operating System Variation](@ref).
463

464
!!! note
465
    The Darwin kernel descends from BSD, which means that `Sys.isbsd()` is
466
    `true` on macOS systems. To exclude macOS from a predicate, use
467
    `Sys.isbsd() && !Sys.isapple()`.
468
"""
469
isbsd(os::Symbol) = (isfreebsd(os) || isopenbsd(os) || isnetbsd(os) || isdragonfly(os) || isapple(os))
×
470

471
"""
472
    Sys.isfreebsd([os])
473

474
Predicate for testing if the OS is a derivative of FreeBSD.
475
See documentation in [Handling Operating System Variation](@ref).
476

477
!!! note
478
    Not to be confused with `Sys.isbsd()`, which is `true` on FreeBSD but also on
479
    other BSD-based systems. `Sys.isfreebsd()` refers only to FreeBSD.
480
!!! compat "Julia 1.1"
481
    This function requires at least Julia 1.1.
482
"""
483
isfreebsd(os::Symbol) = (os === :FreeBSD)
×
484

485
"""
486
    Sys.isopenbsd([os])
487

488
Predicate for testing if the OS is a derivative of OpenBSD.
489
See documentation in [Handling Operating System Variation](@ref).
490

491
!!! note
492
    Not to be confused with `Sys.isbsd()`, which is `true` on OpenBSD but also on
493
    other BSD-based systems. `Sys.isopenbsd()` refers only to OpenBSD.
494
!!! compat "Julia 1.1"
495
    This function requires at least Julia 1.1.
496
"""
497
isopenbsd(os::Symbol) = (os === :OpenBSD)
×
498

499
"""
500
    Sys.isnetbsd([os])
501

502
Predicate for testing if the OS is a derivative of NetBSD.
503
See documentation in [Handling Operating System Variation](@ref).
504

505
!!! note
506
    Not to be confused with `Sys.isbsd()`, which is `true` on NetBSD but also on
507
    other BSD-based systems. `Sys.isnetbsd()` refers only to NetBSD.
508
!!! compat "Julia 1.1"
509
    This function requires at least Julia 1.1.
510
"""
511
isnetbsd(os::Symbol) = (os === :NetBSD)
×
512

513
"""
514
    Sys.isdragonfly([os])
515

516
Predicate for testing if the OS is a derivative of DragonFly BSD.
517
See documentation in [Handling Operating System Variation](@ref).
518

519
!!! note
520
    Not to be confused with `Sys.isbsd()`, which is `true` on DragonFly but also on
521
    other BSD-based systems. `Sys.isdragonfly()` refers only to DragonFly.
522
!!! compat "Julia 1.1"
523
    This function requires at least Julia 1.1.
524
"""
525
isdragonfly(os::Symbol) = (os === :DragonFly)
×
526

527
"""
528
    Sys.iswindows([os])
529

530
Predicate for testing if the OS is a derivative of Microsoft Windows NT.
531
See documentation in [Handling Operating System Variation](@ref).
532
"""
533
iswindows(os::Symbol) = (os === :Windows || os === :NT)
×
534

535
"""
536
    Sys.isapple([os])
537

538
Predicate for testing if the OS is a derivative of Apple Macintosh OS X or Darwin.
539
See documentation in [Handling Operating System Variation](@ref).
540
"""
541
isapple(os::Symbol) = (os === :Apple || os === :Darwin)
×
542

543
"""
544
    Sys.isjsvm([os])
545

546
Predicate for testing if Julia is running in a JavaScript VM (JSVM),
547
including e.g. a WebAssembly JavaScript embedding in a web browser.
548

549
!!! compat "Julia 1.2"
550
    This function requires at least Julia 1.2.
551
"""
552
isjsvm(os::Symbol) = (os === :Emscripten)
×
553

554
"""
555
    Sys.detectwsl()
556

557
Runtime predicate for testing if Julia is running inside
558
Windows Subsystem for Linux (WSL).
559

560
!!! note
561
    Unlike `Sys.iswindows`, `Sys.islinux` etc., this is a runtime test, and thus
562
    cannot meaningfully be used in `@static if` constructs.
563

564
!!! compat "Julia 1.12"
565
    This function requires at least Julia 1.12.
566
"""
567
function detectwsl()
×
568
    # We use the same approach as canonical/snapd do to detect WSL
569
    islinux() && (
×
570
        isfile("/proc/sys/fs/binfmt_misc/WSLInterop")
571
        || isdir("/run/WSL")
572
    )
573
end
574

575
for f in (:isunix, :islinux, :isbsd, :isapple, :iswindows, :isfreebsd, :isopenbsd, :isnetbsd, :isdragonfly, :isjsvm)
576
    @eval $f() = $(getfield(@__MODULE__, f)(KERNEL))
×
577
end
578

579
if iswindows()
580
    function windows_version()
×
581
        verinfo = ccall(:GetVersion, UInt32, ())
×
582
        VersionNumber(verinfo & 0xFF, (verinfo >> 8) & 0xFF, verinfo >> 16)
×
583
    end
584
else
585
    windows_version() = v"0.0"
×
586
end
587

588
"""
589
    Sys.windows_version()
590

591
Return the version number for the Windows NT Kernel as a `VersionNumber`,
592
i.e. `v"major.minor.build"`, or `v"0.0.0"` if this is not running on Windows.
593
"""
594
windows_version
595

596
const WINDOWS_VISTA_VER = v"6.0"
597

598
const isexecutable = Base.isexecutable
599
const isreadable   = Base.isreadable
600
const iswritable   = Base.iswritable
601

602
"""
603
    Sys.which(program_name::String)
604

605
Given a program name, search the current `PATH` to find the first binary with
606
the proper executable permissions that can be run and return an absolute path
607
to it, or return `nothing` if no such program is available. If a path with
608
a directory in it is passed in for `program_name`, tests that exact path
609
for executable permissions only (with `.exe` and `.com` extensions added on
610
Windows platforms); no searching of `PATH` is performed.
611
"""
612
function which(program_name::String)
×
613
    if isempty(program_name)
×
614
       return nothing
×
615
    end
616
    # Build a list of program names that we're going to try
617
    program_names = String[]
×
618
    base_pname = basename(program_name)
×
619
    if iswindows()
×
620
        # If the file already has an extension, try that name first
621
        if !isempty(splitext(base_pname)[2])
×
622
            push!(program_names, base_pname)
×
623
        end
624

625
        # But also try appending .exe and .com`
626
        for pe in (".exe", ".com")
×
627
            push!(program_names, string(base_pname, pe))
×
628
        end
×
629
    else
630
        # On non-windows, we just always search for what we've been given
631
        push!(program_names, base_pname)
×
632
    end
633

634
    path_dirs = String[]
×
635
    program_dirname = dirname(program_name)
×
636
    # If we've been given a path that has a directory name in it, then we
637
    # check to see if that path exists.  Otherwise, we search the PATH.
638
    if isempty(program_dirname)
×
639
        # If we have been given just a program name (not a relative or absolute
640
        # path) then we should search `PATH` for it here:
641
        pathsep = iswindows() ? ';' : ':'
×
642
        path_dirs = map(abspath, eachsplit(get(ENV, "PATH", ""), pathsep))
×
643

644
        # On windows we always check the current directory as well
645
        if iswindows()
×
646
            pushfirst!(path_dirs, pwd())
×
647
        end
648
    else
649
        push!(path_dirs, abspath(program_dirname))
×
650
    end
651

652
    # Here we combine our directories with our program names, searching for the
653
    # first match among all combinations.
654
    for path_dir in path_dirs
×
655
        for pname in program_names
×
656
            program_path = joinpath(path_dir, pname)
×
657
            try
×
658
                # If we find something that matches our name and we can execute
659
                if isfile(program_path) && isexecutable(program_path)
×
660
                    return program_path
×
661
                end
662
            catch e
663
                # If we encounter a permission error, we skip this directory
664
                # and continue to the next directory in the PATH variable.
665
                if isa(e, Base.IOError) && e.code == Base.UV_EACCES
×
666
                    # Permission denied, continue searching
667
                    continue
×
668
                else
669
                    # Rethrow the exception if it's not a permission error
670
                    rethrow(e)
×
671
                end
672
            end
673
        end
×
674
    end
×
675

676
    # If we couldn't find anything, don't return anything
677
    nothing
×
678
end
679
which(program_name::AbstractString) = which(String(program_name))
×
680

681
"""
682
    Sys.username()::String
683

684
Return the username for the current user. If the username cannot be determined
685
or is empty, this function throws an error.
686

687
To retrieve a username that is overridable via an environment variable,
688
e.g., `USER`, consider using
689
```julia
690
user = get(Sys.username, ENV, "USER")
691
```
692

693
!!! compat "Julia 1.11"
694
    This function requires at least Julia 1.11.
695

696
See also [`homedir`](@ref).
697
"""
698
function username()
×
699
    pw = Libc.getpw()
×
700
    isempty(pw.username) && Base.uv_error("username", Base.UV_ENOENT)
×
701
    return pw.username
×
702
end
703

704
end # module Sys
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc