···1+# Generic builder for GNU Octave libraries.
2+# This is a file that contains nested functions. The first, outer, function
3+# is the library- and package-wide details, such as the nixpkgs library, any
4+# additional configuration provided, and the namePrefix to use (based on the
5+# pname and version of Octave), the octave package, etc.
6+7+{ lib
8+, stdenv
9+, config
10+, octave
11+, texinfo
12+, computeRequiredOctavePackages
13+, writeRequiredOctavePackagesHook
14+}:
15+16+# The inner function contains information required to build the individual
17+# libraries.
18+{ fullLibName ? "${attrs.pname}-${attrs.version}"
19+20+, src
21+22+, dontPatch ? false
23+, patches ? []
24+, patchPhase ? ""
25+26+, enableParallelBuilding ? true
27+# Build-time dependencies for the package, which were compiled for the system compiling this.
28+, nativeBuildInputs ? []
29+30+# Build-time dependencies for the package, which may not have been compiled for the system compiling this.
31+, buildInputs ? []
32+33+# Propagate build dependencies so in case we have A -> B -> C,
34+# C can import package A propagated by B
35+# Run-time dependencies for the package.
36+, propagatedBuildInputs ? []
37+38+# Octave packages that are required at runtime for this one.
39+# These behave similarly to propagatedBuildInputs, where if
40+# package A is needed by B, and C needs B, then C also requires A.
41+# The main difference between these and propagatedBuildInputs is
42+# during the package's installation into octave, where all
43+# requiredOctavePackages are ALSO installed into octave.
44+, requiredOctavePackages ? []
45+46+, preBuild ? ""
47+48+, meta ? {}
49+50+, passthru ? {}
51+52+, ... } @ attrs:
53+54+let
55+ requiredOctavePackages' = computeRequiredOctavePackages requiredOctavePackages;
56+57+in stdenv.mkDerivation {
58+ packageName = "${fullLibName}";
59+ # The name of the octave package ends up being
60+ # "octave-version-package-version"
61+ name = "${octave.pname}-${octave.version}-${fullLibName}";
62+63+ # This states that any package built with the function that this returns
64+ # will be an octave package. This is used for ensuring other octave
65+ # packages are installed into octave during the environment building phase.
66+ isOctavePackage = true;
67+68+ OCTAVE_HISTFILE = "/dev/null";
69+70+ inherit src;
71+72+ inherit dontPatch patches patchPhase;
73+74+ dontConfigure = true;
75+76+ enableParallelBuilding = enableParallelBuilding;
77+78+ requiredOctavePackages = requiredOctavePackages';
79+80+ nativeBuildInputs = [
81+ octave
82+ writeRequiredOctavePackagesHook
83+ ]
84+ ++ nativeBuildInputs;
85+86+ buildInputs = buildInputs ++ requiredOctavePackages';
87+88+ propagatedBuildInputs = propagatedBuildInputs ++ [ texinfo ];
89+90+ preBuild = if preBuild == "" then
91+ ''
92+ # This trickery is needed because Octave expects a single directory inside
93+ # at the top-most level of the tarball.
94+ tar --transform 's,^,${fullLibName}/,' -cz * -f ${fullLibName}.tar.gz
95+ ''
96+ else
97+ preBuild;
98+99+ buildPhase = ''
100+ runHook preBuild
101+102+ mkdir -p $out
103+ octave-cli --eval "pkg build $out ${fullLibName}.tar.gz"
104+105+ runHook postBuild
106+ '';
107+108+ # We don't install here, because that's handled when we build the environment
109+ # together with Octave.
110+ dontInstall = true;
111+112+ inherit meta;
113+}
···1+# Setup hook for writing octave packages that are run-time dependencies for
2+# another package to a nix-support file.
3+# `echo`s the full path name to the package derivation that is required.
4+echo "Sourcing octave-write-required-octave-packages-hook.sh"
5+6+octaveWriteRequiredOctavePackagesPhase() {
7+ echo "Executing octaveWriteRequiredOctavePackagesPhase"
8+9+ mkdir -p $out/nix-support
10+ echo ${requiredOctavePackages} > $out/nix-support/required-octave-packages
11+}
12+13+# Yes its a bit long...
14+if [ -z "${dontWriteRequiredOctavePackagesPhase-}" ]; then
15+ echo "Using octaveWriteRequiredOctavePackagesPhase"
16+ preDistPhases+=" octaveWriteRequiredOctavePackagesPhase"
17+fi
···1+# Setup hook for writing octave packages that are run-time dependencies for
2+# another package to a nix-support file.
3+# `echo`s the full path name to the package derivation that is required.
4+echo "Sourcing write-required-octave-packages-hook.sh"
5+6+writeRequiredOctavePackagesPhase() {
7+ echo "Executing writeRequiredOctavePackagesPhase"
8+9+ mkdir -p $out/nix-support
10+ echo ${requiredOctavePackages} > $out/nix-support/required-octave-packages
11+}
12+13+# Yes its a bit long...
14+if [ -z "${dontWriteRequiredOctavePackagesPhase-}" ]; then
15+ echo "Using writeRequiredOctavePackagesPhase"
16+ preDistPhases+=" writeRequiredOctavePackagesPhase"
17+fi
···1+{ buildEnv, octavePackages }:
2+3+# Takes the buildEnv defined for Octave and the set of octavePackages, and returns
4+# a function, which when given a function whose return value is a list of extra
5+# packages to install, builds and returns that environment.
6+f: let packages = f octavePackages; in buildEnv.override { extraLibs = packages; }
···1+{ lib
2+, octave
3+, makeSetupHook
4+, makeWrapper
5+}:
6+7+# Defined in trivial-builders.nix
8+# Imported as wrapOctave in octave/default.nix and passed to octave's buildEnv
9+# as nativeBuildInput
10+# Each of the substitutions is available in the wrap.sh script as @thingSubstituted@
11+makeSetupHook {
12+ name = "${octave.name}-pkgs-setup-hook";
13+ deps = makeWrapper;
14+ substitutions.executable = octave.interpreter;
15+ substitutions.octave = octave;
16+} ./wrap.sh
···1+# Unlinks a directory (given as the first argument), and re-creates that
2+# directory as an actual directory. Then descends into the directory of
3+# the same name in the origin (arg_2/arg_3) and symlinks the contents of
4+# that directory into the passed end-location.
5+unlinkDirReSymlinkContents() {
6+ local dirToUnlink="$1"
7+ local origin="$2"
8+ local contentsLocation="$3"
9+10+ unlink $dirToUnlink/$contentsLocation
11+ mkdir -p $dirToUnlink/$contentsLocation
12+ for f in $origin/$contentsLocation/*; do
13+ ln -s -t "$dirToUnlink/$contentsLocation" "$f"
14+ done
15+}
16+17+# Using unlinkDirReSymlinkContents, un-symlinks directories down to
18+# $out/share/octave, and then creates the octave_packages directory.
19+createOctavePackagesPath() {
20+ local desiredOut=$1
21+ local origin=$2
22+23+ if [ -L "$out/share" ]; then
24+ unlinkDirReSymlinkContents "$desiredOut" "$origin" "share"
25+ fi
26+27+ if [ -L "$out/share/octave" ]; then
28+ unlinkDirReSymlinkContents "$desiredOut" "$origin" "share/octave"
29+ fi
30+31+ # Now that octave_packages has a path rather than symlinks, create the
32+ # octave_packages directory for installed packages.
33+ mkdir -p "$desiredOut/share/octave/octave_packages"
34+}
35+36+# First, descends down to $out/share/octave/site/m/startup/octaverc, and
37+# copies that start-up file. Once done, it performs a `chmod` to allow
38+# writing. Lastly, it `echo`s the location of the locally installed packages
39+# to the startup file, allowing octave to discover installed packages.
40+addPkgLocalList() {
41+ local desiredOut=$1
42+ local origin=$2
43+ local octaveSite="share/octave/site"
44+ local octaveSiteM="$octaveSite/m"
45+ local octaveSiteStartup="$octaveSiteM/startup"
46+ local siteOctavercStartup="$octaveSiteStartup/octaverc"
47+48+ unlinkDirReSymlinkContents "$desiredOut" "$origin" "$octaveSite"
49+ unlinkDirReSymlinkContents "$desiredOut" "$origin" "$octaveSiteM"
50+ unlinkDirReSymlinkContents "$desiredOut" "$origin" "$octaveSiteStartup"
51+52+ unlink "$out/$siteOctavercStartup"
53+ cp "$origin/$siteOctavercStartup" "$desiredOut/$siteOctavercStartup"
54+ chmod u+w "$desiredOut/$siteOctavercStartup"
55+ echo "pkg local_list $out/.octave_packages" >> "$desiredOut/$siteOctavercStartup"
56+}
57+58+# Wrapper function for wrapOctaveProgramsIn. Takes one argument, a
59+# space-delimited string of packages' paths that will be installed.
60+wrapOctavePrograms() {
61+ wrapOctaveProgramsIn "$out/bin" "$out" "$@"
62+}
63+64+# Wraps all octave programs in $out/bin with all the propagated inputs that
65+# a particular package requires. $1 is the directory to look for binaries in
66+# to wrap. $2 is the path to the octave ENVIRONMENT. $3 is the space-delimited
67+# string of packages.
68+wrapOctaveProgramsIn() {
69+ local dir="$1"
70+ local octavePath="$2"
71+ local pkgs="$3"
72+ local f
73+74+ buildOctavePath "$octavePath" "$pkgs"
75+76+ # Find all regular files in the output directory that are executable.
77+ if [ -d "$dir" ]; then
78+ find "$dir" -type f -perm -0100 -print0 | while read -d "" f; do
79+ echo "wrapping \`$f'..."
80+ local -a wrap_args=("$f"
81+ --prefix PATH ':' "$program_PATH"
82+ )
83+ local -a wrapProgramArgs=("${wrap_args[@]}")
84+ wrapProgram "${wrapProgramArgs[@]}"
85+ done
86+ fi
87+}
88+89+# Build the PATH environment variable by walking through the closure of
90+# dependencies. Starts by constructing the `program_PATH` variable with the
91+# environment's path, then adding the original octave's location, and marking
92+# them in `octavePathsSeen`.
93+buildOctavePath() {
94+ local octavePath="$1"
95+ local packages="$2"
96+97+ local pathsToSearch="$octavePath $packages"
98+99+ # Create an empty table of Octave paths.
100+ declare -A octavePathsSeen=()
101+ program_PATH=
102+ octavePathsSeen["$out"]=1
103+ octavePathsSeen["@octave@"]=1
104+ addToSearchPath program_PATH "$out/bin"
105+ addToSearchPath program_PATH "@octave@/bin"
106+ echo "program_PATH to change to is: $program_PATH"
107+ for path in $pathsToSearch; do
108+ echo "Recurse to propagated-build-input: $path"
109+ _addToOctavePath $path
110+ done
111+}
112+113+# Adds the bin directories to the program_PATH variable.
114+# Recurses on any paths declared in `propagated-build-inputs`, while avoiding
115+# duplicating paths by flagging the directires it has seen in `octavePathsSeen`.
116+_addToOctavePath() {
117+ local dir="$1"
118+ # Stop if we've already visited this path.
119+ if [ -n "${octavePathsSeen[$dir]}" ]; then return; fi
120+ octavePathsSeen[$dir]=1
121+ # addToSearchPath is defined in stdenv/generic/setup.sh. It has the effect
122+ # of calling `export X=$dir/...:$X`.
123+ addToSearchPath program_PATH $dir/bin
124+125+ # Inspect the propagated inputs (if they exist) and recur on them.
126+ local prop="$dir/nix-support/propagated-build-inputs"
127+ if [ -e $prop ]; then
128+ for new_path in $(cat $prop); do
129+ _addToOctavePath $new_path
130+ done
131+ fi
132+}
···1+# This file contains the GNU Octave add-on packages set.
2+# Each attribute is an Octave library.
3+# Expressions for the Octave libraries are supposed to be in `pkgs/development/octave-modules/<name>/default.nix`.
4+5+# When contributing a new package, if that package has a dependency on another
6+# octave package, then you DO NOT need to explicitly list it as such when
7+# performing the callPackage. It will be passed implicitly.
8+# In addition, try to use the same dependencies as the ones octave needs, which
9+# should ensure greater compatibility between Octave itself and its packages.
10+11+# Like python-packages.nix, packages from top-level.nix are not in the scope
12+# of the `callPackage` used for packages here. So, when we do need packages
13+# from outside, we can `inherit` them from `pkgs`.
14+{ pkgs
15+, lib
16+, stdenv
17+, fetchurl
18+, newScope
19+, octave
20+}:
21+22+with lib;
23+24+makeScope newScope (self:
25+ let
26+ inherit (octave) blas lapack gfortran python texinfo gnuplot;
27+28+ callPackage = self.callPackage;
29+30+ buildOctavePackage = callPackage ../development/interpreters/octave/build-octave-package.nix {
31+ inherit lib stdenv;
32+ inherit octave;
33+ inherit computeRequiredOctavePackages;
34+ };
35+36+ wrapOctave = callPackage ../development/interpreters/octave/wrap-octave.nix {
37+ inherit octave;
38+ inherit (pkgs) makeSetupHook makeWrapper;
39+ };
40+41+ # Given a list of required Octave package derivations, get a list of
42+ # ALL required Octave packages needed for the ones specified to run.
43+ computeRequiredOctavePackages = drvs: let
44+ # Check whether a derivation is an octave package
45+ hasOctavePackage = drv: drv?isOctavePackage;
46+ packages = filter hasOctavePackage drvs;
47+ in unique (packages ++ concatLists (catAttrs "requiredOctavePackages" packages));
48+49+ in {
50+51+ inherit callPackage buildOctavePackage computeRequiredOctavePackages;
52+53+ inherit (callPackage ../development/interpreters/octave/hooks { })
54+ writeRequiredOctavePackagesHook;
55+56+ arduino = callPackage ../development/octave-modules/arduino {
57+ inherit (pkgs) arduino;
58+ # Full arduino right now. Might be able to use pkgs.arduino-core
59+ # Needs arduinoIDE as a runtime dependency.
60+ };
61+62+ audio = callPackage ../development/octave-modules/audio {
63+ rtmidi = pkgs.rtmidi;
64+ };
65+66+ bim = callPackage ../development/octave-modules/bim { };
67+68+ bsltl = callPackage ../development/octave-modules/bsltl { };
69+70+ cgi = callPackage ../development/octave-modules/cgi { };
71+72+ communications = callPackage ../development/octave-modules/communications {
73+ hdf5 = pkgs.hdf5;
74+ };
75+76+ control = callPackage ../development/octave-modules/control { };
77+78+ io = callPackage ../development/octave-modules/io {
79+ unzip = pkgs.unzip;
80+ };
81+82+ level-set = callPackage ../development/octave-modules/level-set { };
83+84+ linear-algebra = callPackage ../development/octave-modules/linear-algebra { };
85+86+ ltfat = callPackage ../development/octave-modules/ltfat {
87+ fftw = pkgs.fftw;
88+ fftwSinglePrec = pkgs.fftwSinglePrec;
89+ fftwFloat = pkgs.fftwFloat;
90+ fftwLongDouble = pkgs.fftwLongDouble;
91+ portaudio = pkgs.portaudio;
92+ jre = pkgs.jre;
93+ };
94+95+ signal = callPackage ../development/octave-modules/signal { };
96+97+ symbolic = callPackage ../development/octave-modules/symbolic {
98+ # Need to use sympy 1.5.1 for https://github.com/cbm755/octsympy/issues/1023
99+ # It has been addressed, but not merged yet.
100+ pythonEnv = (let
101+ overridenPython = let
102+ packageOverrides = self: super: {
103+ sympy = super.sympy.overridePythonAttrs (old: rec {
104+ version = pkgs.python2Packages.sympy.version;
105+ src = pkgs.python2Packages.sympy.src;
106+ });
107+ };
108+ in python.override {inherit packageOverrides; self = overridenPython; };
109+ in overridenPython.withPackages (ps: [
110+ ps.sympy
111+ ps.mpmath
112+ ]));
113+ };
114+115+ })