Bundling external libraries with Raco Distribute

Hi there,

I apologize in advance for beating a dead horse, but I still haven't found a solution to this problem:
Say I require Gregor for a program I'd like to distribute to the world in binary form (say, Invoicer). I compile to standalone package using raco distribute. Somebody downloads my program, installs it, runs it, and nothing happens. Turns out, this program requires Gregor. An error is displayed in a console window that opens and closes so fast the user doesn't have time to read it. What now?

According to raco's manual, "The raco distribute command combines a stand-alone executable created by raco exe with all of the shared libraries that are needed to run it (...). If this were true, raco would bundle Gregor as bytecode in the resulting package. But it doesn't. From what I understand, no external library can be packaged using raco distribute. It will only bundle base libs included with the standard Racket distribution.

My question: is there a way to compile and package a program for redistribution on blank systems (without Racket installed), with all its dependencies, external or not?

Thanks in advance!

Dex

Is the gregor requirement listed in the info.rkt file for your package?

Hi, I don't have a package description as this is just an app. Is a package required for raco distribute to bundle deps?

Thanks for replying!

edited to make it less confusing for the reader and consistent with @samth's answer:
Short answer: yes no, but I think it should be a package anyway
see @alexh's answers and mine below for why I think so

The way I see it an app is also always a package the only difference to other packages is, that most of the time, you have no reason to publish that package to the racket package index.
So you just create a package, that you can use locally and that you can keep private.

No, packages are not required. But the main distribution is not special with respect to raco exe and raco distribute. So Gregor should be included just as any other library is.

Is it possible that you're using Gregor in a way that doesn't indicate to the system that it should be included, such as with dynamic-require?

1 Like

I tried the following:

  • installed gregor using raco pkg install gregor
  • wrote the following program and saved it to a file named "time.rkt":
#lang racket
(require gregor)
(displayln (~t (today) "E, d MMMM y"))
  • created an executable by running raco exe time.rkt. This produced a file named "time.exe" about 16Mb in size
  • created a distribution by running raco dist time-dist time.exe. This produced a folder named "time-dist" containing the time.exe file plus a lib folder. The entire folder size is 48 Mb, since gregor adds in time zone and locale formatting data for all possible time zones and locales.
  • zipped up the entire time-dist folder and moved it to a machine which had no Racket installed
  • ran the time.exe program in a console window and it printed the current date as expected.

So, creating standalone distributions with external packages is certainly possible and it is also possible with the gregor library.

Alex.

3 Likes

I think this aspect of Racket development is confusing, and perhaps some guide could be written on this topic, however, I will attempt to explain where the "info.rkt" file comes into play.

The scenario I have in mind here is building an application which would be used by people who are not programmers and don't know (or care) what Racket is. While this application is written in Racket, it would be published as a binary that users can download, install and run.

First, you can install any packages you need using raco pkg install ... commands, and build applications using raco exe ... and raco dist ... commands. The application itself can be a Racket source file, possibly requiring other local files using (require "some-other-file.rkt") syntax as well as modules from any installed package on the system. So far, you don't need an "info.rkt" and the application is not a package.

However, if you want to share your application in source code, and perhaps allow others to contribute to it, you will need to write some instructions so others can set up their development environment and be able to build the application.

Here is a low effort way of doing this:

(require colormaps                      ; raco pkg install colormaps
         data-frame                     ; raco pkg install data-frame
         data-frame/gpx
         data-frame/private/rdp-simplify
         framework
         gui-widget-mixins              ; raco pkg install gui-widget-mixins
         map-widget                     ; raco pkg install map-widget
         pict
         plot
         plot-container                 ; raco pkg install plot-container
         plot-container/hover-util
         plot/utils
         qresults-list                  ; raco pkg install qresults-list
         racket/draw)

