Compare commits
464 Commits
v0.22.1
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d464f8c89 | ||
|
|
456a8e3553 | ||
|
|
db94696cf0 | ||
|
|
72bb656b9e | ||
|
|
e092026eb8 | ||
|
|
e5f5749d67 | ||
|
|
6e4f8ea7e4 | ||
|
|
5e8eff24d2 | ||
|
|
36f1801eb8 | ||
|
|
e3deee57ba | ||
|
|
404deb99f4 | ||
|
|
f594bc7aea | ||
|
|
9ed948523a | ||
|
|
72d7c2d558 | ||
|
|
d4a7582955 | ||
|
|
42ac1f0cb2 | ||
|
|
4af61d432f | ||
|
|
52bdaa7bf5 | ||
|
|
96b42238c5 | ||
|
|
c7bd259739 | ||
|
|
0dfc360b1e | ||
|
|
5e578e2e4e | ||
|
|
93111d495b | ||
|
|
b1bbe240d7 | ||
|
|
bbb58ff4c6 | ||
|
|
7a710bee17 | ||
|
|
bc3903d0e0 | ||
|
|
61c8326180 | ||
|
|
c5caa4b838 | ||
|
|
ebdff73c8c | ||
|
|
f78beb71f7 | ||
|
|
74210c7f46 | ||
|
|
eff4451cdd | ||
|
|
8d0fc3e639 | ||
|
|
3736da3f89 | ||
|
|
221e464df3 | ||
|
|
bac5253169 | ||
|
|
fc2ee5cae8 | ||
|
|
e11f83f34b | ||
|
|
6e7fb9a308 | ||
|
|
b156a62a44 | ||
|
|
990e77c55f | ||
|
|
c2fb529819 | ||
|
|
337bf3b944 | ||
|
|
a49b2f4f16 | ||
|
|
ddcf1a4b2e | ||
|
|
82a932c078 | ||
|
|
0781615117 | ||
|
|
9151fc1653 | ||
|
|
3a83b21ce1 | ||
|
|
cfc042d901 | ||
|
|
211ad9e7d9 | ||
|
|
437b259829 | ||
|
|
f524bba869 | ||
|
|
2f31fb5f17 | ||
|
|
c3567cb199 | ||
|
|
ae4c1d11f7 | ||
|
|
cbab451c1a | ||
|
|
9cec17ca26 | ||
|
|
d9c5d91b6f | ||
|
|
6e194c6ffe | ||
|
|
8f0c28037b | ||
|
|
31aabcabf7 | ||
|
|
ca9531d205 | ||
|
|
794c5eb6a0 | ||
|
|
c6cc125e22 | ||
|
|
528c1ed9ba | ||
|
|
52cc603245 | ||
|
|
5e55af2dce | ||
|
|
24ee7c8928 | ||
|
|
605df09ae1 | ||
|
|
4aebef900c | ||
|
|
59c5bef165 | ||
|
|
a18adf74bf | ||
|
|
6426ab1b7e | ||
|
|
7d1de58378 | ||
|
|
82a54378d8 | ||
|
|
e6e8fada8b | ||
|
|
7b541ac322 | ||
|
|
b0a2ea3970 | ||
|
|
cb439a09dd | ||
|
|
f87ee334c2 | ||
|
|
e8f8cf8543 | ||
|
|
8c93fb747b | ||
|
|
1701e929bc | ||
|
|
1bb3e04263 | ||
|
|
e91ae19ec4 | ||
|
|
818ae08c61 | ||
|
|
15f32f2ca1 | ||
|
|
59aa62ea5c | ||
|
|
b4c292ddd0 | ||
|
|
a25655446a | ||
|
|
cf3d59bb2e | ||
|
|
f80287166e | ||
|
|
329dc40b98 | ||
|
|
8328c34a3e | ||
|
|
6c309d3bc9 | ||
|
|
24b49eee83 | ||
|
|
715fab340f | ||
|
|
8231e84d15 | ||
|
|
8dc91a7a5c | ||
|
|
4c195b1a06 | ||
|
|
c6fb6bf5f8 | ||
|
|
ed6161b80c | ||
|
|
93424e4565 | ||
|
|
ca00e42f1d | ||
|
|
357ee1c632 | ||
|
|
cb0a3eaade | ||
|
|
a20d34b8aa | ||
|
|
329910a620 | ||
|
|
c374d04b0d | ||
|
|
b68cf16c85 | ||
|
|
391c4cf099 | ||
|
|
8260599e98 | ||
|
|
3433c8b8a5 | ||
|
|
e53bc780e4 | ||
|
|
53346dbaa6 | ||
|
|
99994ea245 | ||
|
|
3ffe02a2fe | ||
|
|
9b77502360 | ||
|
|
96a97328cf | ||
|
|
1a400383c0 | ||
|
|
4f8ab19355 | ||
|
|
8919677faf | ||
|
|
858b185a0e | ||
|
|
bc738cea32 | ||
|
|
c2196f7d3a | ||
|
|
d45c27fdbd | ||
|
|
173084de19 | ||
|
|
fd2c5fa247 | ||
|
|
73e0e9bdff | ||
|
|
4442414d74 | ||
|
|
8dbf9005f0 | ||
|
|
0c3da1b498 | ||
|
|
278f5818b7 | ||
|
|
c2e85202c7 | ||
|
|
b021b12043 | ||
|
|
89a0c9f4b3 | ||
|
|
259629c300 | ||
|
|
1ce2baf7a2 | ||
|
|
4576a42a0f | ||
|
|
4fba351b92 | ||
|
|
706737245a | ||
|
|
0dbdf49075 | ||
|
|
641075539c | ||
|
|
9428d99991 | ||
|
|
f3cf2e94c4 | ||
|
|
85f13442d2 | ||
|
|
f478a65635 | ||
|
|
eca44600c5 | ||
|
|
d7a4652554 | ||
|
|
d85cdd1946 | ||
|
|
ce3aae1501 | ||
|
|
90c4f9d463 | ||
|
|
93ccd81d86 | ||
|
|
9c5a70ab6c | ||
|
|
5ef58144cb | ||
|
|
41ddbdfd90 | ||
|
|
66924c85a3 | ||
|
|
a4c3fc138c | ||
|
|
62ed2a07a7 | ||
|
|
e7aec9e872 | ||
|
|
b065c3e11e | ||
|
|
88b357c453 | ||
|
|
bb7299c04a | ||
|
|
7a5bddfd15 | ||
|
|
50fe769f82 | ||
|
|
29d39d1adf | ||
|
|
8dde7f3975 | ||
|
|
0cd038273e | ||
|
|
1f5bfe80ed | ||
|
|
4d2611ad8a | ||
|
|
21a97dad31 | ||
|
|
338a01ca6d | ||
|
|
392396ded4 | ||
|
|
a336e0edb7 | ||
|
|
9426fefa00 | ||
|
|
812192eef5 | ||
|
|
b8c8e80965 | ||
|
|
77fd5d8414 | ||
|
|
82050ed371 | ||
|
|
a7381a9413 | ||
|
|
b932783d4d | ||
|
|
0b51f25034 | ||
|
|
d6a182fb5d | ||
|
|
e8635adb21 | ||
|
|
f242e0fd0c | ||
|
|
67b5f6b838 | ||
|
|
9d16f17463 | ||
|
|
f44f5b0db0 | ||
|
|
39ace5fc45 | ||
|
|
0601d6a0c5 | ||
|
|
11869ff872 | ||
|
|
6753605807 | ||
|
|
918db85737 | ||
|
|
1184de8352 | ||
|
|
2470fde5d9 | ||
|
|
abfff43976 | ||
|
|
230687a501 | ||
|
|
5ff8908ff3 | ||
|
|
882e09e50b | ||
|
|
6753f4a7cb | ||
|
|
1dc63dbea6 | ||
|
|
b9dfae4722 | ||
|
|
70412612c7 | ||
|
|
cd741c368c | ||
|
|
16a7bef456 | ||
|
|
85f62728c6 | ||
|
|
092dc96e6c | ||
|
|
2bb20caa5f | ||
|
|
00bcf935e8 | ||
|
|
3751372396 | ||
|
|
e6afeca92f | ||
|
|
35b9307af6 | ||
|
|
567f728579 | ||
|
|
404c5c29a1 | ||
|
|
63712ba6c6 | ||
|
|
ef62d47dc7 | ||
|
|
a4594857fc | ||
|
|
e77572b753 | ||
|
|
8c84c5ff66 | ||
|
|
5d8beaf0ed | ||
|
|
ac405f3d79 | ||
|
|
2e30553310 | ||
|
|
85a61772d8 | ||
|
|
4007f8726d | ||
|
|
a097f7791b | ||
|
|
3d4d89b2c0 | ||
|
|
e461234865 | ||
|
|
2c1d5f9844 | ||
|
|
c4b682b983 | ||
|
|
de0b784d5a | ||
|
|
5f38afdfc7 | ||
|
|
ac67c6e34b | ||
|
|
72deb53832 | ||
|
|
7c87253fd8 | ||
|
|
1136aedd08 | ||
|
|
24e1b56268 | ||
|
|
eef6a79b35 | ||
|
|
556a36cbd7 | ||
|
|
8aa490d6b7 | ||
|
|
d9d085da10 | ||
|
|
d88d720577 | ||
|
|
1d670ae744 | ||
|
|
35ad6f52c1 | ||
|
|
b61bae7640 | ||
|
|
8b7abace8b | ||
|
|
5cf98d9564 | ||
|
|
973a961cb5 | ||
|
|
868d0cb957 | ||
|
|
497f3a3832 | ||
|
|
9843f41bce | ||
|
|
e54fefc2b7 | ||
|
|
90c0889533 | ||
|
|
6696e82ce7 | ||
|
|
dcc55d53db | ||
|
|
92000e81b8 | ||
|
|
125175ae25 | ||
|
|
f60e548a0d | ||
|
|
04dc16a6b1 | ||
|
|
27b90e38db | ||
|
|
7e5ce3ba48 | ||
|
|
f5f7cfdc8f | ||
|
|
3e1a562312 | ||
|
|
ce4d962faa | ||
|
|
b9816a97fc | ||
|
|
f7b9c30456 | ||
|
|
884620a38a | ||
|
|
7503a41773 | ||
|
|
9a5fc6b4a3 | ||
|
|
a31aeed167 | ||
|
|
71f542a951 | ||
|
|
322bd48788 | ||
|
|
b752fa59d4 | ||
|
|
d53e4cc426 | ||
|
|
ee4b7fa3a1 | ||
|
|
d6f02c86d9 | ||
|
|
62efde8e3c | ||
|
|
bda1d94d49 | ||
|
|
3f472039c5 | ||
|
|
912ef34206 | ||
|
|
9c88a48a73 | ||
|
|
4bf5cc9a9a | ||
|
|
08834e2b03 | ||
|
|
8020a111df | ||
|
|
86fb547f7c | ||
|
|
b9556c7c44 | ||
|
|
7bdb106b1b | ||
|
|
2b191cd7f4 | ||
|
|
774f0a4e60 | ||
|
|
faf11efa72 | ||
|
|
5a99142b41 | ||
|
|
a3aca0242a | ||
|
|
72f276fab3 | ||
|
|
21139945df | ||
|
|
900bd2f477 | ||
|
|
29d4a5af44 | ||
|
|
dd9b7ed6a7 | ||
|
|
09ff74be62 | ||
|
|
a94ebfea11 | ||
|
|
8f5fe1d123 | ||
|
|
d4fb58efa3 | ||
|
|
ce900346cc | ||
|
|
7cb64e465f | ||
|
|
eb70c9f5b9 | ||
|
|
a28405700e | ||
|
|
f8f4d94d7a | ||
|
|
32dfb522d6 | ||
|
|
c61c707aa5 | ||
|
|
60d10848c8 | ||
|
|
dcd6b530f9 | ||
|
|
419f0742a0 | ||
|
|
c99174798b | ||
|
|
8df2a4b511 | ||
|
|
c174cf6830 | ||
|
|
5eebd65366 | ||
|
|
625f5323c0 | ||
|
|
e05a32cead | ||
|
|
c69af5d1e5 | ||
|
|
1ac2ee8043 | ||
|
|
36af1c1c73 | ||
|
|
e2fa087002 | ||
|
|
df02bfbad2 | ||
|
|
fecb63843e | ||
|
|
b33e2d09d3 | ||
|
|
f8054aa21a | ||
|
|
8f3a2acc54 | ||
|
|
d1a20908b8 | ||
|
|
dd781f7368 | ||
|
|
9bcc43c4c1 | ||
|
|
77c83af17d | ||
|
|
574bd2db99 | ||
|
|
a76f37da96 | ||
|
|
9e75f3ec0a | ||
|
|
4d42d45897 | ||
|
|
a4b4bfda73 | ||
|
|
1bcdd3a57e | ||
|
|
297a3a1bc9 | ||
|
|
8d01e8c978 | ||
|
|
6be28aa303 | ||
|
|
5e38310515 | ||
|
|
ddfed65485 | ||
|
|
2a16d8bfa8 | ||
|
|
6a40a50a29 | ||
|
|
b2924f68c0 | ||
|
|
41ffe36636 | ||
|
|
24edc72252 | ||
|
|
83b38a26a0 | ||
|
|
914d785e3b | ||
|
|
f99f642fa8 | ||
|
|
e0bf3667e3 | ||
|
|
a24ca50fed | ||
|
|
51e9f37252 | ||
|
|
453900c884 | ||
|
|
4696459d2d | ||
|
|
ad1e3231e5 | ||
|
|
2ef7eb1826 | ||
|
|
fe86019f9a | ||
|
|
9dbb18219f | ||
|
|
451a977de0 | ||
|
|
e604929a4c | ||
|
|
9d591f9f7c | ||
|
|
f8ad915100 | ||
|
|
cbbabe6920 | ||
|
|
81fe460194 | ||
|
|
b894f996c0 | ||
|
|
1ce09847d9 | ||
|
|
722d401394 | ||
|
|
e6f04d5ef9 | ||
|
|
b8e3ecbf00 | ||
|
|
d189387c24 | ||
|
|
9e96ddc5ae | ||
|
|
543bd189af | ||
|
|
43291aa723 | ||
|
|
d0589285f7 | ||
|
|
d079aaa083 | ||
|
|
6c65977e0d | ||
|
|
1b5d786cf5 | ||
|
|
4cf00645bd | ||
|
|
e9149cfc3c | ||
|
|
a5c8111076 | ||
|
|
c3576f712d | ||
|
|
410e6a59b7 | ||
|
|
bd2b2fb75a | ||
|
|
7ae318efd0 | ||
|
|
73e9d56647 | ||
|
|
f87a752b63 | ||
|
|
ae2fec30c3 | ||
|
|
1af5564cbe | ||
|
|
a8f057a701 | ||
|
|
7f3dd38ccc | ||
|
|
8e9adefcd5 | ||
|
|
d276f9700f | ||
|
|
4f111659ec | ||
|
|
eaf330f2a8 | ||
|
|
cdaeb74dc7 | ||
|
|
fbaac46604 | ||
|
|
7f6210ee90 | ||
|
|
63f6e6079a | ||
|
|
d4fd6caae0 | ||
|
|
fd3c18b6fd | ||
|
|
725f427f25 | ||
|
|
32b3e91ef7 | ||
|
|
b7e4602268 | ||
|
|
4a98d4db93 | ||
|
|
9d6bf373be | ||
|
|
cff35c4987 | ||
|
|
d594f84b8f | ||
|
|
f8f01c336c | ||
|
|
12e3665df3 | ||
|
|
fa4778b9fc | ||
|
|
66d297d420 | ||
|
|
56251c11f3 | ||
|
|
40bf9a179b | ||
|
|
095aba0b9f | ||
|
|
4270136598 | ||
|
|
f73d7d2dce | ||
|
|
567566da08 | ||
|
|
30a9ab749d | ||
|
|
8160a96b27 | ||
|
|
10414d3e6c | ||
|
|
1d96c09094 | ||
|
|
e7112fbc6a | ||
|
|
b79761b7eb | ||
|
|
3381899c69 | ||
|
|
c7cf5eabc1 | ||
|
|
d88fa5cf8e | ||
|
|
2ed0e3d737 | ||
|
|
506a40cac1 | ||
|
|
447739fcef | ||
|
|
e60f6f4a6e | ||
|
|
7df35d0da0 | ||
|
|
71b035ece1 | ||
|
|
86a134235e | ||
|
|
24cd0da7fb | ||
|
|
762833a663 | ||
|
|
636d479e5f | ||
|
|
f2184f26fa | ||
|
|
e1686eef7c | ||
|
|
314893982e | ||
|
|
9ab6c30a3d | ||
|
|
ddf94291d4 | ||
|
|
5d1038c512 | ||
|
|
2e40c88d50 | ||
|
|
2bcba57757 | ||
|
|
37330e5e2b | ||
|
|
b4411cf2db | ||
|
|
65d1ae083c | ||
|
|
0b8faa3918 | ||
|
|
f077c7e33b | ||
|
|
9d7410d22e | ||
|
|
e295730d0e | ||
|
|
868327ee14 | ||
|
|
f5430b16bc | ||
|
|
2446695113 | ||
|
|
e0c6cca65c | ||
|
|
84ed4cd331 | ||
|
|
f6d50f790e | ||
|
|
d3c3d23d1e | ||
|
|
33752c2b55 | ||
|
|
26759249ca | ||
|
|
8b4cbbe7b3 | ||
|
|
be71f9fdc4 | ||
|
|
05c1e7ecc2 |
4
.github/workflows/audit.yaml
vendored
4
.github/workflows/audit.yaml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
run:
|
||||
shell: ${{ matrix.system.shell }}
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
|
||||
with:
|
||||
python-version: ${{inputs.python_version}}
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
./share/spack/qa/validate_last_exit.ps1
|
||||
spack -d audit externals
|
||||
./share/spack/qa/validate_last_exit.ps1
|
||||
- uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be
|
||||
- uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673
|
||||
if: ${{ inputs.with_coverage == 'true' }}
|
||||
with:
|
||||
flags: unittests,audits
|
||||
|
||||
16
.github/workflows/bootstrap.yml
vendored
16
.github/workflows/bootstrap.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
make patch unzip which xz python3 python3-devel tree \
|
||||
cmake bison
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Bootstrap clingo
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
run: |
|
||||
brew install cmake bison tree
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
|
||||
@@ -84,15 +84,13 @@ jobs:
|
||||
- name: Setup macOS
|
||||
if: ${{ matrix.runner != 'ubuntu-latest' }}
|
||||
run: |
|
||||
brew install tree
|
||||
# Remove GnuPG since we want to bootstrap it
|
||||
sudo rm -rf /usr/local/bin/gpg
|
||||
brew install tree gawk
|
||||
sudo rm -rf $(command -v gpg gpg2)
|
||||
- name: Setup Ubuntu
|
||||
if: ${{ matrix.runner == 'ubuntu-latest' }}
|
||||
run: |
|
||||
sudo rm -rf $(which gpg) $(which gpg2) $(which patchelf)
|
||||
run: sudo rm -rf $(command -v gpg gpg2 patchelf)
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Bootstrap GnuPG
|
||||
@@ -121,7 +119,7 @@ jobs:
|
||||
run: |
|
||||
sudo rm -rf $(which gpg) $(which gpg2) $(which patchelf)
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
|
||||
|
||||
2
.github/workflows/build-containers.yml
vendored
2
.github/workflows/build-containers.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
||||
if: github.repository == 'spack/spack'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
|
||||
- uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81
|
||||
id: docker_meta
|
||||
|
||||
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
core: ${{ steps.filter.outputs.core }}
|
||||
packages: ${{ steps.filter.outputs.packages }}
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
2
.github/workflows/nightly-win-builds.yml
vendored
2
.github/workflows/nightly-win-builds.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
build-paraview-deps:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
|
||||
|
||||
2
.github/workflows/style/requirements.txt
vendored
2
.github/workflows/style/requirements.txt
vendored
@@ -3,5 +3,5 @@ clingo==5.7.1
|
||||
flake8==7.0.0
|
||||
isort==5.13.2
|
||||
mypy==1.8.0
|
||||
types-six==1.16.21.9
|
||||
types-six==1.16.21.20240513
|
||||
vermin==1.6.0
|
||||
|
||||
20
.github/workflows/unit_tests.yaml
vendored
20
.github/workflows/unit_tests.yaml
vendored
@@ -51,7 +51,7 @@ jobs:
|
||||
on_develop: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
UNIT_TEST_COVERAGE: ${{ matrix.python-version == '3.11' }}
|
||||
run: |
|
||||
share/spack/qa/run-unit-tests
|
||||
- uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be
|
||||
- uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673
|
||||
with:
|
||||
flags: unittests,linux,${{ matrix.concretizer }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
shell:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
COVERAGE: true
|
||||
run: |
|
||||
share/spack/qa/run-shell-tests
|
||||
- uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be
|
||||
- uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673
|
||||
with:
|
||||
flags: shelltests,linux
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@@ -141,7 +141,7 @@ jobs:
|
||||
dnf install -y \
|
||||
bzip2 curl file gcc-c++ gcc gcc-gfortran git gnupg2 gzip \
|
||||
make patch tcl unzip which xz
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
- name: Setup repo and non-root user
|
||||
run: |
|
||||
git --version
|
||||
@@ -160,7 +160,7 @@ jobs:
|
||||
clingo-cffi:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
|
||||
@@ -185,7 +185,7 @@ jobs:
|
||||
SPACK_TEST_SOLVER: clingo
|
||||
run: |
|
||||
share/spack/qa/run-unit-tests
|
||||
- uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be
|
||||
- uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673
|
||||
with:
|
||||
flags: unittests,linux,clingo
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@@ -198,7 +198,7 @@ jobs:
|
||||
os: [macos-13, macos-14]
|
||||
python-version: ["3.11"]
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
|
||||
@@ -223,7 +223,7 @@ jobs:
|
||||
$(which spack) solve zlib
|
||||
common_args=(--dist loadfile --tx '4*popen//python=./bin/spack-tmpconfig python -u ./bin/spack python' -x)
|
||||
$(which spack) unit-test --verbose --cov --cov-config=pyproject.toml --cov-report=xml:coverage.xml "${common_args[@]}"
|
||||
- uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be
|
||||
- uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673
|
||||
with:
|
||||
flags: unittests,macos
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@@ -254,7 +254,7 @@ jobs:
|
||||
./share/spack/qa/validate_last_exit.ps1
|
||||
coverage combine -a
|
||||
coverage xml
|
||||
- uses: codecov/codecov-action@125fc84a9a348dbcf27191600683ec096ec9021c
|
||||
- uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673
|
||||
with:
|
||||
flags: unittests,windows
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
6
.github/workflows/valid-style.yml
vendored
6
.github/workflows/valid-style.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
|
||||
with:
|
||||
python-version: '3.11'
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
style:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
dnf install -y \
|
||||
bzip2 curl file gcc-c++ gcc gcc-gfortran git gnupg2 gzip \
|
||||
make patch tcl unzip which xz
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
|
||||
- name: Setup repo and non-root user
|
||||
run: |
|
||||
git --version
|
||||
|
||||
360
CHANGELOG.md
360
CHANGELOG.md
@@ -1,361 +1,3 @@
|
||||
# v0.22.1 (2024-07-04)
|
||||
|
||||
## Bugfixes
|
||||
- Fix reuse of externals on Linux (#44316)
|
||||
- Ensure parent gcc-runtime version >= child (#44834, #44870)
|
||||
- Ensure the latest gcc-runtime is rpath'ed when multiple exist among link deps (#44219)
|
||||
- Improve version detection of glibc (#44154)
|
||||
- Improve heuristics for solver (#44893, #44976, #45023)
|
||||
- Make strong preferences override reuse (#44373)
|
||||
- Reduce verbosity when C compiler is missing (#44182)
|
||||
- Make missing ccache executable an error when required (#44740)
|
||||
- Make every environment view containing `python` a `venv` (#44382)
|
||||
- Fix external detection for compilers with os but no target (#44156)
|
||||
- Fix version optimization for roots (#44272)
|
||||
- Handle common implementations of pagination of tags in OCI build caches (#43136)
|
||||
- Apply fetched patches to develop specs (#44950)
|
||||
- Avoid Windows wrappers for filesystem utilities on non-Windows (#44126)
|
||||
- Fix issue with long filenames in build caches on Windows (#43851)
|
||||
- Fix formatting issue in `spack audit` (#45045)
|
||||
- CI fixes (#44582, #43965, #43967, #44279, #44213)
|
||||
|
||||
## Package updates
|
||||
- protobuf: fix 3.4:3.21 patch checksum (#44443)
|
||||
- protobuf: update hash for patch needed when="@3.4:3.21" (#44210)
|
||||
- git: bump v2.39 to 2.45; deprecate unsafe versions (#44248)
|
||||
- gcc: use -rpath {rpath_dir} not -rpath={rpath dir} (#44315)
|
||||
- Remove mesa18 and libosmesa (#44264)
|
||||
- Enforce consistency of `gl` providers (#44307)
|
||||
- Require libiconv for iconv (#44335, #45026).
|
||||
Notice that glibc/musl also provide iconv, but are not guaranteed to be
|
||||
complete. Set `packages:iconv:require:[glibc]` to restore the old behavior.
|
||||
- py-matplotlib: qualify when to do a post install (#44191)
|
||||
- rust: fix v1.78.0 instructions (#44127)
|
||||
- suite-sparse: improve setting of the `libs` property (#44214)
|
||||
- netlib-lapack: provide blas and lapack together (#44981)
|
||||
|
||||
|
||||
# v0.22.0 (2024-05-12)
|
||||
|
||||
`v0.22.0` is a major feature release.
|
||||
|
||||
## Features in this release
|
||||
|
||||
1. **Compiler dependencies**
|
||||
|
||||
We are in the process of making compilers proper dependencies in Spack, and a number
|
||||
of changes in `v0.22` support that effort. You may notice nodes in your dependency
|
||||
graphs for compiler runtime libraries like `gcc-runtime` or `libgfortran`, and you
|
||||
may notice that Spack graphs now include `libc`. We've also begun moving compiler
|
||||
configuration from `compilers.yaml` to `packages.yaml` to make it consistent with
|
||||
other externals. We are trying to do this with the least disruption possible, so
|
||||
your existing `compilers.yaml` files should still work. We expect to be done with
|
||||
this transition by the `v0.23` release in November.
|
||||
|
||||
* #41104: Packages compiled with `%gcc` on Linux, macOS and FreeBSD now depend on a
|
||||
new package `gcc-runtime`, which contains a copy of the shared compiler runtime
|
||||
libraries. This enables gcc runtime libraries to be installed and relocated when
|
||||
using a build cache. When building minimal Spack-generated container images it is
|
||||
no longer necessary to install libgfortran, libgomp etc. using the system package
|
||||
manager.
|
||||
|
||||
* #42062: Packages compiled with `%oneapi` now depend on a new package
|
||||
`intel-oneapi-runtime`. This is similar to `gcc-runtime`, and the runtimes can
|
||||
provide virtuals and compilers can inject dependencies on virtuals into compiled
|
||||
packages. This allows us to model library soname compatibility and allows
|
||||
compilers like `%oneapi` to provide virtuals like `sycl` (which can also be
|
||||
provided by standalone libraries). Note that until we have an agreement in place
|
||||
with intel, Intel packages are marked `redistribute(source=False, binary=False)`
|
||||
and must be downloaded outside of Spack.
|
||||
|
||||
* #43272: changes to the optimization criteria of the solver improve the hit-rate of
|
||||
buildcaches by a fair amount. The solver more relaxed compatibility rules and will
|
||||
not try to strictly match compilers or targets of reused specs. Users can still
|
||||
enforce the previous strict behavior with `require:` sections in `packages.yaml`.
|
||||
Note that to enforce correct linking, Spack will *not* reuse old `%gcc` and
|
||||
`%oneapi` specs that do not have the runtime libraries as a dependency.
|
||||
|
||||
* #43539: Spack will reuse specs built with compilers that are *not* explicitly
|
||||
configured in `compilers.yaml`. Because we can now keep runtime libraries in build
|
||||
cache, we do not require you to also have a local configured compiler to *use* the
|
||||
runtime libraries. This improves reuse in buildcaches and avoids conflicts with OS
|
||||
updates that happen underneath Spack.
|
||||
|
||||
* #43190: binary compatibility on `linux` is now based on the `libc` version,
|
||||
instead of on the `os` tag. Spack builds now detect the host `libc` (`glibc` or
|
||||
`musl`) and add it as an implicit external node in the dependency graph. Binaries
|
||||
with a `libc` with the same name and a version less than or equal to that of the
|
||||
detected `libc` can be reused. This is only on `linux`, not `macos` or `Windows`.
|
||||
|
||||
* #43464: each package that can provide a compiler is now detectable using `spack
|
||||
external find`. External packages defining compiler paths are effectively used as
|
||||
compilers, and `spack external find -t compiler` can be used as a substitute for
|
||||
`spack compiler find`. More details on this transition are in
|
||||
[the docs](https://spack.readthedocs.io/en/latest/getting_started.html#manual-compiler-configuration)
|
||||
|
||||
2. **Improved `spack find` UI for Environments**
|
||||
|
||||
If you're working in an enviroment, you likely care about:
|
||||
|
||||
* What are the roots
|
||||
* Which ones are installed / not installed
|
||||
* What's been added that still needs to be concretized
|
||||
|
||||
We've tweaked `spack find` in environments to show this information much more
|
||||
clearly. Installation status is shown next to each root, so you can see what is
|
||||
installed. Roots are also shown in bold in the list of installed packages. There is
|
||||
also a new option for `spack find -r` / `--only-roots` that will only show env
|
||||
roots, if you don't want to look at all the installed specs.
|
||||
|
||||
More details in #42334.
|
||||
|
||||
3. **Improved command-line string quoting**
|
||||
|
||||
We are making some breaking changes to how Spack parses specs on the CLI in order to
|
||||
respect shell quoting instead of trying to fight it. If you (sadly) had to write
|
||||
something like this on the command line:
|
||||
|
||||
```
|
||||
spack install zlib cflags=\"-O2 -g\"
|
||||
```
|
||||
|
||||
That will now result in an error, but you can now write what you probably expected
|
||||
to work in the first place:
|
||||
|
||||
```
|
||||
spack install zlib cflags="-O2 -g"
|
||||
```
|
||||
|
||||
Quoted can also now include special characters, so you can supply flags like:
|
||||
|
||||
```
|
||||
spack intall zlib ldflags='-Wl,-rpath=$ORIGIN/_libs'
|
||||
```
|
||||
|
||||
To reduce ambiguity in parsing, we now require that you *not* put spaces around `=`
|
||||
and `==` when for flags or variants. This would not have broken before but will now
|
||||
result in an error:
|
||||
|
||||
```
|
||||
spack install zlib cflags = "-O2 -g"
|
||||
```
|
||||
|
||||
More details and discussion in #30634.
|
||||
|
||||
4. **Revert default `spack install` behavior to `--reuse`**
|
||||
|
||||
We changed the default concretizer behavior from `--reuse` to `--reuse-deps` in
|
||||
#30990 (in `v0.20`), which meant that *every* `spack install` invocation would
|
||||
attempt to build a new version of the requested package / any environment roots.
|
||||
While this is a common ask for *upgrading* and for *developer* workflows, we don't
|
||||
think it should be the default for a package manager.
|
||||
|
||||
We are going to try to stick to this policy:
|
||||
1. Prioritize reuse and build as little as possible by default.
|
||||
2. Only upgrade or install duplicates if they are explicitly asked for, or if there
|
||||
is a known security issue that necessitates an upgrade.
|
||||
|
||||
With the install command you now have three options:
|
||||
|
||||
* `--reuse` (default): reuse as many existing installations as possible.
|
||||
* `--reuse-deps` / `--fresh-roots`: upgrade (freshen) roots but reuse dependencies if possible.
|
||||
* `--fresh`: install fresh versions of requested packages (roots) and their dependencies.
|
||||
|
||||
We've also introduced `--fresh-roots` as an alias for `--reuse-deps` to make it more clear
|
||||
that it may give you fresh versions. More details in #41302 and #43988.
|
||||
|
||||
5. **More control over reused specs**
|
||||
|
||||
You can now control which packages to reuse and how. There is a new
|
||||
`concretizer:reuse` config option, which accepts the following properties:
|
||||
|
||||
- `roots`: `true` to reuse roots, `false` to reuse just dependencies
|
||||
- `exclude`: list of constraints used to select which specs *not* to reuse
|
||||
- `include`: list of constraints used to select which specs *to* reuse
|
||||
- `from`: list of sources for reused specs (some combination of `local`,
|
||||
`buildcache`, or `external`)
|
||||
|
||||
For example, to reuse only specs compiled with GCC, you could write:
|
||||
|
||||
```yaml
|
||||
concretizer:
|
||||
reuse:
|
||||
roots: true
|
||||
include:
|
||||
- "%gcc"
|
||||
```
|
||||
|
||||
Or, if `openmpi` must be used from externals, and it must be the only external used:
|
||||
|
||||
```yaml
|
||||
concretizer:
|
||||
reuse:
|
||||
roots: true
|
||||
from:
|
||||
- type: local
|
||||
exclude: ["openmpi"]
|
||||
- type: buildcache
|
||||
exclude: ["openmpi"]
|
||||
- type: external
|
||||
include: ["openmpi"]
|
||||
```
|
||||
|
||||
6. **New `redistribute()` directive**
|
||||
|
||||
Some packages can't be redistributed in source or binary form. We need an explicit
|
||||
way to say that in a package.
|
||||
|
||||
Now there is a `redistribute()` directive so that package authors can write:
|
||||
|
||||
```python
|
||||
class MyPackage(Package):
|
||||
redistribute(source=False, binary=False)
|
||||
```
|
||||
|
||||
Like other directives, this works with `when=`:
|
||||
|
||||
```python
|
||||
class MyPackage(Package):
|
||||
# 12.0 and higher are proprietary
|
||||
redistribute(source=False, binary=False, when="@12.0:")
|
||||
|
||||
# can't redistribute when we depend on some proprietary dependency
|
||||
redistribute(source=False, binary=False, when="^proprietary-dependency")
|
||||
```
|
||||
|
||||
More in #20185.
|
||||
|
||||
7. **New `conflict:` and `prefer:` syntax for package preferences**
|
||||
|
||||
Previously, you could express conflicts and preferences in `packages.yaml` through
|
||||
some contortions with `require:`:
|
||||
|
||||
```yaml
|
||||
packages:
|
||||
zlib-ng:
|
||||
require:
|
||||
- one_of: ["%clang", "@:"] # conflict on %clang
|
||||
- any_of: ["+shared", "@:"] # strong preference for +shared
|
||||
```
|
||||
|
||||
You can now use `require:` and `prefer:` for a much more readable configuration:
|
||||
|
||||
```yaml
|
||||
packages:
|
||||
zlib-ng:
|
||||
conflict:
|
||||
- "%clang"
|
||||
prefer:
|
||||
- "+shared"
|
||||
```
|
||||
|
||||
See [the documentation](https://spack.readthedocs.io/en/latest/packages_yaml.html#conflicts-and-strong-preferences)
|
||||
and #41832 for more details.
|
||||
|
||||
8. **`include_concrete` in environments**
|
||||
|
||||
You may want to build on the *concrete* contents of another environment without
|
||||
changing that environment. You can now include the concrete specs from another
|
||||
environment's `spack.lock` with `include_concrete`:
|
||||
|
||||
```yaml
|
||||
spack:
|
||||
specs: []
|
||||
concretizer:
|
||||
unify: true
|
||||
include_concrete:
|
||||
- /path/to/environment1
|
||||
- /path/to/environment2
|
||||
```
|
||||
|
||||
Now, when *this* environment is concretized, it will bring in the already concrete
|
||||
specs from `environment1` and `environment2`, and build on top of them without
|
||||
changing them. This is useful if you have phased deployments, where old deployments
|
||||
should not be modified but you want to use as many of them as possible. More details
|
||||
in #33768.
|
||||
|
||||
9. **`python-venv` isolation**
|
||||
|
||||
Spack has unique requirements for Python because it:
|
||||
1. installs every package in its own independent directory, and
|
||||
2. allows users to register *external* python installations.
|
||||
|
||||
External installations may contain their own installed packages that can interfere
|
||||
with Spack installations, and some distributions (Debian and Ubuntu) even change the
|
||||
`sysconfig` in ways that alter the installation layout of installed Python packages
|
||||
(e.g., with the addition of a `/local` prefix on Debian or Ubuntu). To isolate Spack
|
||||
from these and other issues, we now insert a small `python-venv` package in between
|
||||
`python` and packages that need to install Python code. This isolates Spack's build
|
||||
environment, isolates Spack from any issues with an external python, and resolves a
|
||||
large number of issues we've had with Python installations.
|
||||
|
||||
See #40773 for further details.
|
||||
|
||||
## New commands, options, and directives
|
||||
|
||||
* Allow packages to be pushed to build cache after install from source (#42423)
|
||||
* `spack develop`: stage build artifacts in same root as non-dev builds #41373
|
||||
* Don't delete `spack develop` build artifacts after install (#43424)
|
||||
* `spack find`: add options for local/upstream only (#42999)
|
||||
* `spack logs`: print log files for packages (either partially built or installed) (#42202)
|
||||
* `patch`: support reversing patches (#43040)
|
||||
* `develop`: Add -b/--build-directory option to set build_directory package attribute (#39606)
|
||||
* `spack list`: add `--namesapce` / `--repo` option (#41948)
|
||||
* directives: add `checked_by` field to `license()`, add some license checks
|
||||
* `spack gc`: add options for environments and build dependencies (#41731)
|
||||
* Add `--create` to `spack env activate` (#40896)
|
||||
|
||||
## Performance improvements
|
||||
|
||||
* environment.py: fix excessive re-reads (#43746)
|
||||
* ruamel yaml: fix quadratic complexity bug (#43745)
|
||||
* Refactor to improve `spec format` speed (#43712)
|
||||
* Do not acquire a write lock on the env post install if no views (#43505)
|
||||
* asp.py: fewer calls to `spec.copy()` (#43715)
|
||||
* spec.py: early return in `__str__`
|
||||
* avoid `jinja2` import at startup unless needed (#43237)
|
||||
|
||||
## Other new features of note
|
||||
|
||||
* `archspec`: update to `v0.2.4`: support for Windows, bugfixes for `neoverse-v1` and
|
||||
`neoverse-v2` detection.
|
||||
* `spack config get`/`blame`: with no args, show entire config
|
||||
* `spack env create <env>`: dir if dir-like (#44024)
|
||||
* ASP-based solver: update os compatibility for macOS (#43862)
|
||||
* Add handling of custom ssl certs in urllib ops (#42953)
|
||||
* Add ability to rename environments (#43296)
|
||||
* Add config option and compiler support to reuse across OS's (#42693)
|
||||
* Support for prereleases (#43140)
|
||||
* Only reuse externals when configured (#41707)
|
||||
* Environments: Add support for including views (#42250)
|
||||
|
||||
## Binary caches
|
||||
* Build cache: make signed/unsigned a mirror property (#41507)
|
||||
* tools stack
|
||||
|
||||
## Removals, deprecations, and syntax changes
|
||||
* remove `dpcpp` compiler and package (#43418)
|
||||
* spack load: remove --only argument (#42120)
|
||||
|
||||
## Notable Bugfixes
|
||||
* repo.py: drop deleted packages from provider cache (#43779)
|
||||
* Allow `+` in module file names (#41999)
|
||||
* `cmd/python`: use runpy to allow multiprocessing in scripts (#41789)
|
||||
* Show extension commands with spack -h (#41726)
|
||||
* Support environment variable expansion inside module projections (#42917)
|
||||
* Alert user to failed concretizations (#42655)
|
||||
* shell: fix zsh color formatting for PS1 in environments (#39497)
|
||||
* spack mirror create --all: include patches (#41579)
|
||||
|
||||
## Spack community stats
|
||||
|
||||
* 7,994 total packages; 525 since `v0.21.0`
|
||||
* 178 new Python packages, 5 new R packages
|
||||
* 358 people contributed to this release
|
||||
* 344 committers to packages
|
||||
* 45 committers to core
|
||||
|
||||
|
||||
# v0.21.2 (2024-03-01)
|
||||
|
||||
## Bugfixes
|
||||
@@ -385,7 +27,7 @@
|
||||
- spack graph: fix coloring with environments (#41240)
|
||||
- spack info: sort variants in --variants-by-name (#41389)
|
||||
- Spec.format: error on old style format strings (#41934)
|
||||
- ASP-based solver:
|
||||
- ASP-based solver:
|
||||
- fix infinite recursion when computing concretization errors (#41061)
|
||||
- don't error for type mismatch on preferences (#41138)
|
||||
- don't emit spurious debug output (#41218)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
Spack is a multi-platform package manager that builds and installs
|
||||
multiple versions and configurations of software. It works on Linux,
|
||||
macOS, and many supercomputers. Spack is non-destructive: installing a
|
||||
macOS, Windows, and many supercomputers. Spack is non-destructive: installing a
|
||||
new version of a package does not break existing installations, so many
|
||||
configurations of the same package can coexist.
|
||||
|
||||
|
||||
@@ -22,4 +22,4 @@
|
||||
#
|
||||
# This is compatible across platforms.
|
||||
#
|
||||
exec /usr/bin/env spack python "$@"
|
||||
exec spack python "$@"
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# -------------------------------------------------------------------------
|
||||
# This is the default configuration for Spack's module file generation.
|
||||
#
|
||||
# Settings here are versioned with Spack and are intended to provide
|
||||
# sensible defaults out of the box. Spack maintainers should edit this
|
||||
# file to keep it current.
|
||||
#
|
||||
# Users can override these settings by editing the following files.
|
||||
#
|
||||
# Per-spack-instance settings (overrides defaults):
|
||||
# $SPACK_ROOT/etc/spack/modules.yaml
|
||||
#
|
||||
# Per-user settings (overrides default and site settings):
|
||||
# ~/.spack/modules.yaml
|
||||
# -------------------------------------------------------------------------
|
||||
modules: {}
|
||||
@@ -1,3 +0,0 @@
|
||||
packages:
|
||||
iconv:
|
||||
require: [libiconv]
|
||||
@@ -1433,22 +1433,12 @@ the reserved keywords ``platform``, ``os`` and ``target``:
|
||||
$ spack install libelf os=ubuntu18.04
|
||||
$ spack install libelf target=broadwell
|
||||
|
||||
or together by using the reserved keyword ``arch``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack install libelf arch=cray-CNL10-haswell
|
||||
|
||||
Normally users don't have to bother specifying the architecture if they
|
||||
are installing software for their current host, as in that case the
|
||||
values will be detected automatically. If you need fine-grained control
|
||||
over which packages use which targets (or over *all* packages' default
|
||||
target), see :ref:`package-preferences`.
|
||||
|
||||
.. admonition:: Cray machines
|
||||
|
||||
The situation is a little bit different for Cray machines and a detailed
|
||||
explanation on how the architecture can be set on them can be found at :ref:`cray-support`
|
||||
|
||||
.. _support-for-microarchitectures:
|
||||
|
||||
|
||||
@@ -147,6 +147,15 @@ example, the ``bash`` shell is used to run the ``autogen.sh`` script.
|
||||
def autoreconf(self, spec, prefix):
|
||||
which("bash")("autogen.sh")
|
||||
|
||||
If the ``package.py`` has build instructions in a separate
|
||||
:ref:`builder class <multiple_build_systems>`, the signature for a phase changes slightly:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AutotoolsBuilder(AutotoolsBuilder):
|
||||
def autoreconf(self, pkg, spec, prefix):
|
||||
which("bash")("autogen.sh")
|
||||
|
||||
"""""""""""""""""""""""""""""""""""""""
|
||||
patching configure or Makefile.in files
|
||||
"""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
@@ -25,7 +25,7 @@ use Spack to build packages with the tools.
|
||||
The Spack Python class ``IntelOneapiPackage`` is a base class that is
|
||||
used by ``IntelOneapiCompilers``, ``IntelOneapiMkl``,
|
||||
``IntelOneapiTbb`` and other classes to implement the oneAPI
|
||||
packages. Search for ``oneAPI`` at `<packages.spack.io>`_ for the full
|
||||
packages. Search for ``oneAPI`` at `packages.spack.io <https://packages.spack.io>`_ for the full
|
||||
list of available oneAPI packages, or use::
|
||||
|
||||
spack list -d oneAPI
|
||||
|
||||
@@ -11,7 +11,8 @@ Chaining Spack Installations
|
||||
|
||||
You can point your Spack installation to another installation to use any
|
||||
packages that are installed there. To register the other Spack instance,
|
||||
you can add it as an entry to ``upstreams.yaml``:
|
||||
you can add it as an entry to ``upstreams.yaml`` at any of the
|
||||
:ref:`configuration-scopes`:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
@@ -22,7 +23,8 @@ you can add it as an entry to ``upstreams.yaml``:
|
||||
install_tree: /path/to/another/spack/opt/spack
|
||||
|
||||
``install_tree`` must point to the ``opt/spack`` directory inside of the
|
||||
Spack base directory.
|
||||
Spack base directory, or the location of the ``install_tree`` defined
|
||||
in :ref:`config.yaml <config-yaml>`.
|
||||
|
||||
Once the upstream Spack instance has been added, ``spack find`` will
|
||||
automatically check the upstream instance when querying installed packages,
|
||||
|
||||
@@ -1364,187 +1364,6 @@ This will write the private key to the file `dinosaur.priv`.
|
||||
or for help on an issue or the Spack slack.
|
||||
|
||||
|
||||
.. _cray-support:
|
||||
|
||||
-------------
|
||||
Spack on Cray
|
||||
-------------
|
||||
|
||||
Spack differs slightly when used on a Cray system. The architecture spec
|
||||
can differentiate between the front-end and back-end processor and operating system.
|
||||
For example, on Edison at NERSC, the back-end target processor
|
||||
is "Ivy Bridge", so you can specify to use the back-end this way:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack install zlib target=ivybridge
|
||||
|
||||
You can also use the operating system to build against the back-end:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack install zlib os=CNL10
|
||||
|
||||
Notice that the name includes both the operating system name and the major
|
||||
version number concatenated together.
|
||||
|
||||
Alternatively, if you want to build something for the front-end,
|
||||
you can specify the front-end target processor. The processor for a login node
|
||||
on Edison is "Sandy bridge" so we specify on the command line like so:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack install zlib target=sandybridge
|
||||
|
||||
And the front-end operating system is:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack install zlib os=SuSE11
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Cray compiler detection
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Spack can detect compilers using two methods. For the front-end, we treat
|
||||
everything the same. The difference lies in back-end compiler detection.
|
||||
Back-end compiler detection is made via the Tcl module avail command.
|
||||
Once it detects the compiler it writes the appropriate PrgEnv and compiler
|
||||
module name to compilers.yaml and sets the paths to each compiler with Cray\'s
|
||||
compiler wrapper names (i.e. cc, CC, ftn). During build time, Spack will load
|
||||
the correct PrgEnv and compiler module and will call appropriate wrapper.
|
||||
|
||||
The compilers.yaml config file will also differ. There is a
|
||||
modules section that is filled with the compiler's Programming Environment
|
||||
and module name. On other systems, this field is empty []:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- compiler:
|
||||
modules:
|
||||
- PrgEnv-intel
|
||||
- intel/15.0.109
|
||||
|
||||
As mentioned earlier, the compiler paths will look different on a Cray system.
|
||||
Since most compilers are invoked using cc, CC and ftn, the paths for each
|
||||
compiler are replaced with their respective Cray compiler wrapper names:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
cc: cc
|
||||
cxx: CC
|
||||
f77: ftn
|
||||
fc: ftn
|
||||
|
||||
As opposed to an explicit path to the compiler executable. This allows Spack
|
||||
to call the Cray compiler wrappers during build time.
|
||||
|
||||
For more on compiler configuration, check out :ref:`compiler-config`.
|
||||
|
||||
Spack sets the default Cray link type to dynamic, to better match other
|
||||
other platforms. Individual packages can enable static linking (which is the
|
||||
default outside of Spack on cray systems) using the ``-static`` flag.
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Setting defaults and using Cray modules
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you want to use default compilers for each PrgEnv and also be able
|
||||
to load cray external modules, you will need to set up a ``packages.yaml``.
|
||||
|
||||
Here's an example of an external configuration for cray modules:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
packages:
|
||||
mpich:
|
||||
externals:
|
||||
- spec: "mpich@7.3.1%gcc@5.2.0 arch=cray_xc-haswell-CNL10"
|
||||
modules:
|
||||
- cray-mpich
|
||||
- spec: "mpich@7.3.1%intel@16.0.0.109 arch=cray_xc-haswell-CNL10"
|
||||
modules:
|
||||
- cray-mpich
|
||||
all:
|
||||
providers:
|
||||
mpi: [mpich]
|
||||
|
||||
This tells Spack that for whatever package that depends on mpi, load the
|
||||
cray-mpich module into the environment. You can then be able to use whatever
|
||||
environment variables, libraries, etc, that are brought into the environment
|
||||
via module load.
|
||||
|
||||
.. note::
|
||||
|
||||
For Cray-provided packages, it is best to use ``modules:`` instead of ``prefix:``
|
||||
in ``packages.yaml``, because the Cray Programming Environment heavily relies on
|
||||
modules (e.g., loading the ``cray-mpich`` module adds MPI libraries to the
|
||||
compiler wrapper link line).
|
||||
|
||||
You can set the default compiler that Spack can use for each compiler type.
|
||||
If you want to use the Cray defaults, then set them under ``all:`` in packages.yaml.
|
||||
In the compiler field, set the compiler specs in your order of preference.
|
||||
Whenever you build with that compiler type, Spack will concretize to that version.
|
||||
|
||||
Here is an example of a full packages.yaml used at NERSC
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
packages:
|
||||
mpich:
|
||||
externals:
|
||||
- spec: "mpich@7.3.1%gcc@5.2.0 arch=cray_xc-CNL10-ivybridge"
|
||||
modules:
|
||||
- cray-mpich
|
||||
- spec: "mpich@7.3.1%intel@16.0.0.109 arch=cray_xc-SuSE11-ivybridge"
|
||||
modules:
|
||||
- cray-mpich
|
||||
buildable: False
|
||||
netcdf:
|
||||
externals:
|
||||
- spec: "netcdf@4.3.3.1%gcc@5.2.0 arch=cray_xc-CNL10-ivybridge"
|
||||
modules:
|
||||
- cray-netcdf
|
||||
- spec: "netcdf@4.3.3.1%intel@16.0.0.109 arch=cray_xc-CNL10-ivybridge"
|
||||
modules:
|
||||
- cray-netcdf
|
||||
buildable: False
|
||||
hdf5:
|
||||
externals:
|
||||
- spec: "hdf5@1.8.14%gcc@5.2.0 arch=cray_xc-CNL10-ivybridge"
|
||||
modules:
|
||||
- cray-hdf5
|
||||
- spec: "hdf5@1.8.14%intel@16.0.0.109 arch=cray_xc-CNL10-ivybridge"
|
||||
modules:
|
||||
- cray-hdf5
|
||||
buildable: False
|
||||
all:
|
||||
compiler: [gcc@5.2.0, intel@16.0.0.109]
|
||||
providers:
|
||||
mpi: [mpich]
|
||||
|
||||
Here we tell spack that whenever we want to build with gcc use version 5.2.0 or
|
||||
if we want to build with intel compilers, use version 16.0.0.109. We add a spec
|
||||
for each compiler type for each cray modules. This ensures that for each
|
||||
compiler on our system we can use that external module.
|
||||
|
||||
For more on external packages check out the section :ref:`sec-external-packages`.
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Using Linux containers on Cray machines
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Spack uses environment variables particular to the Cray programming
|
||||
environment to determine which systems are Cray platforms. These
|
||||
environment variables may be propagated into containers that are not
|
||||
using the Cray programming environment.
|
||||
|
||||
To ensure that Spack does not autodetect the Cray programming
|
||||
environment, unset the environment variable ``MODULEPATH``. This
|
||||
will cause Spack to treat a linux container on a Cray system as a base
|
||||
linux distro.
|
||||
|
||||
.. _windows_support:
|
||||
|
||||
----------------
|
||||
|
||||
@@ -476,9 +476,3 @@ implemented using Python's built-in `sys.path
|
||||
:py:mod:`spack.repo` module implements a custom `Python importer
|
||||
<https://docs.python.org/2/library/imp.html>`_.
|
||||
|
||||
.. warning::
|
||||
|
||||
The mechanism for extending packages is not yet extensively tested,
|
||||
and extending packages across repositories imposes inter-repo
|
||||
dependencies, which may be hard to manage. Use this feature at your
|
||||
own risk, but let us know if you have a use case for it.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
sphinx==7.2.6
|
||||
sphinxcontrib-programoutput==0.17
|
||||
sphinx_design==0.5.0
|
||||
sphinx_design==0.6.0
|
||||
sphinx-rtd-theme==2.0.0
|
||||
python-levenshtein==0.25.1
|
||||
docutils==0.20.1
|
||||
pygments==2.17.2
|
||||
pygments==2.18.0
|
||||
urllib3==2.2.1
|
||||
pytest==8.2.0
|
||||
pytest==8.2.2
|
||||
isort==5.13.2
|
||||
black==24.4.2
|
||||
flake8==7.0.0
|
||||
|
||||
@@ -766,7 +766,6 @@ def copy_tree(
|
||||
src: str,
|
||||
dest: str,
|
||||
symlinks: bool = True,
|
||||
allow_broken_symlinks: bool = sys.platform != "win32",
|
||||
ignore: Optional[Callable[[str], bool]] = None,
|
||||
_permissions: bool = False,
|
||||
):
|
||||
@@ -789,8 +788,6 @@ def copy_tree(
|
||||
src (str): the directory to copy
|
||||
dest (str): the destination directory
|
||||
symlinks (bool): whether or not to preserve symlinks
|
||||
allow_broken_symlinks (bool): whether or not to allow broken (dangling) symlinks,
|
||||
On Windows, setting this to True will raise an exception. Defaults to true on unix.
|
||||
ignore (typing.Callable): function indicating which files to ignore
|
||||
_permissions (bool): for internal use only
|
||||
|
||||
@@ -798,8 +795,6 @@ def copy_tree(
|
||||
IOError: if *src* does not match any files or directories
|
||||
ValueError: if *src* is a parent directory of *dest*
|
||||
"""
|
||||
if allow_broken_symlinks and sys.platform == "win32":
|
||||
raise llnl.util.symlink.SymlinkError("Cannot allow broken symlinks on Windows!")
|
||||
if _permissions:
|
||||
tty.debug("Installing {0} to {1}".format(src, dest))
|
||||
else:
|
||||
@@ -872,16 +867,14 @@ def escaped_path(path):
|
||||
copy_mode(s, d)
|
||||
|
||||
for target, d, s in links:
|
||||
symlink(target, d, allow_broken_symlinks=allow_broken_symlinks)
|
||||
symlink(target, d)
|
||||
if _permissions:
|
||||
set_install_permissions(d)
|
||||
copy_mode(s, d)
|
||||
|
||||
|
||||
@system_path_filter
|
||||
def install_tree(
|
||||
src, dest, symlinks=True, ignore=None, allow_broken_symlinks=sys.platform != "win32"
|
||||
):
|
||||
def install_tree(src, dest, symlinks=True, ignore=None):
|
||||
"""Recursively install an entire directory tree rooted at *src*.
|
||||
|
||||
Same as :py:func:`copy_tree` with the addition of setting proper
|
||||
@@ -892,21 +885,12 @@ def install_tree(
|
||||
dest (str): the destination directory
|
||||
symlinks (bool): whether or not to preserve symlinks
|
||||
ignore (typing.Callable): function indicating which files to ignore
|
||||
allow_broken_symlinks (bool): whether or not to allow broken (dangling) symlinks,
|
||||
On Windows, setting this to True will raise an exception.
|
||||
|
||||
Raises:
|
||||
IOError: if *src* does not match any files or directories
|
||||
ValueError: if *src* is a parent directory of *dest*
|
||||
"""
|
||||
copy_tree(
|
||||
src,
|
||||
dest,
|
||||
symlinks=symlinks,
|
||||
allow_broken_symlinks=allow_broken_symlinks,
|
||||
ignore=ignore,
|
||||
_permissions=True,
|
||||
)
|
||||
copy_tree(src, dest, symlinks=symlinks, ignore=ignore, _permissions=True)
|
||||
|
||||
|
||||
@system_path_filter
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from typing import Union
|
||||
|
||||
from llnl.util import lang, tty
|
||||
|
||||
@@ -16,92 +17,66 @@
|
||||
if sys.platform == "win32":
|
||||
from win32file import CreateHardLink
|
||||
|
||||
is_windows = sys.platform == "win32"
|
||||
|
||||
def _windows_symlink(
|
||||
src: str, dst: str, target_is_directory: bool = False, *, dir_fd: Union[int, None] = None
|
||||
):
|
||||
"""On Windows with System Administrator privileges this will be a normal symbolic link via
|
||||
os.symlink. On Windows without privledges the link will be a junction for a directory and a
|
||||
hardlink for a file. On Windows the various link types are:
|
||||
|
||||
def symlink(source_path: str, link_path: str, allow_broken_symlinks: bool = not is_windows):
|
||||
"""
|
||||
Create a link.
|
||||
Symbolic Link: A link to a file or directory on the same or different volume (drive letter) or
|
||||
even to a remote file or directory (using UNC in its path). Need System Administrator
|
||||
privileges to make these.
|
||||
|
||||
On non-Windows and Windows with System Administrator
|
||||
privleges this will be a normal symbolic link via
|
||||
os.symlink.
|
||||
Hard Link: A link to a file on the same volume (drive letter) only. Every file (file's data)
|
||||
has at least 1 hard link (file's name). But when this method creates a new hard link there will
|
||||
be 2. Deleting all hard links effectively deletes the file. Don't need System Administrator
|
||||
privileges.
|
||||
|
||||
On Windows without privledges the link will be a
|
||||
junction for a directory and a hardlink for a file.
|
||||
On Windows the various link types are:
|
||||
|
||||
Symbolic Link: A link to a file or directory on the
|
||||
same or different volume (drive letter) or even to
|
||||
a remote file or directory (using UNC in its path).
|
||||
Need System Administrator privileges to make these.
|
||||
|
||||
Hard Link: A link to a file on the same volume (drive
|
||||
letter) only. Every file (file's data) has at least 1
|
||||
hard link (file's name). But when this method creates
|
||||
a new hard link there will be 2. Deleting all hard
|
||||
links effectively deletes the file. Don't need System
|
||||
Administrator privileges.
|
||||
|
||||
Junction: A link to a directory on the same or different
|
||||
volume (drive letter) but not to a remote directory. Don't
|
||||
need System Administrator privileges.
|
||||
|
||||
Parameters:
|
||||
source_path (str): The real file or directory that the link points to.
|
||||
Must be absolute OR relative to the link.
|
||||
link_path (str): The path where the link will exist.
|
||||
allow_broken_symlinks (bool): On Linux or Mac, don't raise an exception if the source_path
|
||||
doesn't exist. This will still raise an exception on Windows.
|
||||
"""
|
||||
source_path = os.path.normpath(source_path)
|
||||
Junction: A link to a directory on the same or different volume (drive letter) but not to a
|
||||
remote directory. Don't need System Administrator privileges."""
|
||||
source_path = os.path.normpath(src)
|
||||
win_source_path = source_path
|
||||
link_path = os.path.normpath(link_path)
|
||||
link_path = os.path.normpath(dst)
|
||||
|
||||
# Never allow broken links on Windows.
|
||||
if sys.platform == "win32" and allow_broken_symlinks:
|
||||
raise ValueError("allow_broken_symlinks parameter cannot be True on Windows.")
|
||||
# Perform basic checks to make sure symlinking will succeed
|
||||
if os.path.lexists(link_path):
|
||||
raise AlreadyExistsError(f"Link path ({link_path}) already exists. Cannot create link.")
|
||||
|
||||
if not allow_broken_symlinks:
|
||||
# Perform basic checks to make sure symlinking will succeed
|
||||
if os.path.lexists(link_path):
|
||||
raise AlreadyExistsError(
|
||||
f"Link path ({link_path}) already exists. Cannot create link."
|
||||
if not os.path.exists(source_path):
|
||||
if os.path.isabs(source_path):
|
||||
# An absolute source path that does not exist will result in a broken link.
|
||||
raise SymlinkError(
|
||||
f"Source path ({source_path}) is absolute but does not exist. Resulting "
|
||||
f"link would be broken so not making link."
|
||||
)
|
||||
|
||||
if not os.path.exists(source_path):
|
||||
if os.path.isabs(source_path) and not allow_broken_symlinks:
|
||||
# An absolute source path that does not exist will result in a broken link.
|
||||
raise SymlinkError(
|
||||
f"Source path ({source_path}) is absolute but does not exist. Resulting "
|
||||
f"link would be broken so not making link."
|
||||
)
|
||||
else:
|
||||
# os.symlink can create a link when the given source path is relative to
|
||||
# the link path. Emulate this behavior and check to see if the source exists
|
||||
# relative to the link path ahead of link creation to prevent broken
|
||||
# links from being made.
|
||||
link_parent_dir = os.path.dirname(link_path)
|
||||
relative_path = os.path.join(link_parent_dir, source_path)
|
||||
if os.path.exists(relative_path):
|
||||
# In order to work on windows, the source path needs to be modified to be
|
||||
# relative because hardlink/junction dont resolve relative paths the same
|
||||
# way as os.symlink. This is ignored on other operating systems.
|
||||
win_source_path = relative_path
|
||||
else:
|
||||
# os.symlink can create a link when the given source path is relative to
|
||||
# the link path. Emulate this behavior and check to see if the source exists
|
||||
# relative to the link path ahead of link creation to prevent broken
|
||||
# links from being made.
|
||||
link_parent_dir = os.path.dirname(link_path)
|
||||
relative_path = os.path.join(link_parent_dir, source_path)
|
||||
if os.path.exists(relative_path):
|
||||
# In order to work on windows, the source path needs to be modified to be
|
||||
# relative because hardlink/junction dont resolve relative paths the same
|
||||
# way as os.symlink. This is ignored on other operating systems.
|
||||
win_source_path = relative_path
|
||||
elif not allow_broken_symlinks:
|
||||
raise SymlinkError(
|
||||
f"The source path ({source_path}) is not relative to the link path "
|
||||
f"({link_path}). Resulting link would be broken so not making link."
|
||||
)
|
||||
raise SymlinkError(
|
||||
f"The source path ({source_path}) is not relative to the link path "
|
||||
f"({link_path}). Resulting link would be broken so not making link."
|
||||
)
|
||||
|
||||
# Create the symlink
|
||||
if sys.platform == "win32" and not _windows_can_symlink():
|
||||
if not _windows_can_symlink():
|
||||
_windows_create_link(win_source_path, link_path)
|
||||
else:
|
||||
os.symlink(source_path, link_path, target_is_directory=os.path.isdir(source_path))
|
||||
|
||||
|
||||
def islink(path: str) -> bool:
|
||||
def _windows_islink(path: str) -> bool:
|
||||
"""Override os.islink to give correct answer for spack logic.
|
||||
|
||||
For Non-Windows: a link can be determined with the os.path.islink method.
|
||||
@@ -269,7 +244,7 @@ def _windows_create_hard_link(path: str, link: str):
|
||||
CreateHardLink(link, path)
|
||||
|
||||
|
||||
def readlink(path: str, *, dir_fd=None):
|
||||
def _windows_readlink(path: str, *, dir_fd=None):
|
||||
"""Spack utility to override of os.readlink method to work cross platform"""
|
||||
if _windows_is_hardlink(path):
|
||||
return _windows_read_hard_link(path)
|
||||
@@ -338,6 +313,16 @@ def resolve_link_target_relative_to_the_link(link):
|
||||
return os.path.join(link_dir, target)
|
||||
|
||||
|
||||
if sys.platform == "win32":
|
||||
symlink = _windows_symlink
|
||||
readlink = _windows_readlink
|
||||
islink = _windows_islink
|
||||
else:
|
||||
symlink = os.symlink
|
||||
readlink = os.readlink
|
||||
islink = os.path.islink
|
||||
|
||||
|
||||
class SymlinkError(RuntimeError):
|
||||
"""Exception class for errors raised while creating symlinks,
|
||||
junctions and hard links
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
#: PEP440 canonical <major>.<minor>.<micro>.<devN> string
|
||||
__version__ = "0.22.1"
|
||||
__version__ = "0.23.0.dev0"
|
||||
spack_version = __version__
|
||||
|
||||
|
||||
|
||||
@@ -421,6 +421,10 @@ def _check_patch_urls(pkgs, error_cls):
|
||||
r"^https?://(?:patch-diff\.)?github(?:usercontent)?\.com/"
|
||||
r".+/.+/(?:commit|pull)/[a-fA-F0-9]+\.(?:patch|diff)"
|
||||
)
|
||||
github_pull_commits_re = (
|
||||
r"^https?://(?:patch-diff\.)?github(?:usercontent)?\.com/"
|
||||
r".+/.+/pull/\d+/commits/[a-fA-F0-9]+\.(?:patch|diff)"
|
||||
)
|
||||
# Only .diff URLs have stable/full hashes:
|
||||
# https://forum.gitlab.com/t/patches-with-full-index/29313
|
||||
gitlab_patch_url_re = (
|
||||
@@ -436,14 +440,24 @@ def _check_patch_urls(pkgs, error_cls):
|
||||
if not isinstance(patch, spack.patch.UrlPatch):
|
||||
continue
|
||||
|
||||
if re.match(github_patch_url_re, patch.url):
|
||||
if re.match(github_pull_commits_re, patch.url):
|
||||
url = re.sub(r"/pull/\d+/commits/", r"/commit/", patch.url)
|
||||
url = re.sub(r"^(.*)(?<!full_index=1)$", r"\1?full_index=1", url)
|
||||
errors.append(
|
||||
error_cls(
|
||||
f"patch URL in package {pkg_cls.name} "
|
||||
+ "must not be a pull request commit; "
|
||||
+ f"instead use {url}",
|
||||
[patch.url],
|
||||
)
|
||||
)
|
||||
elif re.match(github_patch_url_re, patch.url):
|
||||
full_index_arg = "?full_index=1"
|
||||
if not patch.url.endswith(full_index_arg):
|
||||
errors.append(
|
||||
error_cls(
|
||||
"patch URL in package {0} must end with {1}".format(
|
||||
pkg_cls.name, full_index_arg
|
||||
),
|
||||
f"patch URL in package {pkg_cls.name} "
|
||||
+ f"must end with {full_index_arg}",
|
||||
[patch.url],
|
||||
)
|
||||
)
|
||||
@@ -451,9 +465,7 @@ def _check_patch_urls(pkgs, error_cls):
|
||||
if not patch.url.endswith(".diff"):
|
||||
errors.append(
|
||||
error_cls(
|
||||
"patch URL in package {0} must end with .diff".format(
|
||||
pkg_cls.name
|
||||
),
|
||||
f"patch URL in package {pkg_cls.name} must end with .diff",
|
||||
[patch.url],
|
||||
)
|
||||
)
|
||||
@@ -779,7 +791,7 @@ def check_virtual_with_variants(spec, msg):
|
||||
return
|
||||
error = error_cls(
|
||||
f"{pkg_name}: {msg}",
|
||||
[f"remove variants from '{spec}' in depends_on directive in {filename}"],
|
||||
f"remove variants from '{spec}' in depends_on directive in {filename}",
|
||||
)
|
||||
errors.append(error)
|
||||
|
||||
|
||||
@@ -213,15 +213,18 @@ def _root_spec(spec_str: str) -> str:
|
||||
Args:
|
||||
spec_str: spec to be bootstrapped. Must be without compiler and target.
|
||||
"""
|
||||
# Add a compiler requirement to the root spec.
|
||||
# Add a compiler and platform requirement to the root spec.
|
||||
platform = str(spack.platforms.host())
|
||||
|
||||
if platform == "darwin":
|
||||
spec_str += " %apple-clang"
|
||||
elif platform == "windows":
|
||||
spec_str += " %msvc"
|
||||
elif platform == "linux":
|
||||
spec_str += " %gcc"
|
||||
elif platform == "freebsd":
|
||||
spec_str += " %clang"
|
||||
|
||||
spec_str += f" platform={platform}"
|
||||
target = archspec.cpu.host().family
|
||||
spec_str += f" target={target}"
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@
|
||||
import spack.store
|
||||
import spack.subprocess_context
|
||||
import spack.user_environment
|
||||
import spack.util.executable
|
||||
import spack.util.path
|
||||
import spack.util.pattern
|
||||
from spack import traverse
|
||||
@@ -92,7 +91,7 @@
|
||||
)
|
||||
from spack.util.executable import Executable
|
||||
from spack.util.log_parse import make_log_context, parse_log_events
|
||||
from spack.util.module_cmd import load_module, module, path_from_modules
|
||||
from spack.util.module_cmd import load_module, path_from_modules
|
||||
|
||||
#
|
||||
# This can be set by the user to globally disable parallel builds.
|
||||
@@ -191,14 +190,6 @@ def __call__(self, *args, **kwargs):
|
||||
return super().__call__(*args, **kwargs)
|
||||
|
||||
|
||||
def _on_cray():
|
||||
host_platform = spack.platforms.host()
|
||||
host_os = host_platform.operating_system("default_os")
|
||||
on_cray = str(host_platform) == "cray"
|
||||
using_cnl = re.match(r"cnl\d+", str(host_os))
|
||||
return on_cray, using_cnl
|
||||
|
||||
|
||||
def clean_environment():
|
||||
# Stuff in here sanitizes the build environment to eliminate
|
||||
# anything the user has set that may interfere. We apply it immediately
|
||||
@@ -242,17 +233,6 @@ def clean_environment():
|
||||
if varname.endswith("_ROOT") and varname != "SPACK_ROOT":
|
||||
env.unset(varname)
|
||||
|
||||
# On Cray "cluster" systems, unset CRAY_LD_LIBRARY_PATH to avoid
|
||||
# interference with Spack dependencies.
|
||||
# CNL requires these variables to be set (or at least some of them,
|
||||
# depending on the CNL version).
|
||||
on_cray, using_cnl = _on_cray()
|
||||
if on_cray and not using_cnl:
|
||||
env.unset("CRAY_LD_LIBRARY_PATH")
|
||||
for varname in os.environ.keys():
|
||||
if "PKGCONF" in varname:
|
||||
env.unset(varname)
|
||||
|
||||
# Unset the following variables because they can affect installation of
|
||||
# Autotools and CMake packages.
|
||||
build_system_vars = [
|
||||
@@ -382,11 +362,7 @@ def set_compiler_environment_variables(pkg, env):
|
||||
_add_werror_handling(keep_werror, env)
|
||||
|
||||
# Set the target parameters that the compiler will add
|
||||
# Don't set on cray platform because the targeting module handles this
|
||||
if spec.satisfies("platform=cray"):
|
||||
isa_arg = ""
|
||||
else:
|
||||
isa_arg = spec.architecture.target.optimization_flags(compiler)
|
||||
isa_arg = spec.architecture.target.optimization_flags(compiler)
|
||||
env.set("SPACK_TARGET_ARGS", isa_arg)
|
||||
|
||||
# Trap spack-tracked compiler flags as appropriate.
|
||||
@@ -482,7 +458,10 @@ def set_wrapper_variables(pkg, env):
|
||||
|
||||
# Find ccache binary and hand it to build environment
|
||||
if spack.config.get("config:ccache"):
|
||||
env.set(SPACK_CCACHE_BINARY, spack.util.executable.which_string("ccache", required=True))
|
||||
ccache = Executable("ccache")
|
||||
if not ccache:
|
||||
raise RuntimeError("No ccache binary found in PATH")
|
||||
env.set(SPACK_CCACHE_BINARY, ccache)
|
||||
|
||||
# Gather information about various types of dependencies
|
||||
link_deps = set(pkg.spec.traverse(root=False, deptype=("link")))
|
||||
@@ -761,7 +740,9 @@ def get_rpaths(pkg):
|
||||
# Second module is our compiler mod name. We use that to get rpaths from
|
||||
# module show output.
|
||||
if pkg.compiler.modules and len(pkg.compiler.modules) > 1:
|
||||
rpaths.append(path_from_modules([pkg.compiler.modules[1]]))
|
||||
mod_rpath = path_from_modules([pkg.compiler.modules[1]])
|
||||
if mod_rpath:
|
||||
rpaths.append(mod_rpath)
|
||||
return list(dedupe(filter_system_paths(rpaths)))
|
||||
|
||||
|
||||
@@ -831,14 +812,6 @@ def setup_package(pkg, dirty, context: Context = Context.BUILD):
|
||||
for mod in pkg.compiler.modules:
|
||||
load_module(mod)
|
||||
|
||||
# kludge to handle cray mpich and libsci being automatically loaded by
|
||||
# PrgEnv modules on cray platform. Module unload does no damage when
|
||||
# unnecessary
|
||||
on_cray, _ = _on_cray()
|
||||
if on_cray and not dirty:
|
||||
for mod in ["cray-mpich", "cray-libsci"]:
|
||||
module("unload", mod)
|
||||
|
||||
if target and target.module_name:
|
||||
load_module(target.module_name)
|
||||
|
||||
|
||||
@@ -162,7 +162,9 @@ def initconfig_compiler_entries(self):
|
||||
ld_flags = " ".join(flags["ldflags"])
|
||||
ld_format_string = "CMAKE_{0}_LINKER_FLAGS"
|
||||
# CMake has separate linker arguments for types of builds.
|
||||
for ld_type in ["EXE", "MODULE", "SHARED", "STATIC"]:
|
||||
# 'ldflags' should not be used with CMAKE_STATIC_LINKER_FLAGS which
|
||||
# is used by the archiver, so don't include "STATIC" in this loop:
|
||||
for ld_type in ["EXE", "MODULE", "SHARED"]:
|
||||
ld_string = ld_format_string.format(ld_type)
|
||||
entries.append(cmake_cache_string(ld_string, ld_flags))
|
||||
|
||||
|
||||
@@ -110,9 +110,8 @@ def cuda_flags(arch_list):
|
||||
# From the NVIDIA install guide we know of conflicts for particular
|
||||
# platforms (linux, darwin), architectures (x86, powerpc) and compilers
|
||||
# (gcc, clang). We don't restrict %gcc and %clang conflicts to
|
||||
# platform=linux, since they should also apply to platform=cray, and may
|
||||
# apply to platform=darwin. We currently do not provide conflicts for
|
||||
# platform=darwin with %apple-clang.
|
||||
# platform=linux, since they may apply to platform=darwin. We currently
|
||||
# do not provide conflicts for platform=darwin with %apple-clang.
|
||||
|
||||
# Linux x86_64 compiler conflicts from here:
|
||||
# https://gist.github.com/ax3l/9489132
|
||||
@@ -137,11 +136,14 @@ def cuda_flags(arch_list):
|
||||
conflicts("%gcc@11.2:", when="+cuda ^cuda@:11.5")
|
||||
conflicts("%gcc@12:", when="+cuda ^cuda@:11.8")
|
||||
conflicts("%gcc@13:", when="+cuda ^cuda@:12.3")
|
||||
conflicts("%gcc@14:", when="+cuda ^cuda@:12.4")
|
||||
conflicts("%clang@12:", when="+cuda ^cuda@:11.4.0")
|
||||
conflicts("%clang@13:", when="+cuda ^cuda@:11.5")
|
||||
conflicts("%clang@14:", when="+cuda ^cuda@:11.7")
|
||||
conflicts("%clang@15:", when="+cuda ^cuda@:12.0")
|
||||
conflicts("%clang@16:", when="+cuda ^cuda@:12.3")
|
||||
conflicts("%clang@16:", when="+cuda ^cuda@:12.1")
|
||||
conflicts("%clang@17:", when="+cuda ^cuda@:12.3")
|
||||
conflicts("%clang@18:", when="+cuda ^cuda@:12.4")
|
||||
|
||||
# https://gist.github.com/ax3l/9489132#gistcomment-3860114
|
||||
conflicts("%gcc@10", when="+cuda ^cuda@:11.4.0")
|
||||
|
||||
@@ -846,6 +846,7 @@ def scalapack_libs(self):
|
||||
"^mpich@2:" in spec_root
|
||||
or "^cray-mpich" in spec_root
|
||||
or "^mvapich2" in spec_root
|
||||
or "^mvapich" in spec_root
|
||||
or "^intel-mpi" in spec_root
|
||||
or "^intel-oneapi-mpi" in spec_root
|
||||
or "^intel-parallel-studio" in spec_root
|
||||
@@ -936,32 +937,15 @@ def mpi_setup_dependent_build_environment(self, env, dependent_spec, compilers_o
|
||||
"I_MPI_ROOT": self.normalize_path("mpi"),
|
||||
}
|
||||
|
||||
# CAUTION - SIMILAR code in:
|
||||
# var/spack/repos/builtin/packages/mpich/package.py
|
||||
# var/spack/repos/builtin/packages/openmpi/package.py
|
||||
# var/spack/repos/builtin/packages/mvapich2/package.py
|
||||
#
|
||||
# On Cray, the regular compiler wrappers *are* the MPI wrappers.
|
||||
if "platform=cray" in self.spec:
|
||||
# TODO: Confirm
|
||||
wrapper_vars.update(
|
||||
{
|
||||
"MPICC": compilers_of_client["CC"],
|
||||
"MPICXX": compilers_of_client["CXX"],
|
||||
"MPIF77": compilers_of_client["F77"],
|
||||
"MPIF90": compilers_of_client["F90"],
|
||||
}
|
||||
)
|
||||
else:
|
||||
compiler_wrapper_commands = self.mpi_compiler_wrappers
|
||||
wrapper_vars.update(
|
||||
{
|
||||
"MPICC": compiler_wrapper_commands["MPICC"],
|
||||
"MPICXX": compiler_wrapper_commands["MPICXX"],
|
||||
"MPIF77": compiler_wrapper_commands["MPIF77"],
|
||||
"MPIF90": compiler_wrapper_commands["MPIF90"],
|
||||
}
|
||||
)
|
||||
compiler_wrapper_commands = self.mpi_compiler_wrappers
|
||||
wrapper_vars.update(
|
||||
{
|
||||
"MPICC": compiler_wrapper_commands["MPICC"],
|
||||
"MPICXX": compiler_wrapper_commands["MPICXX"],
|
||||
"MPIF77": compiler_wrapper_commands["MPIF77"],
|
||||
"MPIF90": compiler_wrapper_commands["MPIF90"],
|
||||
}
|
||||
)
|
||||
|
||||
# Ensure that the directory containing the compiler wrappers is in the
|
||||
# PATH. Spack packages add `prefix.bin` to their dependents' paths,
|
||||
|
||||
@@ -24,7 +24,6 @@ class MSBuildPackage(spack.package_base.PackageBase):
|
||||
build_system("msbuild")
|
||||
conflicts("platform=linux", when="build_system=msbuild")
|
||||
conflicts("platform=darwin", when="build_system=msbuild")
|
||||
conflicts("platform=cray", when="build_system=msbuild")
|
||||
|
||||
|
||||
@spack.builder.builder("msbuild")
|
||||
|
||||
@@ -24,7 +24,6 @@ class NMakePackage(spack.package_base.PackageBase):
|
||||
build_system("nmake")
|
||||
conflicts("platform=linux", when="build_system=nmake")
|
||||
conflicts("platform=darwin", when="build_system=nmake")
|
||||
conflicts("platform=cray", when="build_system=nmake")
|
||||
|
||||
|
||||
@spack.builder.builder("nmake")
|
||||
|
||||
@@ -36,9 +36,8 @@ class IntelOneApiPackage(Package):
|
||||
"target=ppc64:",
|
||||
"target=ppc64le:",
|
||||
"target=aarch64:",
|
||||
"platform=darwin:",
|
||||
"platform=cray:",
|
||||
"platform=windows:",
|
||||
"platform=darwin",
|
||||
"platform=windows",
|
||||
]:
|
||||
conflicts(c, msg="This package in only available for x86_64 and Linux")
|
||||
|
||||
|
||||
@@ -106,7 +106,8 @@ def clean(parser, args):
|
||||
|
||||
# Then do the cleaning falling through the cases
|
||||
if args.specs:
|
||||
specs = spack.cmd.parse_specs(args.specs, concretize=True)
|
||||
specs = spack.cmd.parse_specs(args.specs, concretize=False)
|
||||
specs = list(spack.cmd.matching_spec_from_env(x) for x in specs)
|
||||
for spec in specs:
|
||||
msg = "Cleaning build stage [{0}]"
|
||||
tty.msg(msg.format(spec.short_spec))
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.string import plural
|
||||
|
||||
import spack.cmd
|
||||
import spack.cmd.common.arguments
|
||||
import spack.environment as ev
|
||||
@@ -43,5 +46,9 @@ def concretize(parser, args):
|
||||
with env.write_transaction():
|
||||
concretized_specs = env.concretize(force=args.force, tests=tests)
|
||||
if not args.quiet:
|
||||
ev.display_specs(concretized_specs)
|
||||
if concretized_specs:
|
||||
tty.msg(f"Concretized {plural(len(concretized_specs), 'spec')}:")
|
||||
ev.display_specs([concrete for _, concrete in concretized_specs])
|
||||
else:
|
||||
tty.msg("No new specs to concretize.")
|
||||
env.write()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import errno
|
||||
import glob
|
||||
import os
|
||||
|
||||
@@ -11,43 +12,13 @@
|
||||
import spack.cmd
|
||||
import spack.paths
|
||||
import spack.repo
|
||||
from spack.spec import Spec
|
||||
from spack.util.editor import editor
|
||||
import spack.util.editor
|
||||
|
||||
description = "open package files in $EDITOR"
|
||||
section = "packaging"
|
||||
level = "short"
|
||||
|
||||
|
||||
def edit_package(name, repo_path, namespace):
|
||||
"""Opens the requested package file in your favorite $EDITOR.
|
||||
|
||||
Args:
|
||||
name (str): The name of the package
|
||||
repo_path (str): The path to the repository containing this package
|
||||
namespace (str): A valid namespace registered with Spack
|
||||
"""
|
||||
# Find the location of the package
|
||||
if repo_path:
|
||||
repo = spack.repo.Repo(repo_path)
|
||||
elif namespace:
|
||||
repo = spack.repo.PATH.get_repo(namespace)
|
||||
else:
|
||||
repo = spack.repo.PATH
|
||||
path = repo.filename_for_package_name(name)
|
||||
|
||||
spec = Spec(name)
|
||||
if os.path.exists(path):
|
||||
if not os.path.isfile(path):
|
||||
tty.die("Something is wrong. '{0}' is not a file!".format(path))
|
||||
if not os.access(path, os.R_OK):
|
||||
tty.die("Insufficient permissions on '%s'!" % path)
|
||||
else:
|
||||
raise spack.repo.UnknownPackageError(spec.name)
|
||||
|
||||
editor(path)
|
||||
|
||||
|
||||
def setup_parser(subparser):
|
||||
excl_args = subparser.add_mutually_exclusive_group()
|
||||
|
||||
@@ -98,41 +69,67 @@ def setup_parser(subparser):
|
||||
excl_args.add_argument("-r", "--repo", default=None, help="path to repo to edit package in")
|
||||
excl_args.add_argument("-N", "--namespace", default=None, help="namespace of package to edit")
|
||||
|
||||
subparser.add_argument("package", nargs="?", default=None, help="package name")
|
||||
subparser.add_argument("package", nargs="*", default=None, help="package name")
|
||||
|
||||
|
||||
def locate_package(name: str, repo: spack.repo.Repo) -> str:
|
||||
path = repo.filename_for_package_name(name)
|
||||
|
||||
try:
|
||||
with open(path, "r"):
|
||||
return path
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
raise spack.repo.UnknownPackageError(name) from e
|
||||
tty.die(f"Cannot edit package: {e}")
|
||||
|
||||
|
||||
def locate_file(name: str, path: str) -> str:
|
||||
# convert command names to python module name
|
||||
if path == spack.paths.command_path:
|
||||
name = spack.cmd.python_name(name)
|
||||
|
||||
file_path = os.path.join(path, name)
|
||||
|
||||
# Try to open direct match.
|
||||
try:
|
||||
with open(file_path, "r"):
|
||||
return file_path
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
tty.die(f"Cannot edit file: {e}")
|
||||
pass
|
||||
|
||||
# Otherwise try to find a file that starts with the name
|
||||
candidates = glob.glob(file_path + "*")
|
||||
exclude_list = [".pyc", "~"] # exclude binaries and backups
|
||||
files = [f for f in candidates if not any(f.endswith(ext) for ext in exclude_list)]
|
||||
if len(files) > 1:
|
||||
tty.die(
|
||||
f"Multiple files start with `{name}`:\n"
|
||||
+ "\n".join(f" {os.path.basename(f)}" for f in files)
|
||||
)
|
||||
elif not files:
|
||||
tty.die(f"No file for '{name}' was found in {path}")
|
||||
return files[0]
|
||||
|
||||
|
||||
def edit(parser, args):
|
||||
name = args.package
|
||||
|
||||
# By default, edit package files
|
||||
path = spack.paths.packages_path
|
||||
names = args.package
|
||||
|
||||
# If `--command`, `--test`, or `--module` is chosen, edit those instead
|
||||
if args.path:
|
||||
path = args.path
|
||||
if name:
|
||||
# convert command names to python module name
|
||||
if path == spack.paths.command_path:
|
||||
name = spack.cmd.python_name(name)
|
||||
|
||||
path = os.path.join(path, name)
|
||||
if not os.path.exists(path):
|
||||
files = glob.glob(path + "*")
|
||||
exclude_list = [".pyc", "~"] # exclude binaries and backups
|
||||
files = list(filter(lambda x: all(s not in x for s in exclude_list), files))
|
||||
if len(files) > 1:
|
||||
m = "Multiple files exist with the name {0}.".format(name)
|
||||
m += " Please specify a suffix. Files are:\n\n"
|
||||
for f in files:
|
||||
m += " " + os.path.basename(f) + "\n"
|
||||
tty.die(m)
|
||||
if not files:
|
||||
tty.die("No file for '{0}' was found in {1}".format(name, path))
|
||||
path = files[0] # already confirmed only one entry in files
|
||||
|
||||
editor(path)
|
||||
elif name:
|
||||
edit_package(name, args.repo, args.namespace)
|
||||
paths = [locate_file(name, args.path) for name in names] if names else [args.path]
|
||||
spack.util.editor.editor(*paths)
|
||||
elif names:
|
||||
if args.repo:
|
||||
repo = spack.repo.Repo(args.repo)
|
||||
elif args.namespace:
|
||||
repo = spack.repo.PATH.get_repo(args.namespace)
|
||||
else:
|
||||
repo = spack.repo.PATH
|
||||
paths = [locate_package(name, repo) for name in names]
|
||||
spack.util.editor.editor(*paths)
|
||||
else:
|
||||
# By default open the directory where packages live
|
||||
editor(path)
|
||||
spack.util.editor.editor(spack.paths.packages_path)
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
@B{++}, @r{--}, @r{~~}, @B{==} propagate variants to package dependencies
|
||||
|
||||
architecture variants:
|
||||
@m{platform=platform} linux, darwin, cray, etc.
|
||||
@m{platform=platform} linux, darwin, freebsd, windows
|
||||
@m{os=operating_system} specific <operating_system>
|
||||
@m{target=target} specific <target> processor
|
||||
@m{arch=platform-os-target} shortcut for all three above
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
from typing import List
|
||||
|
||||
import llnl.util.filesystem as fs
|
||||
from llnl.string import plural
|
||||
from llnl.util import lang, tty
|
||||
|
||||
import spack.build_environment
|
||||
@@ -61,7 +62,6 @@ def install_kwargs_from_args(args):
|
||||
"dependencies_use_cache": cache_opt(args.use_cache, dep_use_bc),
|
||||
"dependencies_cache_only": cache_opt(args.cache_only, dep_use_bc),
|
||||
"include_build_deps": args.include_build_deps,
|
||||
"explicit": True, # Use true as a default for install command
|
||||
"stop_at": args.until,
|
||||
"unsigned": args.unsigned,
|
||||
"install_deps": ("dependencies" in args.things_to_install),
|
||||
@@ -376,7 +376,9 @@ def _maybe_add_and_concretize(args, env, specs):
|
||||
# `spack concretize`
|
||||
tests = compute_tests_install_kwargs(env.user_specs, args.test)
|
||||
concretized_specs = env.concretize(tests=tests)
|
||||
ev.display_specs(concretized_specs)
|
||||
if concretized_specs:
|
||||
tty.msg(f"Concretized {plural(len(concretized_specs), 'spec')}")
|
||||
ev.display_specs([concrete for _, concrete in concretized_specs])
|
||||
|
||||
# save view regeneration for later, so that we only do it
|
||||
# once, as it can be slow.
|
||||
@@ -473,6 +475,7 @@ def install_without_active_env(args, install_kwargs, reporter_factory):
|
||||
require_user_confirmation_for_overwrite(concrete_specs, args)
|
||||
install_kwargs["overwrite"] = [spec.dag_hash() for spec in concrete_specs]
|
||||
|
||||
installs = [(s.package, install_kwargs) for s in concrete_specs]
|
||||
builder = PackageInstaller(installs)
|
||||
installs = [s.package for s in concrete_specs]
|
||||
install_kwargs["explicit"] = [s.dag_hash() for s in concrete_specs]
|
||||
builder = PackageInstaller(installs, install_kwargs)
|
||||
builder.install()
|
||||
|
||||
@@ -114,15 +114,16 @@ def _process_result(result, show, required_format, kwargs):
|
||||
|
||||
# dump the solutions as concretized specs
|
||||
if "solutions" in show:
|
||||
for spec in result.specs:
|
||||
# With -y, just print YAML to output.
|
||||
if required_format == "yaml":
|
||||
# use write because to_yaml already has a newline.
|
||||
sys.stdout.write(spec.to_yaml(hash=ht.dag_hash))
|
||||
elif required_format == "json":
|
||||
sys.stdout.write(spec.to_json(hash=ht.dag_hash))
|
||||
else:
|
||||
sys.stdout.write(spec.tree(color=sys.stdout.isatty(), **kwargs))
|
||||
if required_format:
|
||||
for spec in result.specs:
|
||||
# With -y, just print YAML to output.
|
||||
if required_format == "yaml":
|
||||
# use write because to_yaml already has a newline.
|
||||
sys.stdout.write(spec.to_yaml(hash=ht.dag_hash))
|
||||
elif required_format == "json":
|
||||
sys.stdout.write(spec.to_json(hash=ht.dag_hash))
|
||||
else:
|
||||
sys.stdout.write(spack.spec.tree(result.specs, color=sys.stdout.isatty(), **kwargs))
|
||||
print()
|
||||
|
||||
if result.unsolved_specs and "solutions" in show:
|
||||
|
||||
@@ -105,11 +105,19 @@ def spec(parser, args):
|
||||
if env:
|
||||
env.concretize()
|
||||
specs = env.concretized_specs()
|
||||
|
||||
# environments are printed together in a combined tree() invocation,
|
||||
# except when using --yaml or --json, which we print spec by spec below.
|
||||
if not args.format:
|
||||
tree_kwargs["key"] = spack.traverse.by_dag_hash
|
||||
tree_kwargs["hashes"] = args.long or args.very_long
|
||||
print(spack.spec.tree([concrete for _, concrete in specs], **tree_kwargs))
|
||||
return
|
||||
else:
|
||||
tty.die("spack spec requires at least one spec or an active environment")
|
||||
|
||||
for input, output in specs:
|
||||
# With -y, just print YAML to output.
|
||||
# With --yaml or --json, just print the raw specs to output
|
||||
if args.format:
|
||||
if args.format == "yaml":
|
||||
# use write because to_yaml already has a newline.
|
||||
|
||||
@@ -151,7 +151,8 @@ def is_installed(spec):
|
||||
key=lambda s: s.dag_hash(),
|
||||
)
|
||||
|
||||
return [spec for spec in specs if is_installed(spec)]
|
||||
with spack.store.STORE.db.read_transaction():
|
||||
return [spec for spec in specs if is_installed(spec)]
|
||||
|
||||
|
||||
def dependent_environments(
|
||||
@@ -239,6 +240,8 @@ def get_uninstall_list(args, specs: List[spack.spec.Spec], env: Optional[ev.Envi
|
||||
print()
|
||||
tty.info("The following environments still reference these specs:")
|
||||
colify([e.name for e in other_dependent_envs.keys()], indent=4)
|
||||
if env:
|
||||
msgs.append("use `spack remove` to remove the spec from the current environment")
|
||||
msgs.append("use `spack env remove` to remove environments")
|
||||
msgs.append("use `spack uninstall --force` to override")
|
||||
print()
|
||||
|
||||
@@ -695,10 +695,6 @@ def compiler_environment(self):
|
||||
try:
|
||||
# load modules and set env variables
|
||||
for module in self.modules:
|
||||
# On cray, mic-knl module cannot be loaded without cce module
|
||||
# See: https://github.com/spack/spack/issues/3153
|
||||
if os.environ.get("CRAY_CPU_TARGET") == "mic-knl":
|
||||
spack.util.module_cmd.load_module("cce")
|
||||
spack.util.module_cmd.load_module(module)
|
||||
|
||||
# apply other compiler environment changes
|
||||
|
||||
@@ -96,6 +96,8 @@ def verbose_flag(self):
|
||||
|
||||
openmp_flag = "-fopenmp"
|
||||
|
||||
# C++ flags based on CMake Modules/Compiler/Clang.cmake
|
||||
|
||||
@property
|
||||
def cxx11_flag(self):
|
||||
if self.real_version < Version("3.3"):
|
||||
@@ -120,6 +122,24 @@ def cxx17_flag(self):
|
||||
|
||||
return "-std=c++17"
|
||||
|
||||
@property
|
||||
def cxx20_flag(self):
|
||||
if self.real_version < Version("5.0"):
|
||||
raise UnsupportedCompilerFlag(self, "the C++20 standard", "cxx20_flag", "< 5.0")
|
||||
elif self.real_version < Version("11.0"):
|
||||
return "-std=c++2a"
|
||||
else:
|
||||
return "-std=c++20"
|
||||
|
||||
@property
|
||||
def cxx23_flag(self):
|
||||
if self.real_version < Version("12.0"):
|
||||
raise UnsupportedCompilerFlag(self, "the C++23 standard", "cxx23_flag", "< 12.0")
|
||||
elif self.real_version < Version("17.0"):
|
||||
return "-std=c++2b"
|
||||
else:
|
||||
return "-std=c++23"
|
||||
|
||||
@property
|
||||
def c99_flag(self):
|
||||
return "-std=c99"
|
||||
@@ -142,7 +162,10 @@ def c17_flag(self):
|
||||
def c23_flag(self):
|
||||
if self.real_version < Version("9.0"):
|
||||
raise UnsupportedCompilerFlag(self, "the C23 standard", "c23_flag", "< 9.0")
|
||||
return "-std=c2x"
|
||||
elif self.real_version < Version("18.0"):
|
||||
return "-std=c2x"
|
||||
else:
|
||||
return "-std=c23"
|
||||
|
||||
@property
|
||||
def cc_pic_flag(self):
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
from llnl.util.link_tree import ConflictingSpecsError
|
||||
from llnl.util.symlink import readlink, symlink
|
||||
|
||||
import spack.cmd
|
||||
import spack.compilers
|
||||
import spack.concretize
|
||||
import spack.config
|
||||
@@ -1948,13 +1949,19 @@ def install_specs(self, specs: Optional[List[Spec]] = None, **install_args):
|
||||
specs = specs if specs is not None else roots
|
||||
|
||||
# Extend the set of specs to overwrite with modified dev specs and their parents
|
||||
install_args["overwrite"] = (
|
||||
install_args.get("overwrite", []) + self._dev_specs_that_need_overwrite()
|
||||
overwrite: Set[str] = set()
|
||||
overwrite.update(install_args.get("overwrite", []), self._dev_specs_that_need_overwrite())
|
||||
install_args["overwrite"] = overwrite
|
||||
|
||||
explicit: Set[str] = set()
|
||||
explicit.update(
|
||||
install_args.get("explicit", []),
|
||||
(s.dag_hash() for s in specs),
|
||||
(s.dag_hash() for s in roots),
|
||||
)
|
||||
install_args["explicit"] = explicit
|
||||
|
||||
installs = [(spec.package, {**install_args, "explicit": spec in roots}) for spec in specs]
|
||||
|
||||
PackageInstaller(installs).install()
|
||||
PackageInstaller([spec.package for spec in specs], install_args).install()
|
||||
|
||||
def all_specs_generator(self) -> Iterable[Spec]:
|
||||
"""Returns a generator for all concrete specs"""
|
||||
@@ -2467,27 +2474,21 @@ def _equiv_dict(first, second):
|
||||
return same_values and same_keys_with_same_overrides
|
||||
|
||||
|
||||
def display_specs(concretized_specs):
|
||||
"""Displays the list of specs returned by `Environment.concretize()`.
|
||||
def display_specs(specs):
|
||||
"""Displays a list of specs traversed breadth-first, covering nodes, with install status.
|
||||
|
||||
Args:
|
||||
concretized_specs (list): list of specs returned by
|
||||
`Environment.concretize()`
|
||||
specs (list): list of specs
|
||||
"""
|
||||
|
||||
def _tree_to_display(spec):
|
||||
return spec.tree(
|
||||
recurse_dependencies=True,
|
||||
format=spack.spec.DISPLAY_FORMAT,
|
||||
status_fn=spack.spec.Spec.install_status,
|
||||
hashlen=7,
|
||||
hashes=True,
|
||||
)
|
||||
|
||||
for user_spec, concrete_spec in concretized_specs:
|
||||
tty.msg("Concretized {0}".format(user_spec))
|
||||
sys.stdout.write(_tree_to_display(concrete_spec))
|
||||
print("")
|
||||
tree_string = spack.spec.tree(
|
||||
specs,
|
||||
format=spack.spec.DISPLAY_FORMAT,
|
||||
hashes=True,
|
||||
hashlen=7,
|
||||
status_fn=spack.spec.Spec.install_status,
|
||||
key=traverse.by_dag_hash,
|
||||
)
|
||||
print(tree_string)
|
||||
|
||||
|
||||
def _concretize_from_constraints(spec_constraints, tests=False):
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
import spack.config
|
||||
import spack.relocate
|
||||
from spack.util.elf import ElfParsingError, parse_elf
|
||||
from spack.util.executable import Executable
|
||||
|
||||
|
||||
def is_shared_library_elf(filepath):
|
||||
@@ -141,7 +140,7 @@ def post_install(spec, explicit=None):
|
||||
return
|
||||
|
||||
# Only enable on platforms using ELF.
|
||||
if not spec.satisfies("platform=linux") and not spec.satisfies("platform=cray"):
|
||||
if not spec.satisfies("platform=linux"):
|
||||
return
|
||||
|
||||
# Disable this hook when bootstrapping, to avoid recursion.
|
||||
@@ -149,10 +148,9 @@ def post_install(spec, explicit=None):
|
||||
return
|
||||
|
||||
# Should failing to locate patchelf be a hard error?
|
||||
patchelf_path = spack.relocate._patchelf()
|
||||
if not patchelf_path:
|
||||
patchelf = spack.relocate._patchelf()
|
||||
if not patchelf:
|
||||
return
|
||||
patchelf = Executable(patchelf_path)
|
||||
|
||||
fixes = find_and_patch_sonames(spec.prefix, spec.package.non_bindable_shared_objects, patchelf)
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ def post_install(spec, explicit=None):
|
||||
return
|
||||
|
||||
# Only enable on platforms using ELF.
|
||||
if not spec.satisfies("platform=linux") and not spec.satisfies("platform=cray"):
|
||||
if not spec.satisfies("platform=linux"):
|
||||
return
|
||||
|
||||
visit_directory_tree(spec.prefix, ElfFilesWithRPathVisitor())
|
||||
|
||||
@@ -600,9 +600,7 @@ def dump_packages(spec: "spack.spec.Spec", path: str) -> None:
|
||||
if node is spec:
|
||||
spack.repo.PATH.dump_provenance(node, dest_pkg_dir)
|
||||
elif source_pkg_dir:
|
||||
fs.install_tree(
|
||||
source_pkg_dir, dest_pkg_dir, allow_broken_symlinks=(sys.platform != "win32")
|
||||
)
|
||||
fs.install_tree(source_pkg_dir, dest_pkg_dir)
|
||||
|
||||
|
||||
def get_dependent_ids(spec: "spack.spec.Spec") -> List[str]:
|
||||
@@ -761,12 +759,8 @@ def __init__(self, pkg: "spack.package_base.PackageBase", install_args: dict):
|
||||
if not self.pkg.spec.concrete:
|
||||
raise ValueError(f"{self.pkg.name} must have a concrete spec")
|
||||
|
||||
# Cache the package phase options with the explicit package,
|
||||
# popping the options to ensure installation of associated
|
||||
# dependencies is NOT affected by these options.
|
||||
|
||||
self.pkg.stop_before_phase = install_args.pop("stop_before", None) # type: ignore[attr-defined] # noqa: E501
|
||||
self.pkg.last_phase = install_args.pop("stop_at", None) # type: ignore[attr-defined]
|
||||
self.pkg.stop_before_phase = install_args.get("stop_before") # type: ignore[attr-defined] # noqa: E501
|
||||
self.pkg.last_phase = install_args.get("stop_at") # type: ignore[attr-defined]
|
||||
|
||||
# Cache the package id for convenience
|
||||
self.pkg_id = package_id(pkg.spec)
|
||||
@@ -1076,19 +1070,17 @@ def flag_installed(self, installed: List[str]) -> None:
|
||||
|
||||
@property
|
||||
def explicit(self) -> bool:
|
||||
"""The package was explicitly requested by the user."""
|
||||
return self.is_root and self.request.install_args.get("explicit", True)
|
||||
return self.pkg.spec.dag_hash() in self.request.install_args.get("explicit", [])
|
||||
|
||||
@property
|
||||
def is_root(self) -> bool:
|
||||
"""The package was requested directly, but may or may not be explicit
|
||||
in an environment."""
|
||||
def is_build_request(self) -> bool:
|
||||
"""The package was requested directly"""
|
||||
return self.pkg == self.request.pkg
|
||||
|
||||
@property
|
||||
def use_cache(self) -> bool:
|
||||
_use_cache = True
|
||||
if self.is_root:
|
||||
if self.is_build_request:
|
||||
return self.request.install_args.get("package_use_cache", _use_cache)
|
||||
else:
|
||||
return self.request.install_args.get("dependencies_use_cache", _use_cache)
|
||||
@@ -1096,7 +1088,7 @@ def use_cache(self) -> bool:
|
||||
@property
|
||||
def cache_only(self) -> bool:
|
||||
_cache_only = False
|
||||
if self.is_root:
|
||||
if self.is_build_request:
|
||||
return self.request.install_args.get("package_cache_only", _cache_only)
|
||||
else:
|
||||
return self.request.install_args.get("dependencies_cache_only", _cache_only)
|
||||
@@ -1122,24 +1114,17 @@ def priority(self):
|
||||
|
||||
class PackageInstaller:
|
||||
"""
|
||||
Class for managing the install process for a Spack instance based on a
|
||||
bottom-up DAG approach.
|
||||
Class for managing the install process for a Spack instance based on a bottom-up DAG approach.
|
||||
|
||||
This installer can coordinate concurrent batch and interactive, local
|
||||
and distributed (on a shared file system) builds for the same Spack
|
||||
instance.
|
||||
This installer can coordinate concurrent batch and interactive, local and distributed (on a
|
||||
shared file system) builds for the same Spack instance.
|
||||
"""
|
||||
|
||||
def __init__(self, installs: List[Tuple["spack.package_base.PackageBase", dict]] = []) -> None:
|
||||
"""Initialize the installer.
|
||||
|
||||
Args:
|
||||
installs (list): list of tuples, where each
|
||||
tuple consists of a package (PackageBase) and its associated
|
||||
install arguments (dict)
|
||||
"""
|
||||
def __init__(
|
||||
self, packages: List["spack.package_base.PackageBase"], install_args: dict
|
||||
) -> None:
|
||||
# List of build requests
|
||||
self.build_requests = [BuildRequest(pkg, install_args) for pkg, install_args in installs]
|
||||
self.build_requests = [BuildRequest(pkg, install_args) for pkg in packages]
|
||||
|
||||
# Priority queue of build tasks
|
||||
self.build_pq: List[Tuple[Tuple[int, int], BuildTask]] = []
|
||||
@@ -1562,7 +1547,7 @@ def _add_tasks(self, request: BuildRequest, all_deps):
|
||||
#
|
||||
# External and upstream packages need to get flagged as installed to
|
||||
# ensure proper status tracking for environment build.
|
||||
explicit = request.install_args.get("explicit", True)
|
||||
explicit = request.pkg.spec.dag_hash() in request.install_args.get("explicit", [])
|
||||
not_local = _handle_external_and_upstream(request.pkg, explicit)
|
||||
if not_local:
|
||||
self._flag_installed(request.pkg)
|
||||
@@ -1683,10 +1668,6 @@ def _install_task(self, task: BuildTask, install_status: InstallStatus) -> None:
|
||||
if not pkg.unit_test_check():
|
||||
return
|
||||
|
||||
# Injecting information to know if this installation request is the root one
|
||||
# to determine in BuildProcessInstaller whether installation is explicit or not
|
||||
install_args["is_root"] = task.is_root
|
||||
|
||||
try:
|
||||
self._setup_install_dir(pkg)
|
||||
|
||||
@@ -1998,8 +1979,8 @@ def install(self) -> None:
|
||||
|
||||
self._init_queue()
|
||||
fail_fast_err = "Terminating after first install failure"
|
||||
single_explicit_spec = len(self.build_requests) == 1
|
||||
failed_explicits = []
|
||||
single_requested_spec = len(self.build_requests) == 1
|
||||
failed_build_requests = []
|
||||
|
||||
install_status = InstallStatus(len(self.build_pq))
|
||||
|
||||
@@ -2197,14 +2178,11 @@ def install(self) -> None:
|
||||
if self.fail_fast:
|
||||
raise InstallError(f"{fail_fast_err}: {str(exc)}", pkg=pkg)
|
||||
|
||||
# Terminate at this point if the single explicit spec has
|
||||
# failed to install.
|
||||
if single_explicit_spec and task.explicit:
|
||||
raise
|
||||
|
||||
# Track explicit spec id and error to summarize when done
|
||||
if task.explicit:
|
||||
failed_explicits.append((pkg, pkg_id, str(exc)))
|
||||
# Terminate when a single build request has failed, or summarize errors later.
|
||||
if task.is_build_request:
|
||||
if single_requested_spec:
|
||||
raise
|
||||
failed_build_requests.append((pkg, pkg_id, str(exc)))
|
||||
|
||||
finally:
|
||||
# Remove the install prefix if anything went wrong during
|
||||
@@ -2227,16 +2205,16 @@ def install(self) -> None:
|
||||
if request.install_args.get("install_package") and request.pkg_id not in self.installed
|
||||
]
|
||||
|
||||
if failed_explicits or missing:
|
||||
for _, pkg_id, err in failed_explicits:
|
||||
if failed_build_requests or missing:
|
||||
for _, pkg_id, err in failed_build_requests:
|
||||
tty.error(f"{pkg_id}: {err}")
|
||||
|
||||
for _, pkg_id in missing:
|
||||
tty.error(f"{pkg_id}: Package was not installed")
|
||||
|
||||
if len(failed_explicits) > 0:
|
||||
pkg = failed_explicits[0][0]
|
||||
ids = [pkg_id for _, pkg_id, _ in failed_explicits]
|
||||
if len(failed_build_requests) > 0:
|
||||
pkg = failed_build_requests[0][0]
|
||||
ids = [pkg_id for _, pkg_id, _ in failed_build_requests]
|
||||
tty.debug(
|
||||
"Associating installation failure with first failed "
|
||||
f"explicit package ({ids[0]}) from {', '.join(ids)}"
|
||||
@@ -2295,7 +2273,7 @@ def __init__(self, pkg: "spack.package_base.PackageBase", install_args: dict):
|
||||
self.verbose = bool(install_args.get("verbose", False))
|
||||
|
||||
# whether installation was explicitly requested by the user
|
||||
self.explicit = install_args.get("is_root", False) and install_args.get("explicit", True)
|
||||
self.explicit = pkg.spec.dag_hash() in install_args.get("explicit", [])
|
||||
|
||||
# env before starting installation
|
||||
self.unmodified_env = install_args.get("unmodified_env", {})
|
||||
@@ -2380,9 +2358,7 @@ def _install_source(self) -> None:
|
||||
src_target = os.path.join(pkg.spec.prefix, "share", pkg.name, "src")
|
||||
tty.debug(f"{self.pre} Copying source to {src_target}")
|
||||
|
||||
fs.install_tree(
|
||||
pkg.stage.source_path, src_target, allow_broken_symlinks=(sys.platform != "win32")
|
||||
)
|
||||
fs.install_tree(pkg.stage.source_path, src_target)
|
||||
|
||||
def _real_install(self) -> None:
|
||||
import spack.builder
|
||||
|
||||
@@ -3,22 +3,12 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
from ._operating_system import OperatingSystem
|
||||
from .cray_backend import CrayBackend
|
||||
from .cray_frontend import CrayFrontend
|
||||
from .freebsd import FreeBSDOs
|
||||
from .linux_distro import LinuxDistro
|
||||
from .mac_os import MacOs
|
||||
from .windows_os import WindowsOs
|
||||
|
||||
__all__ = [
|
||||
"OperatingSystem",
|
||||
"LinuxDistro",
|
||||
"MacOs",
|
||||
"CrayFrontend",
|
||||
"CrayBackend",
|
||||
"WindowsOs",
|
||||
"FreeBSDOs",
|
||||
]
|
||||
__all__ = ["OperatingSystem", "LinuxDistro", "MacOs", "WindowsOs", "FreeBSDOs"]
|
||||
|
||||
#: List of all the Operating Systems known to Spack
|
||||
operating_systems = [LinuxDistro, MacOs, CrayFrontend, CrayBackend, WindowsOs, FreeBSDOs]
|
||||
operating_systems = [LinuxDistro, MacOs, WindowsOs, FreeBSDOs]
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack.error
|
||||
import spack.version
|
||||
from spack.util.module_cmd import module
|
||||
|
||||
from .linux_distro import LinuxDistro
|
||||
|
||||
#: Possible locations of the Cray CLE release file,
|
||||
#: which we look at to get the CNL OS version.
|
||||
_cle_release_file = "/etc/opt/cray/release/cle-release"
|
||||
_clerelease_file = "/etc/opt/cray/release/clerelease"
|
||||
|
||||
|
||||
def read_cle_release_file():
|
||||
"""Read the CLE release file and return a dict with its attributes.
|
||||
|
||||
This file is present on newer versions of Cray.
|
||||
|
||||
The release file looks something like this::
|
||||
|
||||
RELEASE=6.0.UP07
|
||||
BUILD=6.0.7424
|
||||
...
|
||||
|
||||
The dictionary we produce looks like this::
|
||||
|
||||
{
|
||||
"RELEASE": "6.0.UP07",
|
||||
"BUILD": "6.0.7424",
|
||||
...
|
||||
}
|
||||
|
||||
Returns:
|
||||
dict: dictionary of release attributes
|
||||
"""
|
||||
with open(_cle_release_file) as release_file:
|
||||
result = {}
|
||||
for line in release_file:
|
||||
# use partition instead of split() to ensure we only split on
|
||||
# the first '=' in the line.
|
||||
key, _, value = line.partition("=")
|
||||
result[key] = value.strip()
|
||||
return result
|
||||
|
||||
|
||||
def read_clerelease_file():
|
||||
"""Read the CLE release file and return the Cray OS version.
|
||||
|
||||
This file is present on older versions of Cray.
|
||||
|
||||
The release file looks something like this::
|
||||
|
||||
5.2.UP04
|
||||
|
||||
Returns:
|
||||
str: the Cray OS version
|
||||
"""
|
||||
with open(_clerelease_file) as release_file:
|
||||
for line in release_file:
|
||||
return line.strip()
|
||||
|
||||
|
||||
class CrayBackend(LinuxDistro):
|
||||
"""Compute Node Linux (CNL) is the operating system used for the Cray XC
|
||||
series super computers. It is a very stripped down version of GNU/Linux.
|
||||
Any compilers found through this operating system will be used with
|
||||
modules. If updated, user must make sure that version and name are
|
||||
updated to indicate that OS has been upgraded (or downgraded)
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
name = "cnl"
|
||||
version = self._detect_crayos_version()
|
||||
if version:
|
||||
# If we found a CrayOS version, we do not want the information
|
||||
# from LinuxDistro. In order to skip the logic from
|
||||
# distro.linux_distribution, while still calling __init__
|
||||
# methods further up the MRO, we skip LinuxDistro in the MRO and
|
||||
# call the OperatingSystem superclass __init__ method
|
||||
super(LinuxDistro, self).__init__(name, version)
|
||||
else:
|
||||
super().__init__()
|
||||
self.modulecmd = module
|
||||
|
||||
def __str__(self):
|
||||
return self.name + str(self.version)
|
||||
|
||||
@classmethod
|
||||
def _detect_crayos_version(cls):
|
||||
if os.path.isfile(_cle_release_file):
|
||||
release_attrs = read_cle_release_file()
|
||||
if "RELEASE" not in release_attrs:
|
||||
# This Cray system uses a base OS not CLE/CNL
|
||||
return None
|
||||
v = spack.version.Version(release_attrs["RELEASE"])
|
||||
return v[0]
|
||||
elif os.path.isfile(_clerelease_file):
|
||||
v = read_clerelease_file()
|
||||
return spack.version.Version(v)[0]
|
||||
else:
|
||||
# Not all Cray systems run CNL on the backend.
|
||||
# Systems running in what Cray calls "cluster" mode run other
|
||||
# linux OSs under the Cray PE.
|
||||
# So if we don't detect any Cray OS version on the system,
|
||||
# we return None. We can't ever be sure we will get a Cray OS
|
||||
# version.
|
||||
# Returning None allows the calling code to test for the value
|
||||
# being "True-ish" rather than requiring a try/except block.
|
||||
return None
|
||||
|
||||
def arguments_to_detect_version_fn(self, paths):
|
||||
import spack.compilers
|
||||
|
||||
command_arguments = []
|
||||
for compiler_name in spack.compilers.supported_compilers():
|
||||
cmp_cls = spack.compilers.class_for_compiler_name(compiler_name)
|
||||
|
||||
# If the compiler doesn't have a corresponding
|
||||
# Programming Environment, skip to the next
|
||||
if cmp_cls.PrgEnv is None:
|
||||
continue
|
||||
|
||||
if cmp_cls.PrgEnv_compiler is None:
|
||||
tty.die("Must supply PrgEnv_compiler with PrgEnv")
|
||||
|
||||
compiler_id = spack.compilers.CompilerID(self, compiler_name, None)
|
||||
detect_version_args = spack.compilers.DetectVersionArgs(
|
||||
id=compiler_id, variation=(None, None), language="cc", path="cc"
|
||||
)
|
||||
command_arguments.append(detect_version_args)
|
||||
return command_arguments
|
||||
|
||||
def detect_version(self, detect_version_args):
|
||||
import spack.compilers
|
||||
|
||||
modulecmd = self.modulecmd
|
||||
compiler_name = detect_version_args.id.compiler_name
|
||||
compiler_cls = spack.compilers.class_for_compiler_name(compiler_name)
|
||||
output = modulecmd("avail", compiler_cls.PrgEnv_compiler)
|
||||
version_regex = r"({0})/([\d\.]+[\d]-?[\w]*)".format(compiler_cls.PrgEnv_compiler)
|
||||
matches = re.findall(version_regex, output)
|
||||
version = tuple(version for _, version in matches if "classic" not in version)
|
||||
compiler_id = detect_version_args.id
|
||||
value = detect_version_args._replace(id=compiler_id._replace(version=version))
|
||||
return value, None
|
||||
|
||||
def make_compilers(self, compiler_id, paths):
|
||||
import spack.spec
|
||||
|
||||
name = compiler_id.compiler_name
|
||||
cmp_cls = spack.compilers.class_for_compiler_name(name)
|
||||
compilers = []
|
||||
for v in compiler_id.version:
|
||||
comp = cmp_cls(
|
||||
spack.spec.CompilerSpec(name + "@=" + v),
|
||||
self,
|
||||
"any",
|
||||
["cc", "CC", "ftn"],
|
||||
[cmp_cls.PrgEnv, name + "/" + v],
|
||||
)
|
||||
|
||||
compilers.append(comp)
|
||||
return compilers
|
||||
@@ -1,105 +0,0 @@
|
||||
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import re
|
||||
|
||||
import llnl.util.filesystem as fs
|
||||
import llnl.util.lang
|
||||
import llnl.util.tty as tty
|
||||
|
||||
from spack.util.environment import get_path
|
||||
from spack.util.module_cmd import module
|
||||
|
||||
from .linux_distro import LinuxDistro
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def unload_programming_environment():
|
||||
"""Context manager that unloads Cray Programming Environments."""
|
||||
env_bu = None
|
||||
|
||||
# We rely on the fact that the PrgEnv-* modules set the PE_ENV
|
||||
# environment variable.
|
||||
if "PE_ENV" in os.environ:
|
||||
# Copy environment variables to restore them after the compiler
|
||||
# detection. We expect that the only thing PrgEnv-* modules do is
|
||||
# the environment variables modifications.
|
||||
env_bu = os.environ.copy()
|
||||
|
||||
# Get the name of the module from the environment variable.
|
||||
prg_env = "PrgEnv-" + os.environ["PE_ENV"].lower()
|
||||
|
||||
# Unload the PrgEnv-* module. By doing this we intentionally
|
||||
# provoke errors when the Cray's compiler wrappers are executed
|
||||
# (Error: A PrgEnv-* modulefile must be loaded.) so they will not
|
||||
# be detected as valid compilers by the overridden method. We also
|
||||
# expect that the modules that add the actual compilers' binaries
|
||||
# into the PATH environment variable (i.e. the following modules:
|
||||
# 'intel', 'cce', 'gcc', etc.) will also be unloaded since they are
|
||||
# specified as prerequisites in the PrgEnv-* modulefiles.
|
||||
module("unload", prg_env)
|
||||
|
||||
yield
|
||||
|
||||
# Restore the environment.
|
||||
if env_bu is not None:
|
||||
os.environ.clear()
|
||||
os.environ.update(env_bu)
|
||||
|
||||
|
||||
class CrayFrontend(LinuxDistro):
|
||||
"""Represents OS that runs on login and service nodes of the Cray platform.
|
||||
It acts as a regular Linux without Cray-specific modules and compiler
|
||||
wrappers."""
|
||||
|
||||
@property
|
||||
def compiler_search_paths(self):
|
||||
"""Calls the default function but unloads Cray's programming
|
||||
environments first.
|
||||
|
||||
This prevents from detecting Cray compiler wrappers and avoids
|
||||
possible false detections.
|
||||
"""
|
||||
import spack.compilers
|
||||
|
||||
with unload_programming_environment():
|
||||
search_paths = get_path("PATH")
|
||||
|
||||
extract_path_re = re.compile(r"prepend-path[\s]*PATH[\s]*([/\w\.:-]*)")
|
||||
|
||||
for compiler_cls in spack.compilers.all_compiler_types():
|
||||
# Check if the compiler class is supported on Cray
|
||||
prg_env = getattr(compiler_cls, "PrgEnv", None)
|
||||
compiler_module = getattr(compiler_cls, "PrgEnv_compiler", None)
|
||||
if not (prg_env and compiler_module):
|
||||
continue
|
||||
|
||||
# It is supported, check which versions are available
|
||||
output = module("avail", compiler_cls.PrgEnv_compiler)
|
||||
version_regex = r"({0})/([\d\.]+[\d]-?[\w]*)".format(compiler_cls.PrgEnv_compiler)
|
||||
matches = re.findall(version_regex, output)
|
||||
versions = tuple(version for _, version in matches if "classic" not in version)
|
||||
|
||||
# Now inspect the modules and add to paths
|
||||
msg = "[CRAY FE] Detected FE compiler [name={0}, versions={1}]"
|
||||
tty.debug(msg.format(compiler_module, versions))
|
||||
for v in versions:
|
||||
try:
|
||||
current_module = compiler_module + "/" + v
|
||||
out = module("show", current_module)
|
||||
match = extract_path_re.search(out)
|
||||
search_paths += match.group(1).split(":")
|
||||
except Exception as e:
|
||||
msg = (
|
||||
"[CRAY FE] An unexpected error occurred while "
|
||||
"detecting FE compiler [compiler={0}, "
|
||||
" version={1}, error={2}]"
|
||||
)
|
||||
tty.debug(msg.format(compiler_cls.name, v, str(e)))
|
||||
|
||||
search_paths = list(llnl.util.lang.dedupe(search_paths))
|
||||
return fs.search_paths_for_executables(*search_paths)
|
||||
@@ -621,10 +621,6 @@ class PackageBase(WindowsRPath, PackageViewMixin, RedistributionMixin, metaclass
|
||||
#: By default do not run tests within package's install()
|
||||
run_tests = False
|
||||
|
||||
#: Keep -Werror flags, matches config:flags:keep_werror to override config
|
||||
# NOTE: should be type Optional[Literal['all', 'specific', 'none']] in 3.8+
|
||||
keep_werror: Optional[str] = None
|
||||
|
||||
#: Most packages are NOT extendable. Set to True if you want extensions.
|
||||
extendable = False
|
||||
|
||||
@@ -930,6 +926,32 @@ def global_license_file(self):
|
||||
self.global_license_dir, self.name, os.path.basename(self.license_files[0])
|
||||
)
|
||||
|
||||
# NOTE: return type should be Optional[Literal['all', 'specific', 'none']] in
|
||||
# Python 3.8+, but we still support 3.6.
|
||||
@property
|
||||
def keep_werror(self) -> Optional[str]:
|
||||
"""Keep ``-Werror`` flags, matches ``config:flags:keep_werror`` to override config.
|
||||
|
||||
Valid return values are:
|
||||
* ``"all"``: keep all ``-Werror`` flags.
|
||||
* ``"specific"``: keep only ``-Werror=specific-warning`` flags.
|
||||
* ``"none"``: filter out all ``-Werror*`` flags.
|
||||
* ``None``: respect the user's configuration (``"none"`` by default).
|
||||
"""
|
||||
if self.spec.satisfies("%nvhpc@:23.3") or self.spec.satisfies("%pgi"):
|
||||
# Filtering works by replacing -Werror with -Wno-error, but older nvhpc and
|
||||
# PGI do not understand -Wno-error, so we disable filtering.
|
||||
return "all"
|
||||
|
||||
elif self.spec.satisfies("%nvhpc@23.4:"):
|
||||
# newer nvhpc supports -Wno-error but can't disable specific warnings with
|
||||
# -Wno-error=warning. Skip -Werror=warning, but still filter -Werror.
|
||||
return "specific"
|
||||
|
||||
else:
|
||||
# use -Werror disablement by default for other compilers
|
||||
return None
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
if not self.spec.versions.concrete:
|
||||
@@ -1119,9 +1141,10 @@ def _make_stage(self):
|
||||
if not link_format:
|
||||
link_format = "build-{arch}-{hash:7}"
|
||||
stage_link = self.spec.format_path(link_format)
|
||||
source_stage = DevelopStage(compute_stage_name(self.spec), dev_path, stage_link)
|
||||
else:
|
||||
source_stage = self._make_root_stage(self.fetcher)
|
||||
return DevelopStage(compute_stage_name(self.spec), dev_path, stage_link)
|
||||
|
||||
# To fetch the current version
|
||||
source_stage = self._make_root_stage(self.fetcher)
|
||||
|
||||
# all_stages is source + resources + patches
|
||||
all_stages = StageComposite()
|
||||
@@ -1450,8 +1473,10 @@ def do_fetch(self, mirror_only=False):
|
||||
return
|
||||
|
||||
checksum = spack.config.get("config:checksum")
|
||||
fetch = self.stage.needs_fetching
|
||||
if (
|
||||
checksum
|
||||
and fetch
|
||||
and (self.version not in self.versions)
|
||||
and (not isinstance(self.version, GitVersion))
|
||||
):
|
||||
@@ -1558,11 +1583,13 @@ def do_patch(self):
|
||||
tty.debug("Patching failed last time. Restaging.")
|
||||
self.stage.restage()
|
||||
else:
|
||||
# develop specs may have patch failures but should never be restaged
|
||||
tty.warn(
|
||||
f"A patch failure was detected in {self.name}."
|
||||
" Build errors may occur due to this."
|
||||
# develop specs/ DIYStages may have patch failures but
|
||||
# should never be restaged
|
||||
msg = (
|
||||
"A patch failure was detected in %s." % self.name
|
||||
+ " Build errors may occur due to this."
|
||||
)
|
||||
tty.warn(msg)
|
||||
return
|
||||
|
||||
# If this file exists, then we already applied all the patches.
|
||||
@@ -1876,7 +1903,10 @@ def do_install(self, **kwargs):
|
||||
verbose (bool): Display verbose build output (by default,
|
||||
suppresses it)
|
||||
"""
|
||||
PackageInstaller([(self, kwargs)]).install()
|
||||
explicit = kwargs.get("explicit", True)
|
||||
if isinstance(explicit, bool):
|
||||
kwargs["explicit"] = {self.spec.dag_hash()} if explicit else set()
|
||||
PackageInstaller([self], kwargs).install()
|
||||
|
||||
# TODO (post-34236): Update tests and all packages that use this as a
|
||||
# TODO (post-34236): package method to the routine made available to
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
from ._functions import _host, by_name, platforms, prevent_cray_detection, reset
|
||||
from ._platform import Platform
|
||||
from .cray import Cray
|
||||
from .darwin import Darwin
|
||||
from .freebsd import FreeBSD
|
||||
from .linux import Linux
|
||||
@@ -15,7 +14,6 @@
|
||||
|
||||
__all__ = [
|
||||
"Platform",
|
||||
"Cray",
|
||||
"Darwin",
|
||||
"Linux",
|
||||
"FreeBSD",
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
import spack.util.environment
|
||||
|
||||
from .cray import Cray
|
||||
from .darwin import Darwin
|
||||
from .freebsd import FreeBSD
|
||||
from .linux import Linux
|
||||
@@ -16,7 +15,7 @@
|
||||
from .windows import Windows
|
||||
|
||||
#: List of all the platform classes known to Spack
|
||||
platforms = [Cray, Darwin, Linux, Windows, FreeBSD, Test]
|
||||
platforms = [Darwin, Linux, Windows, FreeBSD, Test]
|
||||
|
||||
|
||||
@llnl.util.lang.memoized
|
||||
|
||||
@@ -2,254 +2,10 @@
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
import os
|
||||
import os.path
|
||||
import platform
|
||||
import re
|
||||
|
||||
import archspec.cpu
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.symlink import readlink
|
||||
|
||||
import spack.target
|
||||
import spack.version
|
||||
from spack.operating_systems.cray_backend import CrayBackend
|
||||
from spack.operating_systems.cray_frontend import CrayFrontend
|
||||
from spack.paths import build_env_path
|
||||
from spack.util.executable import Executable
|
||||
from spack.util.module_cmd import module
|
||||
|
||||
from ._platform import NoPlatformError, Platform
|
||||
|
||||
_craype_name_to_target_name = {
|
||||
"x86-cascadelake": "cascadelake",
|
||||
"x86-naples": "zen",
|
||||
"x86-rome": "zen2",
|
||||
"x86-milan": "zen3",
|
||||
"x86-skylake": "skylake_avx512",
|
||||
"mic-knl": "mic_knl",
|
||||
"interlagos": "bulldozer",
|
||||
"abudhabi": "piledriver",
|
||||
}
|
||||
|
||||
_ex_craype_dir = "/opt/cray/pe/cpe"
|
||||
_xc_craype_dir = "/opt/cray/pe/cdt"
|
||||
|
||||
|
||||
def slingshot_network():
|
||||
return os.path.exists("/opt/cray/pe") and (
|
||||
os.path.exists("/lib64/libcxi.so") or os.path.exists("/usr/lib64/libcxi.so")
|
||||
)
|
||||
|
||||
|
||||
def _target_name_from_craype_target_name(name):
|
||||
return _craype_name_to_target_name.get(name, name)
|
||||
|
||||
|
||||
class Cray(Platform):
|
||||
priority = 10
|
||||
|
||||
def __init__(self):
|
||||
"""Create a Cray system platform.
|
||||
|
||||
Target names should use craype target names but not include the
|
||||
'craype-' prefix. Uses first viable target from:
|
||||
self
|
||||
envars [SPACK_FRONT_END, SPACK_BACK_END]
|
||||
configuration file "targets.yaml" with keys 'front_end', 'back_end'
|
||||
scanning /etc/bash/bashrc.local for back_end only
|
||||
"""
|
||||
super().__init__("cray")
|
||||
|
||||
# Make all craype targets available.
|
||||
for target in self._avail_targets():
|
||||
name = _target_name_from_craype_target_name(target)
|
||||
self.add_target(name, spack.target.Target(name, "craype-%s" % target))
|
||||
|
||||
self.back_end = os.environ.get("SPACK_BACK_END", self._default_target_from_env())
|
||||
self.default = self.back_end
|
||||
if self.back_end not in self.targets:
|
||||
# We didn't find a target module for the backend
|
||||
raise NoPlatformError()
|
||||
|
||||
# Setup frontend targets
|
||||
for name in archspec.cpu.TARGETS:
|
||||
if name not in self.targets:
|
||||
self.add_target(name, spack.target.Target(name))
|
||||
self.front_end = os.environ.get("SPACK_FRONT_END", archspec.cpu.host().name)
|
||||
if self.front_end not in self.targets:
|
||||
self.add_target(self.front_end, spack.target.Target(self.front_end))
|
||||
|
||||
front_distro = CrayFrontend()
|
||||
back_distro = CrayBackend()
|
||||
|
||||
self.default_os = str(back_distro)
|
||||
self.back_os = self.default_os
|
||||
self.front_os = str(front_distro)
|
||||
|
||||
self.add_operating_system(self.back_os, back_distro)
|
||||
if self.front_os != self.back_os:
|
||||
self.add_operating_system(self.front_os, front_distro)
|
||||
|
||||
def setup_platform_environment(self, pkg, env):
|
||||
"""Change the linker to default dynamic to be more
|
||||
similar to linux/standard linker behavior
|
||||
"""
|
||||
# Unload these modules to prevent any silent linking or unnecessary
|
||||
# I/O profiling in the case of darshan.
|
||||
modules_to_unload = ["cray-mpich", "darshan", "cray-libsci", "altd"]
|
||||
for mod in modules_to_unload:
|
||||
module("unload", mod)
|
||||
|
||||
env.set("CRAYPE_LINK_TYPE", "dynamic")
|
||||
cray_wrapper_names = os.path.join(build_env_path, "cray")
|
||||
|
||||
if os.path.isdir(cray_wrapper_names):
|
||||
env.prepend_path("PATH", cray_wrapper_names)
|
||||
env.prepend_path("SPACK_ENV_PATH", cray_wrapper_names)
|
||||
|
||||
# Makes spack installed pkg-config work on Crays
|
||||
env.append_path("PKG_CONFIG_PATH", "/usr/lib64/pkgconfig")
|
||||
env.append_path("PKG_CONFIG_PATH", "/usr/local/lib64/pkgconfig")
|
||||
|
||||
# CRAY_LD_LIBRARY_PATH is used at build time by the cray compiler
|
||||
# wrappers to augment LD_LIBRARY_PATH. This is to avoid long load
|
||||
# times at runtime. This behavior is not always respected on cray
|
||||
# "cluster" systems, so we reproduce it here.
|
||||
if os.environ.get("CRAY_LD_LIBRARY_PATH"):
|
||||
env.prepend_path("LD_LIBRARY_PATH", os.environ["CRAY_LD_LIBRARY_PATH"])
|
||||
|
||||
@classmethod
|
||||
def craype_type_and_version(cls):
|
||||
if os.path.isdir(_ex_craype_dir):
|
||||
craype_dir = _ex_craype_dir
|
||||
craype_type = "EX"
|
||||
elif os.path.isdir(_xc_craype_dir):
|
||||
craype_dir = _xc_craype_dir
|
||||
craype_type = "XC"
|
||||
else:
|
||||
return (None, None)
|
||||
|
||||
# Take the default version from known symlink path
|
||||
default_path = os.path.join(craype_dir, "default")
|
||||
if os.path.islink(default_path):
|
||||
version = spack.version.Version(readlink(default_path))
|
||||
return (craype_type, version)
|
||||
|
||||
# If no default version, sort available versions and return latest
|
||||
versions_available = [spack.version.Version(v) for v in os.listdir(craype_dir)]
|
||||
versions_available.sort(reverse=True)
|
||||
if not versions_available:
|
||||
return (craype_type, None)
|
||||
return (craype_type, versions_available[0])
|
||||
|
||||
@classmethod
|
||||
def detect(cls):
|
||||
"""
|
||||
Detect whether this system requires CrayPE module support.
|
||||
|
||||
Systems with newer CrayPE (21.10 for EX systems, future work for CS and
|
||||
XC systems) have compilers and MPI wrappers that can be used directly
|
||||
by path. These systems are considered ``linux`` platforms.
|
||||
|
||||
For systems running an older CrayPE, we detect the Cray platform based
|
||||
on the availability through `module` of the Cray programming
|
||||
environment. If this environment is available, we can use it to find
|
||||
compilers, target modules, etc. If the Cray programming environment is
|
||||
not available via modules, then we will treat it as a standard linux
|
||||
system, as the Cray compiler wrappers and other components of the Cray
|
||||
programming environment are irrelevant without module support.
|
||||
"""
|
||||
if "opt/cray" not in os.environ.get("MODULEPATH", ""):
|
||||
return False
|
||||
|
||||
craype_type, craype_version = cls.craype_type_and_version()
|
||||
if craype_type == "XC":
|
||||
return True
|
||||
if craype_type == "EX" and craype_version < spack.version.Version("21.10"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _default_target_from_env(self):
|
||||
"""Set and return the default CrayPE target loaded in a clean login
|
||||
session.
|
||||
|
||||
A bash subshell is launched with a wiped environment and the list of
|
||||
loaded modules is parsed for the first acceptable CrayPE target.
|
||||
"""
|
||||
# env -i /bin/bash -lc echo $CRAY_CPU_TARGET 2> /dev/null
|
||||
if getattr(self, "default", None) is None:
|
||||
bash = Executable("/bin/bash")
|
||||
output = bash(
|
||||
"--norc",
|
||||
"--noprofile",
|
||||
"-lc",
|
||||
"echo $CRAY_CPU_TARGET",
|
||||
env={"TERM": os.environ.get("TERM", "")},
|
||||
output=str,
|
||||
error=os.devnull,
|
||||
)
|
||||
|
||||
default_from_module = "".join(output.split()) # rm all whitespace
|
||||
if default_from_module:
|
||||
tty.debug("Found default module:%s" % default_from_module)
|
||||
return default_from_module
|
||||
else:
|
||||
front_end = archspec.cpu.host()
|
||||
# Look for the frontend architecture or closest ancestor
|
||||
# available in cray target modules
|
||||
avail = [_target_name_from_craype_target_name(x) for x in self._avail_targets()]
|
||||
for front_end_possibility in [front_end] + front_end.ancestors:
|
||||
if front_end_possibility.name in avail:
|
||||
tty.debug("using front-end architecture or available ancestor")
|
||||
return front_end_possibility.name
|
||||
else:
|
||||
tty.debug("using platform.machine as default")
|
||||
return platform.machine()
|
||||
|
||||
def _avail_targets(self):
|
||||
"""Return a list of available CrayPE CPU targets."""
|
||||
|
||||
def modules_in_output(output):
|
||||
"""Returns a list of valid modules parsed from modulecmd output"""
|
||||
return [i for i in re.split(r"\s\s+|\n", output)]
|
||||
|
||||
def target_names_from_modules(modules):
|
||||
# Craype- module prefixes that are not valid CPU targets.
|
||||
targets = []
|
||||
for mod in modules:
|
||||
if "craype-" in mod:
|
||||
name = mod[7:]
|
||||
name = name.split()[0]
|
||||
_n = name.replace("-", "_") # test for mic-knl/mic_knl
|
||||
is_target_name = name in archspec.cpu.TARGETS or _n in archspec.cpu.TARGETS
|
||||
is_cray_target_name = name in _craype_name_to_target_name
|
||||
if is_target_name or is_cray_target_name:
|
||||
targets.append(name)
|
||||
|
||||
return targets
|
||||
|
||||
def modules_from_listdir():
|
||||
craype_default_path = "/opt/cray/pe/craype/default/modulefiles"
|
||||
if os.path.isdir(craype_default_path):
|
||||
return os.listdir(craype_default_path)
|
||||
return []
|
||||
|
||||
if getattr(self, "_craype_targets", None) is None:
|
||||
strategies = [
|
||||
lambda: modules_in_output(module("avail", "-t", "craype-")),
|
||||
modules_from_listdir,
|
||||
]
|
||||
for available_craype_modules in strategies:
|
||||
craype_modules = available_craype_modules()
|
||||
craype_targets = target_names_from_modules(craype_modules)
|
||||
if craype_targets:
|
||||
self._craype_targets = craype_targets
|
||||
break
|
||||
else:
|
||||
# If nothing is found add platform.machine()
|
||||
# to avoid Spack erroring out
|
||||
self._craype_targets = [platform.machine()]
|
||||
|
||||
return self._craype_targets
|
||||
|
||||
@@ -116,6 +116,8 @@ class Provenance(enum.IntEnum):
|
||||
PACKAGE_PY = enum.auto()
|
||||
# An installed spec
|
||||
INSTALLED = enum.auto()
|
||||
# lower provenance for installed git refs so concretizer prefers StandardVersion installs
|
||||
INSTALLED_GIT_VERSION = enum.auto()
|
||||
# A runtime injected from another package (e.g. a compiler)
|
||||
RUNTIME = enum.auto()
|
||||
|
||||
@@ -844,6 +846,8 @@ def solve(self, setup, specs, reuse=None, output=None, control=None, allow_depre
|
||||
parent_dir = os.path.dirname(__file__)
|
||||
self.control.load(os.path.join(parent_dir, "concretize.lp"))
|
||||
self.control.load(os.path.join(parent_dir, "heuristic.lp"))
|
||||
if spack.config.CONFIG.get("concretizer:duplicates:strategy", "none") != "none":
|
||||
self.control.load(os.path.join(parent_dir, "heuristic_separate.lp"))
|
||||
self.control.load(os.path.join(parent_dir, "display.lp"))
|
||||
if not setup.concretize_everything:
|
||||
self.control.load(os.path.join(parent_dir, "when_possible.lp"))
|
||||
@@ -1878,8 +1882,11 @@ def _spec_clauses(
|
||||
)
|
||||
|
||||
clauses.append(f.variant_value(spec.name, vname, value))
|
||||
|
||||
if variant.propagate:
|
||||
clauses.append(f.propagate(spec.name, fn.variant_value(vname, value)))
|
||||
clauses.append(
|
||||
f.variant_propagation_candidate(spec.name, vname, value, spec.name)
|
||||
)
|
||||
|
||||
# Tell the concretizer that this is a possible value for the
|
||||
# variant, to account for things like int/str values where we
|
||||
@@ -2067,7 +2074,7 @@ def define_ad_hoc_versions_from_specs(
|
||||
# best possible, so they're guaranteed to be used preferentially.
|
||||
version = s.versions.concrete
|
||||
|
||||
if version is None or any(v == version for v in self.possible_versions[s.name]):
|
||||
if version is None or (any((v == version) for v in self.possible_versions[s.name])):
|
||||
continue
|
||||
|
||||
if require_checksum and not _is_checksummed_git_version(version):
|
||||
@@ -2381,9 +2388,16 @@ def concrete_specs(self):
|
||||
# - Add OS to possible OS's
|
||||
for dep in spec.traverse():
|
||||
self.possible_versions[dep.name].add(dep.version)
|
||||
self.declared_versions[dep.name].append(
|
||||
DeclaredVersion(version=dep.version, idx=0, origin=Provenance.INSTALLED)
|
||||
)
|
||||
if isinstance(dep.version, vn.GitVersion):
|
||||
self.declared_versions[dep.name].append(
|
||||
DeclaredVersion(
|
||||
version=dep.version, idx=0, origin=Provenance.INSTALLED_GIT_VERSION
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.declared_versions[dep.name].append(
|
||||
DeclaredVersion(version=dep.version, idx=0, origin=Provenance.INSTALLED)
|
||||
)
|
||||
self.possible_oses.add(dep.os)
|
||||
|
||||
def define_concrete_input_specs(self, specs, possible):
|
||||
@@ -2435,7 +2449,7 @@ def setup(
|
||||
|
||||
if using_libc_compatibility():
|
||||
for libc in self.libcs:
|
||||
self.gen.fact(fn.allowed_libc(libc.name, libc.version))
|
||||
self.gen.fact(fn.host_libc(libc.name, libc.version))
|
||||
|
||||
if not allow_deprecated:
|
||||
self.gen.fact(fn.deprecated_versions_not_allowed())
|
||||
@@ -2734,7 +2748,7 @@ class _Head:
|
||||
node_flag = fn.attr("node_flag_set")
|
||||
node_flag_source = fn.attr("node_flag_source")
|
||||
node_flag_propagate = fn.attr("node_flag_propagate")
|
||||
propagate = fn.attr("propagate")
|
||||
variant_propagation_candidate = fn.attr("variant_propagation_candidate")
|
||||
|
||||
|
||||
class _Body:
|
||||
@@ -2751,7 +2765,7 @@ class _Body:
|
||||
node_flag = fn.attr("node_flag")
|
||||
node_flag_source = fn.attr("node_flag_source")
|
||||
node_flag_propagate = fn.attr("node_flag_propagate")
|
||||
propagate = fn.attr("propagate")
|
||||
variant_propagation_candidate = fn.attr("variant_propagation_candidate")
|
||||
|
||||
|
||||
class ProblemInstanceBuilder:
|
||||
@@ -3225,39 +3239,6 @@ def requires(self, impose: str, *, when: str):
|
||||
self.runtime_conditions.add((imposed_spec, when_spec))
|
||||
self.reset()
|
||||
|
||||
def propagate(self, constraint_str: str, *, when: str):
|
||||
msg = "the 'propagate' method can be called only with pkg('*')"
|
||||
assert self.current_package == "*", msg
|
||||
|
||||
when_spec = spack.spec.Spec(when)
|
||||
assert when_spec.name is None, "only anonymous when specs are accepted"
|
||||
|
||||
placeholder = "XXX"
|
||||
node_variable = "node(ID, Package)"
|
||||
when_spec.name = placeholder
|
||||
|
||||
body_clauses = self._setup.spec_clauses(when_spec, body=True)
|
||||
body_str = (
|
||||
f" {f',{os.linesep} '.join(str(x) for x in body_clauses)},\n"
|
||||
f" not external({node_variable}),\n"
|
||||
f" not runtime(Package)"
|
||||
).replace(f'"{placeholder}"', f"{node_variable}")
|
||||
|
||||
constraint_spec = spack.spec.Spec(constraint_str)
|
||||
assert constraint_spec.name is None, "only anonymous constraint specs are accepted"
|
||||
|
||||
constraint_spec.name = placeholder
|
||||
constraint_clauses = self._setup.spec_clauses(constraint_spec, body=False)
|
||||
for clause in constraint_clauses:
|
||||
if clause.args[0] == "node_compiler_version_satisfies":
|
||||
self._setup.compiler_version_constraints.add(constraint_spec.compiler)
|
||||
args = f'"{constraint_spec.compiler.name}", "{constraint_spec.compiler.versions}"'
|
||||
head_str = f"propagate({node_variable}, node_compiler_version_satisfies({args}))"
|
||||
rule = f"{head_str} :-\n{body_str}.\n\n"
|
||||
self.rules.append(rule)
|
||||
|
||||
self.reset()
|
||||
|
||||
def consume_facts(self):
|
||||
"""Consume the facts collected by this object, and emits rules and
|
||||
facts for the runtimes.
|
||||
@@ -3827,12 +3808,6 @@ class Solver:
|
||||
def __init__(self):
|
||||
self.driver = PyclingoDriver()
|
||||
self.selector = ReusableSpecsSelector(configuration=spack.config.CONFIG)
|
||||
if spack.platforms.host().name == "cray":
|
||||
msg = (
|
||||
"The Cray platform, i.e. 'platform=cray', will be removed in Spack v0.23. "
|
||||
"All Cray machines will be then detected as 'platform=linux'."
|
||||
)
|
||||
warnings.warn(msg)
|
||||
|
||||
@staticmethod
|
||||
def _check_input_and_extract_concrete_specs(specs):
|
||||
|
||||
@@ -256,6 +256,7 @@ possible_version_weight(node(ID, Package), Weight)
|
||||
:- attr("version", node(ID, Package), Version),
|
||||
version_weight(node(ID, Package), Weight),
|
||||
not pkg_fact(Package, version_declared(Version, Weight, "installed")),
|
||||
not pkg_fact(Package, version_declared(Version, Weight, "installed_git_version")),
|
||||
not build(node(ID, Package)),
|
||||
internal_error("Build version weight used for reused package").
|
||||
|
||||
@@ -811,6 +812,37 @@ node_has_variant(node(ID, Package), Variant) :-
|
||||
pkg_fact(Package, variant(Variant)),
|
||||
attr("node", node(ID, Package)).
|
||||
|
||||
% Variant propagation is forwarded to dependencies
|
||||
attr("variant_propagation_candidate", PackageNode, Variant, Value, Source) :-
|
||||
attr("node", PackageNode),
|
||||
depends_on(ParentNode, PackageNode),
|
||||
attr("variant_value", node(_, Source), Variant, Value),
|
||||
attr("variant_propagation_candidate", ParentNode, Variant, _, Source).
|
||||
|
||||
% If the node is a candidate, and it has the variant and value,
|
||||
% then those variant and value should be propagated
|
||||
attr("variant_propagate", node(ID, Package), Variant, Value, Source) :-
|
||||
attr("variant_propagation_candidate", node(ID, Package), Variant, Value, Source),
|
||||
node_has_variant(node(ID, Package), Variant),
|
||||
pkg_fact(Package, variant_possible_value(Variant, Value)),
|
||||
not attr("variant_set", node(ID, Package), Variant).
|
||||
|
||||
% Propagate the value, if there is the corresponding attribute
|
||||
attr("variant_value", PackageNode, Variant, Value) :- attr("variant_propagate", PackageNode, Variant, Value, _).
|
||||
|
||||
% If a variant is propagated, we cannot have extraneous values (this is for multi valued variants)
|
||||
variant_is_propagated(PackageNode, Variant) :- attr("variant_propagate", PackageNode, Variant, _, _).
|
||||
:- variant_is_propagated(PackageNode, Variant),
|
||||
attr("variant_value", PackageNode, Variant, Value),
|
||||
not attr("variant_propagate", PackageNode, Variant, Value, _).
|
||||
|
||||
% Cannot receive different values from different sources on the same variant
|
||||
error(100, "{0} and {1} cannot both propagate variant '{2}' to package {3} with values '{4}' and '{5}'", Source1, Source2, Variant, Package, Value1, Value2) :-
|
||||
attr("variant_propagate", node(X, Package), Variant, Value1, Source1),
|
||||
attr("variant_propagate", node(X, Package), Variant, Value2, Source2),
|
||||
node_has_variant(node(X, Package), Variant),
|
||||
Value1 < Value2, Source1 < Source2.
|
||||
|
||||
% a variant cannot be set if it is not a variant on the package
|
||||
error(100, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package)
|
||||
:- attr("variant_set", node(X, Package), Variant),
|
||||
@@ -888,7 +920,7 @@ variant_not_default(node(ID, Package), Variant, Value)
|
||||
% variants set explicitly on the CLI don't count as non-default
|
||||
not attr("variant_set", node(ID, Package), Variant, Value),
|
||||
% variant values forced by propagation don't count as non-default
|
||||
not propagate(node(ID, Package), variant_value(Variant, Value)),
|
||||
not attr("variant_propagate", node(ID, Package), Variant, Value, _),
|
||||
% variants set on externals that we could use don't count as non-default
|
||||
% this makes spack prefer to use an external over rebuilding with the
|
||||
% default configuration
|
||||
@@ -901,7 +933,7 @@ variant_default_not_used(node(ID, Package), Variant, Value)
|
||||
:- variant_default_value(Package, Variant, Value),
|
||||
node_has_variant(node(ID, Package), Variant),
|
||||
not attr("variant_value", node(ID, Package), Variant, Value),
|
||||
not propagate(node(ID, Package), variant_value(Variant, _)),
|
||||
not attr("variant_propagate", node(ID, Package), Variant, _, _),
|
||||
attr("node", node(ID, Package)).
|
||||
|
||||
% The variant is set in an external spec
|
||||
@@ -958,67 +990,6 @@ pkg_fact(Package, variant_single_value("dev_path"))
|
||||
#defined variant_default_value/3.
|
||||
#defined variant_default_value_from_packages_yaml/3.
|
||||
|
||||
%-----------------------------------------------------------------------------
|
||||
% Propagation semantics
|
||||
%-----------------------------------------------------------------------------
|
||||
|
||||
% Propagation roots have a corresponding attr("propagate", ...)
|
||||
propagate(RootNode, PropagatedAttribute) :- attr("propagate", RootNode, PropagatedAttribute).
|
||||
|
||||
% Propagate an attribute along edges to child nodes
|
||||
propagate(ChildNode, PropagatedAttribute) :-
|
||||
propagate(ParentNode, PropagatedAttribute),
|
||||
depends_on(ParentNode, ChildNode).
|
||||
|
||||
%-----------------------------------------------------------------------------
|
||||
% Activation of propagated values
|
||||
%-----------------------------------------------------------------------------
|
||||
|
||||
%----
|
||||
% Variants
|
||||
%----
|
||||
|
||||
% If a variant is propagated, and can be accepted, set its value
|
||||
attr("variant_value", node(ID, Package), Variant, Value) :-
|
||||
propagate(node(ID, Package), variant_value(Variant, Value)),
|
||||
node_has_variant(node(ID, Package), Variant),
|
||||
pkg_fact(Package, variant_possible_value(Variant, Value)),
|
||||
not attr("variant_set", node(ID, Package), Variant).
|
||||
|
||||
% If a variant is propagated, we cannot have extraneous values
|
||||
variant_is_propagated(PackageNode, Variant) :-
|
||||
attr("variant_value", PackageNode, Variant, Value),
|
||||
propagate(PackageNode, variant_value(Variant, Value)),
|
||||
not attr("variant_set", PackageNode, Variant).
|
||||
|
||||
:- variant_is_propagated(PackageNode, Variant),
|
||||
attr("variant_value", PackageNode, Variant, Value),
|
||||
not propagate(PackageNode, variant_value(Variant, Value)).
|
||||
|
||||
%----
|
||||
% Compiler constraints
|
||||
%----
|
||||
|
||||
attr("node_compiler_version_satisfies", node(ID, Package), Compiler, Version) :-
|
||||
propagate(node(ID, Package), node_compiler_version_satisfies(Compiler, Version)),
|
||||
node_compiler(node(ID, Package), CompilerID),
|
||||
compiler_name(CompilerID, Compiler),
|
||||
not runtime(Package),
|
||||
not external(Package).
|
||||
|
||||
%-----------------------------------------------------------------------------
|
||||
% Runtimes
|
||||
%-----------------------------------------------------------------------------
|
||||
|
||||
% Check whether the DAG has any built package
|
||||
has_built_packages() :- build(X), not external(X).
|
||||
|
||||
% If we build packages, the runtime nodes must use an available compiler
|
||||
1 { node_compiler(PackageNode, CompilerID) : build(PackageNode), not external(PackageNode) } :-
|
||||
has_built_packages(),
|
||||
runtime(RuntimePackage),
|
||||
node_compiler(node(_, RuntimePackage), CompilerID).
|
||||
|
||||
%-----------------------------------------------------------------------------
|
||||
% Platform semantics
|
||||
%-----------------------------------------------------------------------------
|
||||
@@ -1120,15 +1091,10 @@ attr("node_target", PackageNode, Target)
|
||||
:- attr("node", PackageNode), attr("node_target_set", PackageNode, Target).
|
||||
|
||||
% each node has the weight of its assigned target
|
||||
target_weight(Target, 0)
|
||||
:- attr("node", PackageNode),
|
||||
attr("node_target", PackageNode, Target),
|
||||
attr("node_target_set", PackageNode, Target).
|
||||
|
||||
node_target_weight(PackageNode, MinWeight)
|
||||
:- attr("node", PackageNode),
|
||||
attr("node_target", PackageNode, Target),
|
||||
MinWeight = #min { Weight : target_weight(Target, Weight) }.
|
||||
node_target_weight(node(ID, Package), Weight)
|
||||
:- attr("node", node(ID, Package)),
|
||||
attr("node_target", node(ID, Package), Target),
|
||||
target_weight(Target, Weight).
|
||||
|
||||
% compatibility rules for targets among nodes
|
||||
node_target_match(ParentNode, DependencyNode)
|
||||
@@ -1190,12 +1156,12 @@ error(10, "No valid compiler for {0} satisfies '%{1}'", Package, Compiler)
|
||||
|
||||
% If the compiler of a node must satisfy a constraint, then its version
|
||||
% must be chosen among the ones that satisfy said constraint
|
||||
error(100, "Package {0} cannot satisfy '%{1}@{2}'", Package, Compiler, Constraint)
|
||||
error(100, "No valid version for '{0}' compiler '{1}' satisfies '@{2}'", Package, Compiler, Constraint)
|
||||
:- attr("node", node(X, Package)),
|
||||
attr("node_compiler_version_satisfies", node(X, Package), Compiler, Constraint),
|
||||
not compiler_version_satisfies(Compiler, Constraint, _).
|
||||
not compiler_version_satisfies(Compiler, Constraint, _).
|
||||
|
||||
error(100, "Package {0} cannot satisfy '%{1}@{2}'", Package, Compiler, Constraint)
|
||||
error(100, "No valid version for '{0}' compiler '{1}' satisfies '@{2}'", Package, Compiler, Constraint)
|
||||
:- attr("node", node(X, Package)),
|
||||
attr("node_compiler_version_satisfies", node(X, Package), Compiler, Constraint),
|
||||
not compiler_version_satisfies(Compiler, Constraint, ID),
|
||||
@@ -1531,7 +1497,7 @@ opt_criterion(45, "preferred providers (non-roots)").
|
||||
}.
|
||||
|
||||
% Try to minimize the number of compiler mismatches in the DAG.
|
||||
opt_criterion(40, "compiler mismatches that are not required").
|
||||
opt_criterion(40, "compiler mismatches that are not from CLI").
|
||||
#minimize{ 0@240: #true }.
|
||||
#minimize{ 0@40: #true }.
|
||||
#minimize{
|
||||
@@ -1541,7 +1507,7 @@ opt_criterion(40, "compiler mismatches that are not required").
|
||||
not runtime(Dependency)
|
||||
}.
|
||||
|
||||
opt_criterion(39, "compiler mismatches that are required").
|
||||
opt_criterion(39, "compiler mismatches that are not from CLI").
|
||||
#minimize{ 0@239: #true }.
|
||||
#minimize{ 0@39: #true }.
|
||||
#minimize{
|
||||
|
||||
@@ -4,35 +4,21 @@
|
||||
% SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
%=============================================================================
|
||||
% Heuristic to speed-up solves
|
||||
% Heuristic to speed-up solves (node with ID 0)
|
||||
%=============================================================================
|
||||
|
||||
% No duplicates by default (most of them will be true)
|
||||
#heuristic attr("node", node(PackageID, Package)). [100, init]
|
||||
#heuristic attr("node", node(PackageID, Package)). [ 2, factor]
|
||||
#heuristic attr("virtual_node", node(VirtualID, Virtual)). [100, init]
|
||||
#heuristic attr("node", node(1..X-1, Package)) : max_dupes(Package, X), not virtual(Package), X > 1. [-1, sign]
|
||||
#heuristic attr("virtual_node", node(1..X-1, Package)) : max_dupes(Package, X), virtual(Package) , X > 1. [-1, sign]
|
||||
|
||||
% Pick preferred version
|
||||
#heuristic attr("version", node(PackageID, Package), Version) : pkg_fact(Package, version_declared(Version, Weight)), attr("node", node(PackageID, Package)). [40, init]
|
||||
#heuristic version_weight(node(PackageID, Package), 0) : pkg_fact(Package, version_declared(Version, 0 )), attr("node", node(PackageID, Package)). [ 1, sign]
|
||||
#heuristic attr("version", node(PackageID, Package), Version) : pkg_fact(Package, version_declared(Version, 0 )), attr("node", node(PackageID, Package)). [ 1, sign]
|
||||
#heuristic attr("version", node(PackageID, Package), Version) : pkg_fact(Package, version_declared(Version, Weight)), attr("node", node(PackageID, Package)), Weight > 0. [-1, sign]
|
||||
%-----------------
|
||||
% Domain heuristic
|
||||
%-----------------
|
||||
|
||||
% Use default variants
|
||||
#heuristic attr("variant_value", node(PackageID, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("node", node(PackageID, Package)). [40, true]
|
||||
#heuristic attr("variant_value", node(PackageID, Package), Variant, Value) : not variant_default_value(Package, Variant, Value), attr("node", node(PackageID, Package)). [40, false]
|
||||
% Root node
|
||||
#heuristic attr("version", node(0, Package), Version) : pkg_fact(Package, version_declared(Version, 0)), attr("root", node(0, Package)). [35, true]
|
||||
#heuristic version_weight(node(0, Package), 0) : pkg_fact(Package, version_declared(Version, 0)), attr("root", node(0, Package)). [35, true]
|
||||
#heuristic attr("variant_value", node(0, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("root", node(0, Package)). [35, true]
|
||||
#heuristic attr("node_target", node(0, Package), Target) : target_weight(Target, 0), attr("root", node(0, Package)). [35, true]
|
||||
#heuristic node_target_weight(node(0, Package), 0) : attr("root", node(0, Package)). [35, true]
|
||||
#heuristic node_compiler(node(0, Package), CompilerID) : compiler_weight(ID, 0), compiler_id(ID), attr("root", node(0, Package)). [35, true]
|
||||
|
||||
% Use default operating system and platform
|
||||
#heuristic attr("node_os", node(PackageID, Package), OS) : os(OS, 0), attr("root", node(PackageID, Package)). [40, true]
|
||||
#heuristic attr("node_platform", node(PackageID, Package), Platform) : allowed_platform(Platform), attr("root", node(PackageID, Package)). [40, true]
|
||||
|
||||
% Use default targets
|
||||
#heuristic attr("node_target", node(PackageID, Package), Target) : target_weight(Target, Weight), attr("node", node(PackageID, Package)). [30, init]
|
||||
#heuristic attr("node_target", node(PackageID, Package), Target) : target_weight(Target, Weight), attr("node", node(PackageID, Package)). [ 2, factor]
|
||||
#heuristic attr("node_target", node(PackageID, Package), Target) : target_weight(Target, 0), attr("node", node(PackageID, Package)). [ 1, sign]
|
||||
#heuristic attr("node_target", node(PackageID, Package), Target) : target_weight(Target, Weight), attr("node", node(PackageID, Package)), Weight > 0. [-1, sign]
|
||||
|
||||
% Use the default compilers
|
||||
#heuristic node_compiler(node(PackageID, Package), ID) : compiler_weight(ID, 0), compiler_id(ID), attr("node", node(PackageID, Package)). [30, init]
|
||||
% Providers
|
||||
#heuristic attr("node", node(0, Package)) : default_provider_preference(Virtual, Package, 0), possible_in_link_run(Package). [30, true]
|
||||
|
||||
24
lib/spack/spack/solver/heuristic_separate.lp
Normal file
24
lib/spack/spack/solver/heuristic_separate.lp
Normal file
@@ -0,0 +1,24 @@
|
||||
% Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
|
||||
% Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
%
|
||||
% SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
%=============================================================================
|
||||
% Heuristic to speed-up solves (node with ID > 0)
|
||||
%=============================================================================
|
||||
|
||||
% node(ID, _)
|
||||
#heuristic attr("version", node(ID, Package), Version) : pkg_fact(Package, version_declared(Version, 0)), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
||||
#heuristic version_weight(node(ID, Package), 0) : pkg_fact(Package, version_declared(Version, 0)), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
||||
#heuristic attr("variant_value", node(ID, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
||||
#heuristic attr("node_target", node(ID, Package), Target) : pkg_fact(Package, target_weight(Target, 0)), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
||||
#heuristic node_target_weight(node(ID, Package), 0) : attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
||||
#heuristic node_compiler(node(ID, Package), CompilerID) : compiler_weight(CompilerID, 0), compiler_id(CompilerID), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
||||
|
||||
% node(ID, _), split build dependencies
|
||||
#heuristic attr("version", node(ID, Package), Version) : pkg_fact(Package, version_declared(Version, 0)), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||
#heuristic version_weight(node(ID, Package), 0) : pkg_fact(Package, version_declared(Version, 0)), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||
#heuristic attr("variant_value", node(ID, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||
#heuristic attr("node_target", node(ID, Package), Target) : pkg_fact(Package, target_weight(Target, 0)), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||
#heuristic node_target_weight(node(ID, Package), 0) : attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||
#heuristic node_compiler(node(ID, Package), CompilerID) : compiler_weight(CompilerID, 0), compiler_id(CompilerID), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||
@@ -18,15 +18,26 @@ error(100, "Cannot reuse {0} since we cannot determine libc compatibility", Reus
|
||||
ReusedPackage != LibcPackage,
|
||||
not attr("compatible_libc", node(R, ReusedPackage), LibcPackage, LibcVersion).
|
||||
|
||||
% Check whether the DAG has any built package
|
||||
has_built_packages() :- build(X), not external(X).
|
||||
|
||||
% A libc is needed in the DAG
|
||||
:- has_built_packages(), not provider(_, node(0, "libc")).
|
||||
|
||||
% The libc must be chosen among available ones
|
||||
% Non-libc reused specs must be host libc compatible. In case we build packages, we get a
|
||||
% host compatible libc provider from other rules. If nothing is built, there is no libc provider,
|
||||
% since it's pruned from reusable specs, meaning we have to explicitly impose reused specs are host
|
||||
% compatible.
|
||||
:- attr("hash", node(R, ReusedPackage), Hash),
|
||||
not provider(node(R, ReusedPackage), node(0, "libc")),
|
||||
not attr("compatible_libc", node(R, ReusedPackage), _, _).
|
||||
|
||||
% The libc provider must be one that a compiler can target
|
||||
:- has_built_packages(),
|
||||
provider(node(X, LibcPackage), node(0, "libc")),
|
||||
attr("node", node(X, LibcPackage)),
|
||||
attr("version", node(X, LibcPackage), LibcVersion),
|
||||
not allowed_libc(LibcPackage, LibcVersion).
|
||||
not host_libc(LibcPackage, LibcVersion).
|
||||
|
||||
% A built node must depend on libc
|
||||
:- build(PackageNode),
|
||||
|
||||
@@ -1287,6 +1287,102 @@ def copy(self, *args, **kwargs):
|
||||
return self.wrapped_obj.copy(*args, **kwargs)
|
||||
|
||||
|
||||
def tree(
|
||||
specs: List["spack.spec.Spec"],
|
||||
*,
|
||||
color: Optional[bool] = None,
|
||||
depth: bool = False,
|
||||
hashes: bool = False,
|
||||
hashlen: Optional[int] = None,
|
||||
cover: str = "nodes",
|
||||
indent: int = 0,
|
||||
format: str = DEFAULT_FORMAT,
|
||||
deptypes: Union[Tuple[str, ...], str] = "all",
|
||||
show_types: bool = False,
|
||||
depth_first: bool = False,
|
||||
recurse_dependencies: bool = True,
|
||||
status_fn: Optional[Callable[["Spec"], InstallStatus]] = None,
|
||||
prefix: Optional[Callable[["Spec"], str]] = None,
|
||||
key=id,
|
||||
) -> str:
|
||||
"""Prints out specs and their dependencies, tree-formatted with indentation.
|
||||
|
||||
Status function may either output a boolean or an InstallStatus
|
||||
|
||||
Args:
|
||||
color: if True, always colorize the tree. If False, don't colorize the tree. If None,
|
||||
use the default from llnl.tty.color
|
||||
depth: print the depth from the root
|
||||
hashes: if True, print the hash of each node
|
||||
hashlen: length of the hash to be printed
|
||||
cover: either "nodes" or "edges"
|
||||
indent: extra indentation for the tree being printed
|
||||
format: format to be used to print each node
|
||||
deptypes: dependency types to be represented in the tree
|
||||
show_types: if True, show the (merged) dependency type of a node
|
||||
depth_first: if True, traverse the DAG depth first when representing it as a tree
|
||||
recurse_dependencies: if True, recurse on dependencies
|
||||
status_fn: optional callable that takes a node as an argument and return its
|
||||
installation status
|
||||
prefix: optional callable that takes a node as an argument and return its
|
||||
installation prefix
|
||||
"""
|
||||
out = ""
|
||||
|
||||
if color is None:
|
||||
color = clr.get_color_when()
|
||||
|
||||
for d, dep_spec in traverse.traverse_tree(
|
||||
sorted(specs), cover=cover, deptype=deptypes, depth_first=depth_first, key=key
|
||||
):
|
||||
node = dep_spec.spec
|
||||
|
||||
if prefix is not None:
|
||||
out += prefix(node)
|
||||
out += " " * indent
|
||||
|
||||
if depth:
|
||||
out += "%-4d" % d
|
||||
|
||||
if status_fn:
|
||||
status = status_fn(node)
|
||||
if status in list(InstallStatus):
|
||||
out += clr.colorize(status.value, color=color)
|
||||
elif status:
|
||||
out += clr.colorize("@g{[+]} ", color=color)
|
||||
else:
|
||||
out += clr.colorize("@r{[-]} ", color=color)
|
||||
|
||||
if hashes:
|
||||
out += clr.colorize("@K{%s} ", color=color) % node.dag_hash(hashlen)
|
||||
|
||||
if show_types:
|
||||
if cover == "nodes":
|
||||
# when only covering nodes, we merge dependency types
|
||||
# from all dependents before showing them.
|
||||
depflag = 0
|
||||
for ds in node.edges_from_dependents():
|
||||
depflag |= ds.depflag
|
||||
else:
|
||||
# when covering edges or paths, we show dependency
|
||||
# types only for the edge through which we visited
|
||||
depflag = dep_spec.depflag
|
||||
|
||||
type_chars = dt.flag_to_chars(depflag)
|
||||
out += "[%s] " % type_chars
|
||||
|
||||
out += " " * d
|
||||
if d > 0:
|
||||
out += "^"
|
||||
out += node.format(format, color=color) + "\n"
|
||||
|
||||
# Check if we wanted just the first line
|
||||
if not recurse_dependencies:
|
||||
break
|
||||
|
||||
return out
|
||||
|
||||
|
||||
@lang.lazy_lexicographic_ordering(set_hash=False)
|
||||
class Spec:
|
||||
#: Cache for spec's prefix, computed lazily in the corresponding property
|
||||
@@ -2816,9 +2912,7 @@ def _old_concretize(self, tests=False, deprecation_warning=True):
|
||||
|
||||
# Check if we can produce an optimized binary (will throw if
|
||||
# there are declared inconsistencies)
|
||||
# No need on platform=cray because of the targeting modules
|
||||
if not self.satisfies("platform=cray"):
|
||||
self.architecture.target.optimization_flags(self.compiler)
|
||||
self.architecture.target.optimization_flags(self.compiler)
|
||||
|
||||
def _patches_assigned(self):
|
||||
"""Whether patches have been assigned to this spec by the concretizer."""
|
||||
@@ -4606,13 +4700,14 @@ def tree(
|
||||
recurse_dependencies: bool = True,
|
||||
status_fn: Optional[Callable[["Spec"], InstallStatus]] = None,
|
||||
prefix: Optional[Callable[["Spec"], str]] = None,
|
||||
key=id,
|
||||
) -> str:
|
||||
"""Prints out this spec and its dependencies, tree-formatted
|
||||
with indentation.
|
||||
"""Prints out this spec and its dependencies, tree-formatted with indentation.
|
||||
|
||||
Status function may either output a boolean or an InstallStatus
|
||||
See multi-spec ``spack.spec.tree()`` function for details.
|
||||
|
||||
Args:
|
||||
specs: List of specs to format.
|
||||
color: if True, always colorize the tree. If False, don't colorize the tree. If None,
|
||||
use the default from llnl.tty.color
|
||||
depth: print the depth from the root
|
||||
@@ -4630,60 +4725,23 @@ def tree(
|
||||
prefix: optional callable that takes a node as an argument and return its
|
||||
installation prefix
|
||||
"""
|
||||
out = ""
|
||||
|
||||
if color is None:
|
||||
color = clr.get_color_when()
|
||||
|
||||
for d, dep_spec in traverse.traverse_tree(
|
||||
[self], cover=cover, deptype=deptypes, depth_first=depth_first
|
||||
):
|
||||
node = dep_spec.spec
|
||||
|
||||
if prefix is not None:
|
||||
out += prefix(node)
|
||||
out += " " * indent
|
||||
|
||||
if depth:
|
||||
out += "%-4d" % d
|
||||
|
||||
if status_fn:
|
||||
status = status_fn(node)
|
||||
if status in list(InstallStatus):
|
||||
out += clr.colorize(status.value, color=color)
|
||||
elif status:
|
||||
out += clr.colorize("@g{[+]} ", color=color)
|
||||
else:
|
||||
out += clr.colorize("@r{[-]} ", color=color)
|
||||
|
||||
if hashes:
|
||||
out += clr.colorize("@K{%s} ", color=color) % node.dag_hash(hashlen)
|
||||
|
||||
if show_types:
|
||||
if cover == "nodes":
|
||||
# when only covering nodes, we merge dependency types
|
||||
# from all dependents before showing them.
|
||||
depflag = 0
|
||||
for ds in node.edges_from_dependents():
|
||||
depflag |= ds.depflag
|
||||
else:
|
||||
# when covering edges or paths, we show dependency
|
||||
# types only for the edge through which we visited
|
||||
depflag = dep_spec.depflag
|
||||
|
||||
type_chars = dt.flag_to_chars(depflag)
|
||||
out += "[%s] " % type_chars
|
||||
|
||||
out += " " * d
|
||||
if d > 0:
|
||||
out += "^"
|
||||
out += node.format(format, color=color) + "\n"
|
||||
|
||||
# Check if we wanted just the first line
|
||||
if not recurse_dependencies:
|
||||
break
|
||||
|
||||
return out
|
||||
return tree(
|
||||
[self],
|
||||
color=color,
|
||||
depth=depth,
|
||||
hashes=hashes,
|
||||
hashlen=hashlen,
|
||||
cover=cover,
|
||||
indent=indent,
|
||||
format=format,
|
||||
deptypes=deptypes,
|
||||
show_types=show_types,
|
||||
depth_first=depth_first,
|
||||
recurse_dependencies=recurse_dependencies,
|
||||
status_fn=status_fn,
|
||||
prefix=prefix,
|
||||
key=key,
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
@@ -346,6 +346,8 @@ class Stage(LockableStagingDir):
|
||||
similar, and are intended to persist for only one run of spack.
|
||||
"""
|
||||
|
||||
#: Most staging is managed by Spack. DIYStage is one exception.
|
||||
needs_fetching = True
|
||||
requires_patch_success = True
|
||||
|
||||
def __init__(
|
||||
@@ -770,6 +772,8 @@ def __init__(self):
|
||||
"cache_mirror",
|
||||
"steal_source",
|
||||
"disable_mirrors",
|
||||
"needs_fetching",
|
||||
"requires_patch_success",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -808,10 +812,6 @@ def path(self):
|
||||
def archive_file(self):
|
||||
return self[0].archive_file
|
||||
|
||||
@property
|
||||
def requires_patch_success(self):
|
||||
return self[0].requires_patch_success
|
||||
|
||||
@property
|
||||
def keep(self):
|
||||
return self[0].keep
|
||||
@@ -822,7 +822,64 @@ def keep(self, value):
|
||||
item.keep = value
|
||||
|
||||
|
||||
class DIYStage:
|
||||
"""
|
||||
Simple class that allows any directory to be a spack stage. Consequently,
|
||||
it does not expect or require that the source path adhere to the standard
|
||||
directory naming convention.
|
||||
"""
|
||||
|
||||
needs_fetching = False
|
||||
requires_patch_success = False
|
||||
|
||||
def __init__(self, path):
|
||||
if path is None:
|
||||
raise ValueError("Cannot construct DIYStage without a path.")
|
||||
elif not os.path.isdir(path):
|
||||
raise StagePathError("The stage path directory does not exist:", path)
|
||||
|
||||
self.archive_file = None
|
||||
self.path = path
|
||||
self.source_path = path
|
||||
self.created = True
|
||||
|
||||
# DIY stages do nothing as context managers.
|
||||
def __enter__(self):
|
||||
pass
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
pass
|
||||
|
||||
def fetch(self, *args, **kwargs):
|
||||
tty.debug("No need to fetch for DIY.")
|
||||
|
||||
def check(self):
|
||||
tty.debug("No checksum needed for DIY.")
|
||||
|
||||
def expand_archive(self):
|
||||
tty.debug("Using source directory: {0}".format(self.source_path))
|
||||
|
||||
@property
|
||||
def expanded(self):
|
||||
"""Returns True since the source_path must exist."""
|
||||
return True
|
||||
|
||||
def restage(self):
|
||||
raise RestageError("Cannot restage a DIY stage.")
|
||||
|
||||
def create(self):
|
||||
self.created = True
|
||||
|
||||
def destroy(self):
|
||||
# No need to destroy DIY stage.
|
||||
pass
|
||||
|
||||
def cache_local(self):
|
||||
tty.debug("Sources for DIY stages are not cached")
|
||||
|
||||
|
||||
class DevelopStage(LockableStagingDir):
|
||||
needs_fetching = False
|
||||
requires_patch_success = False
|
||||
|
||||
def __init__(self, name, dev_path, reference_link):
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import archspec.cpu
|
||||
|
||||
import llnl.util.filesystem as fs
|
||||
|
||||
import spack.compilers
|
||||
import spack.concretize
|
||||
import spack.operating_systems
|
||||
@@ -25,9 +21,8 @@ def current_host_platform():
|
||||
"""Return the platform of the current host as detected by the
|
||||
'platform' stdlib package.
|
||||
"""
|
||||
if os.path.exists("/opt/cray/pe"):
|
||||
current_platform = spack.platforms.Cray()
|
||||
elif "Linux" in platform.system():
|
||||
current_platform = None
|
||||
if "Linux" in platform.system():
|
||||
current_platform = spack.platforms.Linux()
|
||||
elif "Darwin" in platform.system():
|
||||
current_platform = spack.platforms.Darwin()
|
||||
@@ -222,28 +217,3 @@ def test_concretize_target_ranges(root_target_range, dep_target_range, result, m
|
||||
with spack.concretize.disable_compiler_existence_check():
|
||||
spec.concretize()
|
||||
assert spec.target == spec["b"].target == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"versions,default,expected",
|
||||
[
|
||||
(["21.11", "21.9"], "21.11", False),
|
||||
(["21.11", "21.9"], "21.9", True),
|
||||
(["21.11", "21.9"], None, False),
|
||||
],
|
||||
)
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="Cray does not use windows")
|
||||
def test_cray_platform_detection(versions, default, expected, tmpdir, monkeypatch, working_env):
|
||||
ex_path = str(tmpdir.join("fake_craype_dir"))
|
||||
fs.mkdirp(ex_path)
|
||||
|
||||
with fs.working_dir(ex_path):
|
||||
for version in versions:
|
||||
fs.touch(version)
|
||||
if default:
|
||||
os.symlink(default, "default")
|
||||
|
||||
monkeypatch.setattr(spack.platforms.cray, "_ex_craype_dir", ex_path)
|
||||
os.environ["MODULEPATH"] = "/opt/cray/pe"
|
||||
|
||||
assert spack.platforms.cray.Cray.detect() == expected
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
(["missing-dependency"], ["PKG-DIRECTIVES", "PKG-PROPERTIES"]),
|
||||
# The package use a non existing variant in a depends_on directive
|
||||
(["wrong-variant-in-depends-on"], ["PKG-DIRECTIVES", "PKG-PROPERTIES"]),
|
||||
# This package has a GitHub pull request commit patch URL
|
||||
(["invalid-github-pull-commits-patch-url"], ["PKG-DIRECTIVES", "PKG-PROPERTIES"]),
|
||||
# This package has a GitHub patch URL without full_index=1
|
||||
(["invalid-github-patch-url"], ["PKG-DIRECTIVES", "PKG-PROPERTIES"]),
|
||||
# This package has invalid GitLab patch URLs
|
||||
|
||||
@@ -556,24 +556,6 @@ def test_build_jobs_defaults():
|
||||
)
|
||||
|
||||
|
||||
def test_dirty_disable_module_unload(config, mock_packages, working_env, mock_module_cmd):
|
||||
"""Test that on CRAY platform 'module unload' is not called if the 'dirty'
|
||||
option is on.
|
||||
"""
|
||||
s = spack.spec.Spec("a").concretized()
|
||||
|
||||
# If called with "dirty" we don't unload modules, so no calls to the
|
||||
# `module` function on Cray
|
||||
spack.build_environment.setup_package(s.package, dirty=True)
|
||||
assert not mock_module_cmd.calls
|
||||
|
||||
# If called without "dirty" we unload modules on Cray
|
||||
spack.build_environment.setup_package(s.package, dirty=False)
|
||||
assert mock_module_cmd.calls
|
||||
assert any(("unload", "cray-libsci") == item[0] for item in mock_module_cmd.calls)
|
||||
assert any(("unload", "cray-mpich") == item[0] for item in mock_module_cmd.calls)
|
||||
|
||||
|
||||
class TestModuleMonkeyPatcher:
|
||||
def test_getting_attributes(self, default_mock_concretization):
|
||||
s = default_mock_concretization("libelf")
|
||||
|
||||
@@ -12,21 +12,21 @@
|
||||
|
||||
def test_build_task_errors(install_mockery):
|
||||
with pytest.raises(ValueError, match="must be a package"):
|
||||
inst.BuildTask("abc", None, False, 0, 0, 0, [])
|
||||
inst.BuildTask("abc", None, False, 0, 0, 0, set())
|
||||
|
||||
spec = spack.spec.Spec("trivial-install-test-package")
|
||||
pkg_cls = spack.repo.PATH.get_pkg_class(spec.name)
|
||||
with pytest.raises(ValueError, match="must have a concrete spec"):
|
||||
inst.BuildTask(pkg_cls(spec), None, False, 0, 0, 0, [])
|
||||
inst.BuildTask(pkg_cls(spec), None, False, 0, 0, 0, set())
|
||||
|
||||
spec.concretize()
|
||||
assert spec.concrete
|
||||
with pytest.raises(ValueError, match="must have a build request"):
|
||||
inst.BuildTask(spec.package, None, False, 0, 0, 0, [])
|
||||
inst.BuildTask(spec.package, None, False, 0, 0, 0, set())
|
||||
|
||||
request = inst.BuildRequest(spec.package, {})
|
||||
with pytest.raises(inst.InstallError, match="Cannot create a build task"):
|
||||
inst.BuildTask(spec.package, request, False, 0, 0, inst.STATUS_REMOVED, [])
|
||||
inst.BuildTask(spec.package, request, False, 0, 0, inst.STATUS_REMOVED, set())
|
||||
|
||||
|
||||
def test_build_task_basics(install_mockery):
|
||||
@@ -36,8 +36,8 @@ def test_build_task_basics(install_mockery):
|
||||
|
||||
# Ensure key properties match expectations
|
||||
request = inst.BuildRequest(spec.package, {})
|
||||
task = inst.BuildTask(spec.package, request, False, 0, 0, inst.STATUS_ADDED, [])
|
||||
assert task.explicit # package was "explicitly" requested
|
||||
task = inst.BuildTask(spec.package, request, False, 0, 0, inst.STATUS_ADDED, set())
|
||||
assert not task.explicit
|
||||
assert task.priority == len(task.uninstalled_deps)
|
||||
assert task.key == (task.priority, task.sequence)
|
||||
|
||||
@@ -58,7 +58,7 @@ def test_build_task_strings(install_mockery):
|
||||
|
||||
# Ensure key properties match expectations
|
||||
request = inst.BuildRequest(spec.package, {})
|
||||
task = inst.BuildTask(spec.package, request, False, 0, 0, inst.STATUS_ADDED, [])
|
||||
task = inst.BuildTask(spec.package, request, False, 0, 0, inst.STATUS_ADDED, set())
|
||||
|
||||
# Cover __repr__
|
||||
irep = task.__repr__()
|
||||
|
||||
@@ -828,14 +828,14 @@ def test_keep_and_replace(wrapper_environment):
|
||||
),
|
||||
(
|
||||
"config:flags:keep_werror:specific",
|
||||
["-Werror", "-Werror=specific", "-bah"],
|
||||
["-Werror=specific", "-bah"],
|
||||
["-Werror", "-Werror=specific", "-Werror-specific2", "-bah"],
|
||||
["-Wno-error", "-Werror=specific", "-Werror-specific2", "-bah"],
|
||||
["-Werror"],
|
||||
),
|
||||
(
|
||||
"config:flags:keep_werror:none",
|
||||
["-Werror", "-Werror=specific", "-bah"],
|
||||
["-bah", "-Wno-error", "-Wno-error=specific"],
|
||||
["-Wno-error", "-Wno-error=specific", "-bah"],
|
||||
["-Werror", "-Werror=specific"],
|
||||
),
|
||||
# check non-standard -Werror opts like -Werror-implicit-function-declaration
|
||||
@@ -848,13 +848,13 @@ def test_keep_and_replace(wrapper_environment):
|
||||
(
|
||||
"config:flags:keep_werror:specific",
|
||||
["-Werror", "-Werror-implicit-function-declaration", "-bah"],
|
||||
["-Werror-implicit-function-declaration", "-bah", "-Wno-error"],
|
||||
["-Wno-error", "-Werror-implicit-function-declaration", "-bah"],
|
||||
["-Werror"],
|
||||
),
|
||||
(
|
||||
"config:flags:keep_werror:none",
|
||||
["-Werror", "-Werror-implicit-function-declaration", "-bah"],
|
||||
["-bah", "-Wno-error=implicit-function-declaration"],
|
||||
["-Wno-error", "-bah", "-Wno-error=implicit-function-declaration"],
|
||||
["-Werror", "-Werror-implicit-function-declaration"],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
import spack.caches
|
||||
import spack.cmd.clean
|
||||
import spack.environment as ev
|
||||
import spack.main
|
||||
import spack.package_base
|
||||
import spack.stage
|
||||
@@ -68,6 +69,20 @@ def test_function_calls(command_line, effects, mock_calls_for_clean):
|
||||
assert mock_calls_for_clean[name] == (1 if name in effects else 0)
|
||||
|
||||
|
||||
def test_env_aware_clean(mock_stage, install_mockery, mutable_mock_env_path, monkeypatch):
|
||||
e = ev.create("test", with_view=False)
|
||||
e.add("mpileaks")
|
||||
e.concretize()
|
||||
|
||||
def fail(*args, **kwargs):
|
||||
raise Exception("This should not have been called")
|
||||
|
||||
monkeypatch.setattr(spack.spec.Spec, "concretize", fail)
|
||||
|
||||
with e:
|
||||
clean("mpileaks")
|
||||
|
||||
|
||||
def test_remove_python_cache(tmpdir, monkeypatch):
|
||||
cache_files = ["file1.pyo", "file2.pyc"]
|
||||
source_file = "file1.py"
|
||||
|
||||
@@ -125,18 +125,8 @@ def print_spack_cc(*args):
|
||||
print(os.environ.get("CC", ""))
|
||||
|
||||
|
||||
# `module unload cray-libsci` in test environment causes failure
|
||||
# It does not fail for actual installs
|
||||
# build_environment.py imports module directly, so we monkeypatch it there
|
||||
# rather than in module_cmd
|
||||
def mock_module_noop(*args):
|
||||
pass
|
||||
|
||||
|
||||
def test_dev_build_drop_in(tmpdir, mock_packages, monkeypatch, install_mockery, working_env):
|
||||
monkeypatch.setattr(os, "execvp", print_spack_cc)
|
||||
monkeypatch.setattr(spack.build_environment, "module", mock_module_noop)
|
||||
|
||||
with tmpdir.as_cwd():
|
||||
output = dev_build("-b", "edit", "--drop-in", "sh", "dev-build-test-install@0.0.0")
|
||||
assert "lib/spack/env" in output
|
||||
|
||||
46
lib/spack/spack/test/cmd/edit.py
Normal file
46
lib/spack/spack/test/cmd/edit.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import os
|
||||
|
||||
import spack.paths
|
||||
import spack.repo
|
||||
import spack.util.editor
|
||||
from spack.build_systems import autotools, cmake
|
||||
from spack.main import SpackCommand
|
||||
|
||||
edit = SpackCommand("edit")
|
||||
|
||||
|
||||
def test_edit_packages(monkeypatch, mock_packages: spack.repo.RepoPath):
|
||||
"""Test spack edit a b"""
|
||||
path_a = mock_packages.filename_for_package_name("a")
|
||||
path_b = mock_packages.filename_for_package_name("b")
|
||||
called = False
|
||||
|
||||
def editor(*args: str, **kwargs):
|
||||
nonlocal called
|
||||
called = True
|
||||
assert args[0] == path_a
|
||||
assert args[1] == path_b
|
||||
|
||||
monkeypatch.setattr(spack.util.editor, "editor", editor)
|
||||
edit("a", "b")
|
||||
assert called
|
||||
|
||||
|
||||
def test_edit_files(monkeypatch):
|
||||
"""Test spack edit --build-system autotools cmake"""
|
||||
called = False
|
||||
|
||||
def editor(*args: str, **kwargs):
|
||||
nonlocal called
|
||||
called = True
|
||||
assert os.path.samefile(args[0], autotools.__file__)
|
||||
assert os.path.samefile(args[1], cmake.__file__)
|
||||
|
||||
monkeypatch.setattr(spack.util.editor, "editor", editor)
|
||||
edit("--build-system", "autotools", "cmake")
|
||||
assert called
|
||||
@@ -384,9 +384,18 @@ def test_clang_flags():
|
||||
unsupported_flag_test("cxx17_flag", "clang@3.4")
|
||||
supported_flag_test("cxx17_flag", "-std=c++1z", "clang@3.5")
|
||||
supported_flag_test("cxx17_flag", "-std=c++17", "clang@5.0")
|
||||
unsupported_flag_test("cxx20_flag", "clang@4.0")
|
||||
supported_flag_test("cxx20_flag", "-std=c++2a", "clang@5.0")
|
||||
supported_flag_test("cxx20_flag", "-std=c++20", "clang@11.0")
|
||||
unsupported_flag_test("cxx23_flag", "clang@11.0")
|
||||
supported_flag_test("cxx23_flag", "-std=c++2b", "clang@12.0")
|
||||
supported_flag_test("cxx23_flag", "-std=c++23", "clang@17.0")
|
||||
supported_flag_test("c99_flag", "-std=c99", "clang@3.3")
|
||||
unsupported_flag_test("c11_flag", "clang@2.0")
|
||||
supported_flag_test("c11_flag", "-std=c11", "clang@6.1.0")
|
||||
unsupported_flag_test("c23_flag", "clang@8.0")
|
||||
supported_flag_test("c23_flag", "-std=c2x", "clang@9.0")
|
||||
supported_flag_test("c23_flag", "-std=c23", "clang@18.0")
|
||||
supported_flag_test("cc_pic_flag", "-fPIC", "clang@3.3")
|
||||
supported_flag_test("cxx_pic_flag", "-fPIC", "clang@3.3")
|
||||
supported_flag_test("f77_pic_flag", "-fPIC", "clang@3.3")
|
||||
|
||||
@@ -3,12 +3,8 @@
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
"""Test detection of compiler version"""
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import llnl.util.filesystem as fs
|
||||
|
||||
import spack.compilers.aocc
|
||||
import spack.compilers.arm
|
||||
import spack.compilers.cce
|
||||
@@ -23,7 +19,6 @@
|
||||
import spack.compilers.xl
|
||||
import spack.compilers.xl_r
|
||||
import spack.util.module_cmd
|
||||
from spack.operating_systems.cray_frontend import CrayFrontend
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -413,48 +408,6 @@ def test_xl_version_detection(version_str, expected_version):
|
||||
assert version == expected_version
|
||||
|
||||
|
||||
@pytest.mark.not_on_windows("Not supported on Windows (yet)")
|
||||
@pytest.mark.parametrize(
|
||||
"compiler,version",
|
||||
[
|
||||
("gcc", "8.1.0"),
|
||||
("gcc", "1.0.0-foo"),
|
||||
("pgi", "19.1"),
|
||||
("pgi", "19.1a"),
|
||||
("intel", "9.0.0"),
|
||||
("intel", "0.0.0-foobar"),
|
||||
# ('oneapi', '2021.1'),
|
||||
# ('oneapi', '2021.1-foobar')
|
||||
],
|
||||
)
|
||||
def test_cray_frontend_compiler_detection(compiler, version, tmpdir, monkeypatch, working_env):
|
||||
"""Test that the Cray frontend properly finds compilers form modules"""
|
||||
# setup the fake compiler directory
|
||||
compiler_dir = tmpdir.join(compiler)
|
||||
compiler_exe = compiler_dir.join("cc").ensure()
|
||||
fs.set_executable(str(compiler_exe))
|
||||
|
||||
# mock modules
|
||||
def _module(cmd, *args):
|
||||
module_name = "%s/%s" % (compiler, version)
|
||||
module_contents = "prepend-path PATH %s" % compiler_dir
|
||||
if cmd == "avail":
|
||||
return module_name if compiler in args[0] else ""
|
||||
if cmd == "show":
|
||||
return module_contents if module_name in args else ""
|
||||
|
||||
monkeypatch.setattr(spack.operating_systems.cray_frontend, "module", _module)
|
||||
|
||||
# remove PATH variable
|
||||
os.environ.pop("PATH", None)
|
||||
|
||||
# get a CrayFrontend object
|
||||
cray_fe_os = CrayFrontend()
|
||||
|
||||
paths = cray_fe_os.compiler_search_paths
|
||||
assert paths == [str(compiler_dir)]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"version_str,expected_version",
|
||||
[
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
import spack.variant as vt
|
||||
from spack.concretize import find_spec
|
||||
from spack.spec import CompilerSpec, Spec
|
||||
from spack.version import Version, ver
|
||||
from spack.version import Version, VersionList, ver
|
||||
|
||||
|
||||
def check_spec(abstract, concrete):
|
||||
@@ -1767,21 +1767,21 @@ def test_reuse_with_unknown_package_dont_raise(self, tmpdir, temporary_store, mo
|
||||
assert s.namespace == "builtin.mock"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"specs,expected,libc_offset",
|
||||
"specs,expected",
|
||||
[
|
||||
(["libelf", "libelf@0.8.10"], 1, 1),
|
||||
(["libdwarf%gcc", "libelf%clang"], 2, 1),
|
||||
(["libdwarf%gcc", "libdwarf%clang"], 3, 2),
|
||||
(["libdwarf^libelf@0.8.12", "libdwarf^libelf@0.8.13"], 4, 1),
|
||||
(["hdf5", "zmpi"], 3, 1),
|
||||
(["hdf5", "mpich"], 2, 1),
|
||||
(["hdf5^zmpi", "mpich"], 4, 1),
|
||||
(["mpi", "zmpi"], 2, 1),
|
||||
(["mpi", "mpich"], 1, 1),
|
||||
(["libelf", "libelf@0.8.10"], 1),
|
||||
(["libdwarf%gcc", "libelf%clang"], 2),
|
||||
(["libdwarf%gcc", "libdwarf%clang"], 3),
|
||||
(["libdwarf^libelf@0.8.12", "libdwarf^libelf@0.8.13"], 4),
|
||||
(["hdf5", "zmpi"], 3),
|
||||
(["hdf5", "mpich"], 2),
|
||||
(["hdf5^zmpi", "mpich"], 4),
|
||||
(["mpi", "zmpi"], 2),
|
||||
(["mpi", "mpich"], 1),
|
||||
],
|
||||
)
|
||||
@pytest.mark.only_clingo("Original concretizer cannot concretize in rounds")
|
||||
def test_best_effort_coconcretize(self, specs, expected, libc_offset):
|
||||
def test_best_effort_coconcretize(self, specs, expected):
|
||||
specs = [Spec(s) for s in specs]
|
||||
solver = spack.solver.asp.Solver()
|
||||
solver.reuse = False
|
||||
@@ -1790,9 +1790,7 @@ def test_best_effort_coconcretize(self, specs, expected, libc_offset):
|
||||
for s in result.specs:
|
||||
concrete_specs.update(s.traverse())
|
||||
|
||||
if not spack.solver.asp.using_libc_compatibility():
|
||||
libc_offset = 0
|
||||
|
||||
libc_offset = 1 if spack.solver.asp.using_libc_compatibility() else 0
|
||||
assert len(concrete_specs) == expected + libc_offset
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -2572,6 +2570,29 @@ def test_can_reuse_concrete_externals_for_dependents(self, mutable_config, tmp_p
|
||||
sombrero = result.specs[0]
|
||||
assert sombrero["externaltool"].dag_hash() == external_spec.dag_hash()
|
||||
|
||||
@pytest.mark.only_clingo("Original concretizer cannot reuse")
|
||||
def test_cannot_reuse_host_incompatible_libc(self):
|
||||
"""Test whether reuse concretization correctly fails to reuse a spec with a host
|
||||
incompatible libc."""
|
||||
if not spack.solver.asp.using_libc_compatibility():
|
||||
pytest.skip("This test requires libc nodes")
|
||||
|
||||
# We install b@1 ^glibc@2.30, and b@0 ^glibc@2.28. The former is not host compatible, the
|
||||
# latter is.
|
||||
fst = Spec("b@1").concretized()
|
||||
fst._mark_concrete(False)
|
||||
fst.dependencies("glibc")[0].versions = VersionList(["=2.30"])
|
||||
fst._mark_concrete(True)
|
||||
snd = Spec("b@0").concretized()
|
||||
|
||||
# The spec b@1 ^glibc@2.30 is "more optimal" than b@0 ^glibc@2.28, but due to glibc
|
||||
# incompatibility, it should not be reused.
|
||||
solver = spack.solver.asp.Solver()
|
||||
setup = spack.solver.asp.SpackSolverSetup()
|
||||
result, _, _ = solver.driver.solve(setup, [Spec("b")], reuse=[fst, snd])
|
||||
assert len(result.specs) == 1
|
||||
assert result.specs[0] == snd
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def duplicates_test_repository():
|
||||
@@ -3022,3 +3043,45 @@ def test_spec_filters(specs, include, exclude, expected):
|
||||
factory=lambda: specs, is_usable=lambda x: True, include=include, exclude=exclude
|
||||
)
|
||||
assert f.selected_specs() == expected
|
||||
|
||||
|
||||
@pytest.mark.only_clingo("clingo only reuse feature being tested")
|
||||
@pytest.mark.regression("38484")
|
||||
def test_git_ref_version_can_be_reused(
|
||||
install_mockery_mutable_config, do_not_check_runtimes_on_reuse
|
||||
):
|
||||
first_spec = spack.spec.Spec("git-ref-package@git.2.1.5=2.1.5~opt").concretized()
|
||||
first_spec.package.do_install(fake=True, explicit=True)
|
||||
|
||||
with spack.config.override("concretizer:reuse", True):
|
||||
# reproducer of the issue is that spack will solve when there is a change to the base spec
|
||||
second_spec = spack.spec.Spec("git-ref-package@git.2.1.5=2.1.5+opt").concretized()
|
||||
assert second_spec.dag_hash() != first_spec.dag_hash()
|
||||
# we also want to confirm that reuse actually works so leave variant off to
|
||||
# let solver reuse
|
||||
third_spec = spack.spec.Spec("git-ref-package@git.2.1.5=2.1.5")
|
||||
assert first_spec.satisfies(third_spec)
|
||||
third_spec.concretize()
|
||||
assert third_spec.dag_hash() == first_spec.dag_hash()
|
||||
|
||||
|
||||
@pytest.mark.only_clingo("clingo only reuse feature being tested")
|
||||
@pytest.mark.parametrize("standard_version", ["2.0.0", "2.1.5", "2.1.6"])
|
||||
def test_reuse_prefers_standard_over_git_versions(
|
||||
standard_version, install_mockery_mutable_config, do_not_check_runtimes_on_reuse
|
||||
):
|
||||
"""
|
||||
order matters in this test. typically reuse would pick the highest versioned installed match
|
||||
but we want to prefer the standard version over git ref based versions
|
||||
so install git ref last and ensure it is not picked up by reuse
|
||||
"""
|
||||
standard_spec = spack.spec.Spec(f"git-ref-package@{standard_version}").concretized()
|
||||
standard_spec.package.do_install(fake=True, explicit=True)
|
||||
|
||||
git_spec = spack.spec.Spec("git-ref-package@git.2.1.5=2.1.5").concretized()
|
||||
git_spec.package.do_install(fake=True, explicit=True)
|
||||
|
||||
with spack.config.override("concretizer:reuse", True):
|
||||
test_spec = spack.spec.Spec("git-ref-package@2").concretized()
|
||||
assert git_spec.dag_hash() != test_spec.dag_hash()
|
||||
assert standard_spec.dag_hash() == test_spec.dag_hash()
|
||||
|
||||
@@ -79,13 +79,13 @@ def test_external_nodes_do_not_have_runtimes(runtime_repo, mutable_config, tmp_p
|
||||
[
|
||||
# The reused runtime is older than we need, thus we'll add a more recent one for a
|
||||
("a%gcc@10.2.1", "b%gcc@9.4.0", {"a": "gcc-runtime@10.2.1", "b": "gcc-runtime@9.4.0"}, 2),
|
||||
# The root is compiled with an older compiler, thus we'll NOT reuse the runtime from b
|
||||
("a%gcc@9.4.0", "b%gcc@10.2.1", {"a": "gcc-runtime@9.4.0", "b": "gcc-runtime@9.4.0"}, 1),
|
||||
# The root is compiled with an older compiler, thus we'll reuse the runtime from b
|
||||
("a%gcc@9.4.0", "b%gcc@10.2.1", {"a": "gcc-runtime@10.2.1", "b": "gcc-runtime@10.2.1"}, 1),
|
||||
# Same as before, but tests that we can reuse from a more generic target
|
||||
pytest.param(
|
||||
"a%gcc@9.4.0",
|
||||
"b%gcc@10.2.1 target=x86_64",
|
||||
{"a": "gcc-runtime@9.4.0", "b": "gcc-runtime@9.4.0"},
|
||||
{"a": "gcc-runtime@10.2.1 target=x86_64", "b": "gcc-runtime@10.2.1 target=x86_64"},
|
||||
1,
|
||||
marks=pytest.mark.skipif(
|
||||
str(archspec.cpu.host().family) != "x86_64", reason="test data is x86_64 specific"
|
||||
@@ -102,15 +102,13 @@ def test_external_nodes_do_not_have_runtimes(runtime_repo, mutable_config, tmp_p
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.regression("44444")
|
||||
def test_reusing_specs_with_gcc_runtime(root_str, reused_str, expected, nruntime, runtime_repo):
|
||||
"""Tests that we can reuse specs with a "gcc-runtime" leaf node. In particular, checks
|
||||
that the semantic for gcc-runtimes versions accounts for reused packages too.
|
||||
|
||||
Reusable runtime versions should be lower, or equal, to that of parent nodes.
|
||||
"""
|
||||
root, reused_spec = _concretize_with_reuse(root_str=root_str, reused_str=reused_str)
|
||||
|
||||
assert f"{expected['b']}" in reused_spec
|
||||
runtime_a = root.dependencies("gcc-runtime")[0]
|
||||
assert runtime_a.satisfies(expected["a"])
|
||||
runtime_b = root["b"].dependencies("gcc-runtime")[0]
|
||||
@@ -125,7 +123,8 @@ def test_reusing_specs_with_gcc_runtime(root_str, reused_str, expected, nruntime
|
||||
[
|
||||
# Ensure that, whether we have multiple runtimes in the DAG or not,
|
||||
# we always link only the latest version
|
||||
("a%gcc@10.2.1", "b%gcc@9.4.0", ["gcc-runtime@10.2.1"], ["gcc-runtime@9.4.0"])
|
||||
("a%gcc@10.2.1", "b%gcc@9.4.0", ["gcc-runtime@10.2.1"], ["gcc-runtime@9.4.0"]),
|
||||
("a%gcc@9.4.0", "b%gcc@10.2.1", ["gcc-runtime@10.2.1"], ["gcc-runtime@9.4.0"]),
|
||||
],
|
||||
)
|
||||
def test_views_can_handle_duplicate_runtime_nodes(
|
||||
|
||||
@@ -103,6 +103,23 @@ def test_repo(_create_test_repo, monkeypatch, mock_stage):
|
||||
yield mock_repo_path
|
||||
|
||||
|
||||
class MakeStage:
|
||||
def __init__(self, stage):
|
||||
self.stage = stage
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.stage
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_installs(monkeypatch, tmpdir):
|
||||
stage_path = str(tmpdir.ensure("fake-stage", dir=True))
|
||||
universal_unused_stage = spack.stage.DIYStage(stage_path)
|
||||
monkeypatch.setattr(
|
||||
spack.build_systems.generic.Package, "_make_stage", MakeStage(universal_unused_stage)
|
||||
)
|
||||
|
||||
|
||||
def test_one_package_multiple_reqs(concretize_scope, test_repo):
|
||||
conf_str = """\
|
||||
packages:
|
||||
@@ -497,7 +514,7 @@ def test_oneof_ordering(concretize_scope, test_repo):
|
||||
assert s2.satisfies("@2.5")
|
||||
|
||||
|
||||
def test_reuse_oneof(concretize_scope, _create_test_repo, mutable_database, mock_fetch):
|
||||
def test_reuse_oneof(concretize_scope, _create_test_repo, mutable_database, fake_installs):
|
||||
conf_str = """\
|
||||
packages:
|
||||
y:
|
||||
|
||||
@@ -492,7 +492,7 @@ def test_substitute_date(mock_low_high_config):
|
||||
],
|
||||
)
|
||||
def test_parse_install_tree(config_settings, expected, mutable_config):
|
||||
expected_root = expected[0] or spack.store.DEFAULT_INSTALL_TREE_ROOT
|
||||
expected_root = expected[0] or mutable_config.get("config:install_tree:root")
|
||||
expected_unpadded_root = expected[1] or expected_root
|
||||
expected_proj = expected[2] or spack.directory_layout.default_projections
|
||||
|
||||
@@ -575,7 +575,7 @@ def change_fn(self, section):
|
||||
],
|
||||
)
|
||||
def test_parse_install_tree_padded(config_settings, expected, mutable_config):
|
||||
expected_root = expected[0] or spack.store.DEFAULT_INSTALL_TREE_ROOT
|
||||
expected_root = expected[0] or mutable_config.get("config:install_tree:root")
|
||||
expected_unpadded_root = expected[1] or expected_root
|
||||
expected_proj = expected[2] or spack.directory_layout.default_projections
|
||||
|
||||
@@ -761,25 +761,20 @@ def test_internal_config_from_data():
|
||||
assert config.get("config:checksum", scope="higher") is True
|
||||
|
||||
|
||||
def test_keys_are_ordered():
|
||||
def test_keys_are_ordered(configuration_dir):
|
||||
"""Test that keys in Spack YAML files retain their order from the file."""
|
||||
expected_order = (
|
||||
"bin",
|
||||
"man",
|
||||
"share/man",
|
||||
"share/aclocal",
|
||||
"lib",
|
||||
"lib64",
|
||||
"include",
|
||||
"lib/pkgconfig",
|
||||
"lib64/pkgconfig",
|
||||
"share/pkgconfig",
|
||||
"",
|
||||
"./bin",
|
||||
"./man",
|
||||
"./share/man",
|
||||
"./share/aclocal",
|
||||
"./lib/pkgconfig",
|
||||
"./lib64/pkgconfig",
|
||||
"./share/pkgconfig",
|
||||
"./",
|
||||
)
|
||||
|
||||
config_scope = spack.config.ConfigScope(
|
||||
"modules", os.path.join(spack.paths.test_path, "data", "config")
|
||||
)
|
||||
config_scope = spack.config.ConfigScope("modules", configuration_dir.join("site"))
|
||||
|
||||
data = config_scope.get_section("modules")
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import json
|
||||
import os
|
||||
import os.path
|
||||
import pathlib
|
||||
import re
|
||||
import shutil
|
||||
import stat
|
||||
@@ -32,6 +33,7 @@
|
||||
from llnl.util.filesystem import copy_tree, mkdirp, remove_linked_tree, touchp, working_dir
|
||||
|
||||
import spack.binary_distribution
|
||||
import spack.bootstrap.core
|
||||
import spack.caches
|
||||
import spack.cmd.buildcache
|
||||
import spack.compiler
|
||||
@@ -682,36 +684,34 @@ def configuration_dir(tmpdir_factory, linux_os):
|
||||
directory path.
|
||||
"""
|
||||
tmpdir = tmpdir_factory.mktemp("configurations")
|
||||
install_tree_root = tmpdir_factory.mktemp("opt")
|
||||
modules_root = tmpdir_factory.mktemp("share")
|
||||
tcl_root = modules_root.ensure("modules", dir=True)
|
||||
lmod_root = modules_root.ensure("lmod", dir=True)
|
||||
|
||||
# <test_path>/data/config has mock config yaml files in it
|
||||
# copy these to the site config.
|
||||
test_config = py.path.local(spack.paths.test_path).join("data", "config")
|
||||
test_config.copy(tmpdir.join("site"))
|
||||
test_config = pathlib.Path(spack.paths.test_path) / "data" / "config"
|
||||
shutil.copytree(test_config, tmpdir.join("site"))
|
||||
|
||||
# Create temporary 'defaults', 'site' and 'user' folders
|
||||
tmpdir.ensure("user", dir=True)
|
||||
|
||||
# Slightly modify config.yaml and compilers.yaml
|
||||
if sys.platform == "win32":
|
||||
locks = False
|
||||
else:
|
||||
locks = True
|
||||
|
||||
# Fill out config.yaml, compilers.yaml and modules.yaml templates.
|
||||
solver = os.environ.get("SPACK_TEST_SOLVER", "clingo")
|
||||
config_yaml = test_config.join("config.yaml")
|
||||
modules_root = tmpdir_factory.mktemp("share")
|
||||
tcl_root = modules_root.ensure("modules", dir=True)
|
||||
lmod_root = modules_root.ensure("lmod", dir=True)
|
||||
content = "".join(config_yaml.read()).format(solver, locks, str(tcl_root), str(lmod_root))
|
||||
t = tmpdir.join("site", "config.yaml")
|
||||
t.write(content)
|
||||
locks = sys.platform != "win32"
|
||||
config = tmpdir.join("site", "config.yaml")
|
||||
config_template = test_config / "config.yaml"
|
||||
config.write(config_template.read_text().format(install_tree_root, solver, locks))
|
||||
|
||||
compilers_yaml = test_config.join("compilers.yaml")
|
||||
content = "".join(compilers_yaml.read()).format(
|
||||
linux_os=linux_os, target=str(archspec.cpu.host().family)
|
||||
)
|
||||
t = tmpdir.join("site", "compilers.yaml")
|
||||
t.write(content)
|
||||
target = str(archspec.cpu.host().family)
|
||||
compilers = tmpdir.join("site", "compilers.yaml")
|
||||
compilers_template = test_config / "compilers.yaml"
|
||||
compilers.write(compilers_template.read_text().format(linux_os=linux_os, target=target))
|
||||
|
||||
modules = tmpdir.join("site", "modules.yaml")
|
||||
modules_template = test_config / "modules.yaml"
|
||||
modules.write(modules_template.read_text().format(tcl_root, lmod_root))
|
||||
yield tmpdir
|
||||
|
||||
|
||||
@@ -1702,7 +1702,7 @@ def _factory(name, output, subdir=("bin",)):
|
||||
executable_path = executable_dir / name
|
||||
if sys.platform == "win32":
|
||||
executable_path = executable_dir / (name + ".bat")
|
||||
executable_path.write_text(f"{ shebang }{ output }\n")
|
||||
executable_path.write_text(f"{shebang}{output}\n")
|
||||
executable_path.chmod(0o755)
|
||||
return executable_path
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
concretizer:
|
||||
reuse: True
|
||||
reuse: true
|
||||
targets:
|
||||
granularity: microarchitectures
|
||||
host_compatible: false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
config:
|
||||
install_tree:
|
||||
root: $spack/opt/spack
|
||||
root: {0}
|
||||
template_dirs:
|
||||
- $spack/share/spack/templates
|
||||
- $spack/lib/spack/spack/test/data/templates
|
||||
@@ -13,5 +13,5 @@ config:
|
||||
ssl_certs: $SSL_CERT_FILE
|
||||
checksum: true
|
||||
dirty: false
|
||||
concretizer: {0}
|
||||
locks: {1}
|
||||
concretizer: {1}
|
||||
locks: {2}
|
||||
|
||||
@@ -14,29 +14,25 @@
|
||||
# ~/.spack/modules.yaml
|
||||
# -------------------------------------------------------------------------
|
||||
modules:
|
||||
default: {}
|
||||
prefix_inspections:
|
||||
bin:
|
||||
- PATH
|
||||
man:
|
||||
- MANPATH
|
||||
share/man:
|
||||
- MANPATH
|
||||
share/aclocal:
|
||||
- ACLOCAL_PATH
|
||||
lib:
|
||||
- LIBRARY_PATH
|
||||
- LD_LIBRARY_PATH
|
||||
lib64:
|
||||
- LIBRARY_PATH
|
||||
- LD_LIBRARY_PATH
|
||||
include:
|
||||
- CPATH
|
||||
lib/pkgconfig:
|
||||
- PKG_CONFIG_PATH
|
||||
lib64/pkgconfig:
|
||||
- PKG_CONFIG_PATH
|
||||
share/pkgconfig:
|
||||
- PKG_CONFIG_PATH
|
||||
'':
|
||||
- CMAKE_PREFIX_PATH
|
||||
./bin: [PATH]
|
||||
./man: [MANPATH]
|
||||
./share/man: [MANPATH]
|
||||
./share/aclocal: [ACLOCAL_PATH]
|
||||
./lib/pkgconfig: [PKG_CONFIG_PATH]
|
||||
./lib64/pkgconfig: [PKG_CONFIG_PATH]
|
||||
./share/pkgconfig: [PKG_CONFIG_PATH]
|
||||
./: [CMAKE_PREFIX_PATH]
|
||||
default:
|
||||
roots:
|
||||
tcl: {0}
|
||||
lmod: {1}
|
||||
enable: []
|
||||
tcl:
|
||||
all:
|
||||
autoload: direct
|
||||
lmod:
|
||||
all:
|
||||
autoload: direct
|
||||
hierarchy:
|
||||
- mpi
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
from typing import List, Optional, Union
|
||||
|
||||
import py
|
||||
import pytest
|
||||
@@ -44,12 +45,10 @@ def _mock_repo(root, namespace):
|
||||
repodir.ensure(spack.repo.packages_dir_name, dir=True)
|
||||
yaml = repodir.join("repo.yaml")
|
||||
yaml.write(
|
||||
"""
|
||||
f"""
|
||||
repo:
|
||||
namespace: {0}
|
||||
""".format(
|
||||
namespace
|
||||
)
|
||||
namespace: {namespace}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
@@ -73,53 +72,21 @@ def _true(*args, **kwargs):
|
||||
return True
|
||||
|
||||
|
||||
def create_build_task(pkg, install_args={}):
|
||||
"""
|
||||
Create a built task for the given (concretized) package
|
||||
|
||||
Args:
|
||||
pkg (spack.package_base.PackageBase): concretized package associated with
|
||||
the task
|
||||
install_args (dict): dictionary of kwargs (or install args)
|
||||
|
||||
Return:
|
||||
(BuildTask) A basic package build task
|
||||
"""
|
||||
request = inst.BuildRequest(pkg, install_args)
|
||||
return inst.BuildTask(pkg, request, False, 0, 0, inst.STATUS_ADDED, [])
|
||||
def create_build_task(
|
||||
pkg: spack.package_base.PackageBase, install_args: Optional[dict] = None
|
||||
) -> inst.BuildTask:
|
||||
request = inst.BuildRequest(pkg, {} if install_args is None else install_args)
|
||||
return inst.BuildTask(pkg, request, False, 0, 0, inst.STATUS_ADDED, set())
|
||||
|
||||
|
||||
def create_installer(installer_args):
|
||||
"""
|
||||
Create an installer using the concretized spec for each arg
|
||||
|
||||
Args:
|
||||
installer_args (list): the list of (spec name, kwargs) tuples
|
||||
|
||||
Return:
|
||||
spack.installer.PackageInstaller: the associated package installer
|
||||
"""
|
||||
const_arg = [(spec.package, kwargs) for spec, kwargs in installer_args]
|
||||
return inst.PackageInstaller(const_arg)
|
||||
|
||||
|
||||
def installer_args(spec_names, kwargs={}):
|
||||
"""Return a the installer argument with each spec paired with kwargs
|
||||
|
||||
Args:
|
||||
spec_names (list): list of spec names
|
||||
kwargs (dict or None): install arguments to apply to all of the specs
|
||||
|
||||
Returns:
|
||||
list: list of (spec, kwargs), the installer constructor argument
|
||||
"""
|
||||
arg = []
|
||||
for name in spec_names:
|
||||
spec = spack.spec.Spec(name)
|
||||
spec.concretize()
|
||||
assert spec.concrete
|
||||
arg.append((spec, kwargs))
|
||||
return arg
|
||||
def create_installer(
|
||||
specs: Union[List[str], List[spack.spec.Spec]], install_args: Optional[dict] = None
|
||||
) -> inst.PackageInstaller:
|
||||
"""Create an installer instance for a list of specs or package names that will be
|
||||
concretized."""
|
||||
_specs = [spack.spec.Spec(s).concretized() if isinstance(s, str) else s for s in specs]
|
||||
_install_args = {} if install_args is None else install_args
|
||||
return inst.PackageInstaller([spec.package for spec in _specs], _install_args)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -240,8 +207,7 @@ def test_try_install_from_binary_cache(install_mockery, mock_packages, monkeypat
|
||||
|
||||
|
||||
def test_installer_repr(install_mockery):
|
||||
const_arg = installer_args(["trivial-install-test-package"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["trivial-install-test-package"])
|
||||
|
||||
irep = installer.__repr__()
|
||||
assert irep.startswith(installer.__class__.__name__)
|
||||
@@ -250,8 +216,7 @@ def test_installer_repr(install_mockery):
|
||||
|
||||
|
||||
def test_installer_str(install_mockery):
|
||||
const_arg = installer_args(["trivial-install-test-package"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["trivial-install-test-package"])
|
||||
|
||||
istr = str(installer)
|
||||
assert "#tasks=0" in istr
|
||||
@@ -296,8 +261,7 @@ def _mock_installed(self):
|
||||
builder.add_package("f")
|
||||
|
||||
with spack.repo.use_repositories(builder.root):
|
||||
const_arg = installer_args(["a"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"])
|
||||
|
||||
installer._init_queue()
|
||||
|
||||
@@ -331,8 +295,7 @@ def test_check_last_phase_error(install_mockery):
|
||||
|
||||
|
||||
def test_installer_ensure_ready_errors(install_mockery, monkeypatch):
|
||||
const_arg = installer_args(["trivial-install-test-package"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["trivial-install-test-package"])
|
||||
spec = installer.build_requests[0].pkg.spec
|
||||
|
||||
fmt = r"cannot be installed locally.*{0}"
|
||||
@@ -366,8 +329,7 @@ def test_ensure_locked_err(install_mockery, monkeypatch, tmpdir, capsys):
|
||||
def _raise(lock, timeout=None):
|
||||
raise RuntimeError(mock_err_msg)
|
||||
|
||||
const_arg = installer_args(["trivial-install-test-package"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["trivial-install-test-package"])
|
||||
spec = installer.build_requests[0].pkg.spec
|
||||
|
||||
monkeypatch.setattr(ulk.Lock, "acquire_read", _raise)
|
||||
@@ -382,8 +344,7 @@ def _raise(lock, timeout=None):
|
||||
|
||||
def test_ensure_locked_have(install_mockery, tmpdir, capsys):
|
||||
"""Test _ensure_locked when already have lock."""
|
||||
const_arg = installer_args(["trivial-install-test-package"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["trivial-install-test-package"], {})
|
||||
spec = installer.build_requests[0].pkg.spec
|
||||
pkg_id = inst.package_id(spec)
|
||||
|
||||
@@ -419,8 +380,7 @@ def test_ensure_locked_have(install_mockery, tmpdir, capsys):
|
||||
@pytest.mark.parametrize("lock_type,reads,writes", [("read", 1, 0), ("write", 0, 1)])
|
||||
def test_ensure_locked_new_lock(install_mockery, tmpdir, lock_type, reads, writes):
|
||||
pkg_id = "a"
|
||||
const_arg = installer_args([pkg_id], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer([pkg_id], {})
|
||||
spec = installer.build_requests[0].pkg.spec
|
||||
with tmpdir.as_cwd():
|
||||
ltype, lock = installer._ensure_locked(lock_type, spec.package)
|
||||
@@ -439,8 +399,7 @@ def _pl(db, spec, timeout):
|
||||
return lock
|
||||
|
||||
pkg_id = "a"
|
||||
const_arg = installer_args([pkg_id], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer([pkg_id], {})
|
||||
spec = installer.build_requests[0].pkg.spec
|
||||
|
||||
monkeypatch.setattr(spack.database.SpecLocker, "lock", _pl)
|
||||
@@ -510,7 +469,7 @@ def _conc_spec(compiler):
|
||||
|
||||
def test_update_tasks_for_compiler_packages_as_compiler(mock_packages, config, monkeypatch):
|
||||
spec = spack.spec.Spec("trivial-install-test-package").concretized()
|
||||
installer = inst.PackageInstaller([(spec.package, {})])
|
||||
installer = inst.PackageInstaller([spec.package], {})
|
||||
|
||||
# Add a task to the queue
|
||||
installer._add_init_task(spec.package, installer.build_requests[0], False, {})
|
||||
@@ -694,8 +653,7 @@ def test_check_deps_status_install_failure(install_mockery):
|
||||
for dep in s.traverse(root=False):
|
||||
spack.store.STORE.failure_tracker.mark(dep)
|
||||
|
||||
const_arg = installer_args(["a"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"], {})
|
||||
request = installer.build_requests[0]
|
||||
|
||||
with pytest.raises(inst.InstallError, match="install failure"):
|
||||
@@ -703,8 +661,7 @@ def test_check_deps_status_install_failure(install_mockery):
|
||||
|
||||
|
||||
def test_check_deps_status_write_locked(install_mockery, monkeypatch):
|
||||
const_arg = installer_args(["a"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"], {})
|
||||
request = installer.build_requests[0]
|
||||
|
||||
# Ensure the lock is not acquired
|
||||
@@ -715,8 +672,7 @@ def test_check_deps_status_write_locked(install_mockery, monkeypatch):
|
||||
|
||||
|
||||
def test_check_deps_status_external(install_mockery, monkeypatch):
|
||||
const_arg = installer_args(["a"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"], {})
|
||||
request = installer.build_requests[0]
|
||||
|
||||
# Mock the dependencies as external so assumed to be installed
|
||||
@@ -728,8 +684,7 @@ def test_check_deps_status_external(install_mockery, monkeypatch):
|
||||
|
||||
|
||||
def test_check_deps_status_upstream(install_mockery, monkeypatch):
|
||||
const_arg = installer_args(["a"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"], {})
|
||||
request = installer.build_requests[0]
|
||||
|
||||
# Mock the known dependencies as installed upstream
|
||||
@@ -747,8 +702,7 @@ def _pkgs(compiler, architecture, pkgs):
|
||||
spec = spack.spec.Spec("mpi").concretized()
|
||||
return [(spec.package, True)]
|
||||
|
||||
const_arg = installer_args(["trivial-install-test-package"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["trivial-install-test-package"], {})
|
||||
request = installer.build_requests[0]
|
||||
all_deps = defaultdict(set)
|
||||
|
||||
@@ -763,8 +717,7 @@ def _pkgs(compiler, architecture, pkgs):
|
||||
|
||||
def test_prepare_for_install_on_installed(install_mockery, monkeypatch):
|
||||
"""Test of _prepare_for_install's early return for installed task path."""
|
||||
const_arg = installer_args(["dependent-install"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["dependent-install"], {})
|
||||
request = installer.build_requests[0]
|
||||
|
||||
install_args = {"keep_prefix": True, "keep_stage": True, "restage": False}
|
||||
@@ -779,8 +732,7 @@ def test_installer_init_requests(install_mockery):
|
||||
"""Test of installer initial requests."""
|
||||
spec_name = "dependent-install"
|
||||
with spack.config.override("config:install_missing_compilers", True):
|
||||
const_arg = installer_args([spec_name], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer([spec_name], {})
|
||||
|
||||
# There is only one explicit request in this case
|
||||
assert len(installer.build_requests) == 1
|
||||
@@ -789,8 +741,7 @@ def test_installer_init_requests(install_mockery):
|
||||
|
||||
|
||||
def test_install_task_use_cache(install_mockery, monkeypatch):
|
||||
const_arg = installer_args(["trivial-install-test-package"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["trivial-install-test-package"], {})
|
||||
request = installer.build_requests[0]
|
||||
task = create_build_task(request.pkg)
|
||||
|
||||
@@ -805,8 +756,7 @@ def test_install_task_add_compiler(install_mockery, monkeypatch, capfd):
|
||||
def _add(_compilers):
|
||||
tty.msg(config_msg)
|
||||
|
||||
const_arg = installer_args(["a"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"], {})
|
||||
task = create_build_task(installer.build_requests[0].pkg)
|
||||
task.compiler = True
|
||||
|
||||
@@ -825,8 +775,7 @@ def _add(_compilers):
|
||||
|
||||
def test_release_lock_write_n_exception(install_mockery, tmpdir, capsys):
|
||||
"""Test _release_lock for supposed write lock with exception."""
|
||||
const_arg = installer_args(["trivial-install-test-package"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["trivial-install-test-package"], {})
|
||||
|
||||
pkg_id = "test"
|
||||
with tmpdir.as_cwd():
|
||||
@@ -843,8 +792,7 @@ def test_release_lock_write_n_exception(install_mockery, tmpdir, capsys):
|
||||
@pytest.mark.parametrize("installed", [True, False])
|
||||
def test_push_task_skip_processed(install_mockery, installed):
|
||||
"""Test to ensure skip re-queueing a processed package."""
|
||||
const_arg = installer_args(["a"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"], {})
|
||||
assert len(list(installer.build_tasks)) == 0
|
||||
|
||||
# Mark the package as installed OR failed
|
||||
@@ -861,8 +809,7 @@ def test_push_task_skip_processed(install_mockery, installed):
|
||||
|
||||
def test_requeue_task(install_mockery, capfd):
|
||||
"""Test to ensure cover _requeue_task."""
|
||||
const_arg = installer_args(["a"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"], {})
|
||||
task = create_build_task(installer.build_requests[0].pkg)
|
||||
|
||||
# temporarily set tty debug messages on so we can test output
|
||||
@@ -892,8 +839,7 @@ def _mktask(pkg):
|
||||
def _rmtask(installer, pkg_id):
|
||||
raise RuntimeError("Raise an exception to test except path")
|
||||
|
||||
const_arg = installer_args(["a"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"], {})
|
||||
spec = installer.build_requests[0].pkg.spec
|
||||
|
||||
# Cover task removal happy path
|
||||
@@ -922,8 +868,7 @@ def _chgrp(path, group, follow_symlinks=True):
|
||||
monkeypatch.setattr(prefs, "get_package_group", _get_group)
|
||||
monkeypatch.setattr(fs, "chgrp", _chgrp)
|
||||
|
||||
const_arg = installer_args(["trivial-install-test-package"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["trivial-install-test-package"], {})
|
||||
spec = installer.build_requests[0].pkg.spec
|
||||
|
||||
fs.touchp(spec.prefix)
|
||||
@@ -949,8 +894,7 @@ def test_cleanup_failed_err(install_mockery, tmpdir, monkeypatch, capsys):
|
||||
def _raise_except(lock):
|
||||
raise RuntimeError(msg)
|
||||
|
||||
const_arg = installer_args(["trivial-install-test-package"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["trivial-install-test-package"], {})
|
||||
|
||||
monkeypatch.setattr(lk.Lock, "release_write", _raise_except)
|
||||
pkg_id = "test"
|
||||
@@ -966,8 +910,7 @@ def _raise_except(lock):
|
||||
|
||||
def test_update_failed_no_dependent_task(install_mockery):
|
||||
"""Test _update_failed with missing dependent build tasks."""
|
||||
const_arg = installer_args(["dependent-install"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["dependent-install"], {})
|
||||
spec = installer.build_requests[0].pkg.spec
|
||||
|
||||
for dep in spec.traverse(root=False):
|
||||
@@ -978,8 +921,7 @@ def test_update_failed_no_dependent_task(install_mockery):
|
||||
|
||||
def test_install_uninstalled_deps(install_mockery, monkeypatch, capsys):
|
||||
"""Test install with uninstalled dependencies."""
|
||||
const_arg = installer_args(["dependent-install"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["dependent-install"], {})
|
||||
|
||||
# Skip the actual installation and any status updates
|
||||
monkeypatch.setattr(inst.PackageInstaller, "_install_task", _noop)
|
||||
@@ -996,8 +938,7 @@ def test_install_uninstalled_deps(install_mockery, monkeypatch, capsys):
|
||||
|
||||
def test_install_failed(install_mockery, monkeypatch, capsys):
|
||||
"""Test install with failed install."""
|
||||
const_arg = installer_args(["b"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["b"], {})
|
||||
|
||||
# Make sure the package is identified as failed
|
||||
monkeypatch.setattr(spack.database.FailureTracker, "has_failed", _true)
|
||||
@@ -1012,8 +953,7 @@ def test_install_failed(install_mockery, monkeypatch, capsys):
|
||||
|
||||
def test_install_failed_not_fast(install_mockery, monkeypatch, capsys):
|
||||
"""Test install with failed install."""
|
||||
const_arg = installer_args(["a"], {"fail_fast": False})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"], {"fail_fast": False})
|
||||
|
||||
# Make sure the package is identified as failed
|
||||
monkeypatch.setattr(spack.database.FailureTracker, "has_failed", _true)
|
||||
@@ -1037,8 +977,7 @@ def _interrupt(installer, task, install_status, **kwargs):
|
||||
else:
|
||||
installer.installed.add(task.pkg.name)
|
||||
|
||||
const_arg = installer_args([spec_name], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer([spec_name], {})
|
||||
|
||||
# Raise a KeyboardInterrupt error to trigger early termination
|
||||
monkeypatch.setattr(inst.PackageInstaller, "_install_task", _interrupt)
|
||||
@@ -1064,8 +1003,7 @@ def _install(installer, task, install_status, **kwargs):
|
||||
else:
|
||||
installer.installed.add(task.pkg.name)
|
||||
|
||||
const_arg = installer_args([spec_name], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer([spec_name], {})
|
||||
|
||||
# Raise a KeyboardInterrupt error to trigger early termination
|
||||
monkeypatch.setattr(inst.PackageInstaller, "_install_task", _install)
|
||||
@@ -1091,8 +1029,7 @@ def _install(installer, task, install_status, **kwargs):
|
||||
else:
|
||||
installer.installed.add(task.pkg.name)
|
||||
|
||||
const_arg = installer_args([spec_name, "a"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer([spec_name, "a"], {})
|
||||
|
||||
# Raise a KeyboardInterrupt error to trigger early termination
|
||||
monkeypatch.setattr(inst.PackageInstaller, "_install_task", _install)
|
||||
@@ -1106,25 +1043,21 @@ def _install(installer, task, install_status, **kwargs):
|
||||
|
||||
def test_install_fail_fast_on_detect(install_mockery, monkeypatch, capsys):
|
||||
"""Test fail_fast install when an install failure is detected."""
|
||||
const_arg = installer_args(["b"], {"fail_fast": False})
|
||||
const_arg.extend(installer_args(["c"], {"fail_fast": True}))
|
||||
installer = create_installer(const_arg)
|
||||
pkg_ids = [inst.package_id(spec) for spec, _ in const_arg]
|
||||
b, c = spack.spec.Spec("b").concretized(), spack.spec.Spec("c").concretized()
|
||||
b_id, c_id = inst.package_id(b), inst.package_id(c)
|
||||
|
||||
installer = create_installer([b, c], {"fail_fast": True})
|
||||
|
||||
# Make sure all packages are identified as failed
|
||||
#
|
||||
# This will prevent b from installing, which will cause the build of a
|
||||
# to be skipped.
|
||||
# This will prevent b from installing, which will cause the build of c to be skipped.
|
||||
monkeypatch.setattr(spack.database.FailureTracker, "has_failed", _true)
|
||||
|
||||
with pytest.raises(inst.InstallError, match="after first install failure"):
|
||||
installer.install()
|
||||
|
||||
assert pkg_ids[0] in installer.failed, "Expected b to be marked as failed"
|
||||
assert pkg_ids[1] not in installer.failed, "Expected no attempt to install c"
|
||||
|
||||
out = capsys.readouterr()[1]
|
||||
assert "{0} failed to install".format(pkg_ids[0]) in out
|
||||
assert b_id in installer.failed, "Expected b to be marked as failed"
|
||||
assert c_id not in installer.failed, "Expected no attempt to install c"
|
||||
assert f"{b_id} failed to install" in capsys.readouterr().err
|
||||
|
||||
|
||||
def _test_install_fail_fast_on_except_patch(installer, **kwargs):
|
||||
@@ -1137,8 +1070,7 @@ def _test_install_fail_fast_on_except_patch(installer, **kwargs):
|
||||
@pytest.mark.disable_clean_stage_check
|
||||
def test_install_fail_fast_on_except(install_mockery, monkeypatch, capsys):
|
||||
"""Test fail_fast install when an install failure results from an error."""
|
||||
const_arg = installer_args(["a"], {"fail_fast": True})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["a"], {"fail_fast": True})
|
||||
|
||||
# Raise a non-KeyboardInterrupt exception to trigger fast failure.
|
||||
#
|
||||
@@ -1161,8 +1093,7 @@ def test_install_lock_failures(install_mockery, monkeypatch, capfd):
|
||||
def _requeued(installer, task, install_status):
|
||||
tty.msg("requeued {0}".format(task.pkg.spec.name))
|
||||
|
||||
const_arg = installer_args(["b"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["b"], {})
|
||||
|
||||
# Ensure never acquire a lock
|
||||
monkeypatch.setattr(inst.PackageInstaller, "_ensure_locked", _not_locked)
|
||||
@@ -1181,20 +1112,19 @@ def _requeued(installer, task, install_status):
|
||||
|
||||
def test_install_lock_installed_requeue(install_mockery, monkeypatch, capfd):
|
||||
"""Cover basic install handling for installed package."""
|
||||
const_arg = installer_args(["b"], {})
|
||||
b, _ = const_arg[0]
|
||||
installer = create_installer(const_arg)
|
||||
b = spack.spec.Spec("b").concretized()
|
||||
b_pkg_id = inst.package_id(b)
|
||||
installer = create_installer([b])
|
||||
|
||||
def _prep(installer, task):
|
||||
installer.installed.add(b_pkg_id)
|
||||
tty.msg("{0} is installed".format(b_pkg_id))
|
||||
tty.msg(f"{b_pkg_id} is installed")
|
||||
|
||||
# also do not allow the package to be locked again
|
||||
monkeypatch.setattr(inst.PackageInstaller, "_ensure_locked", _not_locked)
|
||||
|
||||
def _requeued(installer, task, install_status):
|
||||
tty.msg("requeued {0}".format(inst.package_id(task.pkg.spec)))
|
||||
tty.msg(f"requeued {inst.package_id(task.pkg.spec)}")
|
||||
|
||||
# Flag the package as installed
|
||||
monkeypatch.setattr(inst.PackageInstaller, "_prepare_for_install", _prep)
|
||||
@@ -1207,9 +1137,8 @@ def _requeued(installer, task, install_status):
|
||||
|
||||
assert b_pkg_id not in installer.installed
|
||||
|
||||
out = capfd.readouterr()[0]
|
||||
expected = ["is installed", "read locked", "requeued"]
|
||||
for exp, ln in zip(expected, out.split("\n")):
|
||||
for exp, ln in zip(expected, capfd.readouterr().out.splitlines()):
|
||||
assert exp in ln
|
||||
|
||||
|
||||
@@ -1237,8 +1166,7 @@ def _requeued(installer, task, install_status):
|
||||
# Ensure don't continually requeue the task
|
||||
monkeypatch.setattr(inst.PackageInstaller, "_requeue_task", _requeued)
|
||||
|
||||
const_arg = installer_args(["b"], {})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["b"], {})
|
||||
|
||||
with pytest.raises(inst.InstallError, match="request failed"):
|
||||
installer.install()
|
||||
@@ -1253,25 +1181,19 @@ def _requeued(installer, task, install_status):
|
||||
|
||||
def test_install_skip_patch(install_mockery, mock_fetch):
|
||||
"""Test the path skip_patch install path."""
|
||||
spec_name = "b"
|
||||
const_arg = installer_args([spec_name], {"fake": False, "skip_patch": True})
|
||||
installer = create_installer(const_arg)
|
||||
|
||||
installer = create_installer(["b"], {"fake": False, "skip_patch": True})
|
||||
installer.install()
|
||||
|
||||
spec, install_args = const_arg[0]
|
||||
assert inst.package_id(spec) in installer.installed
|
||||
assert inst.package_id(installer.build_requests[0].pkg.spec) in installer.installed
|
||||
|
||||
|
||||
def test_install_implicit(install_mockery, mock_fetch):
|
||||
"""Test the path skip_patch install path."""
|
||||
spec_name = "trivial-install-test-package"
|
||||
const_arg = installer_args([spec_name], {"fake": False})
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer([spec_name], {"fake": False})
|
||||
pkg = installer.build_requests[0].pkg
|
||||
assert not create_build_task(pkg, {"explicit": False}).explicit
|
||||
assert create_build_task(pkg, {"explicit": True}).explicit
|
||||
assert create_build_task(pkg).explicit
|
||||
assert not create_build_task(pkg, {"explicit": []}).explicit
|
||||
assert create_build_task(pkg, {"explicit": [pkg.spec.dag_hash()]}).explicit
|
||||
assert not create_build_task(pkg).explicit
|
||||
|
||||
|
||||
def test_overwrite_install_backup_success(temporary_store, config, mock_packages, tmpdir):
|
||||
@@ -1280,8 +1202,7 @@ def test_overwrite_install_backup_success(temporary_store, config, mock_packages
|
||||
of the original prefix, and leave the original spec marked installed.
|
||||
"""
|
||||
# Get a build task. TODO: refactor this to avoid calling internal methods
|
||||
const_arg = installer_args(["b"])
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["b"])
|
||||
installer._init_queue()
|
||||
task = installer._pop_task()
|
||||
|
||||
@@ -1341,8 +1262,7 @@ def remove(self, spec):
|
||||
self.called = True
|
||||
|
||||
# Get a build task. TODO: refactor this to avoid calling internal methods
|
||||
const_arg = installer_args(["b"])
|
||||
installer = create_installer(const_arg)
|
||||
installer = create_installer(["b"])
|
||||
installer._init_queue()
|
||||
task = installer._pop_task()
|
||||
|
||||
@@ -1375,22 +1295,20 @@ def test_term_status_line():
|
||||
x.clear()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"explicit_args,is_explicit",
|
||||
[({"explicit": False}, False), ({"explicit": True}, True), ({}, True)],
|
||||
)
|
||||
def test_single_external_implicit_install(install_mockery, explicit_args, is_explicit):
|
||||
@pytest.mark.parametrize("explicit", [True, False])
|
||||
def test_single_external_implicit_install(install_mockery, explicit):
|
||||
pkg = "trivial-install-test-package"
|
||||
s = spack.spec.Spec(pkg).concretized()
|
||||
s.external_path = "/usr"
|
||||
create_installer([(s, explicit_args)]).install()
|
||||
assert spack.store.STORE.db.get_record(pkg).explicit == is_explicit
|
||||
args = {"explicit": [s.dag_hash()] if explicit else []}
|
||||
create_installer([s], args).install()
|
||||
assert spack.store.STORE.db.get_record(pkg).explicit == explicit
|
||||
|
||||
|
||||
def test_overwrite_install_does_install_build_deps(install_mockery, mock_fetch):
|
||||
"""When overwrite installing something from sources, build deps should be installed."""
|
||||
s = spack.spec.Spec("dtrun3").concretized()
|
||||
create_installer([(s, {})]).install()
|
||||
create_installer([s]).install()
|
||||
|
||||
# Verify there is a pure build dep
|
||||
edge = s.edges_to_dependencies(name="dtbuild3").pop()
|
||||
@@ -1401,7 +1319,7 @@ def test_overwrite_install_does_install_build_deps(install_mockery, mock_fetch):
|
||||
build_dep.package.do_uninstall()
|
||||
|
||||
# Overwrite install the root dtrun3
|
||||
create_installer([(s, {"overwrite": [s.dag_hash()]})]).install()
|
||||
create_installer([s], {"overwrite": [s.dag_hash()]}).install()
|
||||
|
||||
# Verify that the build dep was also installed.
|
||||
assert build_dep.installed
|
||||
|
||||
@@ -278,8 +278,8 @@ def test_symlinks_false(self, stage):
|
||||
def test_allow_broken_symlinks(self, stage):
|
||||
"""Test installing with a broken symlink."""
|
||||
with fs.working_dir(str(stage)):
|
||||
symlink("nonexistant.txt", "source/broken", allow_broken_symlinks=True)
|
||||
fs.install_tree("source", "dest", symlinks=True, allow_broken_symlinks=True)
|
||||
symlink("nonexistant.txt", "source/broken")
|
||||
fs.install_tree("source", "dest", symlinks=True)
|
||||
assert os.path.islink("dest/broken")
|
||||
assert not os.path.exists(readlink("dest/broken"))
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ def test_symlink_file(tmpdir):
|
||||
fd, real_file = tempfile.mkstemp(prefix="real", suffix=".txt", dir=test_dir)
|
||||
link_file = str(tmpdir.join("link.txt"))
|
||||
assert os.path.exists(link_file) is False
|
||||
symlink.symlink(source_path=real_file, link_path=link_file)
|
||||
symlink.symlink(real_file, link_file)
|
||||
assert os.path.exists(link_file)
|
||||
assert symlink.islink(link_file)
|
||||
|
||||
@@ -32,11 +32,12 @@ def test_symlink_dir(tmpdir):
|
||||
real_dir = os.path.join(test_dir, "real_dir")
|
||||
link_dir = os.path.join(test_dir, "link_dir")
|
||||
os.mkdir(real_dir)
|
||||
symlink.symlink(source_path=real_dir, link_path=link_dir)
|
||||
symlink.symlink(real_dir, link_dir)
|
||||
assert os.path.exists(link_dir)
|
||||
assert symlink.islink(link_dir)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform != "win32", reason="Test is only for Windows")
|
||||
def test_symlink_source_not_exists(tmpdir):
|
||||
"""Test the symlink.symlink method for the case where a source path does not exist"""
|
||||
with tmpdir.as_cwd():
|
||||
@@ -44,7 +45,7 @@ def test_symlink_source_not_exists(tmpdir):
|
||||
real_dir = os.path.join(test_dir, "real_dir")
|
||||
link_dir = os.path.join(test_dir, "link_dir")
|
||||
with pytest.raises(symlink.SymlinkError):
|
||||
symlink.symlink(source_path=real_dir, link_path=link_dir, allow_broken_symlinks=False)
|
||||
symlink._windows_symlink(real_dir, link_dir)
|
||||
|
||||
|
||||
def test_symlink_src_relative_to_link(tmpdir):
|
||||
@@ -61,18 +62,16 @@ def test_symlink_src_relative_to_link(tmpdir):
|
||||
fd, real_file = tempfile.mkstemp(prefix="real", suffix=".txt", dir=subdir_2)
|
||||
link_file = os.path.join(subdir_1, "link.txt")
|
||||
|
||||
symlink.symlink(
|
||||
source_path=f"b/{os.path.basename(real_file)}",
|
||||
link_path=f"a/{os.path.basename(link_file)}",
|
||||
)
|
||||
symlink.symlink(f"b/{os.path.basename(real_file)}", f"a/{os.path.basename(link_file)}")
|
||||
assert os.path.exists(link_file)
|
||||
assert symlink.islink(link_file)
|
||||
# Check dirs
|
||||
assert not os.path.lexists(link_dir)
|
||||
symlink.symlink(source_path="b", link_path="a/c")
|
||||
symlink.symlink("b", "a/c")
|
||||
assert os.path.lexists(link_dir)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform != "win32", reason="Test is only for Windows")
|
||||
def test_symlink_src_not_relative_to_link(tmpdir):
|
||||
"""Test the symlink.symlink functionality where the source value does not exist relative to
|
||||
the link and not relative to the cwd. NOTE that this symlink api call is EXPECTED to raise
|
||||
@@ -88,19 +87,18 @@ def test_symlink_src_not_relative_to_link(tmpdir):
|
||||
link_file = str(tmpdir.join("link.txt"))
|
||||
# Expected SymlinkError because source path does not exist relative to link path
|
||||
with pytest.raises(symlink.SymlinkError):
|
||||
symlink.symlink(
|
||||
source_path=f"d/{os.path.basename(real_file)}",
|
||||
link_path=f"a/{os.path.basename(link_file)}",
|
||||
allow_broken_symlinks=False,
|
||||
symlink._windows_symlink(
|
||||
f"d/{os.path.basename(real_file)}", f"a/{os.path.basename(link_file)}"
|
||||
)
|
||||
assert not os.path.exists(link_file)
|
||||
# Check dirs
|
||||
assert not os.path.lexists(link_dir)
|
||||
with pytest.raises(symlink.SymlinkError):
|
||||
symlink.symlink(source_path="d", link_path="a/c", allow_broken_symlinks=False)
|
||||
symlink._windows_symlink("d", "a/c")
|
||||
assert not os.path.lexists(link_dir)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform != "win32", reason="Test is only for Windows")
|
||||
def test_symlink_link_already_exists(tmpdir):
|
||||
"""Test the symlink.symlink method for the case where a link already exists"""
|
||||
with tmpdir.as_cwd():
|
||||
@@ -108,10 +106,10 @@ def test_symlink_link_already_exists(tmpdir):
|
||||
real_dir = os.path.join(test_dir, "real_dir")
|
||||
link_dir = os.path.join(test_dir, "link_dir")
|
||||
os.mkdir(real_dir)
|
||||
symlink.symlink(real_dir, link_dir, allow_broken_symlinks=False)
|
||||
symlink._windows_symlink(real_dir, link_dir)
|
||||
assert os.path.exists(link_dir)
|
||||
with pytest.raises(symlink.SymlinkError):
|
||||
symlink.symlink(source_path=real_dir, link_path=link_dir, allow_broken_symlinks=False)
|
||||
symlink._windows_symlink(real_dir, link_dir)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not symlink._windows_can_symlink(), reason="Test requires elevated privileges")
|
||||
@@ -122,7 +120,7 @@ def test_symlink_win_file(tmpdir):
|
||||
test_dir = str(tmpdir)
|
||||
fd, real_file = tempfile.mkstemp(prefix="real", suffix=".txt", dir=test_dir)
|
||||
link_file = str(tmpdir.join("link.txt"))
|
||||
symlink.symlink(source_path=real_file, link_path=link_file)
|
||||
symlink.symlink(real_file, link_file)
|
||||
# Verify that all expected conditions are met
|
||||
assert os.path.exists(link_file)
|
||||
assert symlink.islink(link_file)
|
||||
@@ -140,7 +138,7 @@ def test_symlink_win_dir(tmpdir):
|
||||
real_dir = os.path.join(test_dir, "real")
|
||||
link_dir = os.path.join(test_dir, "link")
|
||||
os.mkdir(real_dir)
|
||||
symlink.symlink(source_path=real_dir, link_path=link_dir)
|
||||
symlink.symlink(real_dir, link_dir)
|
||||
# Verify that all expected conditions are met
|
||||
assert os.path.exists(link_dir)
|
||||
assert symlink.islink(link_dir)
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
|
||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import spack.operating_systems.cray_backend as cray_backend
|
||||
|
||||
|
||||
def test_read_cle_release_file(tmpdir, monkeypatch):
|
||||
"""test reading the Cray cle-release file"""
|
||||
cle_release_path = tmpdir.join("cle-release")
|
||||
with cle_release_path.open("w") as f:
|
||||
f.write(
|
||||
"""\
|
||||
RELEASE=6.0.UP07
|
||||
BUILD=6.0.7424
|
||||
DATE=20190611
|
||||
ARCH=noarch
|
||||
NETWORK=ari
|
||||
PATCHSET=35-201906112304
|
||||
DUMMY=foo=bar
|
||||
"""
|
||||
)
|
||||
|
||||
monkeypatch.setattr(cray_backend, "_cle_release_file", str(cle_release_path))
|
||||
attrs = cray_backend.read_cle_release_file()
|
||||
|
||||
assert attrs["RELEASE"] == "6.0.UP07"
|
||||
assert attrs["BUILD"] == "6.0.7424"
|
||||
assert attrs["DATE"] == "20190611"
|
||||
assert attrs["ARCH"] == "noarch"
|
||||
assert attrs["NETWORK"] == "ari"
|
||||
assert attrs["PATCHSET"] == "35-201906112304"
|
||||
assert attrs["DUMMY"] == "foo=bar"
|
||||
|
||||
assert cray_backend.CrayBackend._detect_crayos_version() == 6
|
||||
|
||||
|
||||
def test_read_clerelease_file(tmpdir, monkeypatch):
|
||||
"""test reading the Cray clerelease file"""
|
||||
clerelease_path = tmpdir.join("clerelease")
|
||||
with clerelease_path.open("w") as f:
|
||||
f.write("5.2.UP04\n")
|
||||
|
||||
monkeypatch.setattr(cray_backend, "_clerelease_file", str(clerelease_path))
|
||||
v = cray_backend.read_clerelease_file()
|
||||
|
||||
assert v == "5.2.UP04"
|
||||
|
||||
assert cray_backend.CrayBackend._detect_crayos_version() == 5
|
||||
|
||||
|
||||
def test_cle_release_precedence(tmpdir, monkeypatch):
|
||||
"""test that cle-release file takes precedence over clerelease file."""
|
||||
cle_release_path = tmpdir.join("cle-release")
|
||||
clerelease_path = tmpdir.join("clerelease")
|
||||
|
||||
with cle_release_path.open("w") as f:
|
||||
f.write(
|
||||
"""\
|
||||
RELEASE=6.0.UP07
|
||||
BUILD=6.0.7424
|
||||
DATE=20190611
|
||||
ARCH=noarch
|
||||
NETWORK=ari
|
||||
PATCHSET=35-201906112304
|
||||
DUMMY=foo=bar
|
||||
"""
|
||||
)
|
||||
|
||||
with clerelease_path.open("w") as f:
|
||||
f.write("5.2.UP04\n")
|
||||
|
||||
monkeypatch.setattr(cray_backend, "_clerelease_file", str(clerelease_path))
|
||||
monkeypatch.setattr(cray_backend, "_cle_release_file", str(cle_release_path))
|
||||
|
||||
assert cray_backend.CrayBackend._detect_crayos_version() == 6
|
||||
@@ -270,9 +270,12 @@ def trigger_bad_patch(pkg):
|
||||
def test_patch_failure_develop_spec_exits_gracefully(
|
||||
mock_packages, config, install_mockery, mock_fetch, tmpdir, mock_stage
|
||||
):
|
||||
"""ensure that a failing patch does not trigger exceptions for develop specs"""
|
||||
"""
|
||||
ensure that a failing patch does not trigger exceptions
|
||||
for develop specs
|
||||
"""
|
||||
|
||||
spec = Spec(f"patch-a-dependency ^libelf dev_path={tmpdir}")
|
||||
spec = Spec("patch-a-dependency " "^libelf dev_path=%s" % str(tmpdir))
|
||||
spec.concretize()
|
||||
libelf = spec["libelf"]
|
||||
assert "patches" in list(libelf.variants.keys())
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
import spack.util.executable
|
||||
import spack.util.url as url_util
|
||||
from spack.resource import Resource
|
||||
from spack.stage import DevelopStage, ResourceStage, Stage, StageComposite
|
||||
from spack.stage import DevelopStage, DIYStage, ResourceStage, Stage, StageComposite
|
||||
from spack.util.path import canonicalize_path
|
||||
|
||||
# The following values are used for common fetch and stage mocking fixtures:
|
||||
@@ -146,8 +146,9 @@ def check_destroy(stage, stage_name):
|
||||
assert not os.path.exists(stage_path)
|
||||
|
||||
# tmp stage needs to remove tmp dir too.
|
||||
target = os.path.realpath(stage_path)
|
||||
assert not os.path.exists(target)
|
||||
if not isinstance(stage, DIYStage):
|
||||
target = os.path.realpath(stage_path)
|
||||
assert not os.path.exists(target)
|
||||
|
||||
|
||||
def check_setup(stage, stage_name, archive):
|
||||
@@ -800,6 +801,62 @@ def test_stage_constructor_with_path(self, tmpdir):
|
||||
with Stage("file:///does-not-exist", path=testpath) as stage:
|
||||
assert stage.path == testpath
|
||||
|
||||
def test_diystage_path_none(self):
|
||||
"""Ensure DIYStage for path=None behaves as expected."""
|
||||
with pytest.raises(ValueError):
|
||||
DIYStage(None)
|
||||
|
||||
def test_diystage_path_invalid(self):
|
||||
"""Ensure DIYStage for an invalid path behaves as expected."""
|
||||
with pytest.raises(spack.stage.StagePathError):
|
||||
DIYStage("/path/does/not/exist")
|
||||
|
||||
def test_diystage_path_valid(self, tmpdir):
|
||||
"""Ensure DIYStage for a valid path behaves as expected."""
|
||||
path = str(tmpdir)
|
||||
stage = DIYStage(path)
|
||||
assert stage.path == path
|
||||
assert stage.source_path == path
|
||||
|
||||
# Order doesn't really matter for DIYStage since they are
|
||||
# basically NOOPs; however, call each since they are part
|
||||
# of the normal stage usage and to ensure full test coverage.
|
||||
stage.create() # Only sets the flag value
|
||||
assert stage.created
|
||||
|
||||
stage.cache_local() # Only outputs a message
|
||||
stage.fetch() # Only outputs a message
|
||||
stage.check() # Only outputs a message
|
||||
stage.expand_archive() # Only outputs a message
|
||||
|
||||
assert stage.expanded # The path/source_path does exist
|
||||
|
||||
with pytest.raises(spack.stage.RestageError):
|
||||
stage.restage()
|
||||
|
||||
stage.destroy() # A no-op
|
||||
assert stage.path == path # Ensure can still access attributes
|
||||
assert os.path.exists(stage.source_path) # Ensure path still exists
|
||||
|
||||
def test_diystage_preserve_file(self, tmpdir):
|
||||
"""Ensure DIYStage preserves an existing file."""
|
||||
# Write a file to the temporary directory
|
||||
fn = tmpdir.join(_readme_fn)
|
||||
fn.write(_readme_contents)
|
||||
|
||||
# Instantiate the DIYStage and ensure the above file is unchanged.
|
||||
path = str(tmpdir)
|
||||
stage = DIYStage(path)
|
||||
assert os.path.isdir(path)
|
||||
assert os.path.isfile(str(fn))
|
||||
|
||||
stage.create() # Only sets the flag value
|
||||
|
||||
readmefn = str(fn)
|
||||
assert os.path.isfile(readmefn)
|
||||
with open(readmefn) as _file:
|
||||
_file.read() == _readme_contents
|
||||
|
||||
|
||||
def _create_files_from_tree(base, tree):
|
||||
for name, content in tree.items():
|
||||
|
||||
@@ -272,6 +272,29 @@ def test_breadth_first_versus_depth_first_tree(abstract_specs_chain):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cover", ["nodes", "edges"])
|
||||
@pytest.mark.parametrize("depth_first", [True, False])
|
||||
def test_tree_traversal_with_key(cover, depth_first, abstract_specs_chain):
|
||||
"""Compare two multisource traversals of the same DAG. In one case the DAG consists of unique
|
||||
Spec instances, in the second case there are identical copies of nodes and edges. Traversal
|
||||
should be equivalent when nodes are identified by dag_hash."""
|
||||
a = abstract_specs_chain["chain-a"]
|
||||
c = abstract_specs_chain["chain-c"]
|
||||
kwargs = {"cover": cover, "depth_first": depth_first}
|
||||
dag_hash = lambda s: s.dag_hash()
|
||||
|
||||
# Traverse DAG spanned by a unique set of Spec instances
|
||||
first = traverse.traverse_tree([a, c], key=id, **kwargs)
|
||||
|
||||
# Traverse equivalent DAG with copies of Spec instances included, keyed by dag hash.
|
||||
second = traverse.traverse_tree([a, c.copy()], key=dag_hash, **kwargs)
|
||||
|
||||
# Check that the same nodes are discovered at the same depth
|
||||
node_at_depth_first = [(depth, dag_hash(edge.spec)) for (depth, edge) in first]
|
||||
node_at_depth_second = [(depth, dag_hash(edge.spec)) for (depth, edge) in second]
|
||||
assert node_at_depth_first == node_at_depth_second
|
||||
|
||||
|
||||
def test_breadth_first_versus_depth_first_printing(abstract_specs_chain):
|
||||
"""Test breadth-first versus depth-first tree printing."""
|
||||
s = abstract_specs_chain["chain-a"]
|
||||
|
||||
@@ -87,6 +87,13 @@ def test_url_strip_name_suffixes(url, version, expected):
|
||||
59,
|
||||
"https://github.com/nextflow-io/nextflow/releases/download/v0.20.1/nextflow",
|
||||
),
|
||||
(
|
||||
"hpcviewer",
|
||||
30,
|
||||
"2024.02",
|
||||
51,
|
||||
"https://gitlab.com/hpctoolkit/hpcviewer/-/releases/2024.02/downloads/hpcviewer.tgz",
|
||||
),
|
||||
# Version in stem
|
||||
("zlib", 24, "1.2.10", 29, "http://zlib.net/fossils/zlib-1.2.10.tar.gz"),
|
||||
(
|
||||
|
||||
@@ -563,10 +563,10 @@ def traverse_tree(
|
||||
# identical to DFS, which is much more efficient then.
|
||||
if not depth_first and cover == "edges":
|
||||
edges, parents = breadth_first_to_tree_edges(specs, deptype, key)
|
||||
return traverse_breadth_first_tree_edges(None, edges, parents)
|
||||
return traverse_breadth_first_tree_edges(None, edges, parents, key)
|
||||
elif not depth_first and cover == "nodes":
|
||||
edges = breadth_first_to_tree_nodes(specs, deptype, key)
|
||||
return traverse_breadth_first_tree_nodes(None, edges)
|
||||
return traverse_breadth_first_tree_nodes(None, edges, key)
|
||||
|
||||
return traverse_edges(specs, order="pre", cover=cover, deptype=deptype, key=key, depth=True)
|
||||
|
||||
|
||||
@@ -258,7 +258,9 @@ def parse_version_offset(path):
|
||||
# 9th Pass: Version in path
|
||||
# github.com/repo/name/releases/download/vver/name
|
||||
# e.g. https://github.com/nextflow-io/nextflow/releases/download/v0.20.1/nextflow
|
||||
# e.g. https://gitlab.com/hpctoolkit/hpcviewer/-/releases/2024.02/downloads/hpcviewer.tgz
|
||||
(r"github\.com/[^/]+/[^/]+/releases/download/[a-zA-Z+._-]*v?(\d[\da-zA-Z._-]*)/", path),
|
||||
(r"gitlab\.com/[^/]+/.+/-/releases/[a-zA-Z+._-]*v?(\d[\da-zA-Z._-]*)/downloads/", path),
|
||||
# e.g. ftp://ftp.ncbi.nlm.nih.gov/blast/executables/legacy.NOTSUPPORTED/2.2.26/ncbi.tar.gz
|
||||
(r"(\d[\da-zA-Z._-]*)/[^/]+$", path),
|
||||
]
|
||||
|
||||
@@ -21,16 +21,6 @@ def get_version_lines(version_hashes_dict: dict, url_dict: Optional[dict] = None
|
||||
version_lines = []
|
||||
|
||||
for v, h in version_hashes_dict.items():
|
||||
expand_arg = ""
|
||||
|
||||
# Extract the url for a version if url_dict is provided.
|
||||
url = ""
|
||||
if url_dict is not None and v in url_dict:
|
||||
url = url_dict[v]
|
||||
|
||||
# Add expand_arg since wheels should not be expanded during stanging
|
||||
if url.endswith(".whl") or ".whl#" in url:
|
||||
expand_arg = ", expand=False"
|
||||
version_lines.append(f' version("{v}", sha256="{h}"{expand_arg})')
|
||||
version_lines.append(f' version("{v}", sha256="{h}")')
|
||||
|
||||
return "\n".join(version_lines)
|
||||
|
||||
@@ -296,8 +296,8 @@ def process_scalar(self):
|
||||
if marked(self.event.value):
|
||||
self.saved = self.event.value
|
||||
|
||||
def write_line_break(self):
|
||||
super().write_line_break()
|
||||
def write_line_break(self, data=None):
|
||||
super().write_line_break(data)
|
||||
if self.saved is None:
|
||||
_ANNOTATIONS.append(colorize("@K{---}"))
|
||||
return
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
stages: [ "generate", "build", "publish" ]
|
||||
stages: [ "generate", "build" ]
|
||||
|
||||
variables:
|
||||
SPACK_DISABLE_LOCAL_CONFIG: "1"
|
||||
@@ -259,36 +259,6 @@ default:
|
||||
extends: [ ".base-job" ]
|
||||
stage: build
|
||||
|
||||
protected-publish:
|
||||
# Copy binaries from stack-specific mirrors to a root mirror
|
||||
stage: publish
|
||||
only:
|
||||
- /^develop$/
|
||||
- /^releases\/v.*/
|
||||
- /^v.*/
|
||||
- /^develop-[\d]{4}-[\d]{2}-[\d]{2}$/
|
||||
image: "ghcr.io/spack/python-aws-bash:0.0.1"
|
||||
tags: ["spack", "public", "medium", "aws", "x86_64"]
|
||||
retry:
|
||||
max: 2
|
||||
when: ["runner_system_failure", "stuck_or_timeout_failure"]
|
||||
variables:
|
||||
SPACK_COPY_BUILDCACHE: "${PROTECTED_MIRROR_PUSH_DOMAIN}/${CI_COMMIT_REF_NAME}"
|
||||
SPACK_PIPELINE_TYPE: "spack_protected_branch"
|
||||
KUBERNETES_CPU_REQUEST: 4000m
|
||||
KUBERNETES_MEMORY_REQUEST: 16G
|
||||
script:
|
||||
- . "./share/spack/setup-env.sh"
|
||||
- spack --version
|
||||
- export COPY_SPECS_DIR=${CI_PROJECT_DIR}/jobs_scratch_dir/specs_to_copy
|
||||
- spack buildcache sync --manifest-glob "${COPY_SPECS_DIR}/*.json"
|
||||
- curl -fLsS https://spack.github.io/keys/spack-public-binary-key.pub -o /tmp/spack-public-binary-key.pub
|
||||
- aws s3 cp /tmp/spack-public-binary-key.pub "${SPACK_COPY_BUILDCACHE}/build_cache/_pgp/spack-public-binary-key.pub"
|
||||
- spack buildcache update-index --keys "${SPACK_COPY_BUILDCACHE}"
|
||||
id_tokens:
|
||||
GITLAB_OIDC_TOKEN:
|
||||
aud: "protected_binary_mirror"
|
||||
|
||||
########################################
|
||||
# TEMPLATE FOR ADDING ANOTHER PIPELINE
|
||||
########################################
|
||||
@@ -513,28 +483,6 @@ build_systems-build:
|
||||
- artifacts: True
|
||||
job: build_systems-generate
|
||||
|
||||
###########################################
|
||||
# Build tests for different developer tools
|
||||
###########################################
|
||||
.developer-tools:
|
||||
extends: [ ".linux_x86_64_v3" ]
|
||||
variables:
|
||||
SPACK_CI_STACK_NAME: developer-tools
|
||||
|
||||
developer-tools-generate:
|
||||
extends: [ ".developer-tools", ".generate-x86_64"]
|
||||
|
||||
developer-tools-build:
|
||||
extends: [ ".developer-tools", ".build" ]
|
||||
trigger:
|
||||
include:
|
||||
- artifact: jobs_scratch_dir/cloud-ci-pipeline.yml
|
||||
job: developer-tools-generate
|
||||
strategy: depend
|
||||
needs:
|
||||
- artifacts: True
|
||||
job: developer-tools-generate
|
||||
|
||||
###########################################
|
||||
# Build tests for different developer tools
|
||||
# manylinux2014
|
||||
@@ -742,7 +690,7 @@ tutorial-build:
|
||||
|
||||
ml-linux-x86_64-cpu-generate:
|
||||
extends: [ ".generate-x86_64", .ml-linux-x86_64-cpu, ".tags-x86_64_v4" ]
|
||||
image: ghcr.io/spack/linux-ubuntu22.04-x86_64_v2:v2024-01-29
|
||||
image: ghcr.io/spack/ubuntu-22.04:v2024-05-07
|
||||
|
||||
ml-linux-x86_64-cpu-build:
|
||||
extends: [ ".build", ".ml-linux-x86_64-cpu" ]
|
||||
@@ -765,7 +713,7 @@ ml-linux-x86_64-cpu-build:
|
||||
|
||||
ml-linux-x86_64-cuda-generate:
|
||||
extends: [ ".generate-x86_64", .ml-linux-x86_64-cuda, ".tags-x86_64_v4" ]
|
||||
image: ghcr.io/spack/linux-ubuntu22.04-x86_64_v2:v2024-01-29
|
||||
image: ghcr.io/spack/ubuntu-22.04:v2024-05-07
|
||||
|
||||
ml-linux-x86_64-cuda-build:
|
||||
extends: [ ".build", ".ml-linux-x86_64-cuda" ]
|
||||
|
||||
@@ -10,6 +10,7 @@ set -e
|
||||
# The best solution would be to have the compilers hash (or packages contents) be part of the
|
||||
# individual packages hashes. I don't see this at the moment.
|
||||
# Set to the latest tag including a recent oneapi compiler.
|
||||
# NOTE: If we update this spack version in the future make sure the compiler version also updates.
|
||||
spack_intel_compiler_commit="develop-2023-08-06"
|
||||
|
||||
set_pcluster_defaults() {
|
||||
@@ -23,10 +24,9 @@ set_pcluster_defaults() {
|
||||
|
||||
setup_spack() {
|
||||
spack compiler add --scope site
|
||||
spack external find --scope site
|
||||
# Remove all autotools/buildtools packages. These versions need to be managed by spack or it will
|
||||
# Do not add autotools/buildtools packages. These versions need to be managed by spack or it will
|
||||
# eventually end up in a version mismatch (e.g. when compiling gmp).
|
||||
spack tags build-tools | xargs -I {} spack config --scope site rm packages:{}
|
||||
spack external find --scope site --tag core-packages
|
||||
}
|
||||
|
||||
patch_compilers_yaml() {
|
||||
@@ -99,7 +99,7 @@ install_compilers() {
|
||||
# The compilers needs to be in the same install tree as the rest of the software such that the path
|
||||
# relocation works correctly. This holds the danger that this part will fail when the current spack gets
|
||||
# incompatible with the one in $spack_intel_compiler_commit. Therefore, we make intel installations optional
|
||||
# in package.yaml files.
|
||||
# in package.yaml files and add a fallback `%gcc` version for each application.
|
||||
if [ "x86_64" == "$(arch)" ]; then
|
||||
(
|
||||
CURRENT_SPACK_ROOT=${SPACK_ROOT}
|
||||
|
||||
@@ -19,7 +19,10 @@ packages:
|
||||
llvm:
|
||||
variants: ~lldb
|
||||
mpas-model:
|
||||
require: "precision=single make_target=llvm %arm ^parallelio+pnetcdf"
|
||||
require:
|
||||
- one_of:
|
||||
- "precision=single make_target=llvm %arm ^parallelio+pnetcdf"
|
||||
- "precision=single %gcc ^parallelio+pnetcdf"
|
||||
mpich:
|
||||
require: "mpich pmi=pmi2 device=ch4 netmod=ofi +slurm"
|
||||
nvhpc:
|
||||
|
||||
@@ -2,13 +2,23 @@ spack:
|
||||
view: false
|
||||
|
||||
definitions:
|
||||
- optimized_configs:
|
||||
- gromacs target=neoverse_v1
|
||||
- gromacs target=neoverse_n1
|
||||
- apps:
|
||||
- gromacs
|
||||
- mpas-model
|
||||
- mpich
|
||||
- openfoam
|
||||
# - quantum-espresso : %gcc@12.3.0 on neoverse_v1 fails.
|
||||
# Root cause: internal compiler error: in compute_live_loop_exits, at tree-ssa-loop-manip.cc:247
|
||||
- wrf
|
||||
|
||||
- targets:
|
||||
- 'target=neoverse_v1'
|
||||
- 'target=neoverse_n1'
|
||||
|
||||
specs:
|
||||
- $optimized_configs
|
||||
|
||||
- matrix:
|
||||
- [$apps]
|
||||
- [$targets]
|
||||
ci:
|
||||
pipeline-gen:
|
||||
- build-job:
|
||||
|
||||
@@ -5,13 +5,20 @@ packages:
|
||||
- one_of:
|
||||
- "cflags=-std=c18 target=x86_64_v4"
|
||||
- "cflags=-std=c18 target=x86_64_v3"
|
||||
- "%gcc"
|
||||
when: "%intel"
|
||||
gettext:
|
||||
# Newer gettext cannot build with gcc@12 and old AL2 glibc headers
|
||||
# Older gettext versions do not build correctly with oneapi.
|
||||
require:
|
||||
- one_of:
|
||||
- '@:0.20'
|
||||
- '%oneapi'
|
||||
gromacs:
|
||||
require:
|
||||
- one_of:
|
||||
- "+intel_provided_gcc %intel ^intel-oneapi-mkl target=x86_64_v4"
|
||||
- "+intel_provided_gcc %intel ^intel-oneapi-mkl target=x86_64_v3"
|
||||
- "%gcc"
|
||||
- "+intel_provided_gcc ^intel-oneapi-mkl target=x86_64_v4"
|
||||
- "+intel_provided_gcc ^intel-oneapi-mkl target=x86_64_v3"
|
||||
when: "%intel"
|
||||
intel-mpi:
|
||||
variants: +external-libfabric
|
||||
intel-oneapi-compilers:
|
||||
@@ -21,15 +28,15 @@ packages:
|
||||
lammps:
|
||||
require:
|
||||
- one_of:
|
||||
- "lammps_sizes=bigbig +molecule +kspace +rigid +asphere +opt +openmp +openmp-package +intel %intel ^intel-oneapi-mkl target=x86_64_v4"
|
||||
- "lammps_sizes=bigbig +molecule +kspace +rigid +asphere +opt +openmp +openmp-package %intel ^intel-oneapi-mkl target=x86_64_v3"
|
||||
- "%gcc"
|
||||
- "lammps_sizes=bigbig +molecule +kspace +rigid +asphere +opt +openmp +openmp-package +intel ^intel-oneapi-mkl target=x86_64_v4"
|
||||
- "lammps_sizes=bigbig +molecule +kspace +rigid +asphere +opt +openmp +openmp-package ^intel-oneapi-mkl target=x86_64_v3"
|
||||
when: "%intel"
|
||||
libidn2:
|
||||
require:
|
||||
- one_of:
|
||||
- "cflags=-std=c18 target=x86_64_v4"
|
||||
- "cflags=-std=c18 target=x86_64_v3"
|
||||
- '%gcc'
|
||||
when: "%intel"
|
||||
libfabric:
|
||||
buildable: true
|
||||
externals:
|
||||
@@ -41,13 +48,13 @@ packages:
|
||||
- one_of:
|
||||
- "cflags=-std=c18 target=x86_64_v4"
|
||||
- "cflags=-std=c18 target=x86_64_v3"
|
||||
- "%gcc"
|
||||
when: "%intel"
|
||||
mpas-model:
|
||||
require:
|
||||
- one_of:
|
||||
- "precision=single %intel ^parallelio+pnetcdf target=x86_64_v4"
|
||||
- "precision=single %intel ^parallelio+pnetcdf target=x86_64_v3"
|
||||
- "%gcc"
|
||||
- "precision=single ^parallelio+pnetcdf target=x86_64_v4"
|
||||
- "precision=single ^parallelio+pnetcdf target=x86_64_v3"
|
||||
when: "%intel"
|
||||
mpich:
|
||||
require:
|
||||
- one_of:
|
||||
@@ -67,9 +74,12 @@ packages:
|
||||
palace:
|
||||
require:
|
||||
- one_of:
|
||||
- "palace %oneapi ^fmt@9.1.0 target=x86_64_v4"
|
||||
- "palace %oneapi ^fmt@9.1.0 target=x86_64_v3"
|
||||
- "%gcc ^fmt@9.1.0"
|
||||
- "palace ^fmt@9.1.0 target=x86_64_v4"
|
||||
- "palace ^fmt@9.1.0 target=x86_64_v3"
|
||||
when: "%oneapi"
|
||||
- one_of:
|
||||
- "palace ^fmt@9.1.0"
|
||||
when: "%gcc"
|
||||
pmix:
|
||||
require:
|
||||
- one_of:
|
||||
@@ -78,9 +88,9 @@ packages:
|
||||
quantum-espresso:
|
||||
require:
|
||||
- one_of:
|
||||
- "quantum-espresso@6.6 %intel ^intel-oneapi-mkl+cluster target=x86_64_v4"
|
||||
- "quantum-espresso@6.6 %intel ^intel-oneapi-mkl+cluster target=x86_64_v3"
|
||||
- "%gcc"
|
||||
- "quantum-espresso@6.6 ^intel-oneapi-mkl+cluster target=x86_64_v4"
|
||||
- "quantum-espresso@6.6 ^intel-oneapi-mkl+cluster target=x86_64_v3"
|
||||
when: "%intel"
|
||||
slurm:
|
||||
buildable: false
|
||||
externals:
|
||||
@@ -89,12 +99,13 @@ packages:
|
||||
wrf:
|
||||
require:
|
||||
- one_of:
|
||||
- "wrf@4 build_type=dm+sm %intel target=x86_64_v4"
|
||||
- "wrf@4 build_type=dm+sm %intel target=x86_64_v3"
|
||||
- "wrf@4.2.2 +netcdf_classic fflags=\"-fp-model fast=2 -no-heap-arrays -no-prec-div -no-prec-sqrt -fno-common\" build_type=dm+sm %intel target=x86_64_v3"
|
||||
- "%gcc"
|
||||
- "wrf@4 build_type=dm+sm target=x86_64_v4"
|
||||
- "wrf@4 build_type=dm+sm target=x86_64_v3"
|
||||
- "wrf@4.2.2 +netcdf_classic fflags=\"-fp-model fast=2 -no-heap-arrays -no-prec-div -no-prec-sqrt -fno-common\" build_type=dm+sm target=x86_64_v3"
|
||||
when: "%intel"
|
||||
|
||||
all:
|
||||
compiler: [intel, gcc]
|
||||
compiler: [intel, oneapi, gcc]
|
||||
permissions:
|
||||
read: world
|
||||
write: user
|
||||
|
||||
@@ -2,14 +2,24 @@ spack:
|
||||
view: false
|
||||
|
||||
definitions:
|
||||
- apps:
|
||||
- gromacs %intel
|
||||
- lammps %intel
|
||||
- mpas-model %intel
|
||||
- openfoam %gcc
|
||||
- palace %oneapi
|
||||
- quantum-espresso %intel
|
||||
# - wrf : While building hdf5 cmake errors out with Detecting Fortran/C Interface: Failed to compile
|
||||
# Root cause: ifort cannot deal with arbitrarily long file names.
|
||||
|
||||
- optimized_configs:
|
||||
- palace target=x86_64_v4
|
||||
- palace target=x86_64_v3
|
||||
- targets:
|
||||
- 'target=x86_64_v4'
|
||||
- 'target=x86_64_v3'
|
||||
|
||||
specs:
|
||||
- $optimized_configs
|
||||
|
||||
- matrix:
|
||||
- [$apps]
|
||||
- [$targets]
|
||||
ci:
|
||||
pipeline-gen:
|
||||
- build-job:
|
||||
@@ -28,5 +38,6 @@ spack:
|
||||
# Do not distribute Intel & ARM binaries
|
||||
- - for i in $(aws s3 ls --recursive ${SPACK_REMOTE_MIRROR_OVERRIDE}/build_cache/ | grep intel-oneapi | awk '{print $4}' | sed -e 's?^.*build_cache/??g'); do aws s3 rm ${SPACK_REMOTE_MIRROR_OVERRIDE}/build_cache/$i; done
|
||||
- for i in $(aws s3 ls --recursive ${SPACK_REMOTE_MIRROR_OVERRIDE}/build_cache/ | grep armpl | awk '{print $4}' | sed -e 's?^.*build_cache/??g'); do aws s3 rm ${SPACK_REMOTE_MIRROR_OVERRIDE}/build_cache/$i; done
|
||||
|
||||
cdash:
|
||||
build-group: AWS Packages
|
||||
|
||||
@@ -56,6 +56,16 @@ spack:
|
||||
- openssl certs=system # must be this, system external does not work
|
||||
- libtree
|
||||
- patchelf
|
||||
- sed
|
||||
- which
|
||||
- elfutils
|
||||
- fontconfig
|
||||
- font-util
|
||||
- gdb
|
||||
- flex
|
||||
- graphviz
|
||||
- doxygen
|
||||
- meson
|
||||
|
||||
- arch:
|
||||
- '%gcc target=x86_64_v3'
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
spack:
|
||||
view: false
|
||||
packages:
|
||||
all:
|
||||
require: target=x86_64_v3
|
||||
concretizer:
|
||||
unify: true
|
||||
definitions:
|
||||
- default_specs:
|
||||
# editors
|
||||
- neovim~no_luajit
|
||||
- py-pynvim
|
||||
- emacs@29.1+json+native+treesitter # note, pulls in gcc
|
||||
# - tree-sitter is a dep, should also have cli but no package
|
||||
- nano # just in case
|
||||
# tags and scope search helpers
|
||||
- universal-ctags # only maintained ctags, works better with c++
|
||||
- direnv
|
||||
# runtimes and compilers
|
||||
- python
|
||||
- llvm+link_llvm_dylib~lld~lldb~polly+python build_type=MinSizeRel # for clangd, clang-format
|
||||
- node-js # for editor plugins etc., pyright language server
|
||||
- npm
|
||||
- go # to build fzf, gh, hub
|
||||
- rust+dev # fd, ripgrep, hyperfine, exa, rust-analyzer
|
||||
- binutils+ld+gold+plugins # support linking with built gcc
|
||||
# styling and lints
|
||||
- astyle
|
||||
- cppcheck
|
||||
- uncrustify
|
||||
- py-fprettify
|
||||
- py-fortran-language-server
|
||||
- py-python-lsp-server
|
||||
# cli dev tools
|
||||
- ripgrep
|
||||
- gh
|
||||
- fd
|
||||
- bfs
|
||||
- fzf
|
||||
- tree
|
||||
- jq
|
||||
- py-yq
|
||||
- hub
|
||||
- ncdu
|
||||
- eza
|
||||
- lsd
|
||||
- hyperfine
|
||||
- htop
|
||||
- tmux
|
||||
- ccache
|
||||
# ensure we can use a jobserver build and do this fast
|
||||
- gmake
|
||||
- ninja # should be @kitware, can't be because of meson requirement
|
||||
- "openssl certs=system" # must be this, system external does not work
|
||||
- arch:
|
||||
- '%gcc target=x86_64_v3'
|
||||
|
||||
specs:
|
||||
- matrix:
|
||||
- - $default_specs
|
||||
- - $arch
|
||||
|
||||
ci:
|
||||
pipeline-gen:
|
||||
- build-job:
|
||||
image: "ghcr.io/spack/ubuntu20.04-runner-amd64-gcc-11.4:2023.08.01"
|
||||
|
||||
cdash:
|
||||
build-group: Developer Tools
|
||||
@@ -51,21 +51,21 @@ spack:
|
||||
|
||||
specs:
|
||||
# CPU
|
||||
- adios
|
||||
- alquimia
|
||||
- aml
|
||||
# - adios
|
||||
# - alquimia
|
||||
# - aml
|
||||
- amrex
|
||||
- arborx
|
||||
- argobots
|
||||
# - argobots
|
||||
- ascent # ecp dav
|
||||
- axom
|
||||
- bolt
|
||||
- boost
|
||||
# - bolt
|
||||
# - boost
|
||||
- butterflypack
|
||||
- cabana
|
||||
- caliper
|
||||
- chai
|
||||
- charliecloud
|
||||
# - charliecloud
|
||||
- conduit
|
||||
- cp2k +mpi
|
||||
- datatransferkit
|
||||
@@ -73,15 +73,15 @@ spack:
|
||||
- ecp-data-vis-sdk ~cuda ~rocm +adios2 +ascent +cinema +darshan +faodel +hdf5 ~paraview +pnetcdf +sz +unifyfs +veloc ~visit +vtkm +zfp # +visit: ?
|
||||
- exaworks
|
||||
- flecsi
|
||||
- flit
|
||||
- flux-core
|
||||
# - flit
|
||||
# - flux-core
|
||||
- fortrilinos
|
||||
- gasnet
|
||||
# - gasnet
|
||||
- ginkgo
|
||||
- globalarrays
|
||||
- gmp
|
||||
- gotcha
|
||||
- gptune ~mpispawn
|
||||
# - globalarrays
|
||||
# - gmp
|
||||
# - gotcha
|
||||
# - gptune ~mpispawn
|
||||
- gromacs +cp2k ^cp2k +mpi +dlaf build_system=cmake
|
||||
- h5bench
|
||||
- hdf5-vol-async
|
||||
@@ -110,10 +110,10 @@ spack:
|
||||
- nco
|
||||
- netlib-scalapack
|
||||
- nrm
|
||||
- nvhpc
|
||||
# - nvhpc
|
||||
- omega-h
|
||||
- openfoam
|
||||
- openmpi
|
||||
# - openmpi
|
||||
- openpmd-api
|
||||
- papi
|
||||
- papyrus
|
||||
@@ -144,35 +144,35 @@ spack:
|
||||
- sundials
|
||||
- superlu
|
||||
- superlu-dist
|
||||
- swig@4.0.2-fortran
|
||||
# - swig@4.0.2-fortran
|
||||
- sz3
|
||||
- tasmanian
|
||||
- tau +mpi +python +syscall
|
||||
- trilinos +amesos +amesos2 +anasazi +aztec +belos +boost +epetra +epetraext +ifpack +ifpack2 +intrepid +intrepid2 +isorropia +kokkos +ml +minitensor +muelu +nox +piro +phalanx +rol +rythmos +sacado +stk +shards +shylu +stokhos +stratimikos +teko +tempus +tpetra +trilinoscouplings +zoltan +zoltan2 +superlu-dist gotype=long_long
|
||||
- turbine
|
||||
- umap
|
||||
# - umap
|
||||
- umpire
|
||||
- upcxx
|
||||
- veloc
|
||||
# - veloc
|
||||
- wannier90
|
||||
- xyce +mpi +shared +pymi +pymi_static_tpls
|
||||
# INCLUDED IN ECP DAV CPU
|
||||
- adios2
|
||||
- darshan-runtime
|
||||
- darshan-util
|
||||
- faodel
|
||||
- hdf5
|
||||
- libcatalyst
|
||||
- parallel-netcdf
|
||||
# - adios2
|
||||
# - darshan-runtime
|
||||
# - darshan-util
|
||||
# - faodel
|
||||
# - hdf5
|
||||
# - libcatalyst
|
||||
# - parallel-netcdf
|
||||
# - paraview
|
||||
- py-cinemasci
|
||||
- sz
|
||||
- unifyfs
|
||||
- laghos
|
||||
# - py-cinemasci
|
||||
# - sz
|
||||
# - unifyfs
|
||||
# - visit # silo: https://github.com/spack/spack/issues/39538
|
||||
- vtk-m
|
||||
- zfp
|
||||
# - vtk-m
|
||||
# - zfp
|
||||
# --
|
||||
- laghos
|
||||
# - bricks ~cuda # not respecting target=aarch64?
|
||||
# - dealii # slepc: make[1]: *** internal error: invalid --jobserver-auth string 'fifo:/tmp/GMfifo1313'.
|
||||
# - geopm # geopm: https://github.com/spack/spack/issues/38795
|
||||
@@ -181,25 +181,25 @@ spack:
|
||||
# - variorum # variorum: https://github.com/spack/spack/issues/38786
|
||||
|
||||
# PYTHON PACKAGES
|
||||
- opencv +python3
|
||||
- py-horovod
|
||||
- py-jax
|
||||
- py-jupyterlab
|
||||
- py-matplotlib
|
||||
- py-mpi4py
|
||||
- py-notebook
|
||||
- py-numba
|
||||
- py-numpy
|
||||
- py-openai
|
||||
- py-pandas
|
||||
- py-plotly
|
||||
- py-pooch
|
||||
- py-pytest
|
||||
- py-scikit-learn
|
||||
- py-scipy
|
||||
- py-seaborn
|
||||
- py-tensorflow
|
||||
- py-torch
|
||||
# - opencv +python3
|
||||
# - py-horovod
|
||||
# - py-jax
|
||||
# - py-jupyterlab
|
||||
# - py-matplotlib
|
||||
# - py-mpi4py
|
||||
# - py-notebook
|
||||
# - py-numba
|
||||
# - py-numpy
|
||||
# - py-openai
|
||||
# - py-pandas
|
||||
# - py-plotly
|
||||
# - py-pooch
|
||||
# - py-pytest
|
||||
# - py-scikit-learn
|
||||
# - py-scipy
|
||||
# - py-seaborn
|
||||
# - py-tensorflow
|
||||
# - py-torch
|
||||
|
||||
# CUDA NOARCH
|
||||
- flux-core +cuda
|
||||
@@ -210,100 +210,6 @@ spack:
|
||||
# - bricks +cuda # not respecting target=aarch64?
|
||||
# - legion +cuda # legion: needs NVIDIA driver
|
||||
|
||||
# CUDA 75
|
||||
- amrex +cuda cuda_arch=75
|
||||
- arborx +cuda cuda_arch=75 ^kokkos +wrapper
|
||||
- cabana +cuda cuda_arch=75 ^kokkos +wrapper +cuda_lambda +cuda cuda_arch=75
|
||||
- caliper +cuda cuda_arch=75
|
||||
- chai +cuda cuda_arch=75 ^umpire ~shared
|
||||
# - cp2k +mpi +cuda cuda_arch=75 # cp2k: cp2k only supports cuda_arch ('35', '37', '60', '70', '80')
|
||||
- flecsi +cuda cuda_arch=75
|
||||
- ginkgo +cuda cuda_arch=75
|
||||
- gromacs +cuda cuda_arch=75
|
||||
- heffte +cuda cuda_arch=75
|
||||
- hpx +cuda cuda_arch=75
|
||||
- hypre +cuda cuda_arch=75
|
||||
- kokkos +wrapper +cuda cuda_arch=75
|
||||
- kokkos-kernels +cuda cuda_arch=75 ^kokkos +wrapper +cuda cuda_arch=75
|
||||
- magma +cuda cuda_arch=75
|
||||
- mfem +cuda cuda_arch=75
|
||||
- mgard +serial +openmp +timing +unstructured +cuda cuda_arch=75
|
||||
- omega-h +cuda cuda_arch=75
|
||||
- parsec +cuda cuda_arch=75
|
||||
- petsc +cuda cuda_arch=75
|
||||
- raja +cuda cuda_arch=75
|
||||
- slate +cuda cuda_arch=75
|
||||
- strumpack ~slate +cuda cuda_arch=75
|
||||
- sundials +cuda cuda_arch=75
|
||||
- superlu-dist +cuda cuda_arch=75
|
||||
- tasmanian +cuda cuda_arch=75
|
||||
- trilinos +cuda cuda_arch=75
|
||||
- umpire ~shared +cuda cuda_arch=75
|
||||
# INCLUDED IN ECP DAV CUDA
|
||||
- adios2 +cuda cuda_arch=75
|
||||
# - paraview +cuda cuda_arch=75
|
||||
- vtk-m +cuda cuda_arch=75
|
||||
- zfp +cuda cuda_arch=75
|
||||
# --
|
||||
# - ascent +cuda cuda_arch=75 # ascent: https://github.com/spack/spack/issues/38045
|
||||
# - axom +cuda cuda_arch=75 # axom: https://github.com/spack/spack/issues/29520
|
||||
# - cusz +cuda cuda_arch=75 # cusz: https://github.com/spack/spack/issues/38787
|
||||
# - dealii +cuda cuda_arch=75 # slepc: make[1]: *** internal error: invalid --jobserver-auth string 'fifo:/tmp/GMfifo1313'.
|
||||
# - ecp-data-vis-sdk +adios2 +hdf5 +vtkm +zfp +paraview +cuda cuda_arch=75 # embree: https://github.com/spack/spack/issues/39534
|
||||
# - lammps +cuda cuda_arch=75 # lammps: needs NVIDIA driver
|
||||
# - lbann +cuda cuda_arch=75 # lbann: https://github.com/spack/spack/issues/38788
|
||||
# - libpressio +bitgrooming +bzip2 +fpzip +hdf5 +libdistributed +lua +openmp +python +sz +sz3 +unix +zfp +json +remote +netcdf ~cusz +mgard +cuda cuda_arch=75 # libpressio: CMake Error at CMakeLists.txt:498 (find_library): Could not find CUFile_LIBRARY using the following names: cufile ; +cusz: https://github.com/spack/spack/issues/38787
|
||||
# - py-torch +cuda cuda_arch=75 # skipped, installed by other means
|
||||
# - slepc +cuda cuda_arch=75 # slepc: make[1]: *** internal error: invalid --jobserver-auth string 'fifo:/tmp/GMfifo1313'.
|
||||
# - upcxx +cuda cuda_arch=75 # upcxx: needs NVIDIA driver
|
||||
|
||||
# CUDA 80
|
||||
- amrex +cuda cuda_arch=80
|
||||
- arborx +cuda cuda_arch=80 ^kokkos +wrapper
|
||||
- cabana +cuda cuda_arch=80 ^kokkos +wrapper +cuda_lambda +cuda cuda_arch=80
|
||||
- caliper +cuda cuda_arch=80
|
||||
- chai +cuda cuda_arch=80 ^umpire ~shared
|
||||
# - cp2k +mpi +cuda cuda_arch=80 # cp2k: Error: KeyError: 'Point environment variable LIBSMM_PATH to the absolute path of the libsmm.a file'
|
||||
- flecsi +cuda cuda_arch=80
|
||||
- ginkgo +cuda cuda_arch=80
|
||||
- gromacs +cuda cuda_arch=80
|
||||
- heffte +cuda cuda_arch=80
|
||||
- hpx +cuda cuda_arch=80
|
||||
- hypre +cuda cuda_arch=80
|
||||
- kokkos +wrapper +cuda cuda_arch=80
|
||||
- kokkos-kernels +cuda cuda_arch=80 ^kokkos +wrapper +cuda cuda_arch=80
|
||||
- magma +cuda cuda_arch=80
|
||||
- mfem +cuda cuda_arch=80
|
||||
- mgard +serial +openmp +timing +unstructured +cuda cuda_arch=80
|
||||
- omega-h +cuda cuda_arch=80
|
||||
- parsec +cuda cuda_arch=80
|
||||
- petsc +cuda cuda_arch=80
|
||||
- raja +cuda cuda_arch=80
|
||||
- slate +cuda cuda_arch=80
|
||||
- strumpack ~slate +cuda cuda_arch=80
|
||||
- sundials +cuda cuda_arch=80
|
||||
- superlu-dist +cuda cuda_arch=80
|
||||
- tasmanian +cuda cuda_arch=80
|
||||
- trilinos +cuda cuda_arch=80
|
||||
- umpire ~shared +cuda cuda_arch=80
|
||||
# INCLUDED IN ECP DAV CUDA
|
||||
- adios2 +cuda cuda_arch=80
|
||||
# - paraview +cuda cuda_arch=80
|
||||
- vtk-m +cuda cuda_arch=80
|
||||
- zfp +cuda cuda_arch=80
|
||||
# --
|
||||
# - ascent +cuda cuda_arch=80 # ascent: https://github.com/spack/spack/issues/38045
|
||||
# - axom +cuda cuda_arch=80 # axom: https://github.com/spack/spack/issues/29520
|
||||
# - cusz +cuda cuda_arch=80 # cusz: https://github.com/spack/spack/issues/38787
|
||||
# - dealii +cuda cuda_arch=80 # slepc: make[1]: *** internal error: invalid --jobserver-auth string 'fifo:/tmp/GMfifo1313'.
|
||||
# - ecp-data-vis-sdk +adios2 +hdf5 +vtkm +zfp +paraview +cuda cuda_arch=80 # embree: https://github.com/spack/spack/issues/39534
|
||||
# - lammps +cuda cuda_arch=80 # lammps: needs NVIDIA driver
|
||||
# - lbann +cuda cuda_arch=80 # lbann: https://github.com/spack/spack/issues/38788
|
||||
# - libpressio +bitgrooming +bzip2 +fpzip +hdf5 +libdistributed +lua +openmp +python +sz +sz3 +unix +zfp +json +remote +netcdf ~cusz +mgard +cuda cuda_arch=80 # libpressio: CMake Error at CMakeLists.txt:498 (find_library): Could not find CUFile_LIBRARY using the following names: cufile ; +cusz: https://github.com/spack/spack/issues/38787
|
||||
# - py-torch +cuda cuda_arch=80 # skipped, installed by other means
|
||||
# - slepc +cuda cuda_arch=80 # slepc: make[1]: *** internal error: invalid --jobserver-auth string 'fifo:/tmp/GMfifo1313'.
|
||||
# - upcxx +cuda cuda_arch=80 # upcxx: needs NVIDIA driver
|
||||
|
||||
# CUDA 90
|
||||
- amrex +cuda cuda_arch=90
|
||||
- arborx +cuda cuda_arch=90 ^kokkos +wrapper
|
||||
|
||||
@@ -79,7 +79,7 @@ spack:
|
||||
pipeline-gen:
|
||||
- build-job:
|
||||
image:
|
||||
name: ghcr.io/spack/linux-ubuntu22.04-x86_64_v2:v2024-01-29
|
||||
name: ghcr.io/spack/ubuntu-22.04:v2024-05-07
|
||||
entrypoint: ['']
|
||||
|
||||
cdash:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user