···11+# Generic builder for GNU Octave libraries.
22+# This is a file that contains nested functions. The first, outer, function
33+# is the library- and package-wide details, such as the nixpkgs library, any
44+# additional configuration provided, and the namePrefix to use (based on the
55+# pname and version of Octave), the octave package, etc.
66+77+{ lib
88+, stdenv
99+, config
1010+, octave
1111+, texinfo
1212+, computeRequiredOctavePackages
1313+, writeRequiredOctavePackagesHook
1414+}:
1515+1616+# The inner function contains information required to build the individual
1717+# libraries.
1818+{ fullLibName ? "${attrs.pname}-${attrs.version}"
1919+2020+, src
2121+2222+, dontPatch ? false
2323+, patches ? []
2424+, patchPhase ? ""
2525+2626+, enableParallelBuilding ? true
2727+# Build-time dependencies for the package, which were compiled for the system compiling this.
2828+, nativeBuildInputs ? []
2929+3030+# Build-time dependencies for the package, which may not have been compiled for the system compiling this.
3131+, buildInputs ? []
3232+3333+# Propagate build dependencies so in case we have A -> B -> C,
3434+# C can import package A propagated by B
3535+# Run-time dependencies for the package.
3636+, propagatedBuildInputs ? []
3737+3838+# Octave packages that are required at runtime for this one.
3939+# These behave similarly to propagatedBuildInputs, where if
4040+# package A is needed by B, and C needs B, then C also requires A.
4141+# The main difference between these and propagatedBuildInputs is
4242+# during the package's installation into octave, where all
4343+# requiredOctavePackages are ALSO installed into octave.
4444+, requiredOctavePackages ? []
4545+4646+, preBuild ? ""
4747+4848+, meta ? {}
4949+5050+, passthru ? {}
5151+5252+, ... } @ attrs:
5353+5454+let
5555+ requiredOctavePackages' = computeRequiredOctavePackages requiredOctavePackages;
5656+5757+in stdenv.mkDerivation {
5858+ packageName = "${fullLibName}";
5959+ # The name of the octave package ends up being
6060+ # "octave-version-package-version"
6161+ name = "${octave.pname}-${octave.version}-${fullLibName}";
6262+6363+ # This states that any package built with the function that this returns
6464+ # will be an octave package. This is used for ensuring other octave
6565+ # packages are installed into octave during the environment building phase.
6666+ isOctavePackage = true;
6767+6868+ OCTAVE_HISTFILE = "/dev/null";
6969+7070+ inherit src;
7171+7272+ inherit dontPatch patches patchPhase;
7373+7474+ dontConfigure = true;
7575+7676+ enableParallelBuilding = enableParallelBuilding;
7777+7878+ requiredOctavePackages = requiredOctavePackages';
7979+8080+ nativeBuildInputs = [
8181+ octave
8282+ writeRequiredOctavePackagesHook
8383+ ]
8484+ ++ nativeBuildInputs;
8585+8686+ buildInputs = buildInputs ++ requiredOctavePackages';
8787+8888+ propagatedBuildInputs = propagatedBuildInputs ++ [ texinfo ];
8989+9090+ preBuild = if preBuild == "" then
9191+ ''
9292+ # This trickery is needed because Octave expects a single directory inside
9393+ # at the top-most level of the tarball.
9494+ tar --transform 's,^,${fullLibName}/,' -cz * -f ${fullLibName}.tar.gz
9595+ ''
9696+ else
9797+ preBuild;
9898+9999+ buildPhase = ''
100100+ runHook preBuild
101101+102102+ mkdir -p $out
103103+ octave-cli --eval "pkg build $out ${fullLibName}.tar.gz"
104104+105105+ runHook postBuild
106106+ '';
107107+108108+ # We don't install here, because that's handled when we build the environment
109109+ # together with Octave.
110110+ dontInstall = true;
111111+112112+ inherit meta;
113113+}
···11+# Setup hook for writing octave packages that are run-time dependencies for
22+# another package to a nix-support file.
33+# `echo`s the full path name to the package derivation that is required.
44+echo "Sourcing octave-write-required-octave-packages-hook.sh"
55+66+octaveWriteRequiredOctavePackagesPhase() {
77+ echo "Executing octaveWriteRequiredOctavePackagesPhase"
88+99+ mkdir -p $out/nix-support
1010+ echo ${requiredOctavePackages} > $out/nix-support/required-octave-packages
1111+}
1212+1313+# Yes its a bit long...
1414+if [ -z "${dontWriteRequiredOctavePackagesPhase-}" ]; then
1515+ echo "Using octaveWriteRequiredOctavePackagesPhase"
1616+ preDistPhases+=" octaveWriteRequiredOctavePackagesPhase"
1717+fi
···11+# Setup hook for writing octave packages that are run-time dependencies for
22+# another package to a nix-support file.
33+# `echo`s the full path name to the package derivation that is required.
44+echo "Sourcing write-required-octave-packages-hook.sh"
55+66+writeRequiredOctavePackagesPhase() {
77+ echo "Executing writeRequiredOctavePackagesPhase"
88+99+ mkdir -p $out/nix-support
1010+ echo ${requiredOctavePackages} > $out/nix-support/required-octave-packages
1111+}
1212+1313+# Yes its a bit long...
1414+if [ -z "${dontWriteRequiredOctavePackagesPhase-}" ]; then
1515+ echo "Using writeRequiredOctavePackagesPhase"
1616+ preDistPhases+=" writeRequiredOctavePackagesPhase"
1717+fi
···11+{ buildEnv, octavePackages }:
22+33+# Takes the buildEnv defined for Octave and the set of octavePackages, and returns
44+# a function, which when given a function whose return value is a list of extra
55+# packages to install, builds and returns that environment.
66+f: let packages = f octavePackages; in buildEnv.override { extraLibs = packages; }
···11+{ lib
22+, octave
33+, makeSetupHook
44+, makeWrapper
55+}:
66+77+# Defined in trivial-builders.nix
88+# Imported as wrapOctave in octave/default.nix and passed to octave's buildEnv
99+# as nativeBuildInput
1010+# Each of the substitutions is available in the wrap.sh script as @thingSubstituted@
1111+makeSetupHook {
1212+ name = "${octave.name}-pkgs-setup-hook";
1313+ deps = makeWrapper;
1414+ substitutions.executable = octave.interpreter;
1515+ substitutions.octave = octave;
1616+} ./wrap.sh
+132
pkgs/development/interpreters/octave/wrap.sh
···11+# Unlinks a directory (given as the first argument), and re-creates that
22+# directory as an actual directory. Then descends into the directory of
33+# the same name in the origin (arg_2/arg_3) and symlinks the contents of
44+# that directory into the passed end-location.
55+unlinkDirReSymlinkContents() {
66+ local dirToUnlink="$1"
77+ local origin="$2"
88+ local contentsLocation="$3"
99+1010+ unlink $dirToUnlink/$contentsLocation
1111+ mkdir -p $dirToUnlink/$contentsLocation
1212+ for f in $origin/$contentsLocation/*; do
1313+ ln -s -t "$dirToUnlink/$contentsLocation" "$f"
1414+ done
1515+}
1616+1717+# Using unlinkDirReSymlinkContents, un-symlinks directories down to
1818+# $out/share/octave, and then creates the octave_packages directory.
1919+createOctavePackagesPath() {
2020+ local desiredOut=$1
2121+ local origin=$2
2222+2323+ if [ -L "$out/share" ]; then
2424+ unlinkDirReSymlinkContents "$desiredOut" "$origin" "share"
2525+ fi
2626+2727+ if [ -L "$out/share/octave" ]; then
2828+ unlinkDirReSymlinkContents "$desiredOut" "$origin" "share/octave"
2929+ fi
3030+3131+ # Now that octave_packages has a path rather than symlinks, create the
3232+ # octave_packages directory for installed packages.
3333+ mkdir -p "$desiredOut/share/octave/octave_packages"
3434+}
3535+3636+# First, descends down to $out/share/octave/site/m/startup/octaverc, and
3737+# copies that start-up file. Once done, it performs a `chmod` to allow
3838+# writing. Lastly, it `echo`s the location of the locally installed packages
3939+# to the startup file, allowing octave to discover installed packages.
4040+addPkgLocalList() {
4141+ local desiredOut=$1
4242+ local origin=$2
4343+ local octaveSite="share/octave/site"
4444+ local octaveSiteM="$octaveSite/m"
4545+ local octaveSiteStartup="$octaveSiteM/startup"
4646+ local siteOctavercStartup="$octaveSiteStartup/octaverc"
4747+4848+ unlinkDirReSymlinkContents "$desiredOut" "$origin" "$octaveSite"
4949+ unlinkDirReSymlinkContents "$desiredOut" "$origin" "$octaveSiteM"
5050+ unlinkDirReSymlinkContents "$desiredOut" "$origin" "$octaveSiteStartup"
5151+5252+ unlink "$out/$siteOctavercStartup"
5353+ cp "$origin/$siteOctavercStartup" "$desiredOut/$siteOctavercStartup"
5454+ chmod u+w "$desiredOut/$siteOctavercStartup"
5555+ echo "pkg local_list $out/.octave_packages" >> "$desiredOut/$siteOctavercStartup"
5656+}
5757+5858+# Wrapper function for wrapOctaveProgramsIn. Takes one argument, a
5959+# space-delimited string of packages' paths that will be installed.
6060+wrapOctavePrograms() {
6161+ wrapOctaveProgramsIn "$out/bin" "$out" "$@"
6262+}
6363+6464+# Wraps all octave programs in $out/bin with all the propagated inputs that
6565+# a particular package requires. $1 is the directory to look for binaries in
6666+# to wrap. $2 is the path to the octave ENVIRONMENT. $3 is the space-delimited
6767+# string of packages.
6868+wrapOctaveProgramsIn() {
6969+ local dir="$1"
7070+ local octavePath="$2"
7171+ local pkgs="$3"
7272+ local f
7373+7474+ buildOctavePath "$octavePath" "$pkgs"
7575+7676+ # Find all regular files in the output directory that are executable.
7777+ if [ -d "$dir" ]; then
7878+ find "$dir" -type f -perm -0100 -print0 | while read -d "" f; do
7979+ echo "wrapping \`$f'..."
8080+ local -a wrap_args=("$f"
8181+ --prefix PATH ':' "$program_PATH"
8282+ )
8383+ local -a wrapProgramArgs=("${wrap_args[@]}")
8484+ wrapProgram "${wrapProgramArgs[@]}"
8585+ done
8686+ fi
8787+}
8888+8989+# Build the PATH environment variable by walking through the closure of
9090+# dependencies. Starts by constructing the `program_PATH` variable with the
9191+# environment's path, then adding the original octave's location, and marking
9292+# them in `octavePathsSeen`.
9393+buildOctavePath() {
9494+ local octavePath="$1"
9595+ local packages="$2"
9696+9797+ local pathsToSearch="$octavePath $packages"
9898+9999+ # Create an empty table of Octave paths.
100100+ declare -A octavePathsSeen=()
101101+ program_PATH=
102102+ octavePathsSeen["$out"]=1
103103+ octavePathsSeen["@octave@"]=1
104104+ addToSearchPath program_PATH "$out/bin"
105105+ addToSearchPath program_PATH "@octave@/bin"
106106+ echo "program_PATH to change to is: $program_PATH"
107107+ for path in $pathsToSearch; do
108108+ echo "Recurse to propagated-build-input: $path"
109109+ _addToOctavePath $path
110110+ done
111111+}
112112+113113+# Adds the bin directories to the program_PATH variable.
114114+# Recurses on any paths declared in `propagated-build-inputs`, while avoiding
115115+# duplicating paths by flagging the directires it has seen in `octavePathsSeen`.
116116+_addToOctavePath() {
117117+ local dir="$1"
118118+ # Stop if we've already visited this path.
119119+ if [ -n "${octavePathsSeen[$dir]}" ]; then return; fi
120120+ octavePathsSeen[$dir]=1
121121+ # addToSearchPath is defined in stdenv/generic/setup.sh. It has the effect
122122+ # of calling `export X=$dir/...:$X`.
123123+ addToSearchPath program_PATH $dir/bin
124124+125125+ # Inspect the propagated inputs (if they exist) and recur on them.
126126+ local prop="$dir/nix-support/propagated-build-inputs"
127127+ if [ -e $prop ]; then
128128+ for new_path in $(cat $prop); do
129129+ _addToOctavePath $new_path
130130+ done
131131+ fi
132132+}
···11+# This file contains the GNU Octave add-on packages set.
22+# Each attribute is an Octave library.
33+# Expressions for the Octave libraries are supposed to be in `pkgs/development/octave-modules/<name>/default.nix`.
44+55+# When contributing a new package, if that package has a dependency on another
66+# octave package, then you DO NOT need to explicitly list it as such when
77+# performing the callPackage. It will be passed implicitly.
88+# In addition, try to use the same dependencies as the ones octave needs, which
99+# should ensure greater compatibility between Octave itself and its packages.
1010+1111+# Like python-packages.nix, packages from top-level.nix are not in the scope
1212+# of the `callPackage` used for packages here. So, when we do need packages
1313+# from outside, we can `inherit` them from `pkgs`.
1414+{ pkgs
1515+, lib
1616+, stdenv
1717+, fetchurl
1818+, newScope
1919+, octave
2020+}:
2121+2222+with lib;
2323+2424+makeScope newScope (self:
2525+ let
2626+ inherit (octave) blas lapack gfortran python texinfo gnuplot;
2727+2828+ callPackage = self.callPackage;
2929+3030+ buildOctavePackage = callPackage ../development/interpreters/octave/build-octave-package.nix {
3131+ inherit lib stdenv;
3232+ inherit octave;
3333+ inherit computeRequiredOctavePackages;
3434+ };
3535+3636+ wrapOctave = callPackage ../development/interpreters/octave/wrap-octave.nix {
3737+ inherit octave;
3838+ inherit (pkgs) makeSetupHook makeWrapper;
3939+ };
4040+4141+ # Given a list of required Octave package derivations, get a list of
4242+ # ALL required Octave packages needed for the ones specified to run.
4343+ computeRequiredOctavePackages = drvs: let
4444+ # Check whether a derivation is an octave package
4545+ hasOctavePackage = drv: drv?isOctavePackage;
4646+ packages = filter hasOctavePackage drvs;
4747+ in unique (packages ++ concatLists (catAttrs "requiredOctavePackages" packages));
4848+4949+ in {
5050+5151+ inherit callPackage buildOctavePackage computeRequiredOctavePackages;
5252+5353+ inherit (callPackage ../development/interpreters/octave/hooks { })
5454+ writeRequiredOctavePackagesHook;
5555+5656+ arduino = callPackage ../development/octave-modules/arduino {
5757+ inherit (pkgs) arduino;
5858+ # Full arduino right now. Might be able to use pkgs.arduino-core
5959+ # Needs arduinoIDE as a runtime dependency.
6060+ };
6161+6262+ audio = callPackage ../development/octave-modules/audio {
6363+ rtmidi = pkgs.rtmidi;
6464+ };
6565+6666+ bim = callPackage ../development/octave-modules/bim { };
6767+6868+ bsltl = callPackage ../development/octave-modules/bsltl { };
6969+7070+ cgi = callPackage ../development/octave-modules/cgi { };
7171+7272+ communications = callPackage ../development/octave-modules/communications {
7373+ hdf5 = pkgs.hdf5;
7474+ };
7575+7676+ control = callPackage ../development/octave-modules/control { };
7777+7878+ io = callPackage ../development/octave-modules/io {
7979+ unzip = pkgs.unzip;
8080+ };
8181+8282+ level-set = callPackage ../development/octave-modules/level-set { };
8383+8484+ linear-algebra = callPackage ../development/octave-modules/linear-algebra { };
8585+8686+ ltfat = callPackage ../development/octave-modules/ltfat {
8787+ fftw = pkgs.fftw;
8888+ fftwSinglePrec = pkgs.fftwSinglePrec;
8989+ fftwFloat = pkgs.fftwFloat;
9090+ fftwLongDouble = pkgs.fftwLongDouble;
9191+ portaudio = pkgs.portaudio;
9292+ jre = pkgs.jre;
9393+ };
9494+9595+ signal = callPackage ../development/octave-modules/signal { };
9696+9797+ symbolic = callPackage ../development/octave-modules/symbolic {
9898+ # Need to use sympy 1.5.1 for https://github.com/cbm755/octsympy/issues/1023
9999+ # It has been addressed, but not merged yet.
100100+ pythonEnv = (let
101101+ overridenPython = let
102102+ packageOverrides = self: super: {
103103+ sympy = super.sympy.overridePythonAttrs (old: rec {
104104+ version = pkgs.python2Packages.sympy.version;
105105+ src = pkgs.python2Packages.sympy.src;
106106+ });
107107+ };
108108+ in python.override {inherit packageOverrides; self = overridenPython; };
109109+ in overridenPython.withPackages (ps: [
110110+ ps.sympy
111111+ ps.mpmath
112112+ ]));
113113+ };
114114+115115+ })