This is for an application I published (GitHub - alex-hhh/AL2-Climb-Analysis: Tool to analyze climbs on a bike route loaded from a GPX file -- this application is now part of ActivityLog2). If you try to clone that application and try to run it, you'll encounter all sorts of errors, since it requires modules from packages that are not installed by default. I assumed that the user is experienced enough to read the source code and notice the comments against the require items, but a better approach would have been to write an info file. The info file would have recorded all the packages that are needed for this application and the user could have just installed the application as a package and get all dependencies in.

There is more to be said about how to organize an application type project in Racket, but I always felt that this is a topic of little interest in the general Racket community and the few people who want to do that almost always struggle.

Alex.

3 Likes

Thank you so much for all the details! I haven't had a problem with packages so far, only with compiling to standalone exe. I'll run some tests and get back to you. I must be doing something wrong, starting with the lack of package.

Cheers,

Dex

my opinion, interested in yours:
I think as soon as the app uses anything that isn't a local source file, or part of minimal racket it should be a package and declare its dependencies in the info.rkt.

The only good reason not to do that I can think of, is maybe using some other system to manage this e.g. if denxi needs something that works a bit different (but I am not very familiar with it yet and how it is used best). Basically if you create something that is better than the info.rkt than don't use it.

I don't see how having to look for comments in the source code for what packages to install is low effort, neither for the author nor the contributor. Easier would be if the original author created an info.rkt and then used raco setup --fix-pkg-deps <pkg-name> to let raco setup assist in creating a list of package dependencies.

My question is why don't you (or anyone else) want to use a package?

To me it seems my life is just easier when I use packages for this and I haven't encountered a reason why I would avoid packages for apps. Just because it is a package doesn't mean that I have to publish it.
If not wanting the package to be published is the reason for not creating a package, maybe there could be added a feature to flag a package as private, similar to package.json | npm Docs. As much negative press npm gets, I think it's package json also has some pros.


I would extend that to myself working on my project, if I continue to work on that application a year later, on a different computer then I want a simple way to get it running again and why not make it so I can use raco pkg install in its directory or even raco pkg install --clone <myaccount>/<myproject>

If there is a good reason to avoid making it a package, then I think there is something missing from the package system.

I think there should be a simple way to install and run an app (even if you are just making it easier for your future self) and ideally there aren't very many different custom steps on how to do that. Maybe packages aren't enough for that, maybe something like denxi would be needed for that, or perhaps something like vagrant.

One reason why I initially hesitated to use packages is that I had trouble understanding what I need to provide / how everything fits together.

The good thing is, as long as you don't need multi-collection packages,

raco pkg new <my_package_name>

installs a basic working package, including info.rkt file and even tests.

3 Likes

The info.rkt file is perhaps necessary, but not sufficient for an application. This is because an info file specifies dependent packages, but not their version. In Racket, package versioning is done through a "package catalog", and the default catalog will simply install the latest version of a package, with no simple way to specify a specific version.

So, an application would need at least two things:

  • an info.rkt file to specify the packages that it depends on
  • a package catalog to specify which versions of packages to actually use

There are two solutions to the versioning problem, that I am aware of, one is Bogdan's racksnaps and one is mine, based on git submodules.

I only have experience with writing one application in Racket (one that needs a binary distribution), and I find it difficult to draw general conclusions from one data point. However, my case, the application has more requirements than just being a package. Perhaps the package system should be extended to include support for applications, although I am not sure what features to ask for, and I am currently happy with the way I structured my application.

Alex.

4 Likes

Thanks everybody for posting your experience. I agree that packages are a necessary minimum. On un*x I do everything that way, but on Windows I feel like there should be a modern-looking, GUI-way of doing this more visually. I'm way lazier on Win than on the BSD command line, hence I open DrRacket and code away first. Bad habit. I'll make something, that'll be my punishment.

Dex

To close the issue, turns out the error that was flashing past was about a file required by Gregor. Installing the gregor package fixes the problem. Even if gregor is included in the binary distribution, it'll complain anyway.

There might be a solution to this problem, research needs to be done on how gregor could run without emitting this error on virgin systems.

Dex