1# Configurations that should only be overrided by
2# overrideAttrs
3{
4 pname,
5 version,
6 src,
7 projectName, # "apptainer" or "singularity"
8 vendorHash ? null,
9 deleteVendor ? false,
10 proxyVendor ? false,
11 extraConfigureFlags ? [ ],
12 extraDescription ? "",
13 extraMeta ? { },
14}:
15
16let
17 # Backward compatibility layer for the obsolete workaround of
18 # the "vendor-related attributes not overridable" issue (#86349),
19 # whose solution (#225051) is merged and released.
20 # TODO(@ShamrockLee): Remove after the Nixpkgs 25.05 branch-off.
21 _defaultGoVendorArgs = {
22 inherit vendorHash deleteVendor proxyVendor;
23 };
24in
25{
26 lib,
27 buildGoModule,
28 runCommandLocal,
29 replaceVars,
30 # Native build inputs
31 addDriverRunpath,
32 makeWrapper,
33 pkg-config,
34 util-linux,
35 which,
36 # Build inputs
37 bash,
38 callPackage,
39 conmon,
40 coreutils,
41 cryptsetup,
42 e2fsprogs,
43 fakeroot,
44 fuse2fs ? e2fsprogs.fuse2fs,
45 go,
46 gpgme,
47 libseccomp,
48 libuuid,
49 mount,
50 versionCheckHook,
51 # This is for nvidia-container-cli
52 nvidia-docker,
53 openssl,
54 squashfsTools,
55 squashfuse,
56 # Test dependencies
57 singularity-tools,
58 cowsay,
59 hello,
60 # Overridable configurations
61 enableNvidiaContainerCli ? true,
62 # --nvccli currently requires extra privileges:
63 # https://github.com/apptainer/apptainer/issues/1893#issuecomment-1881240800
64 forceNvcCli ? false,
65 # Compile with seccomp support
66 # SingularityCE 3.10.0 and above requires explicit --without-seccomp when libseccomp is not available.
67 enableSeccomp ? true,
68 # Whether the configure script treat SUID support as default
69 # When equal to enableSuid, it suppress the --with-suid / --without-suid build flag
70 # It can be set to `null` to always pass either --with-suid or --without-suided
71 # Type: null or boolean
72 defaultToSuid ? true,
73 # Whether to compile with SUID support
74 enableSuid ? false,
75 starterSuidPath ? null,
76 # Extra system-wide /**/bin paths to prefix,
77 # useful to specify directories containing binaries with SUID bit set.
78 # The paths take higher precedence over the FHS system PATH specified
79 # inside the upstream source code.
80 # Include "/run/wrappers/bin" by default for the convenience of NixOS users.
81 systemBinPaths ? [ "/run/wrappers/bin" ],
82 # External LOCALSTATEDIR
83 externalLocalStateDir ? null,
84 # Remove the symlinks to `singularity*` when projectName != "singularity"
85 removeCompat ? false,
86 # The defaultPath values to substitute in each source files.
87 #
88 # `defaultPath` are PATH variables hard-coded inside Apptainer/Singularity
89 # binaries to search for third-party utilities, as a hardening for
90 # `$out/bin/starter-suid`.
91 #
92 # The upstream provided values are suitable for FHS-conformant environment.
93 # We substitute them and insert Nixpkgs-specific values.
94 #
95 # Example:
96 # {
97 # "path/to/source/file1" = [ "<originalDefaultPath11>" "<originalDefaultPath12>" ... ];
98 # }
99 sourceFilesWithDefaultPaths ? { },
100 # Placeholders for the obsolete workaround of #86349
101 # TODO(@ShamrockLee): Remove after the Nixpkgs 25.05 branch-off.
102 vendorHash ? null,
103 deleteVendor ? null,
104 proxyVendor ? null,
105}@args:
106
107let
108 # Backward compatibility layer for the obsolete workaround of #86349
109 # TODO(@ShamrockLee): Convert to simple inheritance after the Nixpkgs 25.05 branch-off.
110 moduleArgsOverridingCompat =
111 argName:
112 if args.${argName} or null == null then
113 _defaultGoVendorArgs.${argName}
114 else
115 lib.warn
116 "${projectName}: Override ${argName} with .override is deprecated. Use .overrideAttrs instead."
117 args.${argName};
118 vendorHash = moduleArgsOverridingCompat "vendorHash";
119 deleteVendor = moduleArgsOverridingCompat "deleteVendor";
120 proxyVendor = moduleArgsOverridingCompat "proxyVendor";
121
122 addShellDoubleQuotes = s: lib.escapeShellArg ''"'' + s + lib.escapeShellArg ''"'';
123in
124(buildGoModule {
125 inherit pname version src;
126
127 patches = lib.optionals (projectName == "apptainer") [
128 (replaceVars ./apptainer/0001-ldCache-patch-for-driverLink.patch {
129 inherit (addDriverRunpath) driverLink;
130 })
131 ];
132
133 # Override vendorHash with the output got from
134 # nix-prefetch -E "{ sha256 }: ((import ./. { }).apptainer.override { vendorHash = sha256; }).goModules"
135 # or with `null` when using vendored source tarball.
136 inherit vendorHash deleteVendor proxyVendor;
137
138 # go is used to compile extensions when building container images
139 allowGoReference = true;
140
141 strictDeps = true;
142
143 passthru = {
144 inherit
145 enableSeccomp
146 enableSuid
147 externalLocalStateDir
148 projectName
149 removeCompat
150 starterSuidPath
151 ;
152 };
153
154 nativeBuildInputs = [
155 makeWrapper
156 pkg-config
157 util-linux
158 which
159 ];
160
161 # Search inside the project sources
162 # and see the `control` file of the Debian package from upstream repos
163 # for build-time dependencies and run-time utilities
164 # apptainer/apptainer: https://github.com/apptainer/apptainer/blob/main/dist/debian/control
165 # sylabs/singularity: https://github.com/sylabs/singularity/blob/main/debian/control
166
167 buildInputs = [
168 bash # To patch /bin/sh shebangs.
169 conmon
170 cryptsetup
171 gpgme
172 libuuid
173 openssl
174 squashfsTools # Required at build time by SingularityCE
175 ]
176 # Optional dependencies.
177 # Formatting: Optional dependencies are likely to increase.
178 # Don't squash them into the same line.
179 ++ lib.optional enableNvidiaContainerCli nvidia-docker
180 ++ lib.optional enableSeccomp libseccomp;
181
182 configureScript = "./mconfig";
183
184 configureFlags = [
185 "--localstatedir=${
186 if externalLocalStateDir != null then externalLocalStateDir else "${placeholder "out"}/var/lib"
187 }"
188 "--runstatedir=/var/run"
189 ]
190 ++ lib.optional (!enableSeccomp) "--without-seccomp"
191 ++ lib.optional (enableSuid != defaultToSuid) (
192 if enableSuid then "--with-suid" else "--without-suid"
193 )
194 ++ extraConfigureFlags;
195
196 # causes redefinition of _FORTIFY_SOURCE
197 hardeningDisable = [ "fortify3" ];
198
199 # Packages to provide fallback bin paths
200 # to the Apptainer/Singularity container runtime default PATHs.
201 # Override with `<pkg>.overrideAttrs`.
202 defaultPathInputs = [
203 bash
204 coreutils
205 cryptsetup # cryptsetup
206 fakeroot
207 fuse2fs # Mount ext3 filesystems
208 go
209 mount # mount
210 squashfsTools # mksquashfs unsquashfs # Make / unpack squashfs image
211 squashfuse # squashfuse_ll squashfuse # Mount (without unpacking) a squashfs image without privileges
212 ]
213 ++ lib.optional enableNvidiaContainerCli nvidia-docker;
214
215 postPatch = ''
216 if [[ ! -e .git || ! -e VERSION ]]; then
217 echo "${version}" > VERSION
218 fi
219
220 # Patch shebangs for script run during build
221 patchShebangs --build "$configureScript" makeit e2e scripts mlocal/scripts
222
223 # Patching the hard-coded defaultPath by prefixing the packages in defaultPathInputs
224 ${lib.concatMapAttrsStringSep "\n" (fileName: originalDefaultPaths: ''
225 substituteInPlace ${lib.escapeShellArg fileName} \
226 ${lib.concatMapStringsSep " \\\n " (
227 originalDefaultPath:
228 lib.concatStringsSep " " [
229 "--replace-fail"
230 (addShellDoubleQuotes (lib.escapeShellArg originalDefaultPath))
231 (addShellDoubleQuotes ''$systemDefaultPath''${systemDefaultPath:+:}${lib.escapeShellArg originalDefaultPath}''${inputsDefaultPath:+:}$inputsDefaultPath'')
232 ]
233 ) originalDefaultPaths}
234 '') sourceFilesWithDefaultPaths}
235 '';
236
237 postConfigure = ''
238 # Code borrowed from pkgs/stdenv/generic/setup.sh configurePhase()
239
240 # set to empty if unset
241 : ''${configureFlags=}
242
243 # shellcheck disable=SC2086
244 $configureScript -V ${version} "''${prefixKey:---prefix=}$prefix" $configureFlags "''${configureFlagsArray[@]}"
245
246 # End of the code from pkgs/stdenv/generic/setup.sh configurPhase()
247 '';
248
249 buildPhase = ''
250 runHook preBuild
251 make -C builddir -j"$NIX_BUILD_CORES"
252 runHook postBuild
253 '';
254
255 installPhase = ''
256 runHook preInstall
257 make -C builddir install LOCALSTATEDIR="$out/var/lib"
258 runHook postInstall
259 '';
260
261 postFixup = ''
262 substituteInPlace "$out/bin/run-singularity" \
263 --replace-fail "/usr/bin/env ${projectName}" "$out/bin/${projectName}"
264
265 # Respect PATH from the environment/the user.
266 # Fallback to bin paths provided by Nixpkgs packages.
267 wrapProgram "$out/bin/${projectName}" \
268 --suffix PATH : "$systemDefaultPath" \
269 --suffix PATH : "$inputsDefaultPath"
270
271 # Make changes in the config file
272 ${lib.optionalString forceNvcCli ''
273 substituteInPlace "$out/etc/${projectName}/${projectName}.conf" \
274 --replace-fail "use nvidia-container-cli = no" "use nvidia-container-cli = yes"
275 ''}
276 ${lib.optionalString (enableNvidiaContainerCli && projectName == "singularity") ''
277 substituteInPlace "$out/etc/${projectName}/${projectName}.conf" \
278 --replace-fail "# nvidia-container-cli path =" "nvidia-container-cli path = ${nvidia-docker}/bin/nvidia-container-cli"
279 ''}
280 ${lib.optionalString (removeCompat && (projectName != "singularity")) ''
281 unlink "$out/bin/singularity"
282 for file in "$out"/share/man/man?/singularity*.gz; do
283 if [[ -L "$file" ]]; then
284 unlink "$file"
285 fi
286 done
287 for file in "$out"/share/*-completion/completions/singularity; do
288 if [[ -e "$file" ]]
289 rm "$file"
290 done
291 ''}
292 ${lib.optionalString enableSuid (
293 lib.warnIf (starterSuidPath == null)
294 "${projectName}: Null starterSuidPath when enableSuid produces non-SUID-ed starter-suid and run-time permission denial."
295 ''
296 chmod +x $out/libexec/${projectName}/bin/starter-suid
297 ''
298 )}
299 ${lib.optionalString (enableSuid && (starterSuidPath != null)) ''
300 mv "$out"/libexec/${projectName}/bin/starter-suid{,.orig}
301 ln -s ${lib.escapeShellArg starterSuidPath} "$out/libexec/${projectName}/bin/starter-suid"
302 ''}
303 '';
304
305 nativeInstallCheckInputs = [
306 versionCheckHook
307 ];
308 versionCheckProgram = "${placeholder "out"}/bin/${projectName}";
309 versionCheckProgramArg = "--version";
310 doInstallCheck = true;
311
312 meta = {
313 description = "Application containers for linux" + extraDescription;
314 longDescription = ''
315 Singularity (the upstream) renamed themselves to Apptainer
316 to distinguish themselves from a fork made by Sylabs Inc.. See
317
318 https://sylabs.io/2021/05/singularity-community-edition
319 https://apptainer.org/news/community-announcement-20211130
320 '';
321 license = lib.licenses.bsd3;
322 platforms = lib.platforms.linux;
323 maintainers = with lib.maintainers; [
324 jbedo
325 ShamrockLee
326 ];
327 mainProgram = projectName;
328 }
329 // extraMeta;
330}).overrideAttrs
331 (
332 finalAttrs: prevAttrs: {
333 systemDefaultPath = lib.concatStringsSep ":" systemBinPaths;
334 inputsDefaultPath = lib.makeBinPath finalAttrs.defaultPathInputs;
335 passthru = prevAttrs.passthru or { } // {
336 inherit sourceFilesWithDefaultPaths;
337 tests = {
338 image-hello-cowsay = singularity-tools.buildImage {
339 name = "hello-cowsay";
340 contents = [
341 hello
342 cowsay
343 ];
344 singularity = finalAttrs.finalPackage;
345 };
346 };
347 gpuChecks = lib.optionalAttrs (projectName == "apptainer") {
348 # Should be in tests, but Ofborg would skip image-hello-cowsay because
349 # saxpy is unfree.
350 image-saxpy = callPackage (
351 { singularity-tools, cudaPackages }:
352 singularity-tools.buildImage {
353 name = "saxpy";
354 contents = [ cudaPackages.saxpy ];
355 memSize = 2048;
356 diskSize = 2048;
357 singularity = finalAttrs.finalPackage;
358 }
359 ) { };
360 saxpy = callPackage (
361 { runCommand, writeShellScriptBin }:
362 let
363 unwrapped = writeShellScriptBin "apptainer-cuda-saxpy" ''
364 ${lib.getExe finalAttrs.finalPackage} exec --nv $@ ${finalAttrs.passthru.gpuChecks.image-saxpy} saxpy
365 '';
366 in
367 runCommand "run-apptainer-cuda-saxpy"
368 {
369 requiredSystemFeatures = [ "cuda" ];
370 nativeBuildInputs = [ unwrapped ];
371 passthru = {
372 inherit unwrapped;
373 };
374 }
375 ''
376 apptainer-cuda-saxpy
377 ''
378 ) { };
379 };
380 };
381 }
382 )