meson
meson copied to clipboard
cc.get_define does not work when doing universal builds
Describe the bug
cc.get_define uses $CFLAGS with -E. That is not legal. You should only be using $CPPFLAGS when using $CC -E.
Using $CFLAGS causes configure to fail when building a fat binary, eg mesa does:
cc.get_define('ETIME', prefix : '#include <errno.h>')
We setup our CFLAGS and run meson, eg:
$ CFLAGS="-arch x86_64 -arch arm64" meson build/
but this fails with the following shown in the meson log:
Command line: cc /var/folders/99/yp4q7wrs6ts8mlgwy6njn6280000gn/T/tmpl8i1u1kl/testfile.c -pipe -E -P -arch x86_64 -arch arm64 -P -O0 -std=c11
Code:
#include <errno.h>
#ifndef ETIME
# define ETIME
#endif
"MESON_GET_DEFINE_DELIMITER"
ETIME
Compiler stdout:
Compiler stderr:
clang: error: cannot use 'cpp-output' output with multiple -arch options
system parameters
- Is this a cross build or just a plain native build (for the same computer)? Native
- what operating system? macOS 11
- what Python version? 3.8.7
- what
meson --version
? 0.55.3 - what
ninja --version
if it's a Ninja build ? 1.10.2
This is a really interesting issue, the basic problem here seems to be that we have no concept of a "fat" binary (when people were trying to pack x86 and x86_64 into a single elf container that's what they called it, not sure what you guys call it for mach-o). My understanding is that this is also common on AIX, so we probably want to solve it, not sure what that would look like.
@Ericson2314, this is the sort or problem you usually have good ideas about.
Yeah fat binaries, bootloaders written in different mode, cpuid checks for obscure extensions; these all lay waste to tones of assumptions.
As to CPPFLAGS, yes meson doesn't really recognize it as a separate concept, and I'm not sure whether changing that is a good thing.
I'm guessing multi-arch clang doesn't work with -E
because they do multiple CPP runs for each arch? I think one could still do an -E
that case by doing partial evaluation of the CPP. See https://github.com/ckaestne/TypeChef for some food for thought, for example. And then we would see whether the variable was defined under every configuration the model.
Getting those sorts of techniques into Clang and LLVM is a massive yak shave, but one that I think could bring even bigger benefits to the C/C++ world, so I throw it out there wistfully.
@jeremyhu: what happens if you pass two arch switches and an arch specific argument, say like -msse4_1
? Is clang smart enough to figure out that argument is only valid for the x86_64 code?
@jeremyhu: what happens if you pass two arch switches and an arch specific argument, say like
-msse4_1
? Is clang smart enough to figure out that argument is only valid for the x86_64 code?
Yes:
[1002] ~ $ clang -arch x86_64 -arch arm64 -msse4.1 true.c
[1003] ~ $ clang -arch arm64 -msse4.1 true.c
clang: warning: argument unused during compilation: '-msse4.1' [-Wunused-command-line-argument]
Is it sufficient to simply strip the -arch
options when we run the CPP tests, or will that have other consequences?
If we strip the -arch and there's a -target command line without a valid arch, that will cause problems. For example, I usually do:
-target fat-apple-macos10.9 -arch x86_64 -arch arm64
But that's easily worked around at my level by using:
-target x86_64-apple-macos10.9 -arch x86_64 -arch arm64
So that is probably OK.
On MacPorts we use your existing cross-file system, and set up one build for each arch, with cross-files for each arch we support. Then we lipo them together at the end.
This works for now, for us.
But if you made it work transparently such that cross-files were not needed, all the better.
for interest, here are the three cross-files we use so far (the PPC one I haven't set up yet).
We could flesh it out a bit more perhaps - it wants a 'strip' binary and probably a pkg-config library path set up as well. But these work for us.
We set up a folder for each build, just like Jeremy is doing in his workaround on Xquartz, configure each with these cross files and then lipo the results together at the end.
I added a small patch to meson to have it search /opt/local/share/meson/cross/
automatically for cross-files.
% cat /opt/local/share/meson/cross/arm64-darwin
[host_machine]
system = 'darwin'
cpu_family = 'aarch64'
cpu = 'arm64'
endian = 'little'
[binaries]
pkgconfig = '/opt/local/bin/pkg-config'
cmake = '/opt/local/bin/cmake'
% cat /opt/local/share/meson/cross/i386-darwin
[host_machine]
system = 'darwin'
cpu_family = 'x86'
cpu = 'i386'
endian = 'little'
[binaries]
pkgconfig = '/opt/local/bin/pkg-config'
cmake = '/opt/local/bin/cmake'
% cat /opt/local/share/meson/cross/x86_64-darwin
[host_machine]
system = 'darwin'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[binaries]
pkgconfig = '/opt/local/bin/pkg-config'
cmake = '/opt/local/bin/cmake'
with those cross files, building for arm64 on BigSur Intel, or vice versa, or for both i386 and x86_84 on machines of the 10.4 to 10.13 vintage, works nicely for us, so far.
See also #5290 for a similiar issue
for interest, here are the three cross-files we use so far (the PPC one I haven't set up yet).
Just to update, we have cross-files for ppc
and ppc64
now. That works, mostly. Some issues remain, like with gobject-introspection
on 10.5.8 (ppc+ppc64) and on 10.6.8 (ppc via Rosetta).
See for example: https://github.com/mesonbuild/meson/pull/10442 A suboptimal fix for Rosetta build: https://github.com/mesonbuild/meson/issues/10351#issuecomment-1131530681
In addition, cc.has_header()
always returns false with -arch x86_64 -arch arm64
, producing the same cannot use 'cpp-output' output with multiple -arch options
message in the log.