forked from ocaml/ocaml
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cross compiler #13
Closed
Closed
Cross compiler #13
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
shym
force-pushed
the
native-cross
branch
2 times, most recently
from
October 2, 2024 17:10
b230c19
to
feac416
Compare
shym
force-pushed
the
native-cross
branch
2 times, most recently
from
October 3, 2024 13:32
d7df83a
to
d64fde9
Compare
shym
force-pushed
the
native-cross
branch
3 times, most recently
from
October 4, 2024 13:00
fe87b2e
to
594f018
Compare
Add closed_type_expr
The `runtime` directory must be `-I`ncluded only since PR#12896 and only in ocamltest. When building an OCaml cross compiler, two OCaml compilers are really involved, where the non-cross compiler is used to build the cross one. Most cross-compiler projects do that by overriding variables such as `CAMLOPT` to point to the non-cross compiler during the build of the cross compilers. In these use cases, adding the explicit `-I runtime` makes them generate the cross compilers linking in the cross runtime (which naturally fails) instead of the build/host runtime that the non-cross compiler would use without `-I runtime`. To re-enable those use cases, this patch moves the addition only on `ocamltest/%` targets.
Recall that the only currently officially supported configurations are when `build` ~ `host` = `target`, where '~' means that the code generated for `host` runs on `build` even when they differ (such as when `build` is `x86_64-pc-cygwin` and `host` is `x86_64-pc-windows` (MSVC) or `x86_64-w64-mingw32`). Still, many projects use OCaml cross compilers. All those projects generate a cross compiler by assuming a non-cross OCaml compiler is available in `PATH` (where non-cross means generating code that will run on `host`). For that they need a C compiler and binutils for `target` in order to build the runtime. (Note that the non-cross compiler will link its own (`build`/`host`) runtime into the generated `.opt` cross compilers rather than the just-compiled target runtime.) In that setup the runtime will run only on the `target` so this commit: - sets `cross_compiling` by comparing `build` to `target` (rather than to `host`), as this variable will be used later - uses `target` to set up the tool prefix, - temporarily assigns `host*` values to `target*` values during the libtool configuration, as this detects a `build` to `host` toolchain. Note that all these changes are transparent when `host` = `target`.
As the C toolchain used being configured is generating code for `target`, use `target` in every test that is done according to the toolchain. Note that all these changes are transparent when `host` = `target`.
Import `ax_prog_cc_for_build` from the Autoconf Macro Archive to detect the C toolchain for the build machine when (and only when) we are generating a cross compiler, namely when code generated for the target doesn't run on the build machine Use this build C toolchain by default to compile and link `sak` Link `sak` by calling directly `SAK_CC` instead of `MKEXE_VIA_CC` to use by default the same compiler to link than to compile `sak`, instead of always requiring both to be overridden; this assumes that the full set of flags that end up in `MKEXE_VIA_CC` are not really necessary to link `sak` since it is a really simple program
When building a cross compiler using an already built non-cross compiler, check that they are of the same version as a sanity check, as the cross compiler will be linked using the OCaml code in the source tree and the C runtime from the non-cross compiler
Add a `--with-target-libdir` option to `configure` and assign a Makefile `TARGET_LIBDIR` variable with it Use the value of `LIBDIR` by default for this new variable Use `TARGET_LIBDIR` to define the `OCAML_STDLIB_DIR` macro used by the runtime When building a cross compiler, the OCaml standard library has no reason to be found at the same paths on the host and on the target. This allows users to provide a path that is meaningful to look for libraries to link dynamically on the target.
On Unix platforms, make sure it is possible to have a `flexlink` executable in `PATH` (which is useful for instance when using a cross compiler to Windows), and still be able to configure and build a non-cross compiler
Add a new `Makefile.cross` that gets enabled when building a cross compiler, aka when host is different from target Define two new (phony) targets: - crossopt, to build the cross compilers to the native target (and what is required for such cross compilers to work) - installcross, to install the cross compilers
Add a rule to build flexdll in the cross-compiler setting, namely building flexdll on Unix, by driving its `Makefile` so that Windows resources are not built and only the .opt version is really built (and copied to the byte binary directory nevertheless) Use the `-o` flag to tell `make` to never try to rebuild `flexlink` (as it would otherwise, according to the dependencies in the main `Makefile`)
When building an OCaml cross-compiler Windows to Unix, `sak` gets a Windows string (of UTF-16 `wchar_t`s) and must produce a Unix string (of UTF-8 `char`s). And vice versa when building a cross-compiler Unix to Windows. To make this possible, this commit splits the `encode-C-literal` command into two commands with specific encodings of the result: `encode-C-utf8-literal` and `encode-C-utf16-literal`. Instead of pulling in a library (and the problems of linking with it) for the task, this commit adds the specific and simple UTF-* encoders and decoders that are needed and uses them only when building a cross-compiler (the result is unchanged in non-cross-compiler settings). In the cross-compiler UTF-8 case, the non-printable characters are encoded to get a safer generated code.
Define `Config.target_os_type` so that: - the `%ostype_*` primitives correspond to the target OS type rather than the host OS one, - the default executable name is the expected default of the target platform.
This CI workflow is not intended to be merged on the main branch as is. Its purpose is to help review the cross compiler. If it is deemed interesting to keep it for special cases (to run the test from time to time, rather less regularly), it could be triggered on explicit `workflow_dispatch` or on a specific label. In that case, it might make sense to amend it, in particular the tests for the new cases in `sak` could be dropped.
Opened upstream as 13526. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR makes it possible to build OCaml cross compilers without the various patches that all cross-compiler projects apply at the moment. It builds upon many previous PRs that have made this a lot simpler now than a couple of years ago.
Context
Recall that building a compiler involves 3 system types described by triplets:
build
: the machine on which the compiler is built, usually automatically detected by autoconf'sconfigure
host
: the machine on which the compiler will run,target
: the machine on which the code generated by the compiler will run.So when
build != host
, we are cross-compiling. Whenhost != target
, we are building a cross compiler. This PR tackles issues in that latter case, cross compilers.Currently, the only supported configurations are when
build ~ host = target
, where by~
I mean that the code generated forhost
runs onbuild
even when they differ (such as whenbuild
is Cygwin andhost
is Windows (MSVC or MinGW)).Even though this is not officially supported yet, many projects use OCaml cross compilers. All those projects generate a cross compiler by assuming a non-cross OCaml compiler is available in
PATH
(where “non-cross” means generating code that will run onbuild = host
).Summary
This PR proposes the following main improvements for building cross compilers.
host
andtarget
inconfigure
, where currently most tests abouthost
in fact mean to testtarget
.%ostype_*
primitives that were reporting the OS type of the host instead of the target.sak
about cross compilation between Unix and Windows and autodetect the C toolchain to build it if needed.make
targets:crossopt
to drive the build of the cross compiler andinstallcross
to drive its installation.Note that all the changes of this PR are transparent in the non-cross-compiler cases.
This PR comes with a CI workflow to help review the PR but not intended to be merged (at least, not as is). This CI workflow runs on x86 Linux and:
Sys.os_type
,Sys.unix
, etc.Sys.os_type
,Sys.unix
, etc.qemu-user
sak
cross compiling behavior (Unix to Windows and vice versa).How to test it
To build a cross compiler you first need to have a non-cross compiler of the same version installed in your
$PATH
. Note that they need to be of the same version since the cross compilers will contain the runtime of the non-cross compiler because the C toolchain that will be detected during theconfigure
for the OCaml cross compiler will be the C cross compiler totarget
.Build the non-cross compiler
It could be by creating an opam
trunk
switch or by building manually as usual. For instance,It may be useful to keep a note of the flags used to link with
zstd
, if any:Build the cross compiler
After cleaning the working directory, call
configure
with thetarget
triplet, possibly setting where the library will be installed on the target. So for instance, with the GCC MinGW cross compiler installed, it could be:Notes:
The cross compiler to Windows needs
flexdll
to link the binaries. A simple way to get it is to use theflexdll
submodule (git submodule update --init
if needed) and let thecrossopt
target bootstrapflexdll
.If
pkg-config --libs libzstd
doesn’t return the flags used to link the non-cross runtime, you can specify them with:Use the cross compiler
If you have built a cross compiler to a Unix target, you can simply run as usual:
If you have built a cross compiler to Windows on a Unix host, you must first make sure that
ocamlopt
can find theflexlink
executable in$PATH
when it needs to link. Boostrappingflexdll
builds aflexlink.exe
(note the.exe
), so you can:or any other possibility to make sure
flexlink
can be invoked.Overview of the commits
This PR is meant to be reviewed commit per commit.
$(EXE)
forstripdebug
invocationsruntime
directory only for ocamltestconfigure
to handle properly the cross-compiler casestarget
instead ofhost
to detect the C toolchaintarget
instead ofhost
when relevant in configuration{CC,...}_FOR_BUILD
to buildsak
flexlink
only on relevant targetsMakefile.cross
with the cross-compiler recipessak
in cross-compiler casessak
ostype_*
primitivesConfig
entry for the target OS type