Bs-platform install

I’ve been trying to install bs-platform(the tooling for reasonml) via npm, but have been unable so far.

I have modified the npm prefix to install to a different directory, but it tries to build the ocaml compiler and fails with the following errors:-

./configure: ./sharpbang: /bin/cat: bad interpreter: No such file or directory
./configure: ./sharpbang2: /usr/bin/cat: bad interpreter: No such file or directory
strip: 'tmpheader': No such file
strip: 'tmpheader': No such file
strip: 'tmpheader': No such file
make[2]: *** [Makefile:50: target_camlheader] Error 1
make[2]: *** Waiting for unfinished jobs....
mv: cannot stat 'tmpheader': No such file or directory
make[2]: *** [Makefile:50: camlheader] Error 1
make[1]: *** [Makefile:193: coldstart] Error 2
make: *** [Makefile:143: world.opt] Error 2

Building a local version of the OCaml compiler failed, check the output above for more information. A possible problem is that you don't have a compiler installed.
/home/invokesus/.npm-global/lib/node_modules/bs-platform/scripts/install.js:111
            throw e;
            ^

Error: Command failed: /home/invokesus/.npm-global/lib/node_modules/bs-platform/scripts/buildocaml.sh
./configure: ./sharpbang: /bin/cat: bad interpreter: No such file or directory
./configure: ./sharpbang2: /usr/bin/cat: bad interpreter: No such file or directory
strip: 'tmpheader': No such file
strip: 'tmpheader': No such file
strip: 'tmpheader': No such file
make[2]: *** [Makefile:50: target_camlheader] Error 1
make[2]: *** Waiting for unfinished jobs....
mv: cannot stat 'tmpheader': No such file or directory
make[2]: *** [Makefile:50: camlheader] Error 1
make[1]: *** [Makefile:193: coldstart] Error 2
make: *** [Makefile:143: world.opt] Error 2

    at checkExecSyncError (child_process.js:601:13)
    at Object.execFileSync (child_process.js:621:13)
    at tryToProvideOCamlCompiler (/home/invokesus/.npm-global/lib/node_modules/bs-platform/scripts/install.js:106:27)
    at non_windows_npm_release (/home/invokesus/.npm-global/lib/node_modules/bs-platform/scripts/install.js:157:9)
    at Object.<anonymous> (/home/invokesus/.npm-global/lib/node_modules/bs-platform/scripts/install.js:188:5)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)

Reproduction steps:-

npm i bs-platform

While searching about javascript modules and nix I also came across node2nix, but am not sure how to use it in this context.
Any help would be appreciated.
Thanks!

If you want a rather quick solution without the need for patching I suggest you to use an buildFHSUserEnv:
Here is an example that can be opened with nix-shell: https://github.com/NixOS/nixpkgs/blob/128a446c59872f1df38070655a903b885293b995/pkgs/development/node-packages/default-v10.nix
For node2nix you will to add at least an override to patch the absolute paths. We have same examples in this file: https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/node-packages/default-v10.nix

If you find a solution, you could contribute it to https://github.com/nix-community/nix-environments for other people to use.

I use nix-shell with the following config:

with import <nixpkgs> {};
mkShell {
  buildInputs = [ nodejs-10_x ] ++ (with ocamlPackages_4_02; [ ocaml ninja merlin ]);
  shellHook = ''
    export PATH="`pwd`/node_modules/.bin:$PATH"
  '';
}

@kamilchm do you want to add this to https://github.com/nix-community/nix-environments for future users?

For the record and anyone who was searching, I was able to get a very complete copy of BuckleScript working with NPM dependencies.

First, use node2nix to generate the expressions from a list containing the packages you want:

$ cat node-packages.json
[ "bs-platform", "request", "cloudflare" ]

$ nix run nixpkgs.nodePackages.node2nix -c \
    node2nix --nodejs-10 -i node-packages.json

This writes out a bunch of files, including a default.nix which you can import. You can also do some overrides and whatnot. BuckleScript needs a few fixes, mostly to improve build times (to a minute or two):

  • Reuse a pre-built copy of ninja instead of the vendored version.
  • Reuse an existing copy of the OCaml compiler
  • Fix up the paths to node_modules so bsb and bsc can find their own libraries, etc.

It comes out looking like this:

let
  nodejs = pkgs."nodejs-10_x";
  myNodePackages =
    let np = import ./nix/bs-platform.nix { inherit pkgs system nodejs; };
    in np // {
      bs-platform = np.bs-platform.override {

        # Fix paths so we can use a cached Ninja, instead of compiling it
        preRebuild = ''
          substituteInPlace ./scripts/install.js \
            --replace "var ninja_bin_output = path.join(root_dir, 'lib', 'ninja.exe')" \
                      "var ninja_bin_output = '${pkgs.ninja}/bin/ninja'"

          substituteInPlace ./lib/bsb.ml \
            --replace 'bsc_dir // "ninja.exe"' \
                      '"${pkgs.ninja}/bin/ninja"'
        '';

        # This ensures we don't have to link node_modules into CWD.  Makes it
        # easier to use in nix-shell, or iteratively from ./result, etc
        postInstall = ''
          wrapProgram $out/bin/bsb --prefix npm_config_prefix : $out
          wrapProgram $out/bin/bsc --prefix npm_config_prefix : $out
        '';

        # Use cached ocaml compiler, instead of recompiling one
        buildInputs = with pkgs.ocaml-ng.ocamlPackages_4_02;
          [ ocaml merlin pkgs.makeWrapper ];
      };
    };

Then you can just use myNodePackages.bs-platform and the BuckleScript compiler will be under $out/bin/bsc, etc. I’ve tested BSB, etc all work.

You also probably want a way to include Node packages, though, like I do. For that, you can use pkgs.buildEnv and pkgs.writers.writeBash to write a wrapper:

  myNodeEnv = pkgs.buildEnv {
    name = "node-env";
    paths = with myNodePackages; [ bs-platform request cloudflare ];
    pathsToLink = [ "/lib/node_modules" ];
  };

  myNode = pkgs.writers.writeBash "node" ''
    export NODE_PATH=${myNodeEnv}/lib/node_modules
    exec ${nodejs}/bin/node "$@"
  '';

Now, myNode is a copy of node that has the packages I asked for in node-packages.json available. In practice all I do is invoke bsb and copy the resulting .js files somewhere, and use myNode as an interpreter for them, which includes everything.

3 Likes

I’ve opend PR for inclusing of bs-platform to the nixpkgs. Please check https://github.com/NixOS/nixpkgs/pull/73570 if you want to review it! Thanks!

2 Likes