Cross-Compilation and Multi-Version Manager: raco cross
The raco cross command (implemented in the "raco-cross" package) provides a convenient interface to cross-compilation for Racket. It’s especially handy generating executables that run on platforms other than the one used to create the executable.
For example,
raco cross --target x86_64-linux exe example.rkt
creates an executable named "example" that runs on x86_64 Linux. That is, it sets up a combination of distributions for the current platform and for the x86_64-linux platform, and it runs raco exe as if from the local x86_64-linux installation.
For Racket CS, cross-building executables works for version 8.1.0.6 and later. For Racket BC, cross-build executables works for 7.0 and later. The specific platforms available as cross-compilation targets depends on the set of distributions that are available from an installer site.
The generated "example" executable is not necessarily portable by itself to other machines. As is generally the case with raco exe, the executable needs to be turned into a distribution with raco dist (which is also supplied by the "compiler-lib" package):
raco cross --target x86_64-linux dist example-dist example
The result directory "example-dist" is then ready to be copied to a x86_64 Linux machine and run there.
Since raco cross depends on facilities for managing Racket implementations for different versions and platforms, it can also act as a launcher for a selected native implementation of Racket. For example,
raco cross --version 7.8 racket
installs and runs a minimal installation of Racket version 7.8 for the current platform (assuming that the combination of version, platform, and virtual machine is available).
Use the --native flag to create an installation for a platform other than the current machine’s default, but where the current machine can run executables directly. For example, on Windows where raco runs a 64-bit Racket build,
raco cross --native --platform i383-win32 --vm bc racket
installs and runs a 32-bit build of Racket BC for Windows and runs it directly.
1 Platforms, Versions, and Workspaces for raco cross
The raco cross command takes care of the following tasks:
Downloads minimal Racket installations as needed for a given combination of operating system, architecture, Racket virtual machine (CS versus BC), and version.
By default, raco cross downloads from the main Racket mirror for release distributions, but you can point raco cross to other sites (such as one of the snapshot sites at https://snapshot.racket-lang.org that includes ".tgz" options) using --installers.
Configures the minimal Racket installation to install new packages in installation scope by default.
Configures the minimal Racket installation’s name to a combination of the version, platform name, and virtual machine (instead of just the version).
Configures the minimal Racket installation to compile to machine-independent form if --compile-any is specified or any is used as the target platform.
Installs the "compiler-lib" package so that raco exe is available, unless --skip-pkgs is specified to keep the installation minimal.
Generates a cross-compiler plug-in from Racket sources for the CS variant of Racket. (No extra cross-compilation plugin is needed for BC or for native installations.)
Chains to racket or raco for the target version and virtual machine—
running a native executable, but potentially in cross-compilation mode for a target that is a different operating system and/or architecture.
The version and CS/BC variant of Racket where "raco-cross" is installed and run doesn’t need to be related to the target version and variant. The raco cross command will download and install a version and variant of Racket for the current machine as needed.
The Racket distributions that are downloaded and managed by raco cross are installed in a workspace directory. A workspace directory is tied to a specific Racket version. By default, the workspace directory is (build-path (find-system-path 'addon-dir) "raco-cross" vers) where vers is the specified version. The workspace directory is independent of the Racket installation that is used to run raco cross.
Cross-compilation support depends on having suitable distributions for both the host platform and the target platform. (Use --browse to check which are available, and see also Dealing with Missing Installers.) Some operating systems support more than one platform at a time, and it may be necessary to select a specific host platform to work with a particular target platform. For example, Mac OS on Apple Silicon can run both aarch64-macosx and x86_64-macosx natively, and distribution bundles for Racket BC tend to be available only for x86_64-macosx, so --target x86_64-win32 --vm bc may require --host x86_64-macosx. The --host for a combination of target platform, virtual machine, and version is recorded when the target distribution is installed, so --host is needed only the first time. If the host distribution is already installed, it must be installed as a native distribution.
2 Running raco cross
The following ‹options› are recognized:
--target ‹platform› —
Selects the target platform. The ‹platform› can have any of the following forms: The concatenation of the string form of the symbols returned by (system-type 'arch) and (system-type 'os) on the target platform, with a "-" in between. Some common alternative spellings of the (system-type 'arch) and (system-type 'os) results are also recognized.
Examples: i386-win32, aarch64-macosx, ppc-linux
The string form of the path returned on the target platform by (system-library-subpath #f).
These are mostly the same as the previous case, but also include win32\i386 and win32\x86_64.
The string form of the symbol that is the default value of current-compile-target-machine for the CS implementation of Racket on the target platform.
Examples: ti3nt, tarm64osx, ppc32le
The string any, which is equivalent to the host platform by also specifying --compile-any.
The default target platform is the host platform.
--host ‹platform› —
Selects the platform to run natively as needed for cross-compiling to the target platform. The possible values for ‹platform› are the same as for --target, except that any is not allowed as a host. The default host platform is inferred from the Racket implementation that is used to run raco cross. The host setting for a target platform is recorded when the distribution for the target configuration is installed into the workspace, so it needs to use specified only the first time the target is selected.
--version ‹vers› —
Selects the Racket version to use for the target machine. If --workspace is specified and the workspace directory exists already, the default version is the workspace’s version. Otherwise, the default version is based on the Racket version used to run raco cross, but if that version has a fourth .-separated component, then it is dropped, and a third component is dropped if it is 0.
The version current might be useful with a snapshot download site, but only with a fresh workspace directory each time the snapshot site’s current build changes. See also Snapshots and raco cross.
--native —
Specifies that the target platform runs natively on the current machine, so cross-compilation mode is not needed. Native mode is inferred when the target platform is the same as the host platform. Otherwise, the --native setting is recorded when the distribution for the target configuration is installed into the workspace, so it needs to be specified only the first time the target is selected.
--vm ‹variant› —
Selects the Racket virtual-machine implementation to use for the target machine, either cs or bc. The default matches the Racket implementation that is used to run raco cross.
Beware that only some combinations of platform and Racket implementation are available from installer sites.
--compile-any or -M —
Selects a configuration of the target platform that compiles bytecode to machine-independent form. When any is used as a target, --compile-any is redundant but harmless. A --compile-any configuration is most useful for using raco make to create machine-independent bytecode.
--workspace ‹dir› —
Uses ‹dir› as the workspace directory. The default workspace directory depends on the target version ‹vers›: (build-path (find-system-path 'addon-dir) "raco-cross" ‹vers›).
When a workspace directory is created, the requested (or default) version is recorded with the workspace. Future uses of the workspace default to that version, and an error will be reported if the workspace is used with a different requested version.
--installers ‹url› —
Specifies the site for downloading minimal Racket distributions. A ".tgz" file name is added to the end of ‹url› for downloading. The name of the file to download is constructed based on the version, target machine, and virtual-machine implementation, and that file name is added to the end of ‹url›, but the file name can be overridden through --archive.
The installers URL is needed only when a target configuration is specified for the first time for a given workspace. Furthermore, when both --installers and --workspace are specified, ‹url› is recorded as the default (overwriting any default that may already be recorded) for future uses of the same workspace.
The default ‹url› is https://download.racket-lang.org/installers/‹vers›/. When --workspace is specified and an installers URL is recorded in the workspace, that URL is used as the default, instead.
--archive ‹filename› —
Overrides the archive to use when downloading for the target platform. --skip-pkgs —
Disables installation of the "compiler-lib" package when installing a new distribution. The "compiler-lib" package is installed by default so that raco cross .... exe ... and raco cross .... dist ... will work for the installed target.
--skip-setup —
Skips the raco setup step of some distribution installations. Beware that skipping raco setup may produce an installation that runs slowly by loading from machine-independent compiled files, but --skip-setup may be useful for working around bugs in old distributions. Also, --skip-setup usually should be paired with --skip-pkgs.
-j ‹n› or --jobs ‹n› —
Uses ‹n› parallel jobs for setup actions when installing a new distribution, including the initial package install if --skip-pkgs is not specified. --use-source —
Build a host installation from source. When a host installation is not already available for the target version and virtual machine, build it from a Racket source distribution, which requires tools such as a C compiler and GNU make. Building from source is currently supported only for Unix-like host platforms. The result of building on the current machine is assumed to produce executables matching the intended host; supply ++configure arguments as necessary to configure the build.
++configure —
Adds an argument to the list of arguments that are passed to the Racket configure script when building a host installation from source. These flags are used only with --use-source. For information about available configure arguments, see "README" files in a Racket source distribution.
--quiet or -q —
Suppresses a description of the selected host and target configurations that would otherwise print as raco cross starts. --remove —
Removes any existing installation in the workspace for the target configuration. Beware that any directory in the user’s “addon” space that is specific to the installation (initially configured as a combination of the version, platform, and virtual machine) is not removed. The location of that directory is typically within (find-system-path 'addon-dir).
When --remove is specified, no ‹command› can be given, and other flags are ignored except as they determine the target configuration.
--browse —
Shows available platforms from the installer site. When --browse is specified, no ‹command› can be given, and other flags are ignored except as they determine the installers site, version, and virtual machine. If --vm is not specified, then availability is reported for all version machines.
3 Snapshots and raco cross
By default, raco cross uses a --version argument to locate a suitable distribution from the main Racket download mirror. You can specify an alternative download site with --installers, but at snapshots sites, the Racket version number changes both too quickly too be a convenient designation of the build and too slowly to reliably distinguish the build.
Snapshot sites normally have a main page that provides links with “current” instead of the version number, and they also have build-specific pages (with a hash code and/or date in the URL) to provide the same links. The build-specific pages persist for a few days or weeks, depending on the snapshot site, while the main page turns over more quickly.
The best way to work with snapshots in raco cross is to give each one its own workspace, instead of using the default workspace. That way, you can use current as the version, and you can adjust --installers and --workspace together as suits your purpose.
For example, to run the last Racket from the Utah snapshot, you could write
raco cross \ |
--installers https://www.cs.utah.edu/plt/snapshots/current/installers/ \ |
--version current \ |
--workspace /tmp/todays-snapshot \ |
racket |
The version and installers URL are recorded with a workspace, so those only need to be specified the first time that the workspace is used.
The Utah snapshot updates daily, so tomorrow, throw away "/tmp/todays-snapshot" and start again. If, instead, you need to work with a snapshot build for a few days, locate the snapshot ID at the bottom of the main snapshot page, and use that in a more persistent workspace:
raco cross \ |
--installers https://www.cs.utah.edu/plt/snapshots/20210512-8b4b6cf/installers/ \ |
--version current \ |
--workspace /home/mflatt/snapshots/20210512-8b4b6cf \ |
racket |
4 Dealing with Missing Installers
If the download site does not include an installer for your host platform, and if it’s a Unix-like host platform with conventional build tools installed, then a host Racket installation can be created with --use-source.
For target platforms, raco cross does not directly support building form source. To build your own:
Start with a minimal Racket source distribution for the desired target version. For best results, use a “source plus built packages” distribution.
Follow the build instructions in the source distribution to create an in-place installation. The steps will be something like configure, make, and make install. Be sure to configure with suitable flags like --enable-bcdefault or --enable-csdefault, depending on the default configuration for that version and your desired target virtual machine.
Create a ".tgz" (gzipped tar) archive that contains your in-place installation. All of the archive content should be within a single directory; that directory should contain "collects", for example. The name of the directory within the ".tgz" archive does not matter. The "src" directory (including any intermediate build artifacts) can be omitted from the archive.
When running raco cross, supply --installers with a file:// URL (encoding a complete path) to the directory containing the ".tgz" file, and supply --archive with the name of the ".tgz" file in that directory.