summary refs log tree commit diff
path: root/pkgs/applications/audio/faust/faust2.nix
blob: 21cd3fbdb25a695f9eda04e5fb5388a7487d79c2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
{ stdenv
, coreutils
, fetchFromGitHub
, makeWrapper
, pkgconfig
, llvm
, emscripten
, openssl
, libsndfile
, libmicrohttpd
, vim
}:

with stdenv.lib.strings;

let

  version = "2.5.23";

  src = fetchFromGitHub {
    owner = "grame-cncm";
    repo = "faust";
    rev = version;
    sha256 = "1pci8ac6sqrm3mb3yikmmr3iy35g3nj4iihazif1amqkbdz719rc";
    fetchSubmodules = true;
  };

  meta = with stdenv.lib; {
    homepage = http://faust.grame.fr/;
    downloadPage = https://sourceforge.net/projects/faudiostream/files/;
    license = licenses.gpl2;
    platforms = platforms.linux;
    maintainers = with maintainers; [ magnetophon pmahoney ];
  };

  faust = stdenv.mkDerivation {

    pname = "faust";
    inherit version;

    inherit src;

    nativeBuildInputs = [ makeWrapper pkgconfig vim ];
    buildInputs = [ llvm emscripten openssl libsndfile libmicrohttpd ];


    passthru = {
      inherit wrap wrapWithBuildEnv;
    };


    preConfigure = ''
      makeFlags="$makeFlags prefix=$out LLVM_CONFIG='${llvm}/bin/llvm-config' world"

      # The faust makefiles use 'system ?= $(shell uname -s)' but nix
      # defines 'system' env var, so undefine that so faust detects the
      # correct system.
      unset system
      # sed -e "232s/LLVM_STATIC_LIBS/LLVMLIBS/" -i compiler/Makefile.unix

      # The makefile sets LLVM_<version> depending on the current llvm
      # version, but the detection code is quite brittle.
      #
      # Failing to properly detect the llvm version means that the macro
      # LLVM_VERSION ends up being the raw output of `llvm-config --version`, while
      # the code assumes that it's set to a symbol like `LLVM_35`.  Two problems result:
      # * <command-line>:0:1: error: macro names must be identifiers.; and
      # * a bunch of undefined reference errors due to conditional definitions relying on
      #   LLVM_XY being defined.
      #
      # For now, fix this by 1) pinning the llvm version; 2) manually setting LLVM_VERSION
      # to something the makefile will recognize.
      sed '52iLLVM_VERSION=${stdenv.lib.getVersion llvm}' -i compiler/Makefile.unix
    '';

    postPatch = ''
      # fix build with llvm 5.0.2 by adding it to the list of known versions
      # TODO: check if still needed on next update
      substituteInPlace compiler/Makefile.unix \
        --replace "5.0.0 5.0.1" "5.0.0 5.0.1 5.0.2"
    '';

    # Remove most faust2appl scripts since they won't run properly
    # without additional paths setup. See faust.wrap,
    # faust.wrapWithBuildEnv.
    postInstall = ''
      # syntax error when eval'd directly
      pattern="faust2!(*@(atomsnippets|graph|graphviewer|md|plot|sig|sigviewer|svg))"
      (shopt -s extglob; rm "$out"/bin/$pattern)
    '';

    postFixup = ''
      # Set faustpath explicitly.
      substituteInPlace "$out"/bin/faustpath \
        --replace "/usr/local /usr /opt /opt/local" "$out"

      # The 'faustoptflags' is 'source'd into other faust scripts and
      # not used as an executable, so patch 'uname' usage directly
      # rather than use makeWrapper.
      substituteInPlace "$out"/bin/faustoptflags \
        --replace uname "${coreutils}/bin/uname"

      # wrapper for scripts that don't need faust.wrap*
      for script in "$out"/bin/faust2*; do
        wrapProgram "$script" \
          --prefix PATH : "$out"/bin
      done
    '';

    meta = meta // {
      description = "A functional programming language for realtime audio signal processing";
      longDescription = ''
        FAUST (Functional Audio Stream) is a functional programming
        language specifically designed for real-time signal processing
        and synthesis. FAUST targets high-performance signal processing
        applications and audio plug-ins for a variety of platforms and
        standards.
        The Faust compiler translates DSP specifications into very
        efficient C++ code. Thanks to the notion of architecture,
        FAUST programs can be easily deployed on a large variety of
        audio platforms and plugin formats (jack, alsa, ladspa, maxmsp,
        puredata, csound, supercollider, pure, vst, coreaudio) without
        any change to the FAUST code.

        This package has just the compiler, libraries, and headers.
        Install faust2* for specific faust2appl scripts.
      '';
    };

  };

  # Default values for faust2appl.
  faust2ApplBase =
    { baseName
    , dir ? "tools/faust2appls"
    , scripts ? [ baseName ]
    , ...
    }@args:

    args // {
      name = "${baseName}-${version}";

      inherit src;

      dontBuild = true;

      installPhase = ''
        runHook preInstall

        mkdir -p "$out/bin"
        for script in ${concatStringsSep " " scripts}; do
          cp "${dir}/$script" "$out/bin/"
        done

        runHook postInstall
      '';

      postInstall = ''
        # For the faust2appl script, change 'faustpath' and
        # 'faustoptflags' to absolute paths.
        for script in "$out"/bin/*; do
          substituteInPlace "$script" \
            --replace ". faustpath" ". '${faust}/bin/faustpath'" \
            --replace ". faustoptflags" ". '${faust}/bin/faustoptflags'" \
            --replace " error " "echo"
        done
      '';

      meta = meta // {
        description = "The ${baseName} script, part of faust functional programming language for realtime audio signal processing";
      };
    };

  # Some 'faust2appl' scripts, such as faust2alsa, run faust to
  # generate cpp code, then invoke the c++ compiler to build the code.
  # This builder wraps these scripts in parts of the stdenv such that
  # when the scripts are called outside any nix build, they behave as
  # if they were running inside a nix build in terms of compilers and
  # paths being configured (e.g. rpath is set so that compiled
  # binaries link to the libs inside the nix store)
  #
  # The function takes two main args: the appl name (e.g.
  # 'faust2alsa') and an optional list of propagatedBuildInputs. It
  # returns a derivation that contains only the bin/${appl} script,
  # wrapped up so that it will run as if it was inside a nix build
  # with those build inputs.
  #
  # The build input 'faust' is automatically added to the
  # propagatedBuildInputs.
  wrapWithBuildEnv =
    { baseName
    , propagatedBuildInputs ? [ ]
    , ...
    }@args:

    stdenv.mkDerivation ((faust2ApplBase args) // {

      nativeBuildInputs = [ pkgconfig ];
      buildInputs = [ makeWrapper ];

      propagatedBuildInputs = [ faust ] ++ propagatedBuildInputs;


      postFixup = ''

        # export parts of the build environment
        for script in "$out"/bin/*; do
          wrapProgram "$script" \
            --set FAUSTLIB "${faust}/share/faust" \
            --set FAUST_LIB_PATH "${faust}/share/faust" \
            --set FAUSTINC "${faust}/include/faust" \
            --prefix PATH : "$PATH" \
            --prefix PKG_CONFIG_PATH : "$PKG_CONFIG_PATH" \
            --set NIX_CFLAGS_COMPILE "$NIX_CFLAGS_COMPILE" \
            --set NIX_LDFLAGS "$NIX_LDFLAGS"
        done
      '';
    });

  # Builder for 'faust2appl' scripts, such as faust2firefox that
  # simply need to be wrapped with some dependencies on PATH.
  #
  # The build input 'faust' is automatically added to the PATH.
  wrap =
    { baseName
    , runtimeInputs ? [ ]
    , ...
    }@args:

    let

      runtimePath = concatStringsSep ":" (map (p: "${p}/bin") ([ faust ] ++ runtimeInputs));

    in stdenv.mkDerivation ((faust2ApplBase args) // {

      buildInputs = [ makeWrapper ];

      postFixup = ''
        for script in "$out"/bin/*; do
          wrapProgram "$script" --prefix PATH : "${runtimePath}"
        done
      '';

    });

in faust