How to package external (non-source-code) files with a project?

I’m building up a project using jbuilder. My project is structured like this:

.
├── name.opam
├── src
│   ├── jbuild
│   └── name.ml
└── templates
    └── resources
        ├── resource.file
        ├── resources_a/
        └── resources_b/ 

The code in name.ml will need to access the files in templates. What’s the standard way of telling jbuilder and/or opam that they should package these files up? Additionally, what’s the standard way of accessing and referring to such external, non-ocaml dependencies?

Any references to example projects would be helpful, or to existing documentation. My best efforts haven’t turned anything up yet, but I imagine there is info out there I am missing!

Thanks in advance :slight_smile:

Does this help?

2 Likes

That’s a tremendous help. Thanks!

Do we have a way to install files based on glob or using a rule?

1 Like

I’d also like to know the answer to this.

There is at least files_recursively_in, though, (a) this doesn’t actually address your question and (b) I’m not at all sure whether these dependency specifications can be used in install stanzas…

There is some limited globbing available for specifying dependencies but, again, from the documentation on install stanzas, it’s not all clear to me that these can be used with files.

I find my grasp of what fits where is rather limited, despite having spent a chunk of time with the docs. I wonder if there is a BNF or something of the specification language? It might help give me a clear, compact view of what’s available where…

Just to give this a bump: I still cannot find any simple way of moving a directory of resources in to my build. It seems like the only way to specify files for inclusion is to manually list every single file (just listing a directory doesn’t work, as I’d hoped). If anyone can point me towards projects or docs on this, it would be a help.

Don’t know if it matches your use-case, but using ocamlres it is possible to bake some resources into an executable itself.

Quote:

  • Maurice wants to distribute a single executable for portability so he includes its config files.
  • Jeanine is an indie game developper and she uses the tool to be sure at compile time that she never forgets some asset. She uses the “ocaml” backend and then simple OCaml identifiers to identify her resources.
  • Henry wants to build a single-binary installer, so he includes all the files as an ocamlres tree using the “ocamlres”, format. Then he links the generated module with the ocamlres lib, and calls the “files” output backend at run-time to extract the files.
  • Veronica is a Web developper, and she does not like XHRs, so she embeds some of her resources directly inside her code.
1 Like

That’s an interesting approach! It would probably save me a lot of file manipulation code, now that I think about it. I’ll give a go. Thanks, @keleshev!

Sorry been away from the nets. I don’t know of one. It’s worth checking Jbuilders docs to see if anything new has been added.

1 Like

@anon72795300 I’ve spent some time combing through the docs looking for such a thing. I’ll take finer toothed comb to the same, and then open an issue if I cannot find what I’m looking for.

Your link to logarion was very helpful! Thanks :slight_smile:

Was hoping you could point my way to the last piece of my puzzle: how do we implement cross-platform access to the resources installed in <coaml-system-path>/shared/<package-name>/*? That is, how do we find the path to the shared sources in our executable, without having to hardcode paths to our resource files? I know logarian must be doing this, but my bit of skimming so far hasn’t turned up the relevant lines, and google hasn’t been much help here.

Findlib can help with that. The API is documented here: http://projects.camlcity.org/projects/dl/findlib-1.7.3/doc/ref-html/lib/index.html

2 Likes

This is a big help. Thanks!

The most elegant solution I’ve come up with after a quick skim of the API is something along the lines of

let package_share_dir package_name = 
  Filename.of_parts [Findlib.default_location (); "..";  "share"; package_name] 
  |> Filename.realpath;;

and that will definitely do the trick :slight_smile:

Also don’t forget about this (I’ve never used it, just noticed it): https://opam.ocaml.org/doc/Manual.html#package-name-install
It’s a generic, build-system independent way to install files in locations.

@shonfeder: I never got as far I using the resources I installed under OPAM. I put them there for the developers to copy from if they needed. My resources are most for end-users and I don’t treat OPAM as a way to distribute applications to the general public. @smolkaj’s solution is a good one if that’s what you mean to do.

1 Like