feat(toolchain): cross compile through target triples and sysroots

A triple is set with --target or a target field in the toolchain block, and
everything derived from it follows: platform, arch and the conditionals built
on them come from the triple rather than uname, so a build file can branch on
the platform it is building for instead of the one it is running on.

Tools are taken from the triple prefix when a matching toolchain is installed
(x86_64-w64-mingw32-gcc, -ar, -ranlib) and otherwise the host compiler is
invoked with --target, which covers clang without a prefixed toolchain. An
explicit cc, cxx, ar or ranlib in the build file always wins over the derived
one. --sysroot adds --sysroot to both the compile and link lines.

Each triple gets its own build directory and probe cache under builddir, so a
host tree and a cross tree do not invalidate each other and neither reruns the
other's checks. Probes never execute what they compile, sizeof included, so the
configure stage needed no changes to work against a foreign target.

Executables and shared libraries now take the extension the target platform
uses. Without that the graph expected bin/app while mingw wrote bin/app.exe,
and the link step repeated on every build.

Verified against x86_64-w64-mingw32, which produces a PE32+ binary, and
aarch64-linux-gnu through clang, which produces AArch64 objects.
This commit is contained in:
sneeker committed 2022-07-16 01:16:10 +00:00
1 parent 4eac7cd845
commit 38889de6e6
5 files changed
+120 -24

No files matched your search

+14 -3
View File
@@ -27,6 +27,8 @@ let usage =
" -C DIR change to DIR first";
" -D name=value set an option declared with 'option'";
" --prefix DIR install prefix (default /usr/local)";
" --target TRIPLE cross compile for TRIPLE (e.g. aarch64-linux-gnu)";
" --sysroot DIR sysroot to compile and link against";
" -k keep going after a failure";
" -n dry run, print what would happen";
" -v print each command as it finishes";
@@ -73,12 +75,14 @@ type flags = {
mutable dot : bool;
mutable targets_only : bool;
mutable interval : float;
mutable target : string;
mutable sysroot : string;
}
let fl =
{ file = "build.meow"; jobs = 0; chdir = ""; defs = []; prefix = None; keep = false;
dry = false; verbose = false; quiet = false; dot = false; targets_only = false;
interval = 0.25 }
interval = 0.25; target = ""; sysroot = "" }
let parse_args argv =
let rest = ref [] in
@@ -102,6 +106,8 @@ let parse_args argv =
fl.defs <- fl.defs @ [ (String.sub v 0 i, String.sub v (i + 1) (String.length v - i - 1)) ]);
go r
| "--prefix" :: v :: r -> fl.prefix <- Some v; go r
| "--target" :: v :: r -> fl.target <- v; go r
| "--sysroot" :: v :: r -> fl.sysroot <- v; go r
| "--interval" :: v :: r -> fl.interval <- (try float_of_string v with _ -> 0.25); go r
| "--dot" :: r -> fl.dot <- true; go r
| "--targets" :: r -> fl.targets_only <- true; go r
@@ -111,7 +117,8 @@ let parse_args argv =
| "-q" :: r -> fl.quiet <- true; go r
| "--no-color" :: r -> Style.enabled := false; go r
| ("-h" | "--help") :: _ -> print_endline usage; exit 0
| (("-f" | "-j" | "-C" | "-D" | "--prefix") as o) :: [] -> Diag.error "%s needs a value" o
| (("-f" | "-j" | "-C" | "-D" | "--prefix" | "--target" | "--sysroot") as o) :: [] ->
Diag.error "%s needs a value" o
| a :: r when String.length a > 2 && String.sub a 0 2 = "-j" ->
let v = String.sub a 2 (String.length a - 2) in
fl.jobs <- (try int_of_string v with _ -> Diag.error "-j wants a number, got %S" v);
@@ -144,7 +151,11 @@ let configure () =
Diag.error ~hint:"run 'meowc init <name>' to start one" "no %s here" fl.file;
let overrides = Hashtbl.create 8 in
List.iter (fun (k, v) -> Hashtbl.replace overrides k v) fl.defs;
let env = Eval.create ~overrides ~quiet:fl.quiet ~builddir:"build" in
let env = Eval.create ~overrides ~quiet:fl.quiet ~builddir:"build" ~target:fl.target in
if fl.sysroot <> "" then
Eval.apply_toolchain env
[ { Ast.key = "sysroot"; kspan = Span.none;
values = [ { Ast.text = fl.sysroot; span = Span.none; quoted = false } ] } ];
(match fl.prefix with Some p -> Eval.setvar env "prefix" [ p ] | None -> ());
let stmts = Parse.file fl.file in
Eval.run env (Filename.dirname fl.file) stmts